Merge branch 'peter1' into develop

This commit is contained in:
pramod
2015-08-17 13:28:15 +05:30
15 changed files with 713 additions and 280 deletions
@@ -0,0 +1,353 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.integrationtests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mifosplatform.integrationtests.common.*;
import org.mifosplatform.integrationtests.common.loans.*;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.builder.ResponseSpecBuilder;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.specification.RequestSpecification;
import com.jayway.restassured.specification.ResponseSpecification;
/**
* Tests loan schedule change based on group meeting changes and loan
* rescheduling
**/
@SuppressWarnings({ "rawtypes" })
public class DisbursalAndRepaymentScheduleTest {
private ResponseSpecification responseSpec;
private ResponseSpecification responseSpecForStatusCode403;
private ResponseSpecification generalResponseSpec;
private RequestSpecification requestSpec;
private LoanTransactionHelper loanTransactionHelper;
private LoanRescheduleRequestHelper loanRescheduleRequestHelper;
private Integer loanRescheduleRequestId;
private Integer clientId;
private Integer groupId;
private Integer groupCalendarId;
private Integer loanProductId;
private Integer loanId;
private final String loanPrincipalAmount = "100000.00";
private final String numberOfRepayments = "12";
private final String interestRatePerPeriod = "18";
private final SimpleDateFormat dateFormatterMifosStandard = new SimpleDateFormat("dd MMMM yyyy");
@Before
public void setup() {
Utils.initializeRESTAssured();
}
@Test
public void testRescheduleJLGLoanSynk() {
System.out.println("---------------------------------STARTING RESCHEDULE JLG LOAN TEST ------------------------------------------");
Calendar meetingCalendar = Calendar.getInstance();
meetingCalendar.setFirstDayOfWeek(Calendar.MONDAY);
meetingCalendar.setTime(new java.util.Date());
int today = meetingCalendar.get(Calendar.DAY_OF_WEEK);
// making sure that the meeting calendar is set for the coming monday.
if (today >= Calendar.MONDAY) {
meetingCalendar.add(Calendar.DAY_OF_YEAR, +(Calendar.MONDAY - today + 7));
} else {
meetingCalendar.add(Calendar.DAY_OF_YEAR, +(Calendar.MONDAY - today));
}
Calendar groupMeetingChangeCalendar = (Calendar) meetingCalendar.clone();
meetingCalendar.add(Calendar.WEEK_OF_YEAR, -3);
final String groupMeetingDate = this.dateFormatterMifosStandard.format(meetingCalendar.getTime());
final String disbursalDate = groupMeetingDate; // first meeting date
// after group creation
final String rescheduleSubmittedDate = this.dateFormatterMifosStandard.format(new java.util.Date());
final String loanType = "jlg";
final String rescheduleInterestRate = "28.0";
groupMeetingChangeCalendar.add(Calendar.DAY_OF_YEAR, 1);
final String groupMeetingNewStartDate = this.dateFormatterMifosStandard.format(groupMeetingChangeCalendar.getTime());
// The date
// from
// which we
// start the
// new group
// meeting
// occasion,
// this is a
// tuesday.
groupMeetingChangeCalendar.add(Calendar.WEEK_OF_YEAR, 2);
final String rescheduleDate = this.dateFormatterMifosStandard.format(groupMeetingChangeCalendar.getTime());
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
this.requestSpec.header("X-Mifos-Platform-TenantId", "default");
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
this.generalResponseSpec = new ResponseSpecBuilder().build();
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
this.loanRescheduleRequestHelper = new LoanRescheduleRequestHelper(this.requestSpec, this.responseSpec);
System.out.println("---------------------------------CREATING ENTITIES AND JLG LOAN ------------------------------------------");
// create all required entities
this.createRequiredEntitiesForJLGLoanSync(groupMeetingDate);
final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal(loanPrincipalAmount).withLoanTermFrequency("24")
.withLoanTermFrequencyAsWeeks().withNumberOfRepayments("12").withRepaymentEveryAfter("2")
.withRepaymentFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestCalculationPeriodTypeAsDays()
.withInterestRatePerPeriod(interestRatePerPeriod).withRepaymentFrequencyTypeAsWeeks().withSubmittedOnDate(disbursalDate)
.withExpectedDisbursementDate(disbursalDate).withLoanType(loanType).withSyncDisbursementWithMeetin()
.withCalendarID(this.groupCalendarId.toString())
.build(this.clientId.toString(), this.groupId.toString(), this.loanProductId.toString(), null);
this.loanId = this.loanTransactionHelper.getLoanId(loanApplicationJSON);
// Test for loan account is created
Assert.assertNotNull(this.loanId);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, this.loanId);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
// Test for loan account is created, can be approved
this.loanTransactionHelper.approveLoan(disbursalDate, this.loanId);
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, this.loanId);
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
// Test for loan account approved can be disbursed
this.loanTransactionHelper.disburseLoan(disbursalDate, this.loanId);
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, this.loanId);
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
System.out.println("---------------------------------CHANGING GROUP MEETING DATE ------------------------------------------");
CalendarHelper.updateMeetingCalendarForGroup(this.requestSpec, this.responseSpec, this.groupId, this.groupCalendarId.toString(),
groupMeetingNewStartDate, "2", "2", "2"); // New meeting dates
// will be the tuesday
// after the
// coming
// monday
ArrayList loanRepaymnetSchedule = this.loanTransactionHelper
.getLoanRepaymentSchedule(requestSpec, generalResponseSpec, this.loanId);
ArrayList dueDateLoanSchedule = (ArrayList) ((HashMap) loanRepaymnetSchedule.get(2)).get("dueDate");
Calendar dueDateCalendar = Calendar.getInstance();
dueDateCalendar.setFirstDayOfWeek(Calendar.MONDAY);
dueDateCalendar.set((Integer) dueDateLoanSchedule.get(0), (Integer) dueDateLoanSchedule.get(1) - 1,
(Integer) dueDateLoanSchedule.get(2));
assertEquals("AFTER MEETING CHANGE DATE THE NEXT REPAYMENT SHOULD BE ON TUESDAY", 3, dueDateCalendar.get(Calendar.DAY_OF_WEEK));
System.out.println("---------------------------------CREATING LOAN RESCHEDULE REQUEST------------------------------------------");
String requestJSON = new LoanRescheduleRequestTestBuilder().updateGraceOnInterest("2").updateGraceOnPrincipal("2")
.updateNewInterestRate(rescheduleInterestRate).updateRescheduleFromDate(rescheduleDate)
.updateSubmittedOnDate(rescheduleSubmittedDate).build(this.loanId.toString());
this.loanRescheduleRequestId = this.loanRescheduleRequestHelper.createLoanRescheduleRequest(requestJSON);
this.loanRescheduleRequestHelper.verifyCreationOfLoanRescheduleRequest(this.loanRescheduleRequestId);
loanRepaymnetSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, generalResponseSpec, this.loanId);
dueDateLoanSchedule = (ArrayList) ((HashMap) loanRepaymnetSchedule.get(2)).get("dueDate");
dueDateCalendar.set((Integer) dueDateLoanSchedule.get(0), (Integer) dueDateLoanSchedule.get(1) - 1,
(Integer) dueDateLoanSchedule.get(2));
assertEquals("AFTER MEETING CHANGE DATE THE NEXT REPAYMENT SHOULD BE ON TUESDAY, EVEN AFTER LOAN RESCHEDULE REQUEST WAS SENT", 3,
dueDateCalendar.get(Calendar.DAY_OF_WEEK));
System.out.println("Successfully created loan reschedule request (ID: " + this.loanRescheduleRequestId + ")");
System.out.println("-----------------------------APPROVING LOAN RESCHEDULE REQUEST--------------------------");
requestJSON = new LoanRescheduleRequestTestBuilder().updateSubmittedOnDate(rescheduleSubmittedDate)
.getApproveLoanRescheduleRequestJSON();
this.loanRescheduleRequestHelper.approveLoanRescheduleRequest(this.loanRescheduleRequestId, requestJSON);
final HashMap response = (HashMap) this.loanRescheduleRequestHelper.getLoanRescheduleRequest(loanRescheduleRequestId, "statusEnum");
assertTrue((Boolean) response.get("approved"));
loanRepaymnetSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, generalResponseSpec, this.loanId);
dueDateLoanSchedule = (ArrayList) ((HashMap) loanRepaymnetSchedule.get(2)).get("dueDate");
dueDateCalendar.set((Integer) dueDateLoanSchedule.get(0), (Integer) dueDateLoanSchedule.get(1) - 1,
(Integer) dueDateLoanSchedule.get(2));
assertEquals("AFTER MEETING CHANGE DATE THE NEXT REPAYMENT SHOULD BE ON TUESDAY, EVEN AFTER RESCHEDULE", 3,
dueDateCalendar.get(Calendar.DAY_OF_WEEK));
System.out.println("Successfully changed group meeting date (CAELNDAR ID: " + this.groupCalendarId
+ ") and rescheduled loan (RESCHEDULE ID: " + this.loanRescheduleRequestId + ")");
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpecForStatusCode403);
}
@Test
public void testChangeGroupMeetingMaturedOnDate() {
System.out
.println("---------------------------------STARTING GROUP LOAN MEETING CHANGE DATE EXPECTED MATURED CHANGE------------------------------------------");
Calendar meetingCalendar = Calendar.getInstance();
meetingCalendar.setFirstDayOfWeek(Calendar.MONDAY);
meetingCalendar.setTime(new java.util.Date());
int today = meetingCalendar.get(Calendar.DAY_OF_WEEK);
// making sure that the meeting calendar is set for the coming monday.
if (today >= Calendar.MONDAY) {
meetingCalendar.add(Calendar.DAY_OF_YEAR, +(Calendar.MONDAY - today + 7));
} else {
meetingCalendar.add(Calendar.DAY_OF_YEAR, +(Calendar.MONDAY - today));
}
Calendar groupMeetingChangeCalendar = (Calendar) meetingCalendar.clone();
meetingCalendar.add(Calendar.WEEK_OF_YEAR, -3);
final String groupMeetingDate = this.dateFormatterMifosStandard.format(meetingCalendar.getTime());
final String disbursalDate = groupMeetingDate; // first meeting date
// after group creation
final String loanType = "jlg";
groupMeetingChangeCalendar.add(Calendar.DAY_OF_YEAR, 1);
final String groupMeetingNewStartDate = this.dateFormatterMifosStandard.format(groupMeetingChangeCalendar.getTime());
// The date
// from
// which we
// start the
// new group
// meeting
// occasion,
// this is a
// tuesday.
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
this.requestSpec.header("X-Mifos-Platform-TenantId", "default");
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
this.generalResponseSpec = new ResponseSpecBuilder().build();
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
this.loanRescheduleRequestHelper = new LoanRescheduleRequestHelper(this.requestSpec, this.responseSpec);
System.out.println("---------------------------------CREATING ENTITIES AND JLG LOAN ------------------------------------------");
// create all required entities
this.createRequiredEntitiesForJLGLoanSync(groupMeetingDate);
final String loanApplicationJSON = new LoanApplicationTestBuilder().withPrincipal(loanPrincipalAmount).withLoanTermFrequency("24")
.withLoanTermFrequencyAsWeeks().withNumberOfRepayments("12").withRepaymentEveryAfter("2")
.withRepaymentFrequencyTypeAsMonths().withAmortizationTypeAsEqualInstallments().withInterestCalculationPeriodTypeAsDays()
.withInterestRatePerPeriod(interestRatePerPeriod).withRepaymentFrequencyTypeAsWeeks().withSubmittedOnDate(disbursalDate)
.withExpectedDisbursementDate(disbursalDate).withLoanType(loanType).withSyncDisbursementWithMeetin()
.withCalendarID(this.groupCalendarId.toString())
.build(this.clientId.toString(), this.groupId.toString(), this.loanProductId.toString(), null);
this.loanId = this.loanTransactionHelper.getLoanId(loanApplicationJSON);
// Test for loan account is created
Assert.assertNotNull(this.loanId);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, this.loanId);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
// Test for loan account is created, can be approved
this.loanTransactionHelper.approveLoan(disbursalDate, this.loanId);
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, this.loanId);
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
// Test for loan account approved can be disbursed
this.loanTransactionHelper.disburseLoan(disbursalDate, this.loanId);
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, this.loanId);
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
System.out.println("---------------------------------CHANGING GROUP MEETING DATE ------------------------------------------");
CalendarHelper.updateMeetingCalendarForGroup(this.requestSpec, this.responseSpec, this.groupId, this.groupCalendarId.toString(),
groupMeetingNewStartDate, "2", "2", "2"); // New meeting dates
// will be the tuesday
// after the
// coming
// monday
Calendar expectedMaturityCalendar = Calendar.getInstance();
expectedMaturityCalendar.setFirstDayOfWeek(Calendar.MONDAY);
ArrayList expectedMaturityDate = ((ArrayList) ((HashMap) this.loanTransactionHelper.getLoanDetail(requestSpec, generalResponseSpec,
this.loanId, "timeline")).get("expectedMaturityDate"));
expectedMaturityCalendar.set((Integer) expectedMaturityDate.get(0), (Integer) expectedMaturityDate.get(1) - 1,
(Integer) expectedMaturityDate.get(2));
assertEquals("AFTER MEETING CHANGE DATE THE EXPECTED MATURITY SHOULD BE ON TUESDAY", 3,
expectedMaturityCalendar.get(Calendar.DAY_OF_WEEK));
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpecForStatusCode403);
}
/**
* entities for jlg loan
**/
private void createRequiredEntitiesForJLGLoanSync(final String groupActivationDate) {
this.createGroupEntityWithCalendar("2", "2", "1", groupActivationDate);// frequency=2:Weekly
// , interval=2:
// Every two weeks ,
// repeatsOnDay=1:Monday
// groupActivationDate is decided by the current date
this.createClientEntity();
this.associateClientToGroup(this.groupId, this.clientId);
this.createLoanProductEntity();
}
/*
* Associate client to the group
*/
private void associateClientToGroup(final Integer groupId, final Integer clientId) {
GroupHelper.associateClient(this.requestSpec, this.responseSpec, groupId.toString(), clientId.toString());
GroupHelper.verifyGroupMembers(this.requestSpec, this.responseSpec, groupId, clientId);
}
private void createGroupEntityWithCalendar(final String frequency, final String interval, final String repeatsOnDay,
final String groupActivationDate) {
this.groupId = GroupHelper.createGroup(this.requestSpec, this.responseSpec, groupActivationDate);
GroupHelper.verifyGroupCreatedOnServer(this.requestSpec, this.responseSpec, this.groupId);
final String startDate = groupActivationDate;
this.setGroupCalendarId(CalendarHelper.createMeetingCalendarForGroup(this.requestSpec, this.responseSpec, this.groupId, startDate,
frequency, interval, repeatsOnDay));
}
/**
* create a new client
**/
private void createClientEntity() {
this.clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, this.clientId);
}
/**
* create a new loan product
**/
private void createLoanProductEntity() {
final String loanProductJSON = new LoanProductTestBuilder().withPrincipal(loanPrincipalAmount)
.withNumberOfRepayments(numberOfRepayments).withinterestRatePerPeriod(interestRatePerPeriod)
.withInterestRateFrequencyTypeAsYear().build(null);
this.loanProductId = this.loanTransactionHelper.getLoanProductId(loanProductJSON);
}
public void setGroupCalendarId(Integer groupCalendarId) {
this.groupCalendarId = groupCalendarId;
}
}
@@ -20,29 +20,43 @@ public class CalendarHelper {
private static final String PARENT_ENTITY_NAME = "groups/";
private static final String ENITY_NAME = "/calendars";
public static Integer createMeetingCalendarForGroup(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
final Integer groupId, final String startDate, final String frequency, final String interval, final String repeatsOnDay) {
public static Integer createMeetingCalendarForGroup(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
final Integer groupId, final String startDate, final String frequency, final String interval, final String repeatsOnDay) {
System.out.println("---------------------------------CREATING A MEETING CALENDAR FOR THE GROUP------------------------------");
final String CALENDAR_RESOURCE_URL = BASE_URL + PARENT_ENTITY_NAME + groupId + ENITY_NAME + "?" + Utils.TENANT_IDENTIFIER;
final String CALENDAR_RESOURCE_URL = BASE_URL + PARENT_ENTITY_NAME + groupId + ENITY_NAME + "?" + Utils.TENANT_IDENTIFIER;
System.out.println(CALENDAR_RESOURCE_URL);
return Utils.performServerPost(requestSpec, responseSpec, CALENDAR_RESOURCE_URL, getTestCalendarAsJSON(frequency, interval, repeatsOnDay, startDate),
"resourceId");
return Utils.performServerPost(requestSpec, responseSpec, CALENDAR_RESOURCE_URL,
getTestCalendarAsJSON(frequency, interval, repeatsOnDay, startDate), "resourceId");
}
public static String getTestCalendarAsJSON(final String frequency, final String interval,final String repeatsOnDay,
final String startDate) {
public static Integer updateMeetingCalendarForGroup(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
final Integer groupId, String calendarID, final String startDate, final String frequency, final String interval,
final String repeatsOnDay) {
System.out.println("---------------------------------UPDATING A MEETING CALENDAR FOR THE GROUP------------------------------");
final String CALENDAR_RESOURCE_URL = BASE_URL + PARENT_ENTITY_NAME + groupId + ENITY_NAME + "/" + calendarID;
System.out.println(CALENDAR_RESOURCE_URL);
// TODO: check that resource id indeed exists in calendar update put.
return Utils.performServerPut(requestSpec, responseSpec, CALENDAR_RESOURCE_URL,
getTestCalendarAsJSON(frequency, interval, repeatsOnDay, startDate), "resourceId");
}
public static String getTestCalendarAsJSON(final String frequency, final String interval, final String repeatsOnDay,
final String startDate) {
final HashMap<String, String> map = new HashMap<>();
map.put("dateFormat", "dd MMMM yyyy");
map.put("locale", "en");
map.put("frequency", frequency);
map.put("interval", interval);
map.put("repeating", "true");
map.put("repeatsOnDay", repeatsOnDay );
map.put("repeatsOnDay", repeatsOnDay);
map.put("title", Utils.randomNameGenerator("groups_CollectionMeeting", 4));
map.put("typeId", "1");
map.put("startDate", startDate);
@@ -54,7 +68,8 @@ public class CalendarHelper {
final Integer generatedGroupId, final Integer generatedCalendarId) {
System.out.println("------------------------------CHECK CALENDAR DETAILS------------------------------------\n");
final String CLIENT_URL = "/mifosng-provider/api/v1/groups/" + generatedGroupId + "?associations=all&" + Utils.TENANT_IDENTIFIER;
final String responseCalendarDetailsinJSON = Utils.performServerGet(requestSpec, responseSpec, CLIENT_URL, "collectionMeetingCalendar");
final String responseCalendarDetailsinJSON = Utils.performServerGet(requestSpec, responseSpec, CLIENT_URL,
"collectionMeetingCalendar");
final Integer responseCalendarId = from(responseCalendarDetailsinJSON).get("id");
assertEquals("ERROR IN CREATING THE CALENDAR", generatedCalendarId, responseCalendarId);
}
@@ -50,16 +50,37 @@ public class LoanApplicationTestBuilder {
private String recalculationCompoundingFrequencyDate = null;
private String repaymentsStartingFromDate = null;
private String calendarId;
private boolean syncDisbursementWithMeeting = false;
public String build(final String clientID, final String groupID, final String loanProductId, final String savingsID) {
final HashMap<String, Object> map = new HashMap<>();
map.put("groupId", groupID);
map.put("clientId", clientID);
if (this.loanType == "jlg") {
if (this.calendarId != null) {
map.put("calendarId", this.calendarId);
}
map.put("syncDisbursementWithMeeting", this.syncDisbursementWithMeeting);
}
return build(map, loanProductId, savingsID);
}
public String build(final String ID, final String loanProductId, final String savingsID) {
final HashMap<String, Object> map = new HashMap<>();
map.put("dateFormat", "dd MMMM yyyy");
map.put("locale", "en_GB");
if (this.loanType == "group") {
map.put("groupId", ID);
} else {
map.put("clientId", ID);
}
return build(map, loanProductId, savingsID);
}
private String build(final HashMap<String, Object> map, final String loanProductId, final String savingsID) {
map.put("dateFormat", "dd MMMM yyyy");
map.put("locale", "en_GB");
map.put("productId", loanProductId);
map.put("principal", this.principal);
map.put("loanTermFrequency", this.loanTermFrequency);
@@ -105,6 +126,7 @@ public class LoanApplicationTestBuilder {
if (recalculationCompoundingFrequencyDate != null) {
map.put("recalculationCompoundingFrequencyDate", recalculationCompoundingFrequencyDate);
}
System.out.println("Loan Application request : " + map);
return new Gson().toJson(map);
}
@@ -258,4 +280,32 @@ public class LoanApplicationTestBuilder {
this.repaymentsStartingFromDate = firstRepaymentDate;
return this;
}
/**
* calendarID parameter is used to sync repayments with group meetings,
* especially when using jlg loans
*
* @param calendarId
* the id of the calender record of the group meeting from
* m_calendar table
* @return
*/
public LoanApplicationTestBuilder withCalendarID(String calendarId) {
this.calendarId = calendarId;
return this;
}
/**
* This indicator is used mainly for jlg loans when we want to sync
* disbursement with the group meetings (it seems that if we do use this
* parameter we should also use calendarID to sync repayment with group
* meetings)
*
* @return
*/
public LoanApplicationTestBuilder withSyncDisbursementWithMeetin() {
this.syncDisbursementWithMeeting = true;
return this;
}
}
@@ -11,126 +11,133 @@ import java.util.HashMap;
import com.google.gson.Gson;
public class LoanRescheduleRequestTestBuilder {
private String rescheduleFromDate = "04 December 2014";
private String graceOnPrincipal = "2";
private String graceOnInterest = "2";
private String extraTerms = "2";
private Boolean recalculateInterest = false;
private String newInterestRate = null;
private String adjustedDueDate = null;
private String rescheduleReasonId = "1";
private String rescheduleReasonComment = null;
private String submittedOnDate = "04 September 2014";
public String build(final String loanId) {
final HashMap<String, Object> map = new HashMap<>();
map.put("dateFormat", "dd MMMM yyyy");
private String rescheduleFromDate = "04 December 2014";
private String graceOnPrincipal = "2";
private String graceOnInterest = "2";
private String extraTerms = "2";
private Boolean recalculateInterest = false;
private String newInterestRate = null;
private String adjustedDueDate = null;
private String rescheduleReasonId = "1";
private String rescheduleReasonComment = null;
private String submittedOnDate = "04 September 2014";
public String build(final String loanId) {
final HashMap<String, Object> map = new HashMap<>();
map.put("dateFormat", "dd MMMM yyyy");
map.put("locale", "en_GB");
map.put("loanId", loanId);
map.put("submittedOnDate", submittedOnDate);
map.put("rescheduleFromDate", rescheduleFromDate);
if(graceOnPrincipal != null) {
map.put("graceOnPrincipal", graceOnPrincipal);
}
if(graceOnInterest != null) {
map.put("graceOnInterest", graceOnInterest);
}
if(extraTerms != null) {
map.put("extraTerms", extraTerms);
}
map.put("recalculateInterest", recalculateInterest);
if(newInterestRate != null) {
map.put("newInterestRate", newInterestRate);
}
if(adjustedDueDate != null) {
map.put("adjustedDueDate", adjustedDueDate);
}
map.put("rescheduleReasonId", rescheduleReasonId);
if(rescheduleReasonComment != null) {
map.put("rescheduleReasonComment", rescheduleReasonComment);
}
return new Gson().toJson(map);
}
public LoanRescheduleRequestTestBuilder updateRescheduleFromDate(final String rescheduleFromDate) {
if(rescheduleFromDate != null) {
this.rescheduleFromDate = rescheduleFromDate;
}
return this;
}
public LoanRescheduleRequestTestBuilder updateGraceOnPrincipal(final String graceOnPrincipal) {
this.graceOnPrincipal = graceOnPrincipal;
return this;
}
public LoanRescheduleRequestTestBuilder updateGraceOnInterest(final String graceOnInterest) {
this.graceOnInterest = graceOnInterest;
return this;
}
public LoanRescheduleRequestTestBuilder updateExtraTerms(final String extraTerms) {
this.extraTerms = extraTerms;
return this;
}
public LoanRescheduleRequestTestBuilder updateRecalculateInterest(final Boolean recalculateInterest) {
this.recalculateInterest = recalculateInterest;
return this;
}
public LoanRescheduleRequestTestBuilder updateNewInterestRate(final String newInterestRate) {
this.newInterestRate = newInterestRate;
return this;
}
public LoanRescheduleRequestTestBuilder updateAdjustedDueDate(final String adjustedDueDate) {
this.adjustedDueDate = adjustedDueDate;
return this;
}
public LoanRescheduleRequestTestBuilder updateRescheduleReasonId(final String rescheduleReasonId) {
this.rescheduleReasonId = rescheduleReasonId;
return this;
}
public LoanRescheduleRequestTestBuilder updateRescheduleReasonComment(final String rescheduleReasonComment) {
this.rescheduleReasonComment = rescheduleReasonComment;
return this;
}
public String getRejectLoanRescheduleRequestJSON() {
final HashMap<String, String> map = new HashMap<>();
map.put("rescheduleFromDate", rescheduleFromDate);
if (graceOnPrincipal != null) {
map.put("graceOnPrincipal", graceOnPrincipal);
}
if (graceOnInterest != null) {
map.put("graceOnInterest", graceOnInterest);
}
if (extraTerms != null) {
map.put("extraTerms", extraTerms);
}
map.put("recalculateInterest", recalculateInterest);
if (newInterestRate != null) {
map.put("newInterestRate", newInterestRate);
}
if (adjustedDueDate != null) {
map.put("adjustedDueDate", adjustedDueDate);
}
map.put("rescheduleReasonId", rescheduleReasonId);
if (rescheduleReasonComment != null) {
map.put("rescheduleReasonComment", rescheduleReasonComment);
}
return new Gson().toJson(map);
}
public LoanRescheduleRequestTestBuilder updateRescheduleFromDate(final String rescheduleFromDate) {
if (rescheduleFromDate != null) {
this.rescheduleFromDate = rescheduleFromDate;
}
return this;
}
public LoanRescheduleRequestTestBuilder updateGraceOnPrincipal(final String graceOnPrincipal) {
this.graceOnPrincipal = graceOnPrincipal;
return this;
}
public LoanRescheduleRequestTestBuilder updateGraceOnInterest(final String graceOnInterest) {
this.graceOnInterest = graceOnInterest;
return this;
}
public LoanRescheduleRequestTestBuilder updateExtraTerms(final String extraTerms) {
this.extraTerms = extraTerms;
return this;
}
public LoanRescheduleRequestTestBuilder updateRecalculateInterest(final Boolean recalculateInterest) {
this.recalculateInterest = recalculateInterest;
return this;
}
public LoanRescheduleRequestTestBuilder updateNewInterestRate(final String newInterestRate) {
this.newInterestRate = newInterestRate;
return this;
}
public LoanRescheduleRequestTestBuilder updateAdjustedDueDate(final String adjustedDueDate) {
this.adjustedDueDate = adjustedDueDate;
return this;
}
public LoanRescheduleRequestTestBuilder updateRescheduleReasonId(final String rescheduleReasonId) {
this.rescheduleReasonId = rescheduleReasonId;
return this;
}
public LoanRescheduleRequestTestBuilder updateRescheduleReasonComment(final String rescheduleReasonComment) {
this.rescheduleReasonComment = rescheduleReasonComment;
return this;
}
public LoanRescheduleRequestTestBuilder updateSubmittedOnDate(final String submittedOnDate) {
this.submittedOnDate = submittedOnDate;
return this;
}
public String getRejectLoanRescheduleRequestJSON() {
final HashMap<String, String> map = new HashMap<>();
map.put("locale", "en");
map.put("dateFormat", "dd MMMM yyyy");
map.put("rejectedOnDate", submittedOnDate);
return new Gson().toJson(map);
}
public String getApproveLoanRescheduleRequestJSON() {
final HashMap<String, String> map = new HashMap<>();
}
public String getApproveLoanRescheduleRequestJSON() {
final HashMap<String, String> map = new HashMap<>();
map.put("locale", "en");
map.put("dateFormat", "dd MMMM yyyy");
map.put("approvedOnDate", submittedOnDate);
return new Gson().toJson(map);
}
}
}
@@ -8,33 +8,9 @@ package org.mifosplatform.portfolio.loanaccount.domain;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.*;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import javax.persistence.Version;
import javax.persistence.*;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
@@ -82,32 +58,10 @@ import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
import org.mifosplatform.portfolio.loanaccount.data.LoanTermVariationsData;
import org.mifosplatform.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
import org.mifosplatform.portfolio.loanaccount.exception.ExceedingTrancheCountException;
import org.mifosplatform.portfolio.loanaccount.exception.InvalidLoanStateTransitionException;
import org.mifosplatform.portfolio.loanaccount.exception.InvalidLoanTransactionTypeException;
import org.mifosplatform.portfolio.loanaccount.exception.InvalidRefundDateException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanApplicationDateException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanDisbursalException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentDateException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerAssignmentException;
import org.mifosplatform.portfolio.loanaccount.exception.LoanOfficerUnassignmentDateException;
import org.mifosplatform.portfolio.loanaccount.exception.MultiDisbursementDataRequiredException;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
import org.mifosplatform.portfolio.loanaccount.exception.*;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.*;
import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
import org.mifosplatform.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
import org.mifosplatform.portfolio.loanproduct.domain.RecalculationFrequencyType;
import org.mifosplatform.portfolio.loanproduct.domain.*;
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.data.jpa.domain.AbstractPersistable;
@@ -1320,7 +1274,9 @@ public class Loan extends AbstractPersistable<Long> {
}
}
// the comparison should be done with the tenant date (DateUtils.getLocalDateOfTenant()) and not the server date (new LocalDate())
// the comparison should be done with the tenant date
// (DateUtils.getLocalDateOfTenant()) and not the server date (new
// LocalDate())
if (getSubmittedOnDate().isAfter(DateUtils.getLocalDateOfTenant())) {
final String errorMessage = "The date on which a loan is submitted cannot be in the future.";
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.a.future.date", errorMessage, getSubmittedOnDate());
@@ -2204,7 +2160,7 @@ public class Loan extends AbstractPersistable<Long> {
BigDecimal setPrincipalAmount = BigDecimal.ZERO;
BigDecimal totalAmount = BigDecimal.ZERO;
for (LoanDisbursementDetails disbursementDetails : loanDisburseDetails) {
if(disbursementDetails.actualDisbursementDate() != null){
if (disbursementDetails.actualDisbursementDate() != null) {
setPrincipalAmount = setPrincipalAmount.add(disbursementDetails.principal());
}
totalAmount = totalAmount.add(disbursementDetails.principal());
@@ -3959,7 +3915,7 @@ public class Loan extends AbstractPersistable<Long> {
LocalDate newRepaymentDate = null;
Boolean isFirstTime = true;
LocalDate latestRepaymentDate = null;
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : this.repaymentScheduleInstallments) {
LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
@@ -3982,7 +3938,9 @@ public class Loan extends AbstractPersistable<Long> {
if (isHolidayEnabled) {
newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate, holidays);
}
if (latestRepaymentDate == null || latestRepaymentDate.isBefore(newRepaymentDate)) {
latestRepaymentDate = newRepaymentDate;
}
loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate);
// reset from date to get actual daysInPeriod
@@ -3996,6 +3954,9 @@ public class Loan extends AbstractPersistable<Long> {
tmpFromDate = oldDueDate;
}
}
if (latestRepaymentDate != null) {
this.expectedMaturityDate = latestRepaymentDate.toDate();
}
}
public void updateLoanRepaymentScheduleDates(final LocalDate meetingStartDate, final String recuringRule,
@@ -4009,7 +3970,7 @@ public class Loan extends AbstractPersistable<Long> {
LocalDate newRepaymentDate = null;
LocalDate seedDate = meetingStartDate;
LocalDate latestRepaymentDate = null;
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : this.repaymentScheduleInstallments) {
LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
@@ -4032,6 +3993,9 @@ public class Loan extends AbstractPersistable<Long> {
if (isHolidayEnabled) {
newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate, holidays);
}
if (latestRepaymentDate == null || latestRepaymentDate.isBefore(newRepaymentDate)) {
latestRepaymentDate = newRepaymentDate;
}
loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate);
// reset from date to get actual daysInPeriod
@@ -4042,6 +4006,9 @@ public class Loan extends AbstractPersistable<Long> {
tmpFromDate = oldDueDate;
}
}
if (latestRepaymentDate != null) {
this.expectedMaturityDate = latestRepaymentDate.toDate();
}
}
private LocalDate getMaxDateLimitForNewRepayment(final PeriodFrequencyType periodFrequencyType, final Integer loanRepaymentInterval,
@@ -4929,8 +4896,6 @@ public class Loan extends AbstractPersistable<Long> {
}
/**
* @param loan
* the Loan object
* @return loan disbursement data
**/
public List<DisbursementData> getDisbursmentData() {
@@ -4963,13 +4928,13 @@ public class Loan extends AbstractPersistable<Long> {
* TODO
* @param compoundingCalendarInstance
* TODO
* @param loan
* the Loan object
* @param loanCalendarInstance
* Used for accessing the loan's calendar object
* @return application terms of the Loan object
**/
@SuppressWarnings({ "unused" })
public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency applicationCurrency,
final CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance) {
final CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar) {
LoanProduct loanProduct = loanProduct();
// LoanProductRelatedDetail loanProductRelatedDetail =
// getLoanRepaymentScheduleDetail();
@@ -5003,7 +4968,12 @@ public class Loan extends AbstractPersistable<Long> {
// TODO get calender linked to loan if any exist. As of 17-07-2014,
// could not find a link in the database.
// skip for now and set the Calender object to null
Calendar calendar = null;
// Calendar loanCalendar = null;
// The calendar instance might be null if the loan is not connected
// To a calendar object
// if (loanCalendarInstance != null) {
// loanCalendar = loanCalendarInstance.getCalendar();
// }
final Integer graceOnPrincipalPayment = this.loanRepaymentScheduleDetail.graceOnPrincipalPayment();
final Integer graceOnInterestPayment = this.loanRepaymentScheduleDetail.graceOnInterestPayment();
@@ -5039,7 +5009,7 @@ public class Loan extends AbstractPersistable<Long> {
maxOutstandingBalance, loanVariationTermsData, interestChargedFromDate,
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
recalculationFrequencyType, restCalendarInstance, compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
this.loanProduct.preCloseInterestCalculationStrategy(), rescheduleStrategyMethod);
this.loanProduct.preCloseInterestCalculationStrategy(), rescheduleStrategyMethod, loanCalendar);
}
/**
@@ -7,15 +7,7 @@ package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.*;
import org.joda.time.Days;
import org.joda.time.LocalDate;
@@ -24,16 +16,13 @@ import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.workingdays.domain.RepaymentRescheduleType;
import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.loanaccount.data.DisbursementData;
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummary;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
import org.mifosplatform.portfolio.loanaccount.domain.*;
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
import org.mifosplatform.portfolio.loanaccount.loanschedule.exception.MultiDisbursementEmiAmountException;
import org.mifosplatform.portfolio.loanaccount.loanschedule.exception.MultiDisbursementOutstandingAmoutException;
@@ -101,7 +90,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
LocalDate actualRepaymentDate = periodStartDate;
boolean isFirstRepayment = true;
LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(periodStartDate, loanApplicationTerms,
isFirstRepayment);
isFirstRepayment, holidayDetailDTO);
final LocalDate idealDisbursementDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate(
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate);
@@ -115,7 +104,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
Money outstandingBalance = principalDisbursed;
// Set fixed EMI Amount
updateFixedInstallmentAmount(mc, loanApplicationTerms, actualRepaymentDate, periodNumber, outstandingBalance);
updateFixedInstallmentAmount(mc, loanApplicationTerms, actualRepaymentDate, periodNumber, outstandingBalance, holidayDetailDTO);
// disbursement map for tranche details(will added to outstanding
// balance as per the start date)
@@ -173,7 +162,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
while (!outstandingBalance.isZero() || !disburseDetailMap.isEmpty()) {
actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms,
isFirstRepayment);
isFirstRepayment, holidayDetailDTO);
isFirstRepayment = false;
LocalDate scheduledDueDate = this.scheduledDateGenerator.adjustRepaymentDate(actualRepaymentDate, loanApplicationTerms,
holidayDetailDTO);
@@ -372,7 +361,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// method applies early payment strategy
reducePrincipal = reducePrincipal.plus(unprocessed);
reducePrincipal = applyEarlyPaymentStrategy(loanApplicationTerms, reducePrincipal,
totalCumulativePrincipal, periodNumber, mc);
totalCumulativePrincipal, periodNumber, mc, holidayDetailDTO);
}
// identify late payments and add compounding
// details to
@@ -524,7 +513,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
reducePrincipal = reducePrincipal.plus(earlyPaidAmount);
BigDecimal fixedEmiAmount = loanApplicationTerms.getFixedEmiAmount();
reducePrincipal = applyEarlyPaymentStrategy(loanApplicationTerms, reducePrincipal, totalCumulativePrincipal,
periodNumber + 1, mc);
periodNumber + 1, mc, holidayDetailDTO);
if (fixedEmiAmount.compareTo(loanApplicationTerms.getFixedEmiAmount()) != 0) {
isEmiAmountChanged = true;
}
@@ -597,7 +586,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
if (isEmiAmountChanged) {
updateFixedInstallmentAmount(mc, loanApplicationTerms,
loanApplicationTerms.getExpectedDisbursementDate(), periodNumber, loanApplicationTerms
.getPrincipal().minus(totalCumulativePrincipal));
.getPrincipal().minus(totalCumulativePrincipal), holidayDetailDTO);
}
PrincipalInterest interestTillDate = calculatePrincipalInterestComponentsForPeriod(
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
@@ -642,7 +631,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
principalProcessed = principalProcessed.plus(unprocessed.plus(addToPrinciapal));
BigDecimal fixedEmiAmount = loanApplicationTerms.getFixedEmiAmount();
reducePrincipal = applyEarlyPaymentStrategy(loanApplicationTerms, reducePrincipal,
totalCumulativePrincipal.plus(principalForThisPeriod.minus(principalProcessed)), periodNumber + 1, mc);
totalCumulativePrincipal.plus(principalForThisPeriod.minus(principalProcessed)), periodNumber + 1, mc,
holidayDetailDTO);
if (fixedEmiAmount.compareTo(loanApplicationTerms.getFixedEmiAmount()) != 0) {
isEmiAmountChanged = true;
}
@@ -736,12 +726,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
}
private boolean updateFixedInstallmentAmount(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
LocalDate actualRepaymentDate, int periodNumber, Money outstandingBalance) {
LocalDate actualRepaymentDate, int periodNumber, Money outstandingBalance, final HolidayDetailDTO holidayDetailDTO) {
boolean isAmountChanged = false;
if (loanApplicationTerms.getActualFixedEmiAmount() == null && loanApplicationTerms.getInterestMethod().isDecliningBalnce()
&& loanApplicationTerms.getAmortizationMethod().isEqualInstallment()) {
LocalDate nextPeriodDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms,
false);
false, holidayDetailDTO);
if (periodNumber < loanApplicationTerms.getPrincipalGrace() + 1) {
periodNumber = loanApplicationTerms.getPrincipalGrace() + 1;
}
@@ -803,7 +793,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
do {
actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms,
isFirstRepayment);
isFirstRepayment, holidayDetailDTO);
int daysInPeriod = Days.daysBetween(periodStartDate, actualRepaymentDate).getDays();
if (actualRepaymentDate.isAfter(currentDate)) {
actualRepaymentDate = currentDate;
@@ -932,7 +922,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
* TODO
*/
private Money applyEarlyPaymentStrategy(final LoanApplicationTerms loanApplicationTerms, Money reducePrincipal,
final Money totalCumulativePrincipal, int periodNumber, final MathContext mc) {
final Money totalCumulativePrincipal, int periodNumber, final MathContext mc, final HolidayDetailDTO holidayDetailDTO) {
if (reducePrincipal.isGreaterThanZero()) {
switch (loanApplicationTerms.getRescheduleStrategyMethod()) {
case REDUCE_EMI_AMOUNT:
@@ -941,7 +931,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
if (loanApplicationTerms.getActualFixedEmiAmount() == null) {
loanApplicationTerms.setFixedEmiAmount(null);
updateFixedInstallmentAmount(mc, loanApplicationTerms, loanApplicationTerms.getExpectedDisbursementDate(),
periodNumber, loanApplicationTerms.getPrincipal().minus(totalCumulativePrincipal));
periodNumber, loanApplicationTerms.getPrincipal().minus(totalCumulativePrincipal), holidayDetailDTO);
}
reducePrincipal = reducePrincipal.zero();
break;
@@ -1272,7 +1262,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
@Override
public LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO,
final CalendarInstance restCalendarInstance, final CalendarInstance compoundingCalendarInstance) {
final CalendarInstance restCalendarInstance, final CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar) {
final Loan loan = loanRescheduleRequest.getLoan();
final LoanSummary loanSummary = loan.getSummary();
@@ -1414,7 +1404,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// get the loan application terms from the Loan object
final LoanApplicationTerms loanApplicationTerms = loan.getLoanApplicationTerms(applicationCurrency, restCalendarInstance,
compoundingCalendarInstance);
compoundingCalendarInstance, loanCalendar);
// update the number of repayments
loanApplicationTerms.updateNumberOfRepayments(numberOfRepayments);
@@ -1454,7 +1444,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|| period.periodDueDate().isAfter(loanRescheduleRequest.getRescheduleFromDate()) || period.isNew()) {
installmentDueDate = this.scheduledDateGenerator.generateNextRepaymentDate(installmentDueDate, loanApplicationTerms,
false);
false, holidayDetailDTO);
if (adjustedDueDate != null && periodNumber == 1) {
installmentDueDate = adjustedDueDate;
@@ -13,10 +13,16 @@ import org.joda.time.Years;
import org.mifosplatform.organisation.holiday.service.HolidayUtil;
import org.mifosplatform.organisation.workingdays.domain.RepaymentRescheduleType;
import org.mifosplatform.organisation.workingdays.service.WorkingDaysUtil;
import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarHistory;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.calendar.service.CalendarUtils;
import org.mifosplatform.portfolio.common.domain.DayOfWeekType;
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
import java.util.Set;
public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
@Override
@@ -27,7 +33,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
LocalDate lastRepaymentDate = loanApplicationTerms.getExpectedDisbursementDate();
boolean isFirstRepayment = true;
for (int repaymentPeriod = 1; repaymentPeriod <= numberOfRepayments; repaymentPeriod++) {
lastRepaymentDate = generateNextRepaymentDate(lastRepaymentDate, loanApplicationTerms, isFirstRepayment);
lastRepaymentDate = generateNextRepaymentDate(lastRepaymentDate, loanApplicationTerms, isFirstRepayment, holidayDetailDTO);
isFirstRepayment = false;
}
lastRepaymentDate = adjustRepaymentDate(lastRepaymentDate, loanApplicationTerms, holidayDetailDTO);
@@ -36,15 +42,29 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
@Override
public LocalDate generateNextRepaymentDate(final LocalDate lastRepaymentDate, final LoanApplicationTerms loanApplicationTerms,
boolean isFirstRepayment) {
boolean isFirstRepayment, final HolidayDetailDTO holidayDetailDTO) {
final LocalDate firstRepaymentPeriodDate = loanApplicationTerms.getCalculatedRepaymentsStartingFromLocalDate();
LocalDate dueRepaymentPeriodDate = null;
if (isFirstRepayment && firstRepaymentPeriodDate != null) {
dueRepaymentPeriodDate = firstRepaymentPeriodDate;
} else {
dueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
loanApplicationTerms.getRepaymentEvery(), lastRepaymentDate, loanApplicationTerms.getNthDay(),
loanApplicationTerms.getWeekDayType());
Calendar currentCalendar = loanApplicationTerms.getLoanCalendar();
if (currentCalendar == null) {
dueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
loanApplicationTerms.getRepaymentEvery(), lastRepaymentDate, loanApplicationTerms.getNthDay(),
loanApplicationTerms.getWeekDayType());
} else {
// If we have currentCalendar object, this neans there is a
// calendar associated with
// the loan, and we should use it in order to calculate next
// repayment
LocalDate seedDate = currentCalendar.getStartDateLocalDate();
String reccuringString = currentCalendar.getRecurrence();
dueRepaymentPeriodDate = CalendarUtils.getNewRepaymentMeetingDate(reccuringString, seedDate, dueRepaymentPeriodDate,
loanApplicationTerms.getRepaymentEvery(),
CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(loanApplicationTerms.getLoanTermPeriodFrequencyType()),
holidayDetailDTO.getWorkingDays());
}
}
return dueRepaymentPeriodDate;
}
@@ -54,19 +74,20 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
final HolidayDetailDTO holidayDetailDTO) {
LocalDate adjustedDate = dueRepaymentPeriodDate;
LocalDate nextDueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
loanApplicationTerms.getRepaymentEvery(), adjustedDate, loanApplicationTerms.getNthDay(),
loanApplicationTerms.getWeekDayType());
final RepaymentRescheduleType rescheduleType = RepaymentRescheduleType.fromInt(holidayDetailDTO.getWorkingDays().getRepaymentReschedulingType());
final RepaymentRescheduleType rescheduleType = RepaymentRescheduleType.fromInt(holidayDetailDTO.getWorkingDays()
.getRepaymentReschedulingType());
/**
* Fix for https://mifosforge.jira.com/browse/MIFOSX-1357
*/
// recursively check for the next working meeting day.
while (WorkingDaysUtil.isNonWorkingDay(holidayDetailDTO.getWorkingDays(), nextDueRepaymentPeriodDate) &&
rescheduleType == RepaymentRescheduleType.MOVE_TO_NEXT_REPAYMENT_MEETING_DAY) {
while (WorkingDaysUtil.isNonWorkingDay(holidayDetailDTO.getWorkingDays(), nextDueRepaymentPeriodDate)
&& rescheduleType == RepaymentRescheduleType.MOVE_TO_NEXT_REPAYMENT_MEETING_DAY) {
nextDueRepaymentPeriodDate = getRepaymentPeriodDate(loanApplicationTerms.getRepaymentPeriodFrequencyType(),
loanApplicationTerms.getRepaymentEvery(), nextDueRepaymentPeriodDate, loanApplicationTerms.getNthDay(),
@@ -196,7 +217,7 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator {
LocalDate generatedDate = loanApplicationTerms.getExpectedDisbursementDate();
boolean isFirstRepayment = true;
while (!generatedDate.isAfter(lastRepaymentDate)) {
generatedDate = generateNextRepaymentDate(generatedDate, loanApplicationTerms, isFirstRepayment);
generatedDate = generateNextRepaymentDate(generatedDate, loanApplicationTerms, isFirstRepayment, holidayDetailDTO);
isFirstRepayment = false;
}
generatedDate = adjustRepaymentDate(generatedDate, loanApplicationTerms, holidayDetailDTO);
@@ -18,6 +18,7 @@ import org.joda.time.PeriodType;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.common.domain.DayOfWeekType;
import org.mifosplatform.portfolio.common.domain.DaysInMonthType;
@@ -39,6 +40,8 @@ import org.mifosplatform.portfolio.loanproduct.domain.RecalculationFrequencyType
public final class LoanApplicationTerms {
private final ApplicationCurrency currency;
private final Calendar loanCalendar;
private Integer loanTermFrequency;
private final PeriodFrequencyType loanTermPeriodFrequencyType;
private Integer numberOfRepayments;
@@ -160,7 +163,7 @@ public final class LoanApplicationTerms {
final RecalculationFrequencyType recalculationFrequencyType, final CalendarInstance restCalendarInstance,
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy) {
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar) {
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
@@ -172,7 +175,7 @@ public final class LoanApplicationTerms {
disbursementDatas, maxOutstandingBalance, emiAmountVariations, graceOnArrearsAgeing, daysInMonthType, daysInYearType,
isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance,
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
installmentAmountInMultiplesOf, preClosureInterestCalculationStrategy);
installmentAmountInMultiplesOf, preClosureInterestCalculationStrategy, loanCalendar);
}
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
@@ -188,6 +191,29 @@ public final class LoanApplicationTerms {
final RecalculationFrequencyType compoundingFrequencyType,
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
final LoanRescheduleStrategyMethod rescheduleStrategyMethod) {
final Calendar loanCalendar = null;
return assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDay, dayOfWeek,
expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, inArrearsTolerance,
loanProductRelatedDetail, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations,
interestChargedFromDate, principalThresholdForLastInstalment, installmentAmountInMultiplesOf, recalculationFrequencyType,
restCalendarInstance, compoundingMethod, compoundingCalendarInstance, compoundingFrequencyType,
loanPreClosureInterestCalculationStrategy, rescheduleStrategyMethod, loanCalendar);
}
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
final PeriodFrequencyType loanTermPeriodFrequencyType, NthDayType nthDay, DayOfWeekType dayOfWeek,
final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate,
final LocalDate calculatedRepaymentsStartingFromDate, final Money inArrearsTolerance,
final LoanProductRelatedDetail loanProductRelatedDetail, final boolean multiDisburseLoan, final BigDecimal emiAmount,
final List<DisbursementData> disbursementDatas, final BigDecimal maxOutstandingBalance,
final List<LoanTermVariationsData> emiAmountVariations, final LocalDate interestChargedFromDate,
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
final RecalculationFrequencyType recalculationFrequencyType, final CalendarInstance restCalendarInstance,
final InterestRecalculationCompoundingMethod compoundingMethod, final CalendarInstance compoundingCalendarInstance,
final RecalculationFrequencyType compoundingFrequencyType,
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
final LoanRescheduleStrategyMethod rescheduleStrategyMethod, final Calendar loanCalendar) {
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
@@ -210,7 +236,6 @@ public final class LoanApplicationTerms {
final DaysInMonthType daysInMonthType = loanProductRelatedDetail.fetchDaysInMonthType();
final DaysInYearType daysInYearType = loanProductRelatedDetail.fetchDaysInYearType();
final boolean isInterestRecalculationEnabled = loanProductRelatedDetail.isInterestRecalculationEnabled();
return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, nthDay.getValue(), dayOfWeek, amortizationMethod, interestMethod,
interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
@@ -220,7 +245,7 @@ public final class LoanApplicationTerms {
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
loanPreClosureInterestCalculationStrategy);
loanPreClosureInterestCalculationStrategy, loanCalendar);
}
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
@@ -262,7 +287,7 @@ public final class LoanApplicationTerms {
rescheduleStrategyMethod = interestRecalculationDetails.getRescheduleStrategyMethod();
interestRecalculationCompoundingMethod = interestRecalculationDetails.getInterestRecalculationCompoundingMethod();
}
final Calendar loanCalendar = null;
return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, null, null, amortizationMethod, interestMethod, interestRatePerPeriod,
interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney,
@@ -272,7 +297,7 @@ public final class LoanApplicationTerms {
daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod,
interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
loanPreClosureInterestCalculationStrategy);
loanPreClosureInterestCalculationStrategy, loanCalendar);
}
public static LoanApplicationTerms assembleFrom(final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType,
@@ -292,7 +317,8 @@ public final class LoanApplicationTerms {
applicationTerms.interestRecalculationCompoundingMethod, applicationTerms.restCalendarInstance,
applicationTerms.recalculationFrequencyType, applicationTerms.compoundingCalendarInstance,
applicationTerms.compoundingFrequencyType, applicationTerms.principalThresholdForLastInstalment,
applicationTerms.installmentAmountInMultiplesOf, applicationTerms.preClosureInterestCalculationStrategy);
applicationTerms.installmentAmountInMultiplesOf, applicationTerms.preClosureInterestCalculationStrategy,
applicationTerms.loanCalendar);
}
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
@@ -312,7 +338,7 @@ public final class LoanApplicationTerms {
final CalendarInstance restCalendarInstance, final RecalculationFrequencyType recalculationFrequencyType,
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy) {
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy, final Calendar loanCalendar) {
this.currency = currency;
this.loanTermFrequency = loanTermFrequency;
this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
@@ -359,6 +385,8 @@ public final class LoanApplicationTerms {
this.principalThresholdForLastInstalment = principalThresholdForLastInstalment;
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
this.preClosureInterestCalculationStrategy = preClosureInterestCalculationStrategy;
this.loanCalendar = loanCalendar;
}
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
@@ -1211,8 +1239,11 @@ public final class LoanApplicationTerms {
return this.compoundingFrequencyType;
}
public BigDecimal getActualFixedEmiAmount() {
return this.actualFixedEmiAmount;
}
public Calendar getLoanCalendar() {
return loanCalendar;
}
}
@@ -12,6 +12,7 @@ import java.util.Set;
import org.joda.time.LocalDate;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
@@ -32,8 +33,10 @@ public interface LoanScheduleGenerator {
LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments,
MonetaryCurrency currency, LocalDate onDate, LoanApplicationTerms loanApplicationTerms, MathContext mc,
Set<LoanCharge> charges, HolidayDetailDTO holidayDetailDTO, List<LoanTransaction> loanTransactions, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor);
Set<LoanCharge> charges, HolidayDetailDTO holidayDetailDTO, List<LoanTransaction> loanTransactions,
LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor);
LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance);
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance,
CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar);
}
@@ -17,7 +17,8 @@ public interface ScheduledDateGenerator {
LocalDate idealDisbursementDateBasedOnFirstRepaymentDate(PeriodFrequencyType repaymentPeriodFrequencyType, int repaidEvery,
final LocalDate firstRepaymentDate);
LocalDate generateNextRepaymentDate(LocalDate lastRepaymentDate, LoanApplicationTerms loanApplicationTerms, boolean isFirstRepayment);
LocalDate generateNextRepaymentDate(LocalDate lastRepaymentDate, LoanApplicationTerms loanApplicationTerms, boolean isFirstRepayment,
final HolidayDetailDTO holidayDetailDTO);
LocalDate adjustRepaymentDate(LocalDate dueRepaymentPeriodDate, LoanApplicationTerms loanApplicationTerms,
final HolidayDetailDTO holidayDetailDTO);
@@ -302,7 +302,7 @@ public class LoanScheduleAssembler {
loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, loanVariationTermsData,
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, recalculationFrequencyType,
restCalendarInstance, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy());
installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy(), calendar);
}
private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate,
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain;
import java.math.MathContext;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.DecliningBalanceInterestLoanScheduleGenerator;
@@ -20,19 +21,19 @@ public class DefaultLoanReschedulerFactory implements LoanReschedulerFactory {
public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod,
final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency,
final HolidayDetailDTO holidayDetailDTO, final CalendarInstance restCalendarInstance,
final CalendarInstance compoundingCalendarInstance) {
final CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar) {
LoanRescheduleModel loanRescheduleModel = null;
switch (interestMethod) {
case DECLINING_BALANCE:
loanRescheduleModel = new DecliningBalanceInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance);
applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, loanCalendar);
break;
case FLAT:
loanRescheduleModel = new FlatInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance);
applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, loanCalendar);
break;
case INVALID:
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain;
import java.math.MathContext;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
@@ -16,5 +17,6 @@ public interface LoanReschedulerFactory {
public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod,
final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency,
final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance);
final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance,
final Calendar loanCalendar);
}
@@ -18,6 +18,7 @@ import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyReposit
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
@@ -92,9 +93,15 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
}
final CalendarInstance loanCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
CalendarEntityType.LOANS.getValue());
Calendar loanCalendar = null;
if (loanCalendarInstance != null) {
loanCalendar = loanCalendarInstance.getCalendar();
}
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance);
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
loanCalendar);
LoanRescheduleModel loanRescheduleModelWithOldPeriods = LoanRescheduleModel.createWithSchedulehistory(loanRescheduleModel,
oldPeriods);
return loanRescheduleModelWithOldPeriods;
@@ -8,13 +8,7 @@ package org.mifosplatform.portfolio.loanaccount.rescheduleloan.service;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
@@ -36,38 +30,21 @@ import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
import org.mifosplatform.portfolio.loanaccount.data.HolidayDetailDTO;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargePaidByData;
import org.mifosplatform.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.mifosplatform.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanAccountDomainService;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
import org.mifosplatform.portfolio.loanaccount.domain.LoanInstallmentCharge;
import org.mifosplatform.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummary;
import org.mifosplatform.portfolio.loanaccount.domain.LoanSummaryWrapper;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransaction;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.mifosplatform.portfolio.loanaccount.domain.LoanTransactionType;
import org.mifosplatform.portfolio.loanaccount.domain.*;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistoryRepository;
import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants;
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.data.LoanRescheduleRequestDataValidator;
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.DefaultLoanReschedulerFactory;
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModelRepaymentPeriod;
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository;
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.domain.*;
import org.mifosplatform.portfolio.loanaccount.rescheduleloan.exception.LoanRescheduleRequestNotFoundException;
import org.mifosplatform.portfolio.loanaccount.service.LoanAssembler;
import org.mifosplatform.portfolio.loanaccount.service.LoanChargeReadPlatformService;
@@ -329,8 +306,15 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
}
final CalendarInstance loanCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
CalendarEntityType.LOANS.getValue());
Calendar loanCalendar = null;
if (loanCalendarInstance != null) {
loanCalendar = loanCalendarInstance.getCalendar();
}
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance);
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
loanCalendar);
final Collection<LoanRescheduleModelRepaymentPeriod> periods = loanRescheduleModel.getPeriods();
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
@@ -566,9 +550,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
/**
* handles the data integrity violation exception for loan reschedule write
* services
*
* @param jsonCommand
* JSON command object
*
* @param dve
* data integrity violation exception
* @return void