http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/37dfe1a0/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/recurringdeposit/RecurringDepositProductHelper.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/recurringdeposit/RecurringDepositProductHelper.java
 
b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/recurringdeposit/RecurringDepositProductHelper.java
index 71a92f8..16dc1d2 100644
--- 
a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/recurringdeposit/RecurringDepositProductHelper.java
+++ 
b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/recurringdeposit/RecurringDepositProductHelper.java
@@ -25,6 +25,7 @@ import java.util.Map;
 
 import org.apache.fineract.integrationtests.common.Utils;
 import org.apache.fineract.integrationtests.common.accounting.Account;
+import 
org.apache.fineract.integrationtests.common.fixeddeposit.FixedDepositProductHelper;
 
 import com.google.gson.Gson;
 import com.jayway.restassured.specification.RequestSpecification;
@@ -95,47 +96,12 @@ public class RecurringDepositProductHelper {
     private final String minDepositAmount = "100";
     private final String maxDepositAmount = "1000000";
     private Account[] accountList = null;
+    private List<HashMap<String, String>> chartSlabs = null;
+    private boolean isPrimaryGroupingByAmount = false;
 
     public String build(final String validFrom, final String validTo) {
         final HashMap<String, Object> map = new HashMap<>();
 
-        List<HashMap<String, String>> chartSlabs = new 
ArrayList<HashMap<String, String>>();
-        HashMap<String, String> chartSlabsMap1 = new HashMap<>();
-        chartSlabsMap1.put("description", "First");
-        chartSlabsMap1.put("periodType", MONTHS);
-        chartSlabsMap1.put("fromPeriod", "1");
-        chartSlabsMap1.put("toPeriod", "6");
-        chartSlabsMap1.put("annualInterestRate", "5");
-        chartSlabsMap1.put("locale", LOCALE);
-        chartSlabs.add(0, chartSlabsMap1);
-
-        HashMap<String, String> chartSlabsMap2 = new HashMap<>();
-        chartSlabsMap2.put("description", "Second");
-        chartSlabsMap2.put("periodType", MONTHS);
-        chartSlabsMap2.put("fromPeriod", "7");
-        chartSlabsMap2.put("toPeriod", "12");
-        chartSlabsMap2.put("annualInterestRate", "6");
-        chartSlabsMap2.put("locale", LOCALE);
-        chartSlabs.add(1, chartSlabsMap2);
-
-        HashMap<String, String> chartSlabsMap3 = new HashMap<>();
-        chartSlabsMap3.put("description", "Third");
-        chartSlabsMap3.put("periodType", MONTHS);
-        chartSlabsMap3.put("fromPeriod", "13");
-        chartSlabsMap3.put("toPeriod", "18");
-        chartSlabsMap3.put("annualInterestRate", "7");
-        chartSlabsMap3.put("locale", LOCALE);
-        chartSlabs.add(2, chartSlabsMap3);
-
-        HashMap<String, String> chartSlabsMap4 = new HashMap<>();
-        chartSlabsMap4.put("description", "Fourth");
-        chartSlabsMap4.put("periodType", MONTHS);
-        chartSlabsMap4.put("fromPeriod", "19");
-        chartSlabsMap4.put("toPeriod", "24");
-        chartSlabsMap4.put("annualInterestRate", "8");
-        chartSlabsMap4.put("locale", LOCALE);
-        chartSlabs.add(3, chartSlabsMap4);
-
         List<HashMap<String, Object>> charts = new ArrayList<HashMap<String, 
Object>>();
         HashMap<String, Object> chartsMap = new HashMap<>();
         chartsMap.put("fromDate", validFrom);
@@ -143,6 +109,7 @@ public class RecurringDepositProductHelper {
         chartsMap.put("dateFormat", "dd MMMM yyyy");
         chartsMap.put("locale", LOCALE);
         chartsMap.put("chartSlabs", chartSlabs);
+        chartsMap.put("isPrimaryGroupingByAmount", 
this.isPrimaryGroupingByAmount);
         charts.add(chartsMap);
 
         map.put("charts", charts);
@@ -198,6 +165,26 @@ public class RecurringDepositProductHelper {
         return this;
     }
 
+    public RecurringDepositProductHelper withPeriodRangeChart() {
+        this.chartSlabs = constructChartSlabWithPeriodRange();
+        return this;
+    }
+
+    public RecurringDepositProductHelper withPeriodAndAmountRangeChart() {
+        this.chartSlabs = constructChartSlabWithPeriodAndAmountRange();
+        return this;
+    }
+
+    public RecurringDepositProductHelper withAmountRangeChart() {
+        this.chartSlabs = constructChartSlabWithAmountRange();
+        return this;
+    }
+
+    public RecurringDepositProductHelper withAmountAndPeriodRangeChart() {
+        this.chartSlabs = constructChartSlabWithAmountAndPeriodRange();
+        return this;
+    }
+
     private Map<String, String> getAccountMappingForCashBased() {
         final Map<String, String> map = new HashMap<>();
         if (accountList != null) {
@@ -256,4 +243,205 @@ public class RecurringDepositProductHelper {
         return response;
     }
 
+    public List<HashMap<String, String>> constructChartSlabWithPeriodRange() {
+        List<HashMap<String, String>> chartSlabs = new 
ArrayList<HashMap<String, String>>();
+        HashMap<String, String> chartSlabsMap1 = new HashMap<>();
+        chartSlabsMap1.put("description", "First");
+        chartSlabsMap1.put("periodType", MONTHS);
+        chartSlabsMap1.put("fromPeriod", "1");
+        chartSlabsMap1.put("toPeriod", "6");
+        chartSlabsMap1.put("annualInterestRate", "5");
+        chartSlabsMap1.put("locale", LOCALE);
+        chartSlabs.add(0, chartSlabsMap1);
+
+        HashMap<String, String> chartSlabsMap2 = new HashMap<>();
+        chartSlabsMap2.put("description", "Second");
+        chartSlabsMap2.put("periodType", MONTHS);
+        chartSlabsMap2.put("fromPeriod", "7");
+        chartSlabsMap2.put("toPeriod", "12");
+        chartSlabsMap2.put("annualInterestRate", "6");
+        chartSlabsMap2.put("locale", LOCALE);
+        chartSlabs.add(1, chartSlabsMap2);
+
+        HashMap<String, String> chartSlabsMap3 = new HashMap<>();
+        chartSlabsMap3.put("description", "Third");
+        chartSlabsMap3.put("periodType", MONTHS);
+        chartSlabsMap3.put("fromPeriod", "13");
+        chartSlabsMap3.put("toPeriod", "18");
+        chartSlabsMap3.put("annualInterestRate", "7");
+        chartSlabsMap3.put("locale", LOCALE);
+        chartSlabs.add(2, chartSlabsMap3);
+
+        HashMap<String, String> chartSlabsMap4 = new HashMap<>();
+        chartSlabsMap4.put("description", "Fourth");
+        chartSlabsMap4.put("periodType", MONTHS);
+        chartSlabsMap4.put("fromPeriod", "19");
+        chartSlabsMap4.put("annualInterestRate", "8");
+        chartSlabsMap4.put("locale", LOCALE);
+        chartSlabs.add(3, chartSlabsMap4);
+        return chartSlabs;
+    }
+
+    public List<HashMap<String, String>> 
constructChartSlabWithPeriodAndAmountRange() {
+        List<HashMap<String, String>> chartSlabs = new 
ArrayList<HashMap<String, String>>();
+        HashMap<String, String> chartSlabsMap1 = new HashMap<>();
+        chartSlabsMap1.put("description", "First");
+        chartSlabsMap1.put("periodType", MONTHS);
+        chartSlabsMap1.put("fromPeriod", "1");
+        chartSlabsMap1.put("toPeriod", "6");
+        chartSlabsMap1.put("amountRangeFrom", "1");
+        chartSlabsMap1.put("amountRangeTo", "5000");
+        chartSlabsMap1.put("annualInterestRate", "5");
+        chartSlabsMap1.put("locale", LOCALE);
+        chartSlabs.add(0, chartSlabsMap1);
+
+        HashMap<String, String> chartSlabsMap1_1 = new HashMap<>();
+        chartSlabsMap1_1.put("description", "First");
+        chartSlabsMap1_1.put("periodType", MONTHS);
+        chartSlabsMap1_1.put("fromPeriod", "1");
+        chartSlabsMap1_1.put("toPeriod", "6");
+        chartSlabsMap1_1.put("amountRangeFrom", "5001");
+        chartSlabsMap1_1.put("annualInterestRate", "6");
+        chartSlabsMap1_1.put("locale", LOCALE);
+        chartSlabs.add(0, chartSlabsMap1_1);
+
+        HashMap<String, String> chartSlabsMap2 = new HashMap<>();
+        chartSlabsMap2.put("description", "Second");
+        chartSlabsMap2.put("periodType", MONTHS);
+        chartSlabsMap2.put("fromPeriod", "7");
+        chartSlabsMap2.put("toPeriod", "12");
+        chartSlabsMap2.put("amountRangeFrom", "1");
+        chartSlabsMap2.put("amountRangeTo", "5000");
+        chartSlabsMap2.put("annualInterestRate", "6");
+        chartSlabsMap2.put("locale", LOCALE);
+        chartSlabs.add(1, chartSlabsMap2);
+
+        HashMap<String, String> chartSlabsMap2_2 = new HashMap<>();
+        chartSlabsMap2_2.put("description", "Second");
+        chartSlabsMap2_2.put("periodType", MONTHS);
+        chartSlabsMap2_2.put("fromPeriod", "7");
+        chartSlabsMap2_2.put("toPeriod", "12");
+        chartSlabsMap2_2.put("amountRangeFrom", "5001");
+        chartSlabsMap2_2.put("annualInterestRate", "7");
+        chartSlabsMap2_2.put("locale", LOCALE);
+        chartSlabs.add(1, chartSlabsMap2_2);
+
+        HashMap<String, String> chartSlabsMap3 = new HashMap<>();
+        chartSlabsMap3.put("description", "Third");
+        chartSlabsMap3.put("periodType", MONTHS);
+        chartSlabsMap3.put("fromPeriod", "13");
+        chartSlabsMap3.put("toPeriod", "18");
+        chartSlabsMap3.put("amountRangeFrom", "1");
+        chartSlabsMap3.put("amountRangeTo", "5000");
+        chartSlabsMap3.put("annualInterestRate", "7");
+        chartSlabsMap3.put("locale", LOCALE);
+        chartSlabs.add(2, chartSlabsMap3);
+
+        HashMap<String, String> chartSlabsMap3_1 = new HashMap<>();
+        chartSlabsMap3_1.put("description", "Third");
+        chartSlabsMap3_1.put("periodType", MONTHS);
+        chartSlabsMap3_1.put("fromPeriod", "13");
+        chartSlabsMap3_1.put("toPeriod", "18");
+        chartSlabsMap3_1.put("amountRangeFrom", "5001");
+        chartSlabsMap3_1.put("annualInterestRate", "8");
+        chartSlabsMap3_1.put("locale", LOCALE);
+        chartSlabs.add(2, chartSlabsMap3_1);
+
+        HashMap<String, String> chartSlabsMap4 = new HashMap<>();
+        chartSlabsMap4.put("description", "Fourth");
+        chartSlabsMap4.put("periodType", MONTHS);
+        chartSlabsMap4.put("fromPeriod", "19");
+        chartSlabsMap4.put("amountRangeFrom", "1");
+        chartSlabsMap4.put("amountRangeTo", "5000");
+        chartSlabsMap4.put("annualInterestRate", "8");
+        chartSlabsMap4.put("locale", LOCALE);
+        chartSlabs.add(3, chartSlabsMap4);
+
+        HashMap<String, String> chartSlabsMap4_1 = new HashMap<>();
+        chartSlabsMap4_1.put("description", "Fourth");
+        chartSlabsMap4_1.put("periodType", MONTHS);
+        chartSlabsMap4_1.put("fromPeriod", "19");
+        chartSlabsMap4_1.put("amountRangeFrom", "5001");
+        chartSlabsMap4_1.put("annualInterestRate", "9");
+        chartSlabsMap4_1.put("locale", LOCALE);
+        chartSlabs.add(3, chartSlabsMap4_1);
+
+        return chartSlabs;
+    }
+
+    public List<HashMap<String, String>> 
constructChartSlabWithAmountAndPeriodRange() {
+        this.isPrimaryGroupingByAmount = true;
+        List<HashMap<String, String>> chartSlabs = new 
ArrayList<HashMap<String, String>>();
+        HashMap<String, String> chartSlabsMap1 = new HashMap<>();
+        chartSlabsMap1.put("description", "First");
+        chartSlabsMap1.put("periodType", MONTHS);
+        chartSlabsMap1.put("amountRangeFrom", "1");
+        chartSlabsMap1.put("amountRangeTo", "5000");
+        chartSlabsMap1.put("fromPeriod", "1");
+        chartSlabsMap1.put("toPeriod", "6");
+        chartSlabsMap1.put("annualInterestRate", "5");
+        chartSlabsMap1.put("locale", LOCALE);
+        chartSlabs.add(0, chartSlabsMap1);
+
+        HashMap<String, String> chartSlabsMap2 = new HashMap<>();
+        chartSlabsMap2.put("description", "Second");
+        chartSlabsMap2.put("periodType", MONTHS);
+        chartSlabsMap2.put("fromPeriod", "7");
+        chartSlabsMap2.put("amountRangeFrom", "1");
+        chartSlabsMap2.put("amountRangeTo", "5000");
+        chartSlabsMap2.put("annualInterestRate", "6");
+        chartSlabsMap2.put("locale", LOCALE);
+        chartSlabs.add(1, chartSlabsMap2);
+
+        HashMap<String, String> chartSlabsMap3 = new HashMap<>();
+        chartSlabsMap3.put("description", "Third");
+        chartSlabsMap3.put("periodType", MONTHS);
+        chartSlabsMap3.put("fromPeriod", "1");
+        chartSlabsMap3.put("toPeriod", "6");
+        chartSlabsMap3.put("amountRangeFrom", "5001");
+        chartSlabsMap3.put("annualInterestRate", "7");
+        chartSlabsMap3.put("locale", LOCALE);
+        chartSlabs.add(2, chartSlabsMap3);
+
+        HashMap<String, String> chartSlabsMap4 = new HashMap<>();
+        chartSlabsMap4.put("description", "Fourth");
+        chartSlabsMap4.put("periodType", MONTHS);
+        chartSlabsMap4.put("fromPeriod", "7");
+        chartSlabsMap4.put("amountRangeFrom", "5001");
+        chartSlabsMap4.put("annualInterestRate", "8");
+        chartSlabsMap4.put("locale", LOCALE);
+        chartSlabs.add(3, chartSlabsMap4);
+
+        return chartSlabs;
+    }
+
+    public List<HashMap<String, String>> constructChartSlabWithAmountRange() {
+        this.isPrimaryGroupingByAmount = true;
+        List<HashMap<String, String>> chartSlabs = new 
ArrayList<HashMap<String, String>>();
+        HashMap<String, String> chartSlabsMap1 = new HashMap<>();
+        chartSlabsMap1.put("description", "First");
+        chartSlabsMap1.put("amountRangeFrom", "1");
+        chartSlabsMap1.put("amountRangeTo", "5000");
+        chartSlabsMap1.put("annualInterestRate", "5");
+        chartSlabsMap1.put("locale", LOCALE);
+        chartSlabs.add(0, chartSlabsMap1);
+
+        HashMap<String, String> chartSlabsMap3 = new HashMap<>();
+        chartSlabsMap3.put("description", "Third");
+        chartSlabsMap3.put("amountRangeFrom", "5001");
+        chartSlabsMap3.put("amountRangeTo", "10000");
+        chartSlabsMap3.put("annualInterestRate", "7");
+        chartSlabsMap3.put("locale", LOCALE);
+        chartSlabs.add(1, chartSlabsMap3);
+
+        HashMap<String, String> chartSlabsMap4 = new HashMap<>();
+        chartSlabsMap4.put("description", "Fourth");
+        chartSlabsMap4.put("amountRangeFrom", "10001");
+        chartSlabsMap4.put("annualInterestRate", "8");
+        chartSlabsMap4.put("locale", LOCALE);
+        chartSlabs.add(2, chartSlabsMap4);
+
+        return chartSlabs;
+    }
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/37dfe1a0/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/Calendar.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/Calendar.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/Calendar.java
index 98e8096..52d072d 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/Calendar.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/calendar/domain/Calendar.java
@@ -142,7 +142,12 @@ public class Calendar extends 
AbstractAuditableCustom<AppUser, Long> {
 
     public static Calendar createRepeatingCalendar(final String title, final 
LocalDate startDate, final Integer typeId,
             final CalendarFrequencyType frequencyType, final Integer interval, 
final Integer repeatsOnDay) {
+        final String recurrence = constructRecurrence(frequencyType, interval, 
repeatsOnDay);
+        return createRepeatingCalendar(title, startDate, typeId, recurrence);
+    }
 
+    public static Calendar createRepeatingCalendar(final String title, final 
LocalDate startDate, final Integer typeId,
+            final String recurrence) {
         final String description = null;
         final String location = null;
         final LocalDate endDate = null;
@@ -151,8 +156,6 @@ public class Calendar extends 
AbstractAuditableCustom<AppUser, Long> {
         final Integer remindById = null;
         final Integer firstReminder = null;
         final Integer secondReminder = null;
-        final String recurrence = constructRecurrence(frequencyType, interval, 
repeatsOnDay);
-
         return new Calendar(title, description, location, startDate, endDate, 
duration, typeId, repeating, recurrence, remindById,
                 firstReminder, secondReminder);
     }
@@ -233,7 +236,7 @@ public class Calendar extends 
AbstractAuditableCustom<AppUser, Long> {
 
     }
 
-    public Map<String, Object> update(final JsonCommand command, final Boolean 
areActiveEntitiesSynced ) {
+    public Map<String, Object> update(final JsonCommand command, final Boolean 
areActiveEntitiesSynced) {
 
         final Map<String, Object> actualChanges = new LinkedHashMap<>(9);
 
@@ -345,7 +348,7 @@ public class Calendar extends 
AbstractAuditableCustom<AppUser, Long> {
              * calendar then do not allow to change meeting frequency
              */
 
-            if ( areActiveEntitiesSynced && 
!CalendarUtils.isFrequencySame(this.recurrence, newRecurrence)) {
+            if (areActiveEntitiesSynced && 
!CalendarUtils.isFrequencySame(this.recurrence, newRecurrence)) {
                 final String defaultUserMessage = "Update of meeting frequency 
is not supported";
                 throw new 
CalendarParameterUpdateNotSupportedException("meeting.frequency", 
defaultUserMessage);
             }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/37dfe1a0/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/InterestRateChartApiConstants.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/InterestRateChartApiConstants.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/InterestRateChartApiConstants.java
index 7bce4ee..20f760b 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/InterestRateChartApiConstants.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/InterestRateChartApiConstants.java
@@ -44,6 +44,7 @@ public class InterestRateChartApiConstants {
     public static final String endDateParamName = "endDate";
     public static final String productIdParamName = "productId";
     public static final String productNameParamName = "productName";
+    public static final String isPrimaryGroupingByAmountParamName = 
"isPrimaryGroupingByAmount";
 
     // interest rate chart Slabs parameters
 //    public static final String periodTypeParamName = "periodType";
@@ -63,13 +64,14 @@ public class InterestRateChartApiConstants {
     public static final String deleteParamName = "delete";
 
     public static final Set<String> 
INTERESTRATE_CHART_CREATE_REQUEST_DATA_PARAMETERS = new 
HashSet<>(Arrays.asList(localeParamName,
-            dateFormatParamName, nameParamName, descriptionParamName, 
fromDateParamName, endDateParamName, productIdParamName,
-            chartSlabs));
+            dateFormatParamName, nameParamName, descriptionParamName, 
fromDateParamName, endDateParamName, productIdParamName, chartSlabs,
+            isPrimaryGroupingByAmountParamName));
 
     public static final Set<String> 
INTERESTRATE_CHART_UPDATE_REQUEST_DATA_PARAMETERS = new 
HashSet<>(Arrays.asList(localeParamName,
             dateFormatParamName, idParamName, nameParamName, 
descriptionParamName, fromDateParamName, endDateParamName, chartSlabs,
-            deleteParamName));
+            deleteParamName, isPrimaryGroupingByAmountParamName));
 
     public static final Set<String> 
INTERESTRATE_CHART_RESPONSE_DATA_PARAMETERS = new 
HashSet<>(Arrays.asList(localeParamName,
-            dateFormatParamName, idParamName, nameParamName, 
descriptionParamName, fromDateParamName, endDateParamName, chartSlabs));
+            dateFormatParamName, idParamName, nameParamName, 
descriptionParamName, fromDateParamName, endDateParamName, chartSlabs,
+            isPrimaryGroupingByAmountParamName));
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/37dfe1a0/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartData.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartData.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartData.java
index f7aef96..1b31287 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartData.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartData.java
@@ -18,9 +18,8 @@
  */
 package org.apache.fineract.portfolio.interestratechart.data;
 
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
 
 import org.apache.fineract.infrastructure.codes.data.CodeValueData;
 import org.apache.fineract.infrastructure.core.data.EnumOptionData;
@@ -38,9 +37,10 @@ public class InterestRateChartData {
     private final LocalDate endDate;
     private final Long productId;
     private final String productName;
+    private final boolean isPrimaryGroupingByAmount;
 
     // associations
-    private Set<InterestRateChartSlabData> chartSlabs;
+    private Collection<InterestRateChartSlabData> chartSlabs;
 
     // template
     private final Collection<EnumOptionData> periodTypes;
@@ -53,9 +53,9 @@ public class InterestRateChartData {
     private final Collection<CodeValueData> clientClassificationOptions;
 
     public static InterestRateChartData instance(Long id, String name, String 
description, LocalDate fromDate, LocalDate endDate,
-            Long savingsProductId, String savingsProductName) {
+            boolean isPrimaryGroupingByAmount, Long savingsProductId, String 
savingsProductName) {
         Collection<EnumOptionData> periodTypes = null;
-        Set<InterestRateChartSlabData> chartSlabs = null;
+        Collection<InterestRateChartSlabData> chartSlabs = null;
         final Collection<EnumOptionData> entityTypeOptions = null;
         final Collection<EnumOptionData> attributeNameOptions = null;
         final Collection<EnumOptionData> conditionTypeOptions = null;
@@ -63,17 +63,18 @@ public class InterestRateChartData {
         final Collection<CodeValueData> genderOptions = null;
         final Collection<CodeValueData> clientTypeOptions = null;
         final Collection<CodeValueData> clientClassificationOptions = null;
-        return new InterestRateChartData(id, name, description, fromDate, 
endDate, savingsProductId, savingsProductName, chartSlabs,
-                periodTypes, entityTypeOptions, attributeNameOptions, 
conditionTypeOptions, incentiveTypeOptions, genderOptions,
-                clientTypeOptions, clientClassificationOptions);
+        return new InterestRateChartData(id, name, description, fromDate, 
endDate, isPrimaryGroupingByAmount, savingsProductId,
+                savingsProductName, chartSlabs, periodTypes, 
entityTypeOptions, attributeNameOptions, conditionTypeOptions,
+                incentiveTypeOptions, genderOptions, clientTypeOptions, 
clientClassificationOptions);
     }
 
-    public static InterestRateChartData withSlabs(InterestRateChartData 
interestRateChartData, Set<InterestRateChartSlabData> chartSlabs) {
+    public static InterestRateChartData withSlabs(InterestRateChartData 
interestRateChartData, Collection<InterestRateChartSlabData> chartSlabs) {
         return new InterestRateChartData(interestRateChartData.id, 
interestRateChartData.name, interestRateChartData.description,
-                interestRateChartData.fromDate, interestRateChartData.endDate, 
interestRateChartData.productId,
-                interestRateChartData.productName, chartSlabs, 
interestRateChartData.periodTypes, interestRateChartData.entityTypeOptions,
-                interestRateChartData.attributeNameOptions, 
interestRateChartData.conditionTypeOptions,
-                interestRateChartData.incentiveTypeOptions, 
interestRateChartData.genderOptions, interestRateChartData.clientTypeOptions,
+                interestRateChartData.fromDate, interestRateChartData.endDate, 
interestRateChartData.isPrimaryGroupingByAmount,
+                interestRateChartData.productId, 
interestRateChartData.productName, chartSlabs, 
interestRateChartData.periodTypes,
+                interestRateChartData.entityTypeOptions, 
interestRateChartData.attributeNameOptions,
+                interestRateChartData.conditionTypeOptions, 
interestRateChartData.incentiveTypeOptions,
+                interestRateChartData.genderOptions, 
interestRateChartData.clientTypeOptions,
                 interestRateChartData.clientClassificationOptions);
     }
 
@@ -83,9 +84,10 @@ public class InterestRateChartData {
             final Collection<CodeValueData> genderOptions, final 
Collection<CodeValueData> clientTypeOptions,
             final Collection<CodeValueData> clientClassificationOptions) {
         return new InterestRateChartData(interestRateChartData.id, 
interestRateChartData.name, interestRateChartData.description,
-                interestRateChartData.fromDate, interestRateChartData.endDate, 
interestRateChartData.productId,
-                interestRateChartData.productName, 
interestRateChartData.chartSlabs, periodTypes, entityTypeOptions, 
attributeNameOptions,
-                conditionTypeOptions, incentiveTypeOptions, genderOptions, 
clientTypeOptions, clientClassificationOptions);
+                interestRateChartData.fromDate, interestRateChartData.endDate, 
interestRateChartData.isPrimaryGroupingByAmount,
+                interestRateChartData.productId, 
interestRateChartData.productName, interestRateChartData.chartSlabs, 
periodTypes,
+                entityTypeOptions, attributeNameOptions, conditionTypeOptions, 
incentiveTypeOptions, genderOptions, clientTypeOptions,
+                clientClassificationOptions);
     }
 
     public static InterestRateChartData template(Collection<EnumOptionData> 
periodTypes,
@@ -98,26 +100,28 @@ public class InterestRateChartData {
         final String description = null;
         final LocalDate fromDate = null;
         final LocalDate endDate = null;
+        final boolean isPrimaryGroupingByAmount = false;
         final Long savingsProductId = null;
         final String savingsProductName = null;
-        final Set<InterestRateChartSlabData> chartSlabs = null;
+        final Collection<InterestRateChartSlabData> chartSlabs = null;
 
-        return new InterestRateChartData(id, name, description, fromDate, 
endDate, savingsProductId, savingsProductName, chartSlabs,
-                periodTypes, entityTypeOptions, attributeNameOptions, 
conditionTypeOptions, incentiveTypeOptions, genderOptions,
-                clientTypeOptions, clientClassificationOptions);
+        return new InterestRateChartData(id, name, description, fromDate, 
endDate, isPrimaryGroupingByAmount, savingsProductId,
+                savingsProductName, chartSlabs, periodTypes, 
entityTypeOptions, attributeNameOptions, conditionTypeOptions,
+                incentiveTypeOptions, genderOptions, clientTypeOptions, 
clientClassificationOptions);
     }
 
-    private InterestRateChartData(Long id, String name, String description, 
LocalDate fromDate, LocalDate endDate, Long savingsProductId,
-            String savingsProductName, Set<InterestRateChartSlabData> 
chartSlabs, Collection<EnumOptionData> periodTypes,
-            final Collection<EnumOptionData> entityTypeOptions, final 
Collection<EnumOptionData> attributeNameOptions,
-            final Collection<EnumOptionData> conditionTypeOptions, final 
Collection<EnumOptionData> incentiveTypeOptions,
-            final Collection<CodeValueData> genderOptions, final 
Collection<CodeValueData> clientTypeOptions,
-            final Collection<CodeValueData> clientClassificationOptions) {
+    private InterestRateChartData(Long id, String name, String description, 
LocalDate fromDate, LocalDate endDate,
+            boolean isPrimaryGroupingByAmount, Long savingsProductId, String 
savingsProductName, Collection<InterestRateChartSlabData> chartSlabs,
+            Collection<EnumOptionData> periodTypes, final 
Collection<EnumOptionData> entityTypeOptions,
+            final Collection<EnumOptionData> attributeNameOptions, final 
Collection<EnumOptionData> conditionTypeOptions,
+            final Collection<EnumOptionData> incentiveTypeOptions, final 
Collection<CodeValueData> genderOptions,
+            final Collection<CodeValueData> clientTypeOptions, final 
Collection<CodeValueData> clientClassificationOptions) {
         this.id = id;
         this.name = name;
         this.description = description;
         this.fromDate = fromDate;
         this.endDate = endDate;
+        this.isPrimaryGroupingByAmount = isPrimaryGroupingByAmount;
         this.chartSlabs = chartSlabs;
         this.productId = savingsProductId;
         this.productName = savingsProductName;
@@ -133,7 +137,7 @@ public class InterestRateChartData {
 
     public void addChartSlab(final InterestRateChartSlabData chartSlab) {
         if (this.chartSlabs == null) {
-            this.chartSlabs = new HashSet<>();
+            this.chartSlabs = new ArrayList<>();
         }
 
         this.chartSlabs.add(chartSlab);
@@ -159,7 +163,7 @@ public class InterestRateChartData {
         return this.description;
     }
 
-    public Set<InterestRateChartSlabData> chartSlabs() {
+    public Collection<InterestRateChartSlabData> chartSlabs() {
         return this.chartSlabs;
     }
 
@@ -195,4 +199,9 @@ public class InterestRateChartData {
         return this.clientClassificationOptions;
     }
 
+    
+    public boolean isPrimaryGroupingByAmount() {
+        return this.isPrimaryGroupingByAmount;
+    }
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/37dfe1a0/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartDataValidator.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartDataValidator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartDataValidator.java
index 04c4d22..a325175 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartDataValidator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartDataValidator.java
@@ -26,6 +26,7 @@ import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartA
 import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.endDateParamName;
 import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.fromDateParamName;
 import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.idParamName;
+import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.isPrimaryGroupingByAmountParamName;
 import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.nameParamName;
 import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.productIdParamName;
 
@@ -98,6 +99,11 @@ public class InterestRateChartDataValidator {
             toDate = 
this.fromApiJsonHelper.extractLocalDateNamed(endDateParamName, element);
             
baseDataValidator.reset().parameter(endDateParamName).value(toDate).notNull();
         }
+        
+        Boolean isPrimaryGroupingByAmount = 
this.fromApiJsonHelper.extractBooleanNamed(isPrimaryGroupingByAmountParamName, 
element);
+        if (isPrimaryGroupingByAmount == null) {
+            isPrimaryGroupingByAmount = false;
+        }
 
         if (fromDate != null && toDate != null) {
             if (fromDate.isAfter(toDate)) {
@@ -106,7 +112,7 @@ public class InterestRateChartDataValidator {
         }
 
         // validate chart Slabs
-        validateChartSlabs(element, baseDataValidator);
+        validateChartSlabs(element, baseDataValidator, 
isPrimaryGroupingByAmount);
     }
 
     public void validateUpdate(final String json) {
@@ -151,6 +157,11 @@ public class InterestRateChartDataValidator {
             toDate = 
this.fromApiJsonHelper.extractLocalDateNamed(endDateParamName, element);
             
baseDataValidator.reset().parameter(endDateParamName).value(toDate).notNull();
         }
+        
+        Boolean isPrimaryGroupingByAmount = 
this.fromApiJsonHelper.extractBooleanNamed(isPrimaryGroupingByAmountParamName, 
element);
+        if (isPrimaryGroupingByAmount == null) {
+            isPrimaryGroupingByAmount = false;
+        }
 
         if (fromDate != null && toDate != null) {
             if (fromDate.isAfter(toDate)) {
@@ -158,7 +169,7 @@ public class InterestRateChartDataValidator {
             }
         }
 
-        validateChartSlabs(element, baseDataValidator);
+        validateChartSlabs(element, baseDataValidator, 
isPrimaryGroupingByAmount);
 
     }
 
@@ -166,7 +177,7 @@ public class InterestRateChartDataValidator {
         if (!dataValidationErrors.isEmpty()) { throw new 
PlatformApiDataValidationException(dataValidationErrors); }
     }
 
-    private void validateChartSlabs(JsonElement element, DataValidatorBuilder 
baseDataValidator) {
+    private void validateChartSlabs(JsonElement element, DataValidatorBuilder 
baseDataValidator,final boolean isPrimaryGroupingByAmount) {
 
         if (element.isJsonObject()) {
             final JsonObject topLevelJsonElement = element.getAsJsonObject();
@@ -178,9 +189,9 @@ public class InterestRateChartDataValidator {
                     if (this.fromApiJsonHelper.parameterExists(idParamName, 
interstRateChartElement)) {
                         final Long id = 
this.fromApiJsonHelper.extractLongNamed(idParamName, interstRateChartElement);
                         
baseDataValidator.reset().parameter(idParamName).value(id).notNull().integerGreaterThanZero();
-                        
this.chartSlabDataValidator.validateChartSlabsUpdate(interstRateChartElement, 
baseDataValidator, locale);
+                        
this.chartSlabDataValidator.validateChartSlabsUpdate(interstRateChartElement, 
baseDataValidator, locale, isPrimaryGroupingByAmount);
                     } else {
-                        
this.chartSlabDataValidator.validateChartSlabsCreate(interstRateChartElement, 
baseDataValidator, locale);
+                        
this.chartSlabDataValidator.validateChartSlabsCreate(interstRateChartElement, 
baseDataValidator, locale, isPrimaryGroupingByAmount);
                     }
                 }
             }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/37dfe1a0/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartSlabDataValidator.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartSlabDataValidator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartSlabDataValidator.java
index 45b0ba4..fa7f26a 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartSlabDataValidator.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/data/InterestRateChartSlabDataValidator.java
@@ -84,12 +84,14 @@ public class InterestRateChartSlabDataValidator {
         final String currencyCode = 
this.fromApiJsonHelper.extractStringNamed(currencyCodeParamName, element);
         
baseDataValidator.reset().parameter(currencyCodeParamName).value(currencyCode).notBlank().notExceedingLengthOf(3);
 
-        validateChartSlabsCreate(element, baseDataValidator, locale);
+        final Boolean isPrimaryGroupingByAmount = null;
+        validateChartSlabsCreate(element, baseDataValidator, locale, 
isPrimaryGroupingByAmount);
 
         throwExceptionIfValidationWarningsExist(dataValidationErrors);
     }
 
-    public void validateChartSlabsCreate(final JsonElement element, final 
DataValidatorBuilder baseDataValidator, final Locale locale) {
+    public void validateChartSlabsCreate(final JsonElement element, final 
DataValidatorBuilder baseDataValidator, final Locale locale,
+            final Boolean isPrimaryGroupingByAmount) {
 
         if (this.fromApiJsonHelper.parameterExists(descriptionParamName, 
element)) {
             final String description = 
this.fromApiJsonHelper.extractStringNamed(descriptionParamName, element);
@@ -97,17 +99,25 @@ public class InterestRateChartSlabDataValidator {
         }
 
         final Integer periodType = 
this.fromApiJsonHelper.extractIntegerNamed(periodTypeParamName, element, 
locale);
-        
baseDataValidator.reset().parameter(periodTypeParamName).value(periodType).notNull()
-                .isOneOfTheseValues(PeriodFrequencyType.integerValues());
-
+        if (this.fromApiJsonHelper.parameterExists(periodTypeParamName, 
element)) {
+            
baseDataValidator.reset().parameter(periodTypeParamName).value(periodType)
+                    .isOneOfTheseValues(PeriodFrequencyType.integerValues());
+        }
         Integer toPeriod = null;
 
         final Integer fromPeriod = 
this.fromApiJsonHelper.extractIntegerNamed(fromPeriodParamName, element, 
locale);
-        
baseDataValidator.reset().parameter(fromPeriodParamName).value(fromPeriod).notNull().integerZeroOrGreater();
+        if (this.fromApiJsonHelper.parameterExists(fromPeriodParamName, 
element)) {
+            
baseDataValidator.reset().parameter(fromPeriodParamName).value(fromPeriod).integerZeroOrGreater();
+        }
+
+        if ((isPrimaryGroupingByAmount != null && !isPrimaryGroupingByAmount) 
|| (periodType != null || fromPeriod != null)) {
+            
baseDataValidator.reset().parameter(periodTypeParamName).value(periodType).notNull();
+            
baseDataValidator.reset().parameter(fromPeriodParamName).value(fromPeriod).notNull();
+        }
 
         if (this.fromApiJsonHelper.parameterExists(toPeriodParamName, 
element)) {
             toPeriod = 
this.fromApiJsonHelper.extractIntegerNamed(toPeriodParamName, element, locale);
-            
baseDataValidator.reset().parameter(toPeriodParamName).value(toPeriod).notNull().integerZeroOrGreater();
+            
baseDataValidator.reset().parameter(toPeriodParamName).value(toPeriod).integerGreaterThanZero();
         }
 
         if (fromPeriod != null && toPeriod != null) {
@@ -115,21 +125,26 @@ public class InterestRateChartSlabDataValidator {
                 
baseDataValidator.parameter(fromPeriodParamName).value(fromPeriod).failWithCode("fromperiod.greater.than.to.period");
             }
         }
-        BigDecimal amountRangeFrom = null;
-        BigDecimal amountRangeTo = null;
+        final BigDecimal amountRangeFrom = 
this.fromApiJsonHelper.extractBigDecimalNamed(amountRangeFromParamName, 
element, locale);
+        final BigDecimal amountRangeTo = 
this.fromApiJsonHelper.extractBigDecimalNamed(amountRangeToParamName, element, 
locale);
         if (this.fromApiJsonHelper.parameterExists(amountRangeFromParamName, 
element)) {
-            amountRangeFrom = 
this.fromApiJsonHelper.extractBigDecimalNamed(amountRangeFromParamName, 
element, locale);
-            
baseDataValidator.reset().parameter(amountRangeFromParamName).value(amountRangeFrom).notNull().positiveAmount();
+            
baseDataValidator.reset().parameter(amountRangeFromParamName).value(amountRangeFrom).zeroOrPositiveAmount();
+            if (isPrimaryGroupingByAmount != null && 
isPrimaryGroupingByAmount) {
+                
baseDataValidator.reset().parameter(amountRangeFromParamName).value(amountRangeFrom).notNull();
+            }
         }
 
         if (this.fromApiJsonHelper.parameterExists(amountRangeToParamName, 
element)) {
-            amountRangeTo = 
this.fromApiJsonHelper.extractBigDecimalNamed(amountRangeToParamName, element, 
locale);
-            
baseDataValidator.reset().parameter(amountRangeToParamName).value(amountRangeTo).notNull().positiveAmount();
+            
baseDataValidator.reset().parameter(amountRangeToParamName).value(amountRangeTo).positiveAmount();
+        }
+
+        if (amountRangeFrom == null && fromPeriod == null) {
+            
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("fromperiod.or.amountRangeFrom.required");
         }
 
         if (amountRangeFrom != null && amountRangeTo != null) {
             if (amountRangeFrom.compareTo(amountRangeTo) > 1) {
-                
baseDataValidator.parameter(fromPeriodParamName).value(fromPeriod).failWithCode("fromperiod.greater.than.toperiod");
+                
baseDataValidator.parameter(amountRangeFromParamName).value(fromPeriod).failWithCode("from.amount.greater.than.to.amount");
             }
         }
 
@@ -152,12 +167,14 @@ public class InterestRateChartSlabDataValidator {
         final JsonElement element = this.fromApiJsonHelper.parse(json);
         final JsonObject objectElement = element.getAsJsonObject();
         final Locale locale = 
this.fromApiJsonHelper.extractLocaleParameter(objectElement);
-        validateChartSlabsUpdate(element, baseDataValidator, locale);
+        final Boolean isPrimaryGroupingByAmount = null;
+        validateChartSlabsUpdate(element, baseDataValidator, locale, 
isPrimaryGroupingByAmount);
 
         throwExceptionIfValidationWarningsExist(dataValidationErrors);
     }
 
-    public void validateChartSlabsUpdate(final JsonElement element, final 
DataValidatorBuilder baseDataValidator, final Locale locale) {
+    public void validateChartSlabsUpdate(final JsonElement element, final 
DataValidatorBuilder baseDataValidator, final Locale locale,
+            final Boolean isPrimaryGroupingByAmount) {
 
         if (this.fromApiJsonHelper.parameterExists(descriptionParamName, 
element)) {
             final String description = 
this.fromApiJsonHelper.extractStringNamed(descriptionParamName, element);
@@ -166,8 +183,12 @@ public class InterestRateChartSlabDataValidator {
 
         if (this.fromApiJsonHelper.parameterExists(periodTypeParamName, 
element)) {
             final Integer periodType = 
this.fromApiJsonHelper.extractIntegerNamed(periodTypeParamName, element, 
locale);
-            
baseDataValidator.reset().parameter(periodTypeParamName).value(periodType).notNull()
+            
baseDataValidator.reset().parameter(periodTypeParamName).value(periodType)
                     .isOneOfTheseValues(PeriodFrequencyType.integerValues());
+            if (isPrimaryGroupingByAmount != null && 
!isPrimaryGroupingByAmount) {
+                
baseDataValidator.reset().parameter(periodTypeParamName).value(periodType).notNull();
+            }
+
         }
 
         Integer fromPeriod = null;
@@ -175,12 +196,15 @@ public class InterestRateChartSlabDataValidator {
 
         if (this.fromApiJsonHelper.parameterExists(fromPeriodParamName, 
element)) {
             fromPeriod = 
this.fromApiJsonHelper.extractIntegerNamed(fromPeriodParamName, element, 
locale);
-            
baseDataValidator.reset().parameter(fromPeriodParamName).value(fromPeriod).notNull().integerGreaterThanNumber(-1);
+            
baseDataValidator.reset().parameter(fromPeriodParamName).value(fromPeriod).integerZeroOrGreater();
+            if (isPrimaryGroupingByAmount != null && 
!isPrimaryGroupingByAmount) {
+                
baseDataValidator.reset().parameter(fromPeriodParamName).value(fromPeriod).notNull();
+            }
         }
 
         if (this.fromApiJsonHelper.parameterExists(toPeriodParamName, 
element)) {
             toPeriod = 
this.fromApiJsonHelper.extractIntegerNamed(toPeriodParamName, element, locale);
-            
baseDataValidator.reset().parameter(toPeriodParamName).value(toPeriod).notNull().integerGreaterThanNumber(-1);
+            
baseDataValidator.reset().parameter(toPeriodParamName).value(toPeriod).integerGreaterThanZero();
         }
 
         if (fromPeriod != null && toPeriod != null) {
@@ -192,12 +216,15 @@ public class InterestRateChartSlabDataValidator {
         BigDecimal amountRangeTo = null;
         if (this.fromApiJsonHelper.parameterExists(amountRangeFromParamName, 
element)) {
             amountRangeFrom = 
this.fromApiJsonHelper.extractBigDecimalNamed(amountRangeFromParamName, 
element, locale);
-            
baseDataValidator.reset().parameter(amountRangeFromParamName).value(amountRangeFrom).notNull().positiveAmount();
+            
baseDataValidator.reset().parameter(amountRangeFromParamName).value(amountRangeFrom).zeroOrPositiveAmount();
+            if (isPrimaryGroupingByAmount != null && 
isPrimaryGroupingByAmount) {
+                
baseDataValidator.reset().parameter(amountRangeFromParamName).value(amountRangeFrom).notNull();
+            }
         }
 
         if (this.fromApiJsonHelper.parameterExists(amountRangeToParamName, 
element)) {
             amountRangeTo = 
this.fromApiJsonHelper.extractBigDecimalNamed(amountRangeToParamName, element, 
locale);
-            
baseDataValidator.reset().parameter(amountRangeToParamName).value(amountRangeTo).notNull().positiveAmount();
+            
baseDataValidator.reset().parameter(amountRangeToParamName).value(amountRangeTo).positiveAmount();
         }
 
         if (amountRangeFrom != null && amountRangeTo != null) {

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/37dfe1a0/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChart.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChart.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChart.java
index 428acb3..3537106 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChart.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChart.java
@@ -51,6 +51,7 @@ import 
org.apache.fineract.infrastructure.core.data.ApiParameterError;
 import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
 import 
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
 import 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants;
+import 
org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants;
 import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType;
 import org.joda.time.LocalDate;
 import org.springframework.data.jpa.domain.AbstractPersistable;
@@ -82,12 +83,11 @@ public class InterestRateChart extends 
AbstractPersistable<Long> {
         final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
         final DataValidatorBuilder baseDataValidator = new 
DataValidatorBuilder(dataValidationErrors)
                 .resource(INTERESTRATE_CHART_RESOURCE_NAME);
-
+        this.chartFields = chartFields;
         // validate before setting the other fields
         this.validateChartSlabs(baseDataValidator);
         this.throwExceptionIfValidationWarningsExist(dataValidationErrors);
 
-        this.chartFields = chartFields;
         this.addChartSlabs(interestRateChartSlabs);
 
     }
@@ -97,22 +97,85 @@ public class InterestRateChart extends 
AbstractPersistable<Long> {
 
         Integer tmpPeriodType = null;
         List<InterestRateChartSlab> chartSlabsList = new 
ArrayList<>(chartSlabs);
+        boolean isPrimaryGroupingByAmount = 
this.chartFields.isPrimaryGroupingByAmount();
+        chartSlabsList.sort(new 
InterestRateChartSlabComparator<InterestRateChartSlab>(isPrimaryGroupingByAmount));
+        boolean isPeriodChart = !isPrimaryGroupingByAmount;
+        boolean isAmountChart = isPrimaryGroupingByAmount;
 
         for (int i = 0; i < chartSlabsList.size(); i++) {
             InterestRateChartSlab iSlabs = chartSlabsList.get(i);
-            if (tmpPeriodType == null) {
+            if (!iSlabs.slabFields().isValidChart(isPrimaryGroupingByAmount)) {
+                if (isPrimaryGroupingByAmount) {
+                    
baseDataValidator.parameter(InterestRateChartSlabApiConstants.amountRangeFromParamName).failWithCode("cannot.be.blank");
+                } else {
+                    
baseDataValidator.parameter(InterestRateChartSlabApiConstants.fromPeriodParamName).failWithCode("cannot.be.blank");
+                }
+
+            } else if (i > 0) {
+                if (isPeriodChart ^ iSlabs.slabFields().fromPeriod() != null) {
+                    
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.period.range.incomplete");
+                    isPeriodChart = isPeriodChart || 
iSlabs.slabFields().fromPeriod() != null;
+                }
+                if (isAmountChart ^ iSlabs.slabFields().getAmountRangeFrom() 
!= null) {
+                    
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.amount.range.incomplete");
+                    isAmountChart = isAmountChart || 
iSlabs.slabFields().getAmountRangeFrom() != null;
+                }
+            }
+
+            if (i == 0) {
                 tmpPeriodType = iSlabs.slabFields().periodType();
-            } else if 
(!iSlabs.slabFields().periodType().equals(tmpPeriodType)) {
+                if (iSlabs.slabFields().isNotProperChartStart()) {
+                    
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.range.start.incorrect",
 iSlabs.slabFields()
+                            .fromPeriod(), 
iSlabs.slabFields().getAmountRangeFrom());
+                }
+                isAmountChart = isAmountChart || 
iSlabs.slabFields().getAmountRangeFrom() != null;
+                isPeriodChart = isPeriodChart || 
iSlabs.slabFields().fromPeriod() != null;
+            } else if (iSlabs.slabFields().periodType() != null && 
!iSlabs.slabFields().periodType().equals(tmpPeriodType)) {
                 
baseDataValidator.parameter(periodTypeParamName).value(iSlabs.slabFields().periodType())
                         .failWithCode("period.type.is.not.same", 
tmpPeriodType);
             }
-            for (int j = i + 1; j < chartSlabsList.size(); j++) {
-                InterestRateChartSlab jSlabs = chartSlabsList.get(j);
-                if 
(iSlabs.slabFields().isPeriodOverlapping(jSlabs.slabFields())) {
-                    baseDataValidator
-                            
.failWithCodeNoParameterAddedToErrorCode("chart.slabs.period.overlapping", 
iSlabs.slabFields().fromPeriod(),
-                                    iSlabs.slabFields().toPeriod(), 
jSlabs.slabFields().fromPeriod(), jSlabs.slabFields().toPeriod());
+            if (i + 1 < chartSlabsList.size()) {
+                InterestRateChartSlab nextSlabs = chartSlabsList.get(i + 1);
+                if (iSlabs.slabFields().isValidChart(isPrimaryGroupingByAmount)
+                        && 
nextSlabs.slabFields().isValidChart(isPrimaryGroupingByAmount)) {
+                    if 
(iSlabs.slabFields().isRateChartOverlapping(nextSlabs.slabFields(), 
isPrimaryGroupingByAmount)) {
+                        
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.range.overlapping",
 iSlabs.slabFields()
+                                .fromPeriod(), iSlabs.slabFields().toPeriod(), 
nextSlabs.slabFields().fromPeriod(), nextSlabs.slabFields()
+                                .toPeriod(), 
iSlabs.slabFields().getAmountRangeFrom(), 
iSlabs.slabFields().getAmountRangeTo(), nextSlabs
+                                .slabFields().getAmountRangeFrom(), 
nextSlabs.slabFields().getAmountRangeTo());
+                    } else if 
(iSlabs.slabFields().isRateChartHasGap(nextSlabs.slabFields(), 
isPrimaryGroupingByAmount)) {
+                        
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.range.has.gap",
 iSlabs.slabFields()
+                                .fromPeriod(), iSlabs.slabFields().toPeriod(), 
nextSlabs.slabFields().fromPeriod(), nextSlabs.slabFields()
+                                .toPeriod(), 
iSlabs.slabFields().getAmountRangeFrom(), 
iSlabs.slabFields().getAmountRangeTo(), nextSlabs
+                                .slabFields().getAmountRangeFrom(), 
nextSlabs.slabFields().getAmountRangeTo());
+                    }
+                    if (isPrimaryGroupingByAmount) {
+                        if 
(!iSlabs.slabFields().isAmountSame(nextSlabs.slabFields())) {
+                            if 
(InterestRateChartSlabFields.isNotProperPeriodStart(nextSlabs.slabFields())) {
+                                
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.period.range.start.incorrect",
+                                        nextSlabs.slabFields().toPeriod());
+                            }
+                            if (iSlabs.slabFields().toPeriod() != null) {
+                                
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.period.range.end.incorrect",
 iSlabs
+                                        .slabFields().toPeriod());
+                            }
+
+                        }
+                    } else if 
(!iSlabs.slabFields().isPeriodsSame(nextSlabs.slabFields())) {
+                        if 
(InterestRateChartSlabFields.isNotProperAmountStart(nextSlabs.slabFields())) {
+                            
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.amount.range.start.incorrect",
 nextSlabs
+                                    .slabFields().getAmountRangeFrom());
+                        }
+                        if (iSlabs.slabFields().getAmountRangeTo() != null) {
+                            
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.amount.range.end.incorrect",
 iSlabs
+                                    .slabFields().getAmountRangeTo());
+                        }
+
+                    }
                 }
+            } else if (iSlabs.slabFields().isNotProperPriodEnd()) {
+                
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("chart.slabs.range.end.incorrect",
+                        iSlabs.slabFields().toPeriod(), 
iSlabs.slabFields().getAmountRangeTo());
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/37dfe1a0/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChartFields.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChartFields.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChartFields.java
index ca1f1b0..2b7b7a8 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChartFields.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChartFields.java
@@ -24,6 +24,7 @@ import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartA
 import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.fromDateParamName;
 import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.localeParamName;
 import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.nameParamName;
+import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.isPrimaryGroupingByAmountParamName;
 
 import java.util.Date;
 import java.util.Map;
@@ -56,19 +57,24 @@ public class InterestRateChartFields {
     @Column(name = "end_date", nullable = false)
     private Date endDate;
 
+    @Column(name = "is_primary_grouping_by_amount", nullable = false)
+    private boolean isPrimaryGroupingByAmount;
+
     protected InterestRateChartFields() {
         //
     }
 
-    public static InterestRateChartFields createNew(String name, String 
description, LocalDate fromDate, LocalDate toDate) {
-        return new InterestRateChartFields(name, description, fromDate, 
toDate);
+    public static InterestRateChartFields createNew(String name, String 
description, LocalDate fromDate, LocalDate toDate,
+            boolean isPrimaryGroupingByAmount) {
+        return new InterestRateChartFields(name, description, fromDate, 
toDate, isPrimaryGroupingByAmount);
     }
 
-    private InterestRateChartFields(String name, String description, LocalDate 
fromDate, LocalDate toDate) {
+    private InterestRateChartFields(String name, String description, LocalDate 
fromDate, LocalDate toDate, boolean isPrimaryGroupingByAmount) {
         this.name = name;
         this.description = description;
         this.fromDate = fromDate.toDate();
         this.endDate = (toDate == null) ? null : toDate.toDate();
+        this.isPrimaryGroupingByAmount = isPrimaryGroupingByAmount;
     }
 
     public void update(JsonCommand command, final Map<String, Object> 
actualChanges, final DataValidatorBuilder baseDataValidator) {
@@ -106,6 +112,12 @@ public class InterestRateChartFields {
             this.endDate = newValue.toDate();
         }
 
+        if 
(command.isChangeInBooleanParameterNamed(isPrimaryGroupingByAmountParamName, 
this.isPrimaryGroupingByAmount)) {
+            final boolean newValue = 
command.booleanPrimitiveValueOfParameterNamed(isPrimaryGroupingByAmountParamName);
+            actualChanges.put(isPrimaryGroupingByAmountParamName, newValue);
+            this.isPrimaryGroupingByAmount = newValue;
+        }
+
         if (isFromDateAfterToDate()) {
             
baseDataValidator.parameter(fromDateParamName).value(fromDate).failWithCode("from.date.is.after.to.date");
         }
@@ -144,20 +156,22 @@ public class InterestRateChartFields {
         final LocalDate thatFromDate = that.getFromDateAsLocalDate();
         LocalDate thatEndDate = that.getEndDateAsLocalDate();
         thatEndDate = thatEndDate == null ? DateUtils.getLocalDateOfTenant() : 
thatEndDate;
-        
+
         final LocalDateInterval thisInterval = 
LocalDateInterval.create(thisFromDate, thisEndDate);
         final LocalDateInterval thatInterval = 
LocalDateInterval.create(thatFromDate, thatEndDate);
-        
-        if(thisInterval.containsPortionOf(thatInterval) || 
thatInterval.containsPortionOf(thisInterval)){
-            return true;
-        }
+
+        if (thisInterval.containsPortionOf(thatInterval) || 
thatInterval.containsPortionOf(thisInterval)) { return true; }
         return false;// no overlapping
     }
-    
-    public boolean isApplicableChartFor(final LocalDate target){
+
+    public boolean isApplicableChartFor(final LocalDate target) {
         final LocalDate endDate = this.endDate == null ? 
DateUtils.getLocalDateOfTenant() : this.getEndDateAsLocalDate();
         final LocalDateInterval interval = 
LocalDateInterval.create(getFromDateAsLocalDate(), endDate);
         return interval.contains(target);
     }
 
+    public boolean isPrimaryGroupingByAmount() {
+        return this.isPrimaryGroupingByAmount;
+    }
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/37dfe1a0/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChartSlabComparator.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChartSlabComparator.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChartSlabComparator.java
new file mode 100644
index 0000000..19f4147
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChartSlabComparator.java
@@ -0,0 +1,92 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.interestratechart.domain;
+
+import java.math.BigDecimal;
+import java.util.Comparator;
+
+import 
org.apache.fineract.portfolio.savings.domain.DepositAccountInterestRateChartSlabs;
+
+/**
+ * Sort InterestRateChartSlab by input range 
+ */
+public class InterestRateChartSlabComparator<T> implements Comparator<T> {
+
+    private final boolean isPrimaryGroupingByAmount;
+
+    public InterestRateChartSlabComparator(final boolean 
isPrimaryGroupingByAmount) {
+        this.isPrimaryGroupingByAmount = isPrimaryGroupingByAmount;
+    }
+
+    @Override
+    public int compare(final T o1, final T o2) {
+        int compareResult = 0;
+        InterestRateChartSlabFields slabs1 = null;
+        InterestRateChartSlabFields slabs2 = null;
+        if (o1 instanceof InterestRateChartSlab) {
+            slabs1 = ((InterestRateChartSlab) o1).slabFields();
+            slabs2 = ((InterestRateChartSlab) o2).slabFields();
+        } else if (o1 instanceof DepositAccountInterestRateChartSlabs) {
+            slabs1 = ((DepositAccountInterestRateChartSlabs) o1).slabFields();
+            slabs2 = ((DepositAccountInterestRateChartSlabs) o2).slabFields();
+        } else {
+            return compareResult;
+        }
+
+        if (slabs1.isPeriodsSame(slabs2) && slabs1.isAmountSame(slabs2)) {
+            compareResult = 0;
+        } else {
+            if (isPrimaryGroupingByAmount) {
+                if (slabs1.isAmountSame(slabs2)) {
+                    compareResult = comparePeriods(slabs1, slabs2);
+                } else {
+                    compareResult = compareAmounts(slabs1, slabs2);
+                }
+            } else {
+                if (slabs1.isPeriodsSame(slabs2)) {
+                    compareResult = compareAmounts(slabs1, slabs2);
+                } else {
+                    compareResult = comparePeriods(slabs1, slabs2);
+                }
+            }
+        }
+        return compareResult;
+    }
+
+    private int comparePeriods(final InterestRateChartSlabFields slabs1, 
InterestRateChartSlabFields slabs2) {
+        int compareResult = 0;
+        Integer periodFrom1 = slabs1.fromPeriod();
+        Integer periodFrom2 = slabs2.fromPeriod();
+        if (periodFrom1 != null && periodFrom2 != null) {
+            compareResult = periodFrom1.compareTo(periodFrom2);
+        }
+        return compareResult;
+    }
+
+    private int compareAmounts(final InterestRateChartSlabFields slabs1, 
InterestRateChartSlabFields slabs2) {
+        int compareResult = 0;
+        BigDecimal amountFrom1 = slabs1.getAmountRangeFrom();
+        BigDecimal amountFrom2 = slabs2.getAmountRangeFrom();
+        if (amountFrom1 != null && amountFrom2 != null) {
+            compareResult = amountFrom1.compareTo(amountFrom2);
+        }
+        return compareResult;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/37dfe1a0/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChartSlabFields.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChartSlabFields.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChartSlabFields.java
index 334772c..b8c00de 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChartSlabFields.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/domain/InterestRateChartSlabFields.java
@@ -51,15 +51,23 @@ public class InterestRateChartSlabFields {
     @Column(name = "period_type_enum", nullable = false)
     private Integer periodType;
 
-    @Column(name = "from_period", nullable = false)
+    @Column(name = "from_period")
     private Integer fromPeriod;
 
-    @Column(name = "to_period", nullable = true)
+    @Column(name = "to_period")
     private Integer toPeriod;
 
     @Column(name = "amount_range_from", scale = 6, precision = 19)
     private BigDecimal amountRangeFrom;
 
+    public BigDecimal getAmountRangeFrom() {
+        return this.amountRangeFrom;
+    }
+
+    public BigDecimal getAmountRangeTo() {
+        return this.amountRangeTo;
+    }
+
     @Column(name = "amount_range_to", scale = 6, precision = 19)
     private BigDecimal amountRangeTo;
 
@@ -84,7 +92,7 @@ public class InterestRateChartSlabFields {
             final Integer fromPeriod, final Integer toPeriod, final BigDecimal 
amountRangeFrom, final BigDecimal amountRangeTo,
             final BigDecimal annualInterestRate, final String currencyCode) {
         this.description = description;
-        this.periodType = (periodFrequencyType == null) ? null : 
periodFrequencyType.getValue();
+        this.periodType = (periodFrequencyType == null || 
periodFrequencyType.isInvalid()) ? null : periodFrequencyType.getValue();
         this.fromPeriod = fromPeriod;
         this.toPeriod = toPeriod;
         this.amountRangeFrom = amountRangeFrom;
@@ -183,17 +191,129 @@ public class InterestRateChartSlabFields {
         return this.toPeriod;
     }
 
-    public boolean isPeriodOverlapping(final InterestRateChartSlabFields that) 
{
-        if (that.toPeriod == null) {
-            if (this.toPeriod == null) { return true; }
-            return that.fromPeriod <= this.toPeriod;
+    public boolean isRateChartHasGap(final InterestRateChartSlabFields that, 
final boolean isPrimaryGroupingByAmount) {
+        boolean isPeriodSame = isPeriodsSame(that);
+        boolean isAmountSame = isAmountSame(that);
+        boolean hasPeriods = this.fromPeriod != null || that.fromPeriod != 
null;
+        boolean hasAmounts = this.amountRangeFrom != null || 
that.amountRangeFrom != null;
+        if (isPrimaryGroupingByAmount) {
+            if (isAmountSame) {
+                if (hasPeriods) {
+                    if (this.toPeriod == null) { return true; }
+                    return isNotProperPeriodStart(that.fromPeriod);
+                }
+            } else {
+                return isNotProperAmountStart(that.amountRangeFrom) || 
isNotProperPeriodStart(that);
+            }
+        } else {
+            if (isPeriodSame) {
+                if (hasAmounts) {
+                    if (this.amountRangeTo == null) { return true; }
+                    return isNotProperAmountStart(that.amountRangeFrom);
+                }
+            } else {
+                return isNotProperPeriodStart(that.fromPeriod) || 
isNotProperAmountStart(that);
+            }
+        }
+        return false;
+    }
+
+    public boolean isValidChart(boolean isPrimaryGroupingByAmount) {
+        return (!isPrimaryGroupingByAmount && this.fromPeriod != null) || 
(isPrimaryGroupingByAmount && this.amountRangeFrom != null);
+    }
+
+    public boolean isNotProperChartStart() {
+        return isNotProperPeriodStart(this) || isNotProperAmountStart(this);
+    }
+
+    public static boolean isNotProperAmountStart(final 
InterestRateChartSlabFields interestRateChartSlabFields) {
+        return interestRateChartSlabFields.amountRangeFrom != null
+                && 
(interestRateChartSlabFields.amountRangeFrom.compareTo(BigDecimal.ONE) != 0 && 
interestRateChartSlabFields.amountRangeFrom
+                        .compareTo(BigDecimal.ZERO) != 0);
+    }
+
+    private boolean isNotProperAmountStart(final BigDecimal amount) {
+        return this.amountRangeTo == null || (amount != null && 
amount.compareTo(this.amountRangeTo.add(BigDecimal.ONE)) != 0);
+    }
+
+    private boolean isNotProperPeriodStart(final Integer period) {
+        return this.toPeriod == null || (period != null && 
period.compareTo(this.toPeriod + 1) != 0);
+    }
+
+    public static boolean isNotProperPeriodStart(InterestRateChartSlabFields 
interestRateChartSlabFields) {
+        return interestRateChartSlabFields.fromPeriod != null
+                && !(interestRateChartSlabFields.fromPeriod.equals(1) || 
interestRateChartSlabFields.fromPeriod.equals(0));
+    }
+
+    public boolean isNotProperPriodEnd() {
+        return !(this.toPeriod == null && this.amountRangeTo == null);
+
+    }
+
+    public boolean isRateChartOverlapping(final InterestRateChartSlabFields 
that, final boolean isPrimaryGroupingByAmount) {
+        boolean isPeriodOverLapping = isPeriodOverlapping(that);
+        boolean isAmountOverLapping = isAmountOverlapping(that);
+        boolean isPeriodSame = isPeriodsSame(that);
+        boolean isAmountSame = isAmountSame(that);
+        boolean isOverlapping = false;
+        if (isPrimaryGroupingByAmount) {
+            isOverlapping = (isAmountOverLapping && !isAmountSame) || 
(isPeriodOverLapping && isAmountSame);
+        } else {
+            isOverlapping = (isPeriodOverLapping && !isPeriodSame) || 
(isAmountOverLapping && isPeriodSame);
         }
+
+        return isOverlapping;
+    }
+
+    private boolean isPeriodOverlapping(final InterestRateChartSlabFields 
that) {
+        if (isIntegerSame(that.toPeriod, this.toPeriod)) {
+            return true;
+        } else if (isIntegerSame(that.fromPeriod, this.fromPeriod)) {
+            return true;
+        } else if (this.toPeriod == null) {
+            return true;
+        } else if (that.toPeriod == null) { return that.fromPeriod <= 
this.toPeriod; }
         return this.fromPeriod <= that.toPeriod && that.fromPeriod <= 
this.toPeriod;
     }
 
+    private boolean isAmountOverlapping(final InterestRateChartSlabFields 
that) {
+        if (isBigDecimalSame(that.amountRangeFrom, this.amountRangeFrom)) {
+            return true;
+        } else if (isBigDecimalSame(that.amountRangeTo, this.amountRangeTo)) {
+            return true;
+        } else if (this.amountRangeTo == null) {
+            return true;
+        } else if (that.amountRangeTo == null) { return 
that.amountRangeFrom.compareTo(this.amountRangeTo) < 1; }
+        return this.amountRangeFrom.compareTo(that.amountRangeTo) < 1 && 
that.amountRangeFrom.compareTo(this.amountRangeTo) < 1;
+    }
+
+    public boolean isAmountSame(final InterestRateChartSlabFields that) {
+        return isBigDecimalSame(this.amountRangeFrom, that.amountRangeFrom) && 
isBigDecimalSame(this.amountRangeTo, that.amountRangeTo);
+    }
+
+    public boolean isPeriodsSame(final InterestRateChartSlabFields that) {
+        return isIntegerSame(this.fromPeriod, that.fromPeriod) && 
isIntegerSame(this.toPeriod, that.toPeriod);
+    }
+
+    public boolean isIntegerSame(final Integer obj1, final Integer obj2) {
+        if (obj1 == null || obj2 == null) {
+            if (obj1 == obj2) { return true; }
+            return false;
+        }
+        return obj1.equals(obj2);
+    }
+
+    public boolean isBigDecimalSame(final BigDecimal obj1, final BigDecimal 
obj2) {
+        if (obj1 == null || obj2 == null) {
+            if (obj1 == obj2) { return true; }
+            return false;
+        }
+        return obj1.compareTo(obj2) == 0;
+    }
+
     public boolean isBetweenPeriod(final LocalDate periodStartDate, final 
LocalDate periodEndDate) {
         final Integer compare = depositPeriod(periodStartDate, periodEndDate);
-        return (compare < this.fromPeriod || (this.toPeriod != null && compare 
> this.toPeriod)) ? false : true;
+        return isPeriodBetween(compare);
     }
 
     public boolean isAmountRangeProvided() {
@@ -233,8 +353,16 @@ public class InterestRateChartSlabFields {
             returnValue = depositAmount.compareTo(amountRangeFrom) >= 0 && 
depositAmount.compareTo(amountRangeTo) <= 0;
         } else if (amountRangeFrom != null) {
             returnValue = depositAmount.compareTo(amountRangeFrom) >= 0;
-        } else if (amountRangeTo != null) {
-            returnValue = depositAmount.compareTo(amountRangeTo) <= 0;
+        }
+        return returnValue;
+    }
+
+    public boolean isPeriodBetween(final Integer periods) {
+        boolean returnValue = true;
+        if (fromPeriod != null && toPeriod != null) {
+            returnValue = periods.compareTo(fromPeriod) >= 0 && 
periods.compareTo(toPeriod) <= 0;
+        } else if (fromPeriod != null) {
+            returnValue = periods.compareTo(fromPeriod) >= 0;
         }
         return returnValue;
     }

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/37dfe1a0/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/service/InterestRateChartAssembler.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/service/InterestRateChartAssembler.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/service/InterestRateChartAssembler.java
index a2a65db..a7f29e3 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/service/InterestRateChartAssembler.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/service/InterestRateChartAssembler.java
@@ -22,6 +22,7 @@ import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartA
 import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.descriptionParamName;
 import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.endDateParamName;
 import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.fromDateParamName;
+import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.isPrimaryGroupingByAmountParamName;
 import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartApiConstants.nameParamName;
 import static 
org.apache.fineract.portfolio.interestratechart.InterestRateChartSlabApiConstants.currencyCodeParamName;
 
@@ -65,33 +66,38 @@ public class InterestRateChartAssembler {
      * request
      */
     public InterestRateChart assembleFrom(final JsonCommand command) {
-
-        final JsonElement element = command.parsedJson();
         final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
-        @SuppressWarnings("unused")
         final DataValidatorBuilder baseDataValidator = new 
DataValidatorBuilder(dataValidationErrors)
                 .resource(INTERESTRATE_CHART_RESOURCE_NAME);
+        final JsonElement element = command.parsedJson();
         final String currencyCode = 
this.fromApiJsonHelper.extractStringNamed(currencyCodeParamName, element);
-        final InterestRateChart newChart = this.assembleFrom(element, 
currencyCode);
-
+        final InterestRateChart newChart = this.assembleFrom(element, 
currencyCode, baseDataValidator);
         throwExceptionIfValidationWarningsExist(dataValidationErrors);
         return newChart;
     }
 
-    public InterestRateChart assembleFrom(final JsonElement element, final 
String currencyCode) {
+    private void throwExceptionIfValidationWarningsExist(final 
List<ApiParameterError> dataValidationErrors) {
+        if (!dataValidationErrors.isEmpty()) { throw new 
PlatformApiDataValidationException(dataValidationErrors); }
+    }
+
+    public InterestRateChart assembleFrom(final JsonElement element, final 
String currencyCode, final DataValidatorBuilder baseDataValidator) {
 
         final String name = 
this.fromApiJsonHelper.extractStringNamed(nameParamName, element);
         final String description = 
this.fromApiJsonHelper.extractStringNamed(descriptionParamName, element);
         final LocalDate fromDate = 
this.fromApiJsonHelper.extractLocalDateNamed(fromDateParamName, element);
         final LocalDate toDate = 
this.fromApiJsonHelper.extractLocalDateNamed(endDateParamName, element);
-        
+        Boolean isPrimaryGroupingByAmount = 
this.fromApiJsonHelper.extractBooleanNamed(isPrimaryGroupingByAmountParamName, 
element);
+        if (isPrimaryGroupingByAmount == null) {
+            isPrimaryGroupingByAmount = false;
+        }
 
         // assemble chart Slabs
-        final Collection<InterestRateChartSlab> newChartSlabs = 
this.chartSlabAssembler.assembleChartSlabsFrom(element,
-                currencyCode);
+        final Collection<InterestRateChartSlab> newChartSlabs = 
this.chartSlabAssembler.assembleChartSlabsFrom(element, currencyCode);
 
-        final InterestRateChartFields fields = 
InterestRateChartFields.createNew(name, description, fromDate, toDate);
+        final InterestRateChartFields fields = 
InterestRateChartFields.createNew(name, description, fromDate, toDate,
+                isPrimaryGroupingByAmount);
         final InterestRateChart newChart = InterestRateChart.createNew(fields, 
newChartSlabs);
+        newChart.validateChartSlabs(baseDataValidator);
         return newChart;
     }
 
@@ -100,8 +106,4 @@ public class InterestRateChartAssembler {
                 .findOneWithNotFoundDetection(interestRateChartId);
         return interestRateChart;
     }
-
-    private void throwExceptionIfValidationWarningsExist(final 
List<ApiParameterError> dataValidationErrors) {
-        if (!dataValidationErrors.isEmpty()) { throw new 
PlatformApiDataValidationException(dataValidationErrors); }
-    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/37dfe1a0/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/service/InterestRateChartReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/service/InterestRateChartReadPlatformServiceImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/service/InterestRateChartReadPlatformServiceImpl.java
index 86eefad..d03e502 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/service/InterestRateChartReadPlatformServiceImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/interestratechart/service/InterestRateChartReadPlatformServiceImpl.java
@@ -86,8 +86,21 @@ public class InterestRateChartReadPlatformServiceImpl 
implements InterestRateCha
     @Override
     public Collection<InterestRateChartData> retrieveAllWithSlabs(Long 
productId) {
         this.context.authenticatedUser();
-        String sql = "select " + this.chartExtractor.schema() + " where sp.id 
= ? order by irc.id, ircd.id";
-        return this.jdbcTemplate.query(sql, this.chartExtractor, new Object[] 
{ productId });
+        StringBuilder sql = new StringBuilder();
+        sql.append("select ");
+        sql.append(this.chartExtractor.schema());
+        sql.append(" where sp.id = ? order by irc.id, ");
+        sql.append("CASE ");
+        sql.append("WHEN isPrimaryGroupingByAmount then ircd.amount_range_from 
");
+        sql.append("WHEN isPrimaryGroupingByAmount then ircd.amount_range_to 
");
+        sql.append("END,");
+        sql.append("ircd.from_period, ircd.to_period,");
+        sql.append("CASE ");
+        sql.append("WHEN !isPrimaryGroupingByAmount then 
ircd.amount_range_from ");
+        sql.append("WHEN !isPrimaryGroupingByAmount then ircd.amount_range_to 
");
+        sql.append("END");
+        
+        return this.jdbcTemplate.query(sql.toString(), this.chartExtractor, 
new Object[] { productId });
     }
 
     @Override
@@ -177,6 +190,7 @@ public class InterestRateChartReadPlatformServiceImpl 
implements InterestRateCha
             sqlBuilder
                     .append("irc.id as ircId, irc.name as ircName, 
irc.description as ircDescription,")
                     .append("irc.from_date as ircFromDate, irc.end_date as 
ircEndDate, ")
+                    .append("irc.is_primary_grouping_by_amount as 
isPrimaryGroupingByAmount, ")
                     .append("ircd.id as ircdId, ircd.description as 
ircdDescription, ircd.period_type_enum ircdPeriodTypeId, ")
                     .append("ircd.from_period as ircdFromPeriod, 
ircd.to_period as ircdToPeriod, ircd.amount_range_from as ircdAmountRangeFrom, 
")
                     .append("ircd.amount_range_to as ircdAmountRangeTo, 
ircd.annual_interest_rate as ircdAnnualInterestRate, ")
@@ -239,6 +253,7 @@ public class InterestRateChartReadPlatformServiceImpl 
implements InterestRateCha
 
             sqlBuilder.append("irc.id as ircId, irc.name as ircName, 
irc.description as ircDescription, ")
                     .append("irc.from_date as ircFromDate, irc.end_date as 
ircEndDate, ")
+                    .append("irc.is_primary_grouping_by_amount as 
isPrimaryGroupingByAmount, ")
                     .append("sp.id as savingsProductId, sp.name as 
savingsProductName ").append("from ")
                     .append("m_interest_rate_chart irc ")
                     .append("left join m_deposit_product_interest_rate_chart 
dpirc on irc.id=dpirc.interest_rate_chart_id ")
@@ -253,10 +268,11 @@ public class InterestRateChartReadPlatformServiceImpl 
implements InterestRateCha
             final String description = rs.getString("ircDescription");
             final LocalDate fromDate = JdbcSupport.getLocalDate(rs, 
"ircFromDate");
             final LocalDate endDate = JdbcSupport.getLocalDate(rs, 
"ircEndDate");
+            final boolean isPrimaryGroupingByAmount = 
rs.getBoolean("isPrimaryGroupingByAmount");
             final Long savingsProductId = 
JdbcSupport.getLongDefaultToNullIfZero(rs, "savingsProductId");
             final String savingsProductName = 
rs.getString("savingsProductName");
 
-            return InterestRateChartData.instance(id, name, description, 
fromDate, endDate, savingsProductId, savingsProductName);
+            return InterestRateChartData.instance(id, name, description, 
fromDate, endDate, isPrimaryGroupingByAmount, savingsProductId, 
savingsProductName);
         }
 
     }
@@ -299,7 +315,10 @@ public class InterestRateChartReadPlatformServiceImpl 
implements InterestRateCha
             final Integer fromPeriod = JdbcSupport.getInteger(rs, 
"ircdFromPeriod");
             final Integer toPeriod = JdbcSupport.getInteger(rs, 
"ircdToPeriod");
             final Integer periodTypeId = JdbcSupport.getInteger(rs, 
"ircdPeriodTypeId");
-            final EnumOptionData periodType = 
InterestRateChartEnumerations.periodType(periodTypeId);
+            EnumOptionData periodType = null;
+            if (periodTypeId != null) {
+                periodType = 
InterestRateChartEnumerations.periodType(periodTypeId);
+            }
             final BigDecimal amountRangeFrom = 
rs.getBigDecimal("ircdAmountRangeFrom");
             final BigDecimal amountRangeTo = 
rs.getBigDecimal("ircdAmountRangeTo");
             final BigDecimal annualInterestRate = 
rs.getBigDecimal("ircdAnnualInterestRate");

Reply via email to