Index: F:/CURRENT DEV/Mifos Workspace/mifos/test/org/mifos/application/accounts/loan/business/TestLoanBO.java
===================================================================
--- F:/CURRENT DEV/Mifos Workspace/mifos/test/org/mifos/application/accounts/loan/business/TestLoanBO.java	(revision 12276)
+++ F:/CURRENT DEV/Mifos Workspace/mifos/test/org/mifos/application/accounts/loan/business/TestLoanBO.java	(working copy)
@@ -5337,7 +5337,7 @@
 				.getOriginalPrincipal());
 
 	}
-
+	
 	public void testCreateLoanAccountWithDecliningInterestPrincipalDueOnLastInstallment()
 			throws NumberFormatException, PropertyNotFoundException,
 			SystemException, ApplicationException {
@@ -5398,6 +5398,244 @@
 
 	}
 
+
+	public void testCreateLoanAccountWithEqualPrincipalDecliningInterestNoGracePeriod()
+			throws NumberFormatException, PropertyNotFoundException,
+			SystemException, ApplicationException {
+		Date startDate = new Date(System.currentTimeMillis());
+
+		MeetingBO meeting = TestObjectFactory.createMeeting(TestObjectFactory
+				.getNewMeetingForToday(WEEKLY, EVERY_SECOND_WEEK,
+						CUSTOMER_MEETING));
+		center = TestObjectFactory.createCenter("Center", meeting);
+		group = TestObjectFactory.createGroupUnderCenter("Group",
+				CustomerStatus.GROUP_ACTIVE, center);
+		LoanOfferingBO loanOffering = TestObjectFactory.createLoanOffering(
+				"Loan", "L", ApplicableTo.GROUPS, startDate,
+				PrdStatus.LOAN_ACTIVE, 300.0, 1.2, (short) 3,
+				InterestType.DECLINING_EPI, false, false, center
+						.getCustomerMeeting().getMeeting(), GraceType.NONE,
+				"1", "1");
+		loanOffering.updateLoanOfferingSameForAllLoan(loanOffering);
+		List<FeeView> feeViewList = new ArrayList<FeeView>();
+
+		accountBO = LoanBO.createLoan(TestUtils.makeUser(), loanOffering,
+				group, AccountState.LOAN_ACTIVE_IN_GOOD_STANDING, new Money(
+						"300.0"), Short.valueOf("6"), startDate, false, // 6
+				// installments
+				1.2, (short) 0, new FundBO(), feeViewList, null);
+		new TestObjectPersistence().persist(accountBO);
+		assertEquals(6, accountBO.getAccountActionDates().size());
+
+		HashMap fees0 = new HashMap();
+
+		Set<AccountActionDateEntity> actionDateEntities = ((LoanBO) accountBO)
+				.getAccountActionDates();
+		LoanScheduleEntity[] paymentsArray = getSortedAccountActionDateEntity(actionDateEntities);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 1), "50.9", "0.1",
+				fees0, paymentsArray[0]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 2), "50.9", "0.1",
+				fees0, paymentsArray[1]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 3), "50.9", "0.1",
+				fees0, paymentsArray[2]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 4), "50.9", "0.1",
+				fees0, paymentsArray[3]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 5), "50.0", "0.0",
+				fees0, paymentsArray[4]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 6), "46.4", "0.0",
+				fees0, paymentsArray[5]);
+
+		LoanSummaryEntity loanSummaryEntity = ((LoanBO) accountBO)
+				.getLoanSummary();
+
+		assertEquals(new Money("300.0"), loanSummaryEntity
+				.getOriginalPrincipal());
+
+	}
+
+
+	public void testCreateLoanAccountWithEqualPrincipalDecliningInterestGraceAllRepayments()
+			throws NumberFormatException, PropertyNotFoundException,
+			SystemException, ApplicationException {
+
+		short graceDuration = (short) 2;
+		MeetingBO meeting = TestObjectFactory.createMeeting(TestObjectFactory
+				.getNewMeetingForToday(WEEKLY, EVERY_SECOND_WEEK,
+						CUSTOMER_MEETING));
+		center = TestObjectFactory.createCenter("Center", meeting);
+		group = TestObjectFactory.createGroupUnderCenter("Group",
+				CustomerStatus.GROUP_ACTIVE, center);
+		LoanOfferingBO loanOffering = TestObjectFactory.createLoanOffering(
+				"Loan", ApplicableTo.GROUPS, new Date(System
+						.currentTimeMillis()), PrdStatus.LOAN_ACTIVE, 300.0,
+				1.2, (short) 3, InterestType.DECLINING_EPI, false, false, center
+						.getCustomerMeeting().getMeeting());
+		loanOffering.updateLoanOfferingSameForAllLoan(loanOffering);
+		List<FeeView> feeViewList = new ArrayList<FeeView>();
+
+		accountBO = LoanBO.createLoan(TestUtils.makeUser(), loanOffering,
+				group, AccountState.LOAN_ACTIVE_IN_GOOD_STANDING, new Money(
+						"300.0"), Short.valueOf("6"), new Date(System
+						.currentTimeMillis()), false, // 6 installments
+				1.2, graceDuration, new FundBO(), feeViewList, null);
+		new TestObjectPersistence().persist(accountBO);
+		assertEquals(6, accountBO.getAccountActionDates().size());
+		HashMap fees0 = new HashMap();
+
+		Set<AccountActionDateEntity> actionDateEntities = ((LoanBO) accountBO)
+				.getAccountActionDates();
+		LoanScheduleEntity[] paymentsArray = getSortedAccountActionDateEntity(actionDateEntities);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * (1 + graceDuration)),
+				"50.9", "0.1", fees0, paymentsArray[0]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * (2 + graceDuration)),
+				"50.9", "0.1", fees0, paymentsArray[1]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * (3 + graceDuration)),
+				"50.9", "0.1", fees0, paymentsArray[2]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * (4 + graceDuration)),
+				"50.9", "0.1", fees0, paymentsArray[3]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * (5 + graceDuration)),
+				"50.0", "0.0", fees0, paymentsArray[4]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * (6 + graceDuration)),
+				"46.4", "0.0", fees0, paymentsArray[5]);
+
+		LoanSummaryEntity loanSummaryEntity = ((LoanBO) accountBO)
+				.getLoanSummary();
+		assertEquals(new Money("300.0"), loanSummaryEntity
+				.getOriginalPrincipal());
+
+	}
+
+	public void testCreateLoanAccountWithEqualPrincipalDecliningInterestGracePrincipalOnly()
+			throws NumberFormatException, PropertyNotFoundException,
+			SystemException, ApplicationException {
+
+		short graceDuration = (short) 2;
+		MeetingBO meeting = TestObjectFactory.createMeeting(TestObjectFactory
+				.getNewMeetingForToday(WEEKLY, EVERY_SECOND_WEEK,
+						CUSTOMER_MEETING));
+		center = TestObjectFactory.createCenter("Center", meeting);
+		group = TestObjectFactory.createGroupUnderCenter("Group",
+				CustomerStatus.GROUP_ACTIVE, center);
+		LoanOfferingBO loanOffering = TestObjectFactory.createLoanOffering(
+				"Loan", "L", ApplicableTo.GROUPS, new Date(System
+						.currentTimeMillis()), PrdStatus.LOAN_ACTIVE, 300.0,
+				1.2, (short) 3, InterestType.DECLINING_EPI, false, false, center
+						.getCustomerMeeting().getMeeting(),
+				GraceType.PRINCIPALONLYGRACE, "1", "1");
+		loanOffering.updateLoanOfferingSameForAllLoan(loanOffering);
+		List<FeeView> feeViewList = new ArrayList<FeeView>();
+
+		accountBO = LoanBO.createLoan(TestUtils.makeUser(), loanOffering,
+				group, AccountState.LOAN_ACTIVE_IN_GOOD_STANDING, new Money(
+						"300.0"), Short.valueOf("6"), new Date(System
+						.currentTimeMillis()), false, // 6 installments
+				1.2, graceDuration, new FundBO(), feeViewList, null);
+		new TestObjectPersistence().persist(accountBO);
+		assertEquals(6, accountBO.getAccountActionDates().size());
+
+		HashMap fees0 = new HashMap();
+
+		Set<AccountActionDateEntity> actionDateEntities = ((LoanBO) accountBO)
+				.getAccountActionDates();
+		LoanScheduleEntity[] paymentsArray = getSortedAccountActionDateEntity(actionDateEntities);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 1), "0.0", "0.1",
+				fees0, paymentsArray[0]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 2), "0.0", "0.1",
+				fees0, paymentsArray[1]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 3), "75.0", "0.1",
+				fees0, paymentsArray[2]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 4), "75.0", "0.1",
+				fees0, paymentsArray[3]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 5), "75.0", "0.1",
+				fees0, paymentsArray[4]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 6), "75.0", "0.0",
+				fees0, paymentsArray[5]);
+
+		LoanSummaryEntity loanSummaryEntity = ((LoanBO) accountBO)
+				.getLoanSummary();
+		assertEquals(new Money("300.0"), loanSummaryEntity
+				.getOriginalPrincipal());
+
+	}
+	
+	public void testCreateLoanAccountWithEqualPrincipalDecliningInterestPrincipalDueOnLastInstallment()
+			throws NumberFormatException, PropertyNotFoundException,
+			SystemException, ApplicationException {
+		Date startDate = new Date(System.currentTimeMillis());
+
+		short graceDuration = (short) 2;
+		MeetingBO meeting = TestObjectFactory.createMeeting(TestObjectFactory
+				.getNewMeetingForToday(WEEKLY, EVERY_SECOND_WEEK,
+						CUSTOMER_MEETING));
+		center = TestObjectFactory.createCenter("Center", meeting);
+		group = TestObjectFactory.createGroupUnderCenter("Group",
+				CustomerStatus.GROUP_ACTIVE, center);
+		LoanOfferingBO loanOffering = TestObjectFactory.createLoanOffering(
+				"Loan", "Loan".substring(0, 1), ApplicableTo.GROUPS, startDate,
+				PrdStatus.LOAN_ACTIVE, 300.0, 1.2, (short) 3,
+				InterestType.DECLINING_EPI, false, true, center
+						.getCustomerMeeting().getMeeting(), GraceType.NONE,
+				"1", "1");
+		loanOffering.updateLoanOfferingSameForAllLoan(loanOffering);
+		List<FeeView> feeViewList = new ArrayList<FeeView>();
+
+		accountBO = LoanBO.createLoan(TestUtils.makeUser(), loanOffering,
+				group, AccountState.LOAN_ACTIVE_IN_GOOD_STANDING, new Money(
+						"300.0"), Short.valueOf("6"), startDate, false, // 6
+				// installments
+				1.2, graceDuration, new FundBO(), feeViewList, null);
+		new TestObjectPersistence().persist(accountBO);
+		assertEquals(6, accountBO.getAccountActionDates().size());
+
+		HashMap fees0 = new HashMap();
+
+		Set<AccountActionDateEntity> actionDateEntities = ((LoanBO) accountBO)
+				.getAccountActionDates();
+		LoanScheduleEntity[] paymentsArray = getSortedAccountActionDateEntity(actionDateEntities);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 1), "0.0", "0.1",
+				fees0, paymentsArray[0]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 2), "0.0", "0.1",
+				fees0, paymentsArray[1]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 3), "0.0", "0.1",
+				fees0, paymentsArray[2]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 4), "0.0", "0.1",
+				fees0, paymentsArray[3]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 5), "0.0", "0.1",
+				fees0, paymentsArray[4]);
+
+		checkLoanScheduleEntity(incrementCurrentDate(14 * 6), "300.0", "0.1",
+				fees0, paymentsArray[5]);
+
+		LoanSummaryEntity loanSummaryEntity = ((LoanBO) accountBO)
+				.getLoanSummary();
+		assertEquals(new Money("300.0"), loanSummaryEntity
+				.getOriginalPrincipal());
+
+	}
+
 	private java.sql.Date setDate(int dayUnit, int interval) {
 		Calendar calendar = new GregorianCalendar();
 		calendar.setTime(DateUtils.getCurrentDateWithoutTimeStamp());
Index: F:/CURRENT DEV/Mifos Workspace/mifos/test/org/mifos/application/productdefinition/struts/action/LoanPrdActionTest.java
===================================================================
--- F:/CURRENT DEV/Mifos Workspace/mifos/test/org/mifos/application/productdefinition/struts/action/LoanPrdActionTest.java	(revision 12276)
+++ F:/CURRENT DEV/Mifos Workspace/mifos/test/org/mifos/application/productdefinition/struts/action/LoanPrdActionTest.java	(working copy)
@@ -141,7 +141,7 @@
 				((List<MasterDataEntity>) SessionUtils.getAttribute(
 						ProductDefinitionConstants.LOANGRACEPERIODTYPELIST,
 						request)).size());
-		assertEquals("The size of interest types list", 2,
+		assertEquals("The size of interest types list", 3,
 				((List<MasterDataEntity>) SessionUtils.getAttribute(
 						ProductDefinitionConstants.INTERESTTYPESLIST, request))
 						.size());
@@ -751,7 +751,7 @@
 				((List<MasterDataEntity>) SessionUtils.getAttribute(
 						ProductDefinitionConstants.LOANGRACEPERIODTYPELIST,
 						request)).size());
-		assertEquals("The size of interest types list", 2,
+		assertEquals("The size of interest types list", 3,
 				((List<MasterDataEntity>) SessionUtils.getAttribute(
 						ProductDefinitionConstants.INTERESTTYPESLIST, request))
 						.size());
@@ -1330,6 +1330,124 @@
 										.getAttribute(ProductDefinitionConstants.LOANPRODUCTID)));
 	}
 
+
+	public void testCreateDecliningInterestEqualPrincipalDisbursementFail() throws Exception {
+		fee = TestObjectFactory.createPeriodicAmountFee("Loan Periodic",
+				FeeCategory.LOAN, "100.0", RecurrenceType.MONTHLY, (short) 1);
+		setRequestPathInfo("/loanproductaction.do");
+		addRequestParameter("method", "load");
+		actionPerform();
+
+		flowKey = (String) request.getAttribute(Constants.CURRENTFLOWKEY);
+
+		setRequestPathInfo("/loanproductaction.do");
+		addRequestParameter("method", "preview");
+		addRequestParameter(Constants.CURRENTFLOWKEY, flowKey);
+
+		addRequestParameter("prdOfferingName", "Loan Offering");
+		addRequestParameter("prdOfferingShortName", "LOAN");
+		addRequestParameter("prdCategory", "1");
+		addRequestParameter("startDate", offSetCurrentDate(0, userContext
+				.getPreferredLocale()));
+		addRequestParameter("endDate", offSetCurrentDate(1, userContext
+				.getPreferredLocale()));
+		addRequestParameter("prdApplicableMaster", "1");
+		addRequestParameter("minLoanAmount", "2000");
+		addRequestParameter("maxLoanAmount", "11000");
+		addRequestParameter("defaultLoanAmount", "5000");
+		addRequestParameter("interestTypes", "4");
+		addRequestParameter("maxInterestRate", "12");
+		addRequestParameter("minInterestRate", "1");
+		addRequestParameter("defInterestRate", "4");
+		addRequestParameter("freqOfInstallments", "2");
+		addRequestParameter("prdOfferinFees", new String[] { fee.getFeeId()
+				.toString() });
+		addRequestParameter("loanOfferingFunds", new String[] { "1" });
+		addRequestParameter("recurAfter", "1");
+		addRequestParameter("maxNoInstallments", "14");
+		addRequestParameter("minNoInstallments", "2");
+		addRequestParameter("defNoInstallments", "11");
+		addRequestParameter("intDedDisbursementFlag", "1");
+		addRequestParameter("principalGLCode", "35");
+		addRequestParameter("interestGLCode", "45");
+		addRequestParameter("loanAmtCalcType", "1");
+		addRequestParameter("calcInstallmentType", "1");
+		actionPerform();
+		setRequestPathInfo("/loanproductaction.do");
+		addRequestParameter("method", "create");
+		addRequestParameter(Constants.CURRENTFLOWKEY, flowKey);
+		actionPerform();
+		verifyActionErrors(new String[] { "exceptions.declineinterestdisbursementdeduction" });
+
+	}
+
+	public void testCreateDecliningInterestEqualPrincipalDisbursementSuccess()
+			throws Exception {
+		fee = TestObjectFactory.createPeriodicAmountFee("Loan Periodic",
+				FeeCategory.LOAN, "100.0", RecurrenceType.MONTHLY, (short) 1);
+		setRequestPathInfo("/loanproductaction.do");
+		addRequestParameter("method", "load");
+		actionPerform();
+
+		flowKey = (String) request.getAttribute(Constants.CURRENTFLOWKEY);
+
+		setRequestPathInfo("/loanproductaction.do");
+		addRequestParameter("method", "preview");
+		addRequestParameter(Constants.CURRENTFLOWKEY, flowKey);
+
+		addRequestParameter("prdOfferingName", "Loan Offering");
+		addRequestParameter("prdOfferingShortName", "LOAN");
+		addRequestParameter("prdCategory", "1");
+		addRequestParameter("startDate", offSetCurrentDate(0, userContext
+				.getPreferredLocale()));
+		addRequestParameter("endDate", offSetCurrentDate(1, userContext
+				.getPreferredLocale()));
+		addRequestParameter("prdApplicableMaster", "1");
+		addRequestParameter("minLoanAmount", "2000");
+		addRequestParameter("maxLoanAmount", "11000");
+		addRequestParameter("defaultLoanAmount", "5000");
+		addRequestParameter("interestTypes", "4");
+		addRequestParameter("maxInterestRate", "12");
+		addRequestParameter("minInterestRate", "1");
+		addRequestParameter("defInterestRate", "4");
+		addRequestParameter("freqOfInstallments", "2");
+		addRequestParameter("prdOfferinFees", new String[] { fee.getFeeId()
+				.toString() });
+		addRequestParameter("loanOfferingFunds", new String[] { "1" });
+		addRequestParameter("recurAfter", "1");
+		addRequestParameter("maxNoInstallments", "14");
+		addRequestParameter("minNoInstallments", "2");
+		addRequestParameter("defNoInstallments", "11");
+		// addRequestParameter("intDedDisbursementFlag", "0");
+		addRequestParameter("principalGLCode", "35");
+		addRequestParameter("interestGLCode", "45");
+		addRequestParameter("loanAmtCalcType", "1");
+		addRequestParameter("calcInstallmentType", "1");
+		actionPerform();
+		setRequestPathInfo("/loanproductaction.do");
+		addRequestParameter("method", "create");
+		addRequestParameter(Constants.CURRENTFLOWKEY, flowKey);
+		actionPerform();
+
+		verifyNoActionErrors();
+		verifyNoActionMessages();
+		verifyForward(ActionForwards.create_success.toString());
+
+		assertNotNull(request
+				.getAttribute(ProductDefinitionConstants.LOANPRODUCTID));
+		assertNotNull(request
+				.getAttribute(ProductDefinitionConstants.LOANPRDGLOBALOFFERINGNUM));
+		assertNull(((FlowManager) request.getSession().getAttribute(
+				Constants.FLOWMANAGER)).getFlow(flowKey));
+
+		TestObjectFactory
+				.removeObject((LoanOfferingBO) TestObjectFactory
+						.getObject(
+								LoanOfferingBO.class,
+								(Short) request
+										.getAttribute(ProductDefinitionConstants.LOANPRODUCTID)));
+	}
+
 	private String offSetCurrentDate(int noOfDays, Locale locale) {
 		Calendar currentDateCalendar = new GregorianCalendar();
 		int year = currentDateCalendar.get(Calendar.YEAR);
Index: F:/CURRENT DEV/Mifos Workspace/mifos/test/org/mifos/application/productdefinition/business/LoanOfferingBOTest.java
===================================================================
--- F:/CURRENT DEV/Mifos Workspace/mifos/test/org/mifos/application/productdefinition/business/LoanOfferingBOTest.java	(revision 12276)
+++ F:/CURRENT DEV/Mifos Workspace/mifos/test/org/mifos/application/productdefinition/business/LoanOfferingBOTest.java	(working copy)
@@ -1297,6 +1297,43 @@
 	}
 
 
+	public void testLoanOfferingWithEqualPrincipalDecliningInterestDeductionAtDisbursement() {
+		try {
+			createIntitalObjects();
+			interestTypes = new InterestTypesEntity(InterestType.DECLINING_EPI);
+			Date startDate = offSetCurrentDate(0);
+			Date endDate = offSetCurrentDate(2);
+			new LoanOfferingBO(TestObjectFactory.getContext(), "Loan Offering",
+					"LOAP", productCategory, prdApplicableMaster, startDate,
+					endDate, null, null, null, interestTypes,
+					new Money("1000"), new Money("3000"), new Money("2000.0"),
+					12.0, 2.0, 3.0, (short) 20, (short) 11, (short) 17, false,
+					true, false, null, null, frequency, principalglCodeEntity,
+					intglCodeEntity);
+			fail();
+		}
+		catch (ProductDefinitionException e) {
+			assertEquals("exceptions.declineinterestdisbursementdeduction", e
+					.getKey());
+		}
+	}
+
+	public void testLoanOfferingWithEqualPrincipalDecliningInterestNoDeductionAtDisbursement()
+			throws Exception {
+		createIntitalObjects();
+		interestTypes = new InterestTypesEntity(InterestType.DECLINING_EPI);
+		Date startDate = offSetCurrentDate(0);
+		Date endDate = offSetCurrentDate(2);
+		LoanOfferingBO loanOffering = new LoanOfferingBO(TestObjectFactory
+				.getContext(), "Loan Offering", "LOAP", productCategory,
+				prdApplicableMaster, startDate, endDate, null, null, null,
+				interestTypes, new Money("1000"), new Money("3000"), new Money(
+						"2000.0"), 12.0, 2.0, 3.0, (short) 20, (short) 11,
+				(short) 17, false, false, false, null, null, frequency,
+				principalglCodeEntity, intglCodeEntity);
+		assertEquals(InterestType.DECLINING_EPI, loanOffering.getInterestType());
+	}
+
 	public void testPrdOfferingView() {
 		PrdOfferingView prdOfferingView = new PrdOfferingView();
 		prdOfferingView.setGlobalPrdOfferingNum("1234");
Index: F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/accounts/loan/business/LoanBO.java
===================================================================
--- F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/accounts/loan/business/LoanBO.java	(revision 12276)
+++ F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/accounts/loan/business/LoanBO.java	(working copy)
@@ -1965,7 +1965,9 @@
 				InterestType.FLAT.getValue()))
 			return getFlatInterestAmount(installmentEndDate);
 		if (getLoanOffering().getInterestTypes().getId().equals(
-				InterestType.DECLINING.getValue()))
+				InterestType.DECLINING.getValue()) 
+				|| getLoanOffering().getInterestTypes().getId().equals(
+						InterestType.DECLINING_EPI.getValue()))
 			return getDecliningInterestAmount(installmentEndDate);
 
 		return null;
@@ -2189,8 +2191,10 @@
 					InterestType.FLAT.getValue())) {
 				return principalInLastPayment(loanInterest);
 			}
-			else if (getLoanOffering().getInterestTypes().getId().equals(
-					InterestType.DECLINING.getValue())) {
+			else if ((getLoanOffering().getInterestTypes().getId().equals(
+					InterestType.DECLINING.getValue())) 
+						|| (getLoanOffering().getInterestTypes().getId().equals( 
+								InterestType.DECLINING_EPI.getValue()))) {
 				return principalInLastPaymentDecliningInterest(loanInterest);
 			}
 		}
@@ -2201,8 +2205,10 @@
 					InterestType.FLAT.getValue())) {
 				return allInstallments(loanInterest);
 			}
-			else if (getLoanOffering().getInterestTypes().getId().equals(
-					InterestType.DECLINING.getValue())) {
+			else if ((getLoanOffering().getInterestTypes().getId().equals(
+					InterestType.DECLINING.getValue())) 
+						|| (getLoanOffering().getInterestTypes().getId().equals
+								( InterestType.DECLINING_EPI.getValue()))) {
 				return allDecliningInstallments(loanInterest);
 			}
 		}
@@ -2363,6 +2369,8 @@
 				|| getGraceType() == GraceType.NONE) {
 
 			double principalBalance = getLoanAmount().getAmountDoubleValue();
+			double principalPerInstallmentEqual = getLoanAmount().getAmountDoubleValue()
+							/ getNoOfInstallments();
 
 			EMIInstallment installment = null;
 			double principalPaidCurrentPeriod = 0;
@@ -2380,9 +2388,18 @@
 				Money interstPerInstallmentM = new Money(Double
 						.toString(interestPerInstallment));
 				installment.setInterest(interstPerInstallmentM);
-				principalPaidCurrentPeriod = Math.abs(loanInterest
-						.getAmountDoubleValue()
-						- interestPerInstallment);
+				if (getLoanOffering().getInterestTypes().getId().equals(
+						InterestType.DECLINING.getValue())) {
+					principalPaidCurrentPeriod = Math.abs(loanInterest
+							.getAmountDoubleValue()
+							- interestPerInstallment);
+				}
+				else if (getLoanOffering().getInterestTypes().getId().equals( 
+						InterestType.DECLINING_EPI.getValue()))	{
+					principalPaidCurrentPeriod = Math.abs(principalPerInstallmentEqual);
+					
+				}
+				
 				installment.setPrincipal(new Money(Double
 						.toString(principalPaidCurrentPeriod)));
 				principalBalance = principalBalance
@@ -2411,9 +2428,19 @@
 			for (int i = getGracePeriodDuration(); i < getNoOfInstallments(); i++) {
 
 				installment = new EMIInstallment();
-				principalPaidCurrentPeriod = Math.abs(loanInterest
-						.getAmountDoubleValue()
-						- interestPerInstallment);
+				//soham
+				if (getLoanOffering().getInterestTypes().getId().equals(
+						InterestType.DECLINING.getValue())) {
+					principalPaidCurrentPeriod = Math.abs(loanInterest
+							.getAmountDoubleValue()
+							- interestPerInstallment);
+				}	
+				else if (getLoanOffering().getInterestTypes().getId().equals( 
+						InterestType.DECLINING_EPI.getValue()))	{
+					principalPaidCurrentPeriod = getLoanAmount().getAmountDoubleValue()
+														/ (getNoOfInstallments()- getGracePeriodDuration());
+					
+				}
 				if (principalBalance > 0) {
 					interestPerInstallment = Math
 							.abs(principalBalance
@@ -2425,9 +2452,25 @@
 						.toString(interestPerInstallment));
 				installment.setInterest(interstPerInstallmentM);
 
-				principalPaidCurrentPeriod = Math.abs(loanInterest
-						.getAmountDoubleValue()
-						- interestPerInstallment);
+				//TODO: 28-Jan-08 Why is this repeated? Removing this fails the test 
+				//testCreateLoanAccountWithDecliningInterestGracePrincipalOnly.
+				//Thus currently left it as is with changes for declining_epi
+				
+				if (getLoanOffering().getInterestTypes().getId().equals(
+						InterestType.DECLINING.getValue())) {
+					principalPaidCurrentPeriod = Math.abs(loanInterest
+							.getAmountDoubleValue()
+							- interestPerInstallment);
+				}	
+				else if (getLoanOffering().getInterestTypes().getId().equals( 
+						InterestType.DECLINING_EPI.getValue()))	{
+					principalPaidCurrentPeriod = getLoanAmount().getAmountDoubleValue()
+														/ (getNoOfInstallments()- getGracePeriodDuration());
+					
+				}
+				// principalPaidCurrentPeriod = Math.abs(loanInterest
+				//		.getAmountDoubleValue()
+				//		- interestPerInstallment);
 				installment.setPrincipal(new Money(Double
 						.toString(principalPaidCurrentPeriod)));
 				principalBalance = principalBalance
Index: F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/productdefinition/struts/actionforms/LoanPrdActionForm.java
===================================================================
--- F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/productdefinition/struts/actionforms/LoanPrdActionForm.java	(revision 12276)
+++ F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/productdefinition/struts/actionforms/LoanPrdActionForm.java	(working copy)
@@ -2098,9 +2098,12 @@
 						+ getIntDedDisbursementFlag());
 
 		if (getInterestTypes() != null
-				&& getInterestTypes().equals(
+				&& (getInterestTypes().equals(
 						InterestType.DECLINING.getValue()
-								.toString())) {
+								.toString()) 
+								|| getInterestTypes().equals(
+										InterestType.DECLINING_EPI.getValue()
+										.toString()))){
 
 			if (null != getIntDedDisbursementFlag()
 					&& getIntDedDisbursementFlag().equals("1")) {
Index: F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/productdefinition/business/AddInterestCalcRule.java
===================================================================
--- F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/productdefinition/business/AddInterestCalcRule.java	(revision 0)
+++ F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/productdefinition/business/AddInterestCalcRule.java	(revision 0)
@@ -0,0 +1,100 @@
+package org.mifos.application.productdefinition.business;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.mifos.application.master.business.MifosLookUpEntity;
+import org.mifos.framework.persistence.Upgrade;
+
+/* AddInterestCalcRule adds a new type of interest calculation method
+ * e.g. Declining Balance - Equal Principal. This setting is used to
+ * calculate interest with declining method, but with principal being
+ * equal in all installments.
+ */
+public class AddInterestCalcRule extends Upgrade {
+
+	private final int newRuleId;
+	private final int categoryId;
+	private final String lookupName;
+	private final String description;
+
+	private final Short locale;
+	private final String message;
+
+	public AddInterestCalcRule(int higherVersion, int newRuleId, 
+		int categoryId, String lookupName, String description, Short locale, String message) {
+		super(higherVersion);
+		this.newRuleId = newRuleId;
+		this.lookupName = lookupName;		
+		this.categoryId = categoryId;
+		this.description = description;
+		this.locale = locale;
+		this.message = message;
+	}
+	
+	@Override
+	public void upgrade(Connection connection) throws IOException, SQLException {
+		int lookupEntity = MifosLookUpEntity.INTEREST_TYPES;
+
+		int lookupId = insertLookupValue(connection, lookupEntity, lookupName);
+		insertMessage(connection, lookupId, locale, message);
+		addInterestType(connection, newRuleId, description, lookupId);
+		upgradeVersion(connection);
+	}
+
+	@Override
+	public void downgrade(Connection connection) throws IOException,
+			SQLException {
+		short lookupId = findLookupId(connection);
+
+		deleteFromInterestTypes(connection);
+		deleteFromLookupValueLocale(connection, lookupId);
+		deleteFromLookupValue(connection, lookupId);
+
+		downgradeVersion(connection);
+	}
+
+	private void addInterestType(Connection connection, 
+		int newRuleId, String description, int lookupId) 
+	throws SQLException {
+		PreparedStatement statement = connection.prepareStatement(
+			"INSERT INTO INTEREST_TYPES(" +
+			"  INTEREST_TYPE_ID,LOOKUP_ID,CATEGORY_ID,DESCRIPTON)" +
+			"VALUES(?,?,?,?)");
+		statement.setInt(1, newRuleId);
+		statement.setInt(2, lookupId);
+		statement.setInt(3, categoryId);
+		statement.setString(4, description);
+		statement.executeUpdate();
+		statement.close();
+	}
+
+	private short findLookupId(Connection connection) throws SQLException {
+		PreparedStatement statement = connection.prepareStatement(
+			"select LOOKUP_ID " +
+			"from INTEREST_TYPES where INTEREST_TYPE_ID = ?");
+		statement.setInt(1, newRuleId);
+		ResultSet results = statement.executeQuery();
+		if (results.next()) {
+			short lookupId = results.getShort("LOOKUP_ID");
+			statement.close();
+			return lookupId;
+		}
+		else {
+			statement.close();
+			throw new RuntimeException(
+				"unable to downgrade: no Interest type " + newRuleId);
+		}
+	}
+	
+	private void deleteFromInterestTypes(Connection connection) throws SQLException {
+		PreparedStatement statement = connection.prepareStatement(
+			"delete from INTEREST_TYPES where INTEREST_TYPE_ID = ?");
+		statement.setInt(1, newRuleId);
+		statement.executeUpdate();
+		statement.close();
+	}
+}
Index: F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/productdefinition/business/LoanOfferingBO.java
===================================================================
--- F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/productdefinition/business/LoanOfferingBO.java	(revision 12276)
+++ F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/productdefinition/business/LoanOfferingBO.java	(working copy)
@@ -802,7 +802,8 @@
 			throw new ProductDefinitionException("errors.create");
 		}
 
-		if (interestTypes.getId().equals(InterestType.DECLINING.getValue())
+		if ((interestTypes.getId().equals(InterestType.DECLINING.getValue())
+				||(interestTypes.getId().equals(InterestType.DECLINING_EPI.getValue())))
 				&& intDedDisbursement) {
 			throw new ProductDefinitionException(
 					ProductDefinitionConstants.DECLINEINTERESTDISBURSEMENTDEDUCTION);
@@ -835,7 +836,8 @@
 			throw new ProductDefinitionException("errors.create");
 		}
 
-		if (interestTypes.getId().equals(InterestType.DECLINING.getValue())
+		if ((interestTypes.getId().equals(InterestType.DECLINING.getValue())
+				||(interestTypes.getId().equals(InterestType.DECLINING_EPI.getValue())))
 				&& intDedDisbursement) {
 			throw new ProductDefinitionException(
 					ProductDefinitionConstants.DECLINEINTERESTDISBURSEMENTDEDUCTION);
Index: F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/productdefinition/util/helpers/InterestType.java
===================================================================
--- F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/productdefinition/util/helpers/InterestType.java	(revision 12276)
+++ F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/productdefinition/util/helpers/InterestType.java	(working copy)
@@ -5,7 +5,8 @@
 
 	FLAT((short) 1), 
 	DECLINING((short) 2), 
-	COMPOUND((short) 3);
+	COMPOUND((short) 3),
+	DECLINING_EPI((short) 4); //Equal Principal Installments
 
 	private Short value;
 
Index: F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/master/business/MifosLookUpEntity.java
===================================================================
--- F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/master/business/MifosLookUpEntity.java	(revision 12276)
+++ F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/application/master/business/MifosLookUpEntity.java	(working copy)
@@ -61,6 +61,7 @@
 	public static final int ACCOUNT_STATE_FLAG = 70;
 	public static final int ACTIVITY = 87;
 	public static final int REPAYMENT_RULE = 91;
+	public static final int INTEREST_TYPES = 37;
 	
 	private Short entityId;
 
Index: F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/framework/persistence/DatabaseVersionPersistence.java
===================================================================
--- F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/framework/persistence/DatabaseVersionPersistence.java	(revision 12276)
+++ F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/framework/persistence/DatabaseVersionPersistence.java	(working copy)
@@ -26,10 +26,12 @@
 import org.mifos.framework.hibernate.helper.HibernateUtil;
 import org.mifos.framework.security.AddActivity;
 import org.mifos.framework.security.util.resources.SecurityConstants;
+import org.mifos.application.productdefinition.business.AddInterestCalcRule;
+import org.mifos.application.productdefinition.util.helpers.InterestType;
 
 public class DatabaseVersionPersistence {
 
-	public static final int APPLICATION_VERSION = 172;
+	public static final int APPLICATION_VERSION = 173;
 	public static final int FIRST_NUMBERED_VERSION = 100;
 
 	public static void register(Map<Integer, Upgrade> register, Upgrade upgrade) {
@@ -70,6 +72,7 @@
 		register(register, new Upgrade167());
 		register(register, new Upgrade169());
 		register170(register);
+		register173(register);
 		return Collections.unmodifiableMap(register);
 	}
 
@@ -245,6 +248,14 @@
 				"Can view admin documents")));
 		
 	}
+	
+	private static void register173(Map<Integer, Upgrade> register) {
+		register(register, new AddInterestCalcRule(173,InterestType.DECLINING_EPI.getValue(),
+				1, "InterestTypes-DecliningBalance-EqualPrincipalInstallment",
+				"Declining Balance-Equal Principal Installment",ENGLISH_LOCALE,
+				"Declining Balance-Equal Principal Installment"));
+	}	
+	
 	private final Connection connection;
 	private final Map<Integer, Upgrade> registeredUpgrades;
 
Index: F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/framework/persistence/Upgrade.java
===================================================================
--- F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/framework/persistence/Upgrade.java	(revision 12276)
+++ F:/CURRENT DEV/Mifos Workspace/mifos/src/org/mifos/framework/persistence/Upgrade.java	(working copy)
@@ -101,6 +101,25 @@
 		return newLookupId;
 	}
 
+	protected int insertLookupValue(Connection connection, 
+			int lookupEntity, String lookupName) throws SQLException {
+		/* With the new configuration the LookupNames should not be blank*/
+		
+		int largestLookupId = largestLookupId(connection);
+		
+		int newLookupId = largestLookupId + 1;
+		PreparedStatement statement = connection.prepareStatement(
+			"insert into LOOKUP_VALUE(" +
+			"LOOKUP_ID,ENTITY_ID,LOOKUP_NAME) " +
+			"VALUES(?,?,?)");
+		statement.setInt(1, newLookupId);
+		statement.setInt(2, lookupEntity);
+		statement.setString(3, lookupName);
+	
+		statement.executeUpdate();
+		statement.close();
+		return newLookupId;
+	}
 	private int largestLookupId(Connection connection) throws SQLException {
 		Statement statement = connection.createStatement();
 		ResultSet results = statement.executeQuery(
Index: F:/CURRENT DEV/Mifos Workspace/mifos/sql/latest-data.sql
===================================================================
--- F:/CURRENT DEV/Mifos Workspace/mifos/sql/latest-data.sql	(revision 12276)
+++ F:/CURRENT DEV/Mifos Workspace/mifos/sql/latest-data.sql	(working copy)
@@ -17,7 +17,7 @@
 -- apply Index.sql
 -- apply all upgrades to date
 
-INSERT INTO DATABASE_VERSION(DATABASE_VERSION) VALUES(172);
+INSERT INTO DATABASE_VERSION(DATABASE_VERSION) VALUES(173);
 
 /* The table Currency holds configuration related items for a currency like display symbol,rounding mode etc which is to be applied on a currency -- Configuration */
 /* To set the default currency, enter 1 in the default_currency field */
@@ -400,6 +400,8 @@
 -- Entity: InterestTypes
 INSERT INTO LOOKUP_VALUE(LOOKUP_ID,ENTITY_ID,LOOKUP_NAME) VALUES(79, 37, 'InterestTypes-Flat');
 INSERT INTO LOOKUP_VALUE(LOOKUP_ID,ENTITY_ID,LOOKUP_NAME) VALUES(80, 37, 'InterestTypes-DecliningBalance');
+INSERT INTO LOOKUP_VALUE(LOOKUP_ID,ENTITY_ID,LOOKUP_NAME) VALUES(603,37, 'InterestTypes-DecliningBalance-EqualPrincipalInstallment');
+
 -- Entity: CategoryType
 INSERT INTO LOOKUP_VALUE(LOOKUP_ID,ENTITY_ID,LOOKUP_NAME) VALUES(81, 38, 'CategoryType-AllCustomers');
 INSERT INTO LOOKUP_VALUE(LOOKUP_ID,ENTITY_ID,LOOKUP_NAME) VALUES(82, 38, 'CategoryType-Client');
@@ -1315,6 +1317,8 @@
 VALUES(157,1,79,'Flat');
 INSERT INTO LOOKUP_VALUE_LOCALE(LOOKUP_VALUE_ID,LOCALE_ID,LOOKUP_ID,LOOKUP_VALUE) 		
 VALUES(158,1,80,'Declining Balance');
+INSERT INTO LOOKUP_VALUE_LOCALE(LOOKUP_VALUE_ID,LOCALE_ID,LOOKUP_ID,LOOKUP_VALUE)
+VALUES(946,1,603,'Declining Balance-Equal Principal Installment');
 
 /* VALUES for category_type*/
 INSERT INTO LOOKUP_VALUE_LOCALE(LOOKUP_VALUE_ID,LOCALE_ID,LOOKUP_ID,LOOKUP_VALUE) 		
@@ -3273,6 +3277,8 @@
 VALUES(1,79,1,'Flat');
 INSERT INTO INTEREST_TYPES (INTEREST_TYPE_ID, LOOKUP_ID, CATEGORY_ID, DESCRIPTON)
 VALUES(2,80,1,'Declining');
+INSERT INTO INTEREST_TYPES (INTEREST_TYPE_ID, LOOKUP_ID, CATEGORY_ID, DESCRIPTON) 
+VALUES(4,603,1,'Declining Balance-Equal Principal Installment');
 
 INSERT INTO INTEREST_CALC_RULE (INTEREST_CALC_RULE_ID, LOOKUP_ID) 
 VALUES(1,88);
