You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by na...@apache.org on 2016/08/01 13:39:25 UTC
[1/5] incubator-fineract git commit: FINERACT-202 : enabling the
option for multi reshedule
Repository: incubator-fineract
Updated Branches:
refs/heads/develop ada9ced9a -> c44cf55fc
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestReadPlatformServiceImpl.java
index c880364..19f6b79 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestReadPlatformServiceImpl.java
@@ -29,6 +29,7 @@ import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
+import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
@@ -36,6 +37,7 @@ import org.apache.fineract.portfolio.loanaccount.rescheduleloan.data.LoanResched
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.data.LoanRescheduleRequestEnumerations;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.data.LoanRescheduleRequestStatusEnumData;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.data.LoanRescheduleRequestTimelineData;
+import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
@@ -71,13 +73,8 @@ public class LoanRescheduleRequestReadPlatformServiceImpl implements LoanResched
sqlBuilder.append("mc.id as clientId, ");
sqlBuilder.append("ml.account_no as loanAccountNumber, ");
sqlBuilder.append("lr.reschedule_from_installment as rescheduleFromInstallment, ");
- sqlBuilder.append("lr.grace_on_principal as graceOnPrincipal, ");
- sqlBuilder.append("lr.grace_on_interest as graceOnInterest, ");
sqlBuilder.append("lr.reschedule_from_date as rescheduleFromDate, ");
- sqlBuilder.append("lr.adjusted_due_date as adjustedDueDate, ");
- sqlBuilder.append("lr.extra_terms as extraTerms, ");
sqlBuilder.append("lr.recalculate_interest as recalculateInterest, ");
- sqlBuilder.append("lr.interest_rate as interestRate, ");
sqlBuilder.append("lr.reschedule_reason_cv_id as rescheduleReasonCvId, ");
sqlBuilder.append("cv.code_value as rescheduleReasonCvValue, ");
sqlBuilder.append("lr.reschedule_reason_comment as rescheduleReasonComment, ");
@@ -95,7 +92,14 @@ public class LoanRescheduleRequestReadPlatformServiceImpl implements LoanResched
sqlBuilder.append("lr.rejected_on_date as rejectedOnDate, ");
sqlBuilder.append("rbu.username as rejectedByUsername, ");
sqlBuilder.append("rbu.firstname as rejectedByFirstname, ");
- sqlBuilder.append("rbu.lastname as rejectedByLastname ");
+ sqlBuilder.append("rbu.lastname as rejectedByLastname, ");
+
+ sqlBuilder.append("tv.id as termId,");
+ sqlBuilder.append("tv.term_type as termType,");
+ sqlBuilder.append("tv.applicable_date as variationApplicableFrom, ");
+ sqlBuilder.append("tv.decimal_value as decimalValue, ");
+ sqlBuilder.append("tv.date_value as dateValue, ");
+ sqlBuilder.append("tv.is_specific_to_installment as isSpecificToInstallment ");
sqlBuilder.append("from " + loanRescheduleRequestTableName() + " lr ");
sqlBuilder.append("left join m_code_value cv on cv.id = lr.reschedule_reason_cv_id ");
@@ -104,6 +108,8 @@ public class LoanRescheduleRequestReadPlatformServiceImpl implements LoanResched
sqlBuilder.append("left join m_appuser rbu on rbu.id = lr.rejected_by_user_id ");
sqlBuilder.append("left join m_loan ml on ml.id = lr.loan_id ");
sqlBuilder.append("left join m_client mc on mc.id = ml.client_id ");
+ sqlBuilder.append("join m_loan_reschedule_request_term_variations_mapping rrtvm on lr.id = rrtvm.loan_reschedule_request_id ");
+ sqlBuilder.append("join m_loan_term_variations tv on tv.id = rrtvm.loan_term_variations_id and tv.parent_id is null") ;
this.schema = sqlBuilder.toString();
}
@@ -127,12 +133,7 @@ public class LoanRescheduleRequestReadPlatformServiceImpl implements LoanResched
final String loanAccountNumber = rs.getString("loanAccountNumber");
final Long clientId = rs.getLong("clientId");
final Integer rescheduleFromInstallment = JdbcSupport.getInteger(rs, "rescheduleFromInstallment");
- final Integer graceOnPrincipal = JdbcSupport.getInteger(rs, "graceOnPrincipal");
- final Integer graceOnInterest = JdbcSupport.getInteger(rs, "graceOnInterest");
final LocalDate rescheduleFromDate = JdbcSupport.getLocalDate(rs, "rescheduleFromDate");
- final LocalDate adjustedDueDate = JdbcSupport.getLocalDate(rs, "adjustedDueDate");
- final Integer extraTerms = JdbcSupport.getInteger(rs, "extraTerms");
- final BigDecimal interestRate = rs.getBigDecimal("interestRate");
final Long rescheduleReasonCvId = JdbcSupport.getLong(rs, "rescheduleReasonCvId");
final String rescheduleReasonCvValue = rs.getString("rescheduleReasonCvValue");
final CodeValueData rescheduleReasonCodeValue = CodeValueData.instance(rescheduleReasonCvId, rescheduleReasonCvValue);
@@ -157,14 +158,40 @@ public class LoanRescheduleRequestReadPlatformServiceImpl implements LoanResched
final LoanRescheduleRequestTimelineData timeline = new LoanRescheduleRequestTimelineData(submittedOnDate, submittedByUsername,
submittedByFirstname, submittedByLastname, approvedOnDate, approvedByUsername, approvedByFirstname, approvedByLastname,
rejectedOnDate, rejectedByUsername, rejectedByFirstname, rejectedByLastname);
-
- return LoanRescheduleRequestData.instance(id, loanId, statusEnum, rescheduleFromInstallment, graceOnPrincipal, graceOnInterest,
- rescheduleFromDate, adjustedDueDate, extraTerms, interestRate, rescheduleReasonCodeValue, rescheduleReasonComment,
- timeline, clientName, loanAccountNumber, clientId, recalculateInterest, rescheduleReasons);
+
+ Collection<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
+
+ do {
+ Long tempId = rs.getLong("id");
+ if (id.equals(tempId)) {
+ loanTermVariations.add(fetchLoanTermVariation(rs));
+ } else {
+ rs.previous();
+ break;
+ }
+ } while (rs.next());
+
+ return LoanRescheduleRequestData.instance(id, loanId, statusEnum, rescheduleFromInstallment, rescheduleFromDate,
+ rescheduleReasonCodeValue, rescheduleReasonComment, timeline, clientName, loanAccountNumber, clientId,
+ recalculateInterest, rescheduleReasons, loanTermVariations);
+ }
+
+ private LoanTermVariationsData fetchLoanTermVariation(final ResultSet rs) throws SQLException {
+ final Long id = rs.getLong("termId");
+ final LocalDate variationApplicableFrom = JdbcSupport.getLocalDate(rs, "variationApplicableFrom");
+ final BigDecimal decimalValue = rs.getBigDecimal("decimalValue");
+ final LocalDate dateValue = JdbcSupport.getLocalDate(rs, "dateValue");
+ final boolean isSpecificToInstallment = rs.getBoolean("isSpecificToInstallment");
+ final int termType = rs.getInt("termType");
+
+ final LoanTermVariationsData loanTermVariationsData = new LoanTermVariationsData(id,
+ LoanEnumerations.loanvariationType(termType), variationApplicableFrom, decimalValue, dateValue,
+ isSpecificToInstallment);
+ return loanTermVariationsData;
}
}
-
+
@Override
public List<LoanRescheduleRequestData> readLoanRescheduleRequests(Long loanId) {
final Loan loan = this.loanRepository.findOne(loanId);
@@ -209,12 +236,7 @@ public class LoanRescheduleRequestReadPlatformServiceImpl implements LoanResched
final Long loanId = null;
final LoanRescheduleRequestStatusEnumData statusEnum = null;
final Integer rescheduleFromInstallment = null;
- final Integer graceOnPrincipal = null;
- final Integer graceOnInterest = null;
final LocalDate rescheduleFromDate = null;
- final LocalDate adjustedDueDate = null;
- final Integer extraTerms = null;
- final BigDecimal interestRate = null;
final CodeValueData rescheduleReasonCodeValue = null;
final String rescheduleReasonComment = null;
final LoanRescheduleRequestTimelineData timeline = null;
@@ -222,9 +244,10 @@ public class LoanRescheduleRequestReadPlatformServiceImpl implements LoanResched
final String loanAccountNumber = null;
final Long clientId = null;
final Boolean recalculateInterest = null;
+ final Collection<LoanTermVariationsData> loanTermVariationsData = null;
- return LoanRescheduleRequestData.instance(id, loanId, statusEnum, rescheduleFromInstallment, graceOnPrincipal, graceOnInterest,
- rescheduleFromDate, adjustedDueDate, extraTerms, interestRate, rescheduleReasonCodeValue, rescheduleReasonComment,
- timeline, clientName, loanAccountNumber, clientId, recalculateInterest, rescheduleReasons);
+ return LoanRescheduleRequestData.instance(id, loanId, statusEnum, rescheduleFromInstallment, rescheduleFromDate,
+ rescheduleReasonCodeValue, rescheduleReasonComment, timeline, clientName, loanAccountNumber, clientId, recalculateInterest,
+ rescheduleReasons, loanTermVariationsData);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
index 74ec624..6c70d7c 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
@@ -22,9 +22,9 @@ 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.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -33,64 +33,52 @@ import java.util.Set;
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper;
-import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
+import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
+import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
-import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
-import org.apache.fineract.organisation.holiday.domain.Holiday;
-import org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
-import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
-import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
-import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
-import org.apache.fineract.portfolio.calendar.domain.Calendar;
-import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
-import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
-import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
-import org.apache.fineract.portfolio.floatingrates.exception.FloatingRateNotFoundException;
-import org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
-import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
-import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidByData;
+import org.apache.fineract.portfolio.account.service.AccountTransfersWritePlatformService;
+import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
-import org.apache.fineract.portfolio.loanaccount.domain.DefaultLoanLifecycleStateMachine;
+import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallmentRepository;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRescheduleRequestToTermVariationMapping;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary;
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
+import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistoryRepository;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.data.LoanRescheduleRequestDataValidator;
-import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.DefaultLoanReschedulerFactory;
-import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
-import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModelRepaymentPeriod;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.exception.LoanRescheduleRequestNotFoundException;
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
-import org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService;
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
-import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
-import org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
import org.apache.fineract.useradministration.domain.AppUser;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
@@ -107,25 +95,25 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
private final static Logger logger = LoggerFactory.getLogger(LoanRescheduleRequestWritePlatformServiceImpl.class);
- private final LoanRepositoryWrapper loanRepositoryWrapper;
private final CodeValueRepositoryWrapper codeValueRepositoryWrapper;
private final PlatformSecurityContext platformSecurityContext;
private final LoanRescheduleRequestDataValidator loanRescheduleRequestDataValidator;
private final LoanRescheduleRequestRepository loanRescheduleRequestRepository;
private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
- private final ConfigurationDomainService configurationDomainService;
- private final HolidayRepositoryWrapper holidayRepository;
- private final WorkingDaysRepositoryWrapper workingDaysRepository;
private final LoanRepaymentScheduleHistoryRepository loanRepaymentScheduleHistoryRepository;
private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService;
- private final CalendarInstanceRepository calendarInstanceRepository;
- private final LoanChargeReadPlatformService loanChargeReadPlatformService;
private final LoanTransactionRepository loanTransactionRepository;
private final JournalEntryWritePlatformService journalEntryWritePlatformService;
private final LoanRepository loanRepository;
private final LoanAssembler loanAssembler;
- private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
private final LoanUtilService loanUtilService;
+ private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
+ private final LoanScheduleGeneratorFactory loanScheduleFactory;
+ private final LoanSummaryWrapper loanSummaryWrapper;
+ private final AccountTransfersWritePlatformService accountTransfersWritePlatformService;
+ private final DefaultScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
+ private final LoanAccountDomainService loanAccountDomainService;
+ private final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository;
/**
* LoanRescheduleRequestWritePlatformServiceImpl constructor
@@ -133,38 +121,39 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
* @return void
**/
@Autowired
- public LoanRescheduleRequestWritePlatformServiceImpl(LoanRepositoryWrapper loanRepositoryWrapper,
- CodeValueRepositoryWrapper codeValueRepositoryWrapper, PlatformSecurityContext platformSecurityContext,
- LoanRescheduleRequestDataValidator loanRescheduleRequestDataValidator,
- LoanRescheduleRequestRepository loanRescheduleRequestRepository,
- ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository, ConfigurationDomainService configurationDomainService,
- HolidayRepositoryWrapper holidayRepository, WorkingDaysRepositoryWrapper workingDaysRepository,
- LoanRepaymentScheduleHistoryRepository loanRepaymentScheduleHistoryRepository,
+ public LoanRescheduleRequestWritePlatformServiceImpl(final CodeValueRepositoryWrapper codeValueRepositoryWrapper,
+ final PlatformSecurityContext platformSecurityContext,
+ final LoanRescheduleRequestDataValidator loanRescheduleRequestDataValidator,
+ final LoanRescheduleRequestRepository loanRescheduleRequestRepository,
+ final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
+ final LoanRepaymentScheduleHistoryRepository loanRepaymentScheduleHistoryRepository,
final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService,
- final CalendarInstanceRepository calendarInstanceRepository, final LoanChargeReadPlatformService loanChargeReadPlatformService,
final LoanTransactionRepository loanTransactionRepository,
final JournalEntryWritePlatformService journalEntryWritePlatformService, final LoanRepository loanRepository,
- final LoanAssembler loanAssembler, final FloatingRatesReadPlatformService floatingRatesReadPlatformService,
- final LoanUtilService loanUtilService) {
- this.loanRepositoryWrapper = loanRepositoryWrapper;
+ final LoanAssembler loanAssembler, final LoanUtilService loanUtilService,
+ final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
+ final LoanScheduleGeneratorFactory loanScheduleFactory, final LoanSummaryWrapper loanSummaryWrapper,
+ final AccountTransfersWritePlatformService accountTransfersWritePlatformService,
+ final LoanAccountDomainService loanAccountDomainService,
+ final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository) {
this.codeValueRepositoryWrapper = codeValueRepositoryWrapper;
this.platformSecurityContext = platformSecurityContext;
this.loanRescheduleRequestDataValidator = loanRescheduleRequestDataValidator;
this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
this.applicationCurrencyRepository = applicationCurrencyRepository;
- this.configurationDomainService = configurationDomainService;
- this.holidayRepository = holidayRepository;
- this.workingDaysRepository = workingDaysRepository;
this.loanRepaymentScheduleHistoryRepository = loanRepaymentScheduleHistoryRepository;
this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService;
- this.calendarInstanceRepository = calendarInstanceRepository;
- this.loanChargeReadPlatformService = loanChargeReadPlatformService;
this.loanTransactionRepository = loanTransactionRepository;
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
this.loanRepository = loanRepository;
this.loanAssembler = loanAssembler;
- this.floatingRatesReadPlatformService = floatingRatesReadPlatformService;
this.loanUtilService = loanUtilService;
+ this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
+ this.loanScheduleFactory = loanScheduleFactory;
+ this.loanSummaryWrapper = loanSummaryWrapper;
+ this.accountTransfersWritePlatformService = accountTransfersWritePlatformService;
+ this.loanAccountDomainService = loanAccountDomainService;
+ this.repaymentScheduleInstallmentRepository = repaymentScheduleInstallmentRepository;
}
/**
@@ -182,7 +171,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
final Long loanId = jsonCommand.longValueOfParameterNamed(RescheduleLoansApiConstants.loanIdParamName);
// use the loan id to get a Loan entity object
- final Loan loan = this.loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
+ final Loan loan = this.loanAssembler.assembleFrom(loanId);
// validate the request in the JsonCommand object passed as
// parameter
@@ -275,12 +264,24 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
}
final LoanRescheduleRequest loanRescheduleRequest = LoanRescheduleRequest.instance(loan,
- LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(), rescheduleFromInstallment, graceOnPrincipal, graceOnInterest,
- rescheduleFromDate, adjustedDueDate, extraTerms, recalculateInterest, interestRate, rescheduleReasonCodeValue,
- rescheduleReasonComment, submittedOnDate, this.platformSecurityContext.authenticatedUser(), null, null, null, null);
+ LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(), rescheduleFromInstallment, rescheduleFromDate,
+ recalculateInterest, rescheduleReasonCodeValue, rescheduleReasonComment, submittedOnDate,
+ this.platformSecurityContext.authenticatedUser(), null, null, null, null);
+
+ // update reschedule request to term variations mapping
+ List<LoanRescheduleRequestToTermVariationMapping> loanRescheduleRequestToTermVariationMappings = new ArrayList<>();
+ final Boolean isActive = false;
+ final boolean isSpecificToInstallment = false;
+ BigDecimal decimalValue = null;
+ Date dueDate = null;
+ // create term variations for flat and declining balance loans
+ createLoanTermVariationsForRegularLoans(loan, graceOnPrincipal, graceOnInterest, extraTerms, interestRate, rescheduleFromDate,
+ adjustedDueDate, loanRescheduleRequest, loanRescheduleRequestToTermVariationMappings, isActive,
+ isSpecificToInstallment, decimalValue, dueDate);
// create a new entry in the m_loan_reschedule_request table
this.loanRescheduleRequestRepository.save(loanRescheduleRequest);
+ this.loanRepository.save(loan);
return new CommandProcessingResultBuilder().withCommandId(jsonCommand.commandId()).withEntityId(loanRescheduleRequest.getId())
.withLoanId(loan.getId()).build();
@@ -295,6 +296,63 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
}
}
+ private void createLoanTermVariationsForRegularLoans(final Loan loan, final Integer graceOnPrincipal, final Integer graceOnInterest,
+ final Integer extraTerms, final BigDecimal interestRate, Date rescheduleFromDate, Date adjustedDueDate,
+ final LoanRescheduleRequest loanRescheduleRequest,
+ List<LoanRescheduleRequestToTermVariationMapping> loanRescheduleRequestToTermVariationMappings, final Boolean isActive,
+ final boolean isSpecificToInstallment, BigDecimal decimalValue, Date dueDate) {
+
+ if (rescheduleFromDate != null && adjustedDueDate != null) {
+ LoanTermVariations parent = null;
+ final Integer termType = LoanTermVariationType.DUE_DATE.getValue();
+ createLoanTermVariations(termType, loan, rescheduleFromDate, adjustedDueDate, loanRescheduleRequestToTermVariationMappings,
+ isActive, isSpecificToInstallment, decimalValue, parent);
+ }
+
+ if (rescheduleFromDate != null && interestRate != null) {
+ LoanTermVariations parent = null;
+ final Integer termType = LoanTermVariationType.INTEREST_RATE_FROM_INSTALLMENT.getValue();
+ createLoanTermVariations(termType, loan, rescheduleFromDate, dueDate, loanRescheduleRequestToTermVariationMappings, isActive,
+ isSpecificToInstallment, interestRate, parent);
+ }
+
+ if (rescheduleFromDate != null && graceOnPrincipal != null) {
+ final Integer termType = LoanTermVariationType.GRACE_ON_PRINCIPAL.getValue();
+ LoanTermVariations parent = null;
+ parent = createLoanTermVariations(termType, loan, rescheduleFromDate, dueDate, loanRescheduleRequestToTermVariationMappings,
+ isActive, isSpecificToInstallment, BigDecimal.valueOf(graceOnPrincipal), parent);
+
+ BigDecimal extraTermsBasedOnGracePeriods = BigDecimal.valueOf(graceOnPrincipal);
+ createLoanTermVariations(LoanTermVariationType.EXTEND_REPAYMENT_PERIOD.getValue(), loan, rescheduleFromDate, dueDate,
+ loanRescheduleRequestToTermVariationMappings, isActive, isSpecificToInstallment, extraTermsBasedOnGracePeriods, parent);
+
+ }
+
+ if (rescheduleFromDate != null && graceOnInterest != null) {
+ LoanTermVariations parent = null;
+ final Integer termType = LoanTermVariationType.GRACE_ON_INTEREST.getValue();
+ createLoanTermVariations(termType, loan, rescheduleFromDate, dueDate, loanRescheduleRequestToTermVariationMappings, isActive,
+ isSpecificToInstallment, BigDecimal.valueOf(graceOnInterest), parent);
+ }
+
+ if (rescheduleFromDate != null && extraTerms != null) {
+ LoanTermVariations parent = null;
+ final Integer termType = LoanTermVariationType.EXTEND_REPAYMENT_PERIOD.getValue();
+ createLoanTermVariations(termType, loan, rescheduleFromDate, dueDate, loanRescheduleRequestToTermVariationMappings, isActive,
+ isSpecificToInstallment, BigDecimal.valueOf(extraTerms), parent);
+ }
+ loanRescheduleRequest.updateLoanRescheduleRequestToTermVariationMappings(loanRescheduleRequestToTermVariationMappings);
+ }
+
+ private LoanTermVariations createLoanTermVariations(final Integer termType, final Loan loan, Date rescheduleFromDate,
+ Date adjustedDueDate, List<LoanRescheduleRequestToTermVariationMapping> loanRescheduleRequestToTermVariationMappings,
+ final Boolean isActive, final boolean isSpecificToInstallment, final BigDecimal decimalValue, LoanTermVariations parent) {
+ LoanTermVariations loanTermVariation = new LoanTermVariations(termType, rescheduleFromDate, decimalValue, adjustedDueDate,
+ isSpecificToInstallment, loan, loan.status().getValue(), isActive, parent);
+ loanRescheduleRequestToTermVariationMappings.add(LoanRescheduleRequestToTermVariationMapping.createNew(loanTermVariation));
+ return loanTermVariation;
+ }
+
@Override
@Transactional
public CommandProcessingResult approve(JsonCommand jsonCommand) {
@@ -322,132 +380,112 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
changes.put("approvedOnDate", approvedOnDate.toString(dateTimeFormatter));
changes.put("approvedByUserId", appUser.getId());
- if (!changes.isEmpty()) {
- Loan loan = loanRescheduleRequest.getLoan();
- final LoanSummary loanSummary = loan.getSummary();
-
- final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
- final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan
- .getDisbursementDate().toDate());
- final WorkingDays workingDays = this.workingDaysRepository.findOne();
- final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
- final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
- final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
-
- final InterestMethod interestMethod = loan.getLoanRepaymentScheduleDetail().getInterestMethod();
- final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
- final MathContext mathContext = new MathContext(8, roundingMode);
-
- Collection<LoanRepaymentScheduleHistory> loanRepaymentScheduleHistoryList = this.loanScheduleHistoryWritePlatformService
- .createLoanScheduleArchive(loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
-
- HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
- CalendarInstance restCalendarInstance = null;
- CalendarInstance compoundingCalendarInstance = null;
- if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
- restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
- loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
- 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();
- }
- FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
- Boolean isSkipRepaymentOnFirstMonth = false;
- Integer numberOfDays = 0;
- boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
- if(isSkipRepaymentOnFirstMonthEnabled){
- isSkipRepaymentOnFirstMonth = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), loanCalendar);
- if(isSkipRepaymentOnFirstMonth) { numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue(); }
-
- }
- LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
- loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
- loanCalendar, floatingRateDTO, isSkipRepaymentOnFirstMonth, numberOfDays);
-
- final Collection<LoanRescheduleModelRepaymentPeriod> periods = loanRescheduleModel.getPeriods();
- List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
- Collection<LoanCharge> waiveLoanCharges = new ArrayList<>();
- final Set<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails = null;
- for (LoanRescheduleModelRepaymentPeriod period : periods) {
-
- if (period.isNew()) {
- LoanRepaymentScheduleInstallment repaymentScheduleInstallment = new LoanRepaymentScheduleInstallment(loan,
- period.periodNumber(), period.periodFromDate(), period.periodDueDate(), period.principalDue(),
- period.interestDue(), BigDecimal.ZERO, BigDecimal.ZERO, false, compoundingDetails);
-
- loan.addLoanRepaymentScheduleInstallment(repaymentScheduleInstallment);
- repaymentScheduleInstallments.add(repaymentScheduleInstallment) ;
- }
-
- else {
- for (LoanRepaymentScheduleInstallment repaymentScheduleInstallment : repaymentScheduleInstallments) {
-
- if (repaymentScheduleInstallment.getInstallmentNumber().equals(period.oldPeriodNumber())) {
-
- LocalDate periodDueDate = repaymentScheduleInstallment.getDueDate();
- Money zeroAmount = Money.of(currency, new BigDecimal(0));
-
- repaymentScheduleInstallment.updateInstallmentNumber(period.periodNumber());
- repaymentScheduleInstallment.updateFromDate(period.periodFromDate());
- repaymentScheduleInstallment.updateDueDate(period.periodDueDate());
- repaymentScheduleInstallment.updatePrincipal(period.principalDue());
- repaymentScheduleInstallment.updateInterestCharged(period.interestDue());
-
- if (Money.of(currency, period.principalDue()).isZero() && Money.of(currency, period.interestDue()).isZero()
- && repaymentScheduleInstallment.isNotFullyPaidOff()) {
-
- if (repaymentScheduleInstallment.getPenaltyChargesOutstanding(currency).isGreaterThan(zeroAmount)
- || repaymentScheduleInstallment.getFeeChargesOutstanding(currency).isGreaterThan(zeroAmount)) {
-
- waiveLoanCharges.addAll(loan.getLoanCharges(periodDueDate));
- }
- }
-
- break;
- }
+ Loan loan = loanRescheduleRequest.getLoan();
+ final List<Long> existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds());
+ final List<Long> existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds());
+
+ ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan,
+ loanRescheduleRequest.getRescheduleFromDate());
+
+ Collection<LoanRepaymentScheduleHistory> loanRepaymentScheduleHistoryList = this.loanScheduleHistoryWritePlatformService
+ .createLoanScheduleArchive(loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
+
+ final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
+
+ LocalDate rescheduleFromDate = null;
+ Set<LoanTermVariations> activeLoanTermVariations = loan.getActiveLoanTermVariations();
+ LoanTermVariations dueDateVariationInCurrentRequest = loanRescheduleRequest.getDueDateTermVariationIfExists();
+ if (dueDateVariationInCurrentRequest != null && activeLoanTermVariations != null) {
+ LocalDate fromScheduleDate = dueDateVariationInCurrentRequest.fetchTermApplicaDate();
+ LocalDate currentScheduleDate = fromScheduleDate;
+ LocalDate modifiedScheduleDate = dueDateVariationInCurrentRequest.fetchDateValue();
+ Map<LocalDate, LocalDate> changeMap = new HashMap<>();
+ changeMap.put(currentScheduleDate, modifiedScheduleDate);
+ for (LoanTermVariations activeLoanTermVariation : activeLoanTermVariations) {
+ if (activeLoanTermVariation.getTermType().isDueDateVariation()
+ && activeLoanTermVariation.fetchDateValue().equals(dueDateVariationInCurrentRequest.fetchTermApplicaDate())) {
+ activeLoanTermVariation.markAsInactive();
+ rescheduleFromDate = activeLoanTermVariation.fetchTermApplicaDate();
+ dueDateVariationInCurrentRequest.setTermApplicableFrom(rescheduleFromDate.toDate());
+ } else if (!activeLoanTermVariation.fetchTermApplicaDate().isBefore(fromScheduleDate)) {
+ while (currentScheduleDate.isBefore(activeLoanTermVariation.fetchTermApplicaDate())) {
+ currentScheduleDate = this.scheduledDateGenerator.generateNextRepaymentDate(currentScheduleDate,
+ loanApplicationTerms, false, loanApplicationTerms.getHolidayDetailDTO());
+ modifiedScheduleDate = this.scheduledDateGenerator.generateNextRepaymentDate(modifiedScheduleDate,
+ loanApplicationTerms, false, loanApplicationTerms.getHolidayDetailDTO());
+ changeMap.put(currentScheduleDate, modifiedScheduleDate);
+ }
+ if (changeMap.containsKey(activeLoanTermVariation.fetchTermApplicaDate())) {
+ activeLoanTermVariation.setTermApplicableFrom(changeMap.get(activeLoanTermVariation.fetchTermApplicaDate())
+ .toDate());
}
}
}
-
- for (LoanRepaymentScheduleHistory loanRepaymentScheduleHistory : loanRepaymentScheduleHistoryList) {
- this.loanRepaymentScheduleHistoryRepository.save(loanRepaymentScheduleHistory);
+ }
+ if (rescheduleFromDate == null) {
+ rescheduleFromDate = loanRescheduleRequest.getRescheduleFromDate();
+ }
+ for (LoanRescheduleRequestToTermVariationMapping mapping : loanRescheduleRequest
+ .getLoanRescheduleRequestToTermVariationMappings()) {
+ mapping.getLoanTermVariations().updateIsActive(true);
+ }
+ BigDecimal annualNominalInterestRate = null;
+ List<LoanTermVariationsData> loanTermVariations = new ArrayList<>();
+ loan.constructLoanTermVariations(scheduleGeneratorDTO.getFloatingRateDTO(), annualNominalInterestRate, loanTermVariations);
+ loanApplicationTerms.getLoanTermVariations().setExceptionData(loanTermVariations);
+
+ /*for (LoanTermVariationsData loanTermVariation : loanApplicationTerms.getLoanTermVariations().getDueDateVariation()) {
+ if (rescheduleFromDate.isBefore(loanTermVariation.getTermApplicableFrom())) {
+ LocalDate applicableDate = this.scheduledDateGenerator.generateNextRepaymentDate(rescheduleFromDate,
+ loanApplicationTerms, false, loanApplicationTerms.getHolidayDetailDTO());
+ if (loanTermVariation.getTermApplicableFrom().equals(applicableDate)) {
+ LocalDate adjustedDate = this.scheduledDateGenerator.generateNextRepaymentDate(adjustedApplicableDate,
+ loanApplicationTerms, false, loanApplicationTerms.getHolidayDetailDTO());
+ loanTermVariation.setApplicableFromDate(adjustedDate);
+ }
}
+ }*/
+
+ final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
+ final MathContext mathContext = new MathContext(8, roundingMode);
+ final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.loanRepaymentScheduleTransactionProcessorFactory
+ .determineProcessor(loan.transactionProcessingStrategy());
+ final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
+ final LoanLifecycleStateMachine loanLifecycleStateMachine = null;
+ loan.setHelpers(loanLifecycleStateMachine, this.loanSummaryWrapper, this.loanRepaymentScheduleTransactionProcessorFactory);
+ final LoanScheduleDTO loanSchedule = loanScheduleGenerator.rescheduleNextInstallments(mathContext, loanApplicationTerms,
+ loan, loanApplicationTerms.getHolidayDetailDTO(),
+ loanRepaymentScheduleTransactionProcessor, rescheduleFromDate);
+
+ loan.updateLoanSchedule(loanSchedule.getInstallments(), appUser);
+ loan.recalculateAllCharges();
+ ChangedTransactionDetail changedTransactionDetail = loan.processTransactions();
+
+ for (LoanRepaymentScheduleHistory loanRepaymentScheduleHistory : loanRepaymentScheduleHistoryList) {
+ this.loanRepaymentScheduleHistoryRepository.save(loanRepaymentScheduleHistory);
+ }
- loan.updateRescheduledByUser(appUser);
- loan.updateRescheduledOnDate(new LocalDate());
-
- // waive all loan charges of zero instalments
- waiveLoanCharges(loan, waiveLoanCharges);
-
- // update the Loan summary
- loanSummary.updateSummary(currency, loan.getPrincpal(), repaymentScheduleInstallments, new LoanSummaryWrapper(), true, null);
-
- // update the total number of schedule repayments
- loan.updateNumberOfRepayments(periods.size());
-
- // update the loan term frequency (loan term frequency = number
- // of repayments)
- loan.updateTermFrequency(periods.size());
-
- // update the status of the request
- loanRescheduleRequest.approve(appUser, approvedOnDate);
-
- // update the derived fields of each loan repayments schedule
- // instalments
- for (final LoanRepaymentScheduleInstallment repaymentScheduleInstallment : repaymentScheduleInstallments) {
- repaymentScheduleInstallment.updateDerivedFields(currency, new LocalDate());
+ loan.updateRescheduledByUser(appUser);
+ loan.updateRescheduledOnDate(new LocalDate());
+
+ // update the status of the request
+ loanRescheduleRequest.approve(appUser, approvedOnDate);
+
+ // update the loan object
+ saveAndFlushLoanWithDataIntegrityViolationChecks(loan);
+
+ if (changedTransactionDetail != null) {
+ for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
+ this.loanTransactionRepository.save(mapEntry.getValue());
+ // update loan with references to the newly created
+ // transactions
+ loan.addLoanTransaction(mapEntry.getValue());
+ this.accountTransfersWritePlatformService.updateLoanTransaction(mapEntry.getKey(), mapEntry.getValue());
}
-
- // updates maturity date
- loan.updateLoanScheduleDependentDerivedFields();
- // update the loan object
- this.loanRepository.save(loan);
}
+ postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
+
+ this.loanAccountDomainService.recalculateAccruals(loan, true);
return new CommandProcessingResultBuilder().withCommandId(jsonCommand.commandId()).withEntityId(loanRescheduleRequestId)
.withLoanId(loanRescheduleRequest.getLoan().getId()).with(changes).build();
@@ -462,60 +500,24 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
}
}
- /**
- * waive all charges in the collection
- *
- * @param loan
- * Loan object
- * @param loanCharges
- * collection of LoanCharge objects
- * @return void
- **/
- private void waiveLoanCharges(Loan loan, Collection<LoanCharge> loanCharges) {
- AppUser currentUser = this.platformSecurityContext.authenticatedUser();
- this.loanAssembler.setHelpers(loan);
-
- for (LoanCharge loanCharge : loanCharges) {
-
- if (loanCharge.isChargePending()) {
- Integer loanInstallmentNumber = null;
-
- if (loanCharge.isInstalmentFee()) {
- LoanInstallmentCharge chargePerInstallment = loanCharge.getUnpaidInstallmentLoanCharge();
-
- if (chargePerInstallment != null) {
- loanInstallmentNumber = chargePerInstallment.getRepaymentInstallment().getInstallmentNumber();
- }
- }
-
- final Map<String, Object> changes = new LinkedHashMap<>(3);
-
- final List<Long> existingTransactionIds = new ArrayList<>();
- final List<Long> existingReversedTransactionIds = new ArrayList<>();
- LocalDate recalculateFrom = null;
- if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
- recalculateFrom = DateUtils.getLocalDateOfTenant();
- }
-
- ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
-
- Money accruedCharge = Money.zero(loan.getCurrency());
- if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
- Collection<LoanChargePaidByData> chargePaidByDatas = this.loanChargeReadPlatformService.retriveLoanChargesPaidBy(
- loanCharge.getId(), LoanTransactionType.ACCRUAL, loanInstallmentNumber);
- for (LoanChargePaidByData chargePaidByData : chargePaidByDatas) {
- accruedCharge = accruedCharge.plus(chargePaidByData.getAmount());
- }
+ private void saveAndFlushLoanWithDataIntegrityViolationChecks(final Loan loan) {
+ try {
+ List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
+ for (LoanRepaymentScheduleInstallment installment : installments) {
+ if (installment.getId() == null) {
+ this.repaymentScheduleInstallmentRepository.save(installment);
}
-
- final LoanTransaction loanTransaction = loan.waiveLoanCharge(loanCharge, defaultLoanLifecycleStateMachine(), changes,
- existingTransactionIds, existingReversedTransactionIds, loanInstallmentNumber, scheduleGeneratorDTO, accruedCharge,
- currentUser);
-
- this.loanTransactionRepository.save(loanTransaction);
-
- postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds);
}
+ this.loanRepository.saveAndFlush(loan);
+ } catch (final DataIntegrityViolationException e) {
+ final Throwable realCause = e.getCause();
+ final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+ final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.transaction");
+ if (realCause.getMessage().toLowerCase().contains("external_id_unique")) {
+ baseDataValidator.reset().parameter("externalId").failWithCode("value.must.be.unique");
+ }
+ if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
+ "Validation errors exist.", dataValidationErrors); }
}
}
@@ -528,11 +530,6 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
}
- private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() {
- final List<LoanStatus> allowedLoanStatuses = Arrays.asList(LoanStatus.values());
- return new DefaultLoanLifecycleStateMachine(allowedLoanStatuses);
- }
-
@Override
@Transactional
public CommandProcessingResult reject(JsonCommand jsonCommand) {
@@ -562,6 +559,11 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
if (!changes.isEmpty()) {
loanRescheduleRequest.reject(appUser, rejectedOnDate);
+ Set<LoanRescheduleRequestToTermVariationMapping> loanRescheduleRequestToTermVariationMappings = loanRescheduleRequest
+ .getLoanRescheduleRequestToTermVariationMappings();
+ for (LoanRescheduleRequestToTermVariationMapping loanRescheduleRequestToTermVariationMapping : loanRescheduleRequestToTermVariationMappings) {
+ loanRescheduleRequestToTermVariationMapping.getLoanTermVariations().markAsInactive();
+ }
}
return new CommandProcessingResultBuilder().withCommandId(jsonCommand.commandId()).withEntityId(loanRescheduleRequestId)
@@ -593,20 +595,4 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
"Unknown data integrity issue with resource.");
}
- private FloatingRateDTO constructFloatingRateDTO(final Loan loan) {
- FloatingRateDTO floatingRateDTO = null;
- if (loan.loanProduct().isLinkedToFloatingInterestRate()) {
- boolean isFloatingInterestRate = loan.getIsFloatingInterestRate();
- BigDecimal interestRateDiff = loan.getInterestRateDifferential();
- List<FloatingRatePeriodData> baseLendingRatePeriods = null;
- try {
- baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate().getRatePeriods();
- } catch (final FloatingRateNotFoundException ex) {
- // Do not do anything
- }
- floatingRateDTO = new FloatingRateDTO(isFloatingInterestRate, loan.getDisbursementDate(), interestRateDiff,
- baseLendingRatePeriods);
- }
- return floatingRateDTO;
- }
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
index dffd39c..18c9058 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanEnumerations.java
@@ -551,6 +551,22 @@ public class LoanEnumerations {
optionData = new EnumOptionData(LoanTermVariationType.PRINCIPAL_AMOUNT.getValue().longValue(),
LoanTermVariationType.PRINCIPAL_AMOUNT.getCode(), "principalAmount");
break;
+ case GRACE_ON_INTEREST:
+ optionData = new EnumOptionData(LoanTermVariationType.GRACE_ON_INTEREST.getValue().longValue(),
+ LoanTermVariationType.GRACE_ON_INTEREST.getCode(), "graceOnInterest");
+ break;
+ case GRACE_ON_PRINCIPAL:
+ optionData = new EnumOptionData(LoanTermVariationType.GRACE_ON_PRINCIPAL.getValue().longValue(),
+ LoanTermVariationType.GRACE_ON_PRINCIPAL.getCode(), "graceOnPrincipal");
+ break;
+ case EXTEND_REPAYMENT_PERIOD:
+ optionData = new EnumOptionData(LoanTermVariationType.EXTEND_REPAYMENT_PERIOD.getValue().longValue(),
+ LoanTermVariationType.EXTEND_REPAYMENT_PERIOD.getCode(), "extendRepaymentPeriod");
+ break;
+ case INTEREST_RATE_FROM_INSTALLMENT:
+ optionData = new EnumOptionData(LoanTermVariationType.INTEREST_RATE_FROM_INSTALLMENT.getValue().longValue(),
+ LoanTermVariationType.INTEREST_RATE_FROM_INSTALLMENT.getCode(), "interestRateForInstallment");
+ break;
default:
optionData = new EnumOptionData(LoanTermVariationType.INVALID.getValue().longValue(),
LoanTermVariationType.INVALID.getCode(), "Invalid");
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/resources/sql/migrations/core_db/V313__multi_rescheduling_script.sql
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V313__multi_rescheduling_script.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V313__multi_rescheduling_script.sql
new file mode 100644
index 0000000..1fca1d1
--- /dev/null
+++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V313__multi_rescheduling_script.sql
@@ -0,0 +1,141 @@
+ALTER TABLE `m_loan_term_variations`
+ ADD COLUMN `is_active` TINYINT(1) NOT NULL DEFAULT '1' AFTER `applied_on_loan_status`;
+
+ALTER TABLE `m_loan_term_variations`
+ ADD COLUMN `parent_id` BIGINT(20) NULL DEFAULT NULL AFTER `is_active`;
+
+ALTER TABLE `m_loan_term_variations`
+ ADD COLUMN `reshedule_request_id` BIGINT(20) NULL DEFAULT NULL AFTER `parent_id`;
+
+insert into m_loan_term_variations(`loan_id`, `term_type`, `applicable_date`, `decimal_value`, `date_value` , `is_specific_to_installment`, `applied_on_loan_status`, `reshedule_request_id` , `is_active` , `parent_id`)
+(
+select
+mlrr.loan_id,
+ 7 term_type,
+ ifnull(mlrr.adjusted_due_date,mlrr.reschedule_from_date) applicable_date,
+ mlrr.grace_on_interest decimal_value,
+ null date_value,
+ 1 is_specific_to_installment,
+ 300 applied_on_loan_status_id,
+ mlrr.id reshedule_request_id,
+ if(mlrr.status_enum = 200 ,1,0) is_active,
+ null parent_id
+from m_loan_reschedule_request mlrr
+where mlrr.grace_on_interest is not null);
+
+insert into m_loan_term_variations(`loan_id`, `term_type`, `applicable_date`, `decimal_value`, `date_value` , `is_specific_to_installment`, `applied_on_loan_status`, `reshedule_request_id` , `is_active` , `parent_id`)
+(
+select
+mlrr.loan_id,
+ 8 term_type,
+ ifnull(mlrr.adjusted_due_date,mlrr.reschedule_from_date) applicable_date,
+ mlrr.grace_on_principal decimal_value,
+ null date_value,
+ 1 is_specific_to_installment,
+ 300 applied_on_loan_status_id,
+ mlrr.id reshedule_request_id,
+ if(mlrr.status_enum = 200 ,1,0) is_active,
+ null parent_id
+from m_loan_reschedule_request mlrr
+where mlrr.grace_on_principal is not null);
+
+insert into m_loan_term_variations(`loan_id`, `term_type`, `applicable_date`, `decimal_value`, `date_value` , `is_specific_to_installment`, `applied_on_loan_status`, `reshedule_request_id` , `is_active` , `parent_id`)
+(
+select
+mlrr.loan_id,
+ 4 term_type,
+ mlrr.reschedule_from_date applicable_date,
+ null decimal_value,
+ mlrr.adjusted_due_date date_value,
+ 1 is_specific_to_installment,
+ 300 applied_on_loan_status_id,
+ mlrr.id reshedule_request_id,
+ if(mlrr.status_enum = 200 ,1,0) is_active,
+ null parent_id
+from m_loan_reschedule_request mlrr
+where mlrr.adjusted_due_date is not null);
+
+insert into m_loan_term_variations(`loan_id`, `term_type`, `applicable_date`, `decimal_value`, `date_value` , `is_specific_to_installment`, `applied_on_loan_status`, `reshedule_request_id` , `is_active` , `parent_id`)
+(
+select
+mlrr.loan_id,
+ 9 term_type,
+ ifnull(mlrr.adjusted_due_date,mlrr.reschedule_from_date) applicable_date,
+ mlrr.extra_terms decimal_value,
+ null date_value,
+ 1 is_specific_to_installment,
+ 300 applied_on_loan_status_id,
+ mlrr.id reshedule_request_id,
+ if(mlrr.status_enum = 200 ,1,0) is_active,
+ null parent_id
+from m_loan_reschedule_request mlrr
+where mlrr.extra_terms is not null);
+
+insert into m_loan_term_variations(`loan_id`, `term_type`, `applicable_date`, `decimal_value`, `date_value` , `is_specific_to_installment`, `applied_on_loan_status`, `reshedule_request_id` , `is_active` , `parent_id`)
+(
+select
+mlrr.loan_id,
+ 2 term_type,
+ ifnull(mlrr.adjusted_due_date,mlrr.reschedule_from_date) applicable_date,
+ mlrr.interest_rate decimal_value,
+ null date_value,
+ 1 is_specific_to_installment,
+ 300 applied_on_loan_status_id,
+ mlrr.id reshedule_request_id,
+ if(mlrr.status_enum = 200 ,1,0) is_active,
+ null parent_id
+from m_loan_reschedule_request mlrr
+where mlrr.interest_rate is not null);
+
+insert into m_loan_term_variations(`loan_id`, `term_type`, `applicable_date`, `decimal_value`, `date_value` , `is_specific_to_installment`, `applied_on_loan_status`, `reshedule_request_id` , `is_active` , `parent_id`)
+(
+select
+mlrr.loan_id,
+ 9 term_type,
+ mlrr.reschedule_from_date applicable_date,
+ if(ifnull(mlrr.grace_on_principal,0) > ifnull(mlrr.grace_on_interest,0),mlrr.grace_on_principal,mlrr.grace_on_interest) decimal_value,
+ null date_value,
+ 1 is_specific_to_installment,
+ 300 applied_on_loan_status_id,
+ mlrr.id reshedule_request_id,
+ if(mlrr.status_enum = 200 ,1,0) is_active,
+ (select distinct mlt.id
+ from m_loan_term_variations mlt
+ where mlt.reshedule_request_id is not null
+ and (mlt.term_type =8 or mlt.term_type = 7)
+ and mlt.reshedule_request_id = mlrr.id
+ order by mlt.term_type desc limit 1) parent_id
+from m_loan_reschedule_request mlrr
+where (mlrr.grace_on_interest is not null or mlrr.grace_on_principal is not null));
+
+ALTER TABLE `m_loan_reschedule_request`
+ DROP COLUMN `grace_on_principal`,
+ DROP COLUMN `grace_on_interest`,
+ DROP COLUMN `extra_terms`,
+ DROP COLUMN `interest_rate`,
+ DROP COLUMN `adjusted_due_date`;
+
+CREATE TABLE `m_loan_reschedule_request_term_variations_mapping` (
+ `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
+ `loan_reschedule_request_id` BIGINT(20) NOT NULL,
+ `loan_term_variations_id` BIGINT(20) NOT NULL,
+ PRIMARY KEY (`id`),
+ INDEX `FK__m_loan_reschedule_request` (`loan_reschedule_request_id`),
+ INDEX `FK__m_loan_term_variations` (`loan_term_variations_id`),
+ CONSTRAINT `FK__m_loan_reschedule_request` FOREIGN KEY (`loan_reschedule_request_id`) REFERENCES `m_loan_reschedule_request` (`id`),
+ CONSTRAINT `FK__m_loan_term_variations` FOREIGN KEY (`loan_term_variations_id`) REFERENCES `m_loan_term_variations` (`id`)
+)
+COLLATE='utf8_general_ci'
+ENGINE=InnoDB
+AUTO_INCREMENT=1
+;
+
+insert ignore into m_loan_reschedule_request_term_variations_mapping (`loan_reschedule_request_id`, `loan_term_variations_id`)
+(
+select distinct mltv.reshedule_request_id,mltv.id
+from m_loan_term_variations mltv
+where reshedule_request_id is not null
+);
+
+ALTER TABLE `m_loan_term_variations`
+ DROP COLUMN `reshedule_request_id`;
\ No newline at end of file
[2/5] incubator-fineract git commit: FINERACT-202 : enabling the
option for multi reshedule
Posted by na...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
index c1f91ea..0746522 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java
@@ -21,7 +21,9 @@ package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.Date;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
@@ -192,6 +194,25 @@ public final class LoanApplicationTerms {
private final boolean isSkipRepaymentOnFirstDayOfMonth;
private final HolidayDetailDTO holidayDetailDTO;
+
+ private final Set<Integer> periodNumbersApplicableForPrincipalGrace = new HashSet<>();
+
+ private final Set<Integer> periodNumbersApplicableForInterestGrace = new HashSet<>();
+
+
+ // used for FLAT loans when interest rate changed
+ private Integer excludePeriodsForCalculation = 0;
+ private Money totalPrincipalAccountedForInterestCalcualtion;
+
+
+ //used for FLAT loans generation on modifying terms
+ private Money totalPrincipalAccounted;
+ private Money totalInterestAccounted;
+ private int periodsCompleted = 0;
+ private int extraPeriods = 0;
+
+
+
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
@@ -482,6 +503,12 @@ public final class LoanApplicationTerms {
this.isInterestChargedFromDateSameAsDisbursalDateEnabled = isInterestChargedFromDateSameAsDisbursalDateEnabled;
this.holidayDetailDTO = holidayDetailDTO;
this.allowCompoundingOnEod = allowCompoundingOnEod;
+ Integer periodNumber = 1;
+ updatePeriodNumberApplicableForPrincipalOrInterestGrace(periodNumber);
+ updateRecurringMoratoriumOnPrincipalPeriods(periodNumber);
+ this.totalPrincipalAccountedForInterestCalcualtion = principal.zero();
+ this.totalInterestAccounted = principal.zero();
+ this.totalPrincipalAccounted = principal.zero();
}
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
@@ -706,7 +733,8 @@ public final class LoanApplicationTerms {
switch (this.interestMethod) {
case FLAT:
final BigDecimal interestRateForLoanTerm = calculateFlatInterestRateForLoanTerm(calculator, mc);
- totalInterestDue = this.principal.multiplyRetainScale(interestRateForLoanTerm, mc.getRoundingMode());
+ totalInterestDue = this.principal.minus(totalPrincipalAccountedForInterestCalcualtion).multiplyRetainScale(interestRateForLoanTerm,
+ mc.getRoundingMode());
break;
case DECLINING_BALANCE:
@@ -715,10 +743,6 @@ public final class LoanApplicationTerms {
break;
}
- if (this.totalInterestDue != null) {
- totalInterestDue = this.totalInterestDue;
- }
-
return totalInterestDue;
}
@@ -844,13 +868,19 @@ public final class LoanApplicationTerms {
private Money calculateTotalInterestPerInstallmentWithoutGrace(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc) {
final Money totalInterestForLoanTerm = calculateTotalFlatInterestDueWithoutGrace(calculator, mc);
-
- return totalInterestForLoanTerm.dividedBy(Long.valueOf(this.actualNumberOfRepayments), mc.getRoundingMode());
+ Money interestPerInstallment = totalInterestForLoanTerm.dividedBy(Long.valueOf(this.actualNumberOfRepayments) - defaultToZeroIfNull(this.excludePeriodsForCalculation), mc.getRoundingMode());
+ if (this.excludePeriodsForCalculation < this.periodsCompleted) {
+ Money interestLeft = this.totalInterestDue.minus(this.totalInterestAccounted);
+ interestPerInstallment = interestLeft.dividedBy(Long.valueOf(this.actualNumberOfRepayments)
+ - defaultToZeroIfNull(this.periodsCompleted), mc.getRoundingMode());
+ }
+
+ return interestPerInstallment;
}
private Money calculateTotalPrincipalPerPeriodWithoutGrace(final MathContext mc, final int periodNumber) {
final int totalRepaymentsWithCapitalPayment = calculateNumberOfRepaymentsWithPrincipalPayment();
- Money principalPerPeriod = this.principal.dividedBy(totalRepaymentsWithCapitalPayment, mc.getRoundingMode()).plus(
+ Money principalPerPeriod = this.principal.minus(totalPrincipalAccounted).dividedBy(totalRepaymentsWithCapitalPayment, mc.getRoundingMode()).plus(
this.adjustPrincipalForFlatLoans);
if (isPrincipalGraceApplicableForThisPeriod(periodNumber)) {
principalPerPeriod = principalPerPeriod.zero();
@@ -906,11 +936,30 @@ public final class LoanApplicationTerms {
final Money totalInterestFree = interestPerGracePeriod.multipliedBy(getInterestChargingGrace());
final Money realTotalInterestForLoan = totalInterestForLoanTerm.minus(totalInterestFree);
-
- final Integer interestPaymentDuePeriods = calculateNumberOfRepaymentPeriodsWhereInterestPaymentIsDue(this.actualNumberOfRepayments);
-
+
+
+
+ Integer interestPaymentDuePeriods = calculateNumberOfRemainingInterestPaymentPeriods(this.actualNumberOfRepayments,
+ this.excludePeriodsForCalculation);
interestForInstallment = realTotalInterestForLoan
.dividedBy(BigDecimal.valueOf(interestPaymentDuePeriods), mc.getRoundingMode());
+ if (this.excludePeriodsForCalculation < this.periodsCompleted) {
+ Money interestLeft = this.totalInterestDue.minus(this.totalInterestAccounted);
+ Integer interestDuePeriods = calculateNumberOfRemainingInterestPaymentPeriods(this.actualNumberOfRepayments,
+ this.periodsCompleted);
+ interestForInstallment = interestLeft.dividedBy(Long.valueOf(interestDuePeriods), mc.getRoundingMode());
+ }
+ if(!this.periodNumbersApplicableForInterestGrace.isEmpty()){
+ int periodsElapsed = calculateLastInterestGracePeriod(periodNumber);
+ if (periodsElapsed > this.excludePeriodsForCalculation && periodsElapsed > this.periodsCompleted) {
+ Money interestLeft = this.totalInterestDue.minus(this.totalInterestAccounted);
+ Integer interestDuePeriods = calculateNumberOfRemainingInterestPaymentPeriods(this.actualNumberOfRepayments,
+ periodsElapsed);
+ interestForInstallment = interestLeft.dividedBy(Long.valueOf(interestDuePeriods), mc.getRoundingMode());
+ }
+ }
+
+
}
return interestForInstallment;
@@ -1032,24 +1081,46 @@ public final class LoanApplicationTerms {
private int calculateNumberOfRepaymentsWithPrincipalPayment() {
int numPeriods = calculateNumberOfRemainingPrincipalPaymentPeriods(this.actualNumberOfRepayments,
- this.getRecurringMoratoriumOnPrincipalPeriods(), this.getPrincipalGrace(), 0);
+ this.periodsCompleted);
+// numPeriods = numPeriods - this.periodsCompleted;
return numPeriods;
}
-
- private Integer calculateNumberOfRepaymentPeriodsWhereInterestPaymentIsDue(final Integer totalNumberOfRepaymentPeriods) {
- return totalNumberOfRepaymentPeriods - Math.max(getInterestChargingGrace(), getInterestPaymentGrace());
+
+ private Integer calculateNumberOfRemainingInterestPaymentPeriods(final Integer totalNumberOfRepaymentPeriods, int periodsElapsed) {
+ int principalFeePeriods = 0;
+ for (Integer intNumber : this.periodNumbersApplicableForInterestGrace) {
+ if (intNumber > periodsElapsed) {
+ principalFeePeriods++;
+ }
+ }
+ Integer periodsRemaining = totalNumberOfRepaymentPeriods - periodsElapsed - principalFeePeriods;
+ return periodsRemaining;
+ }
+
+ private Integer calculateLastInterestGracePeriod(int periodNumber){
+ int lastGracePeriod = 0;
+ for (Integer grace : this.periodNumbersApplicableForInterestGrace) {
+ if(grace < periodNumber && lastGracePeriod < grace){
+ lastGracePeriod = grace;
+ }
+ }
+ return lastGracePeriod;
}
public boolean isPrincipalGraceApplicableForThisPeriod(final int periodNumber) {
- if (this.getRecurringMoratoriumOnPrincipalPeriods() > 0) {
- return ((periodNumber > 0 && periodNumber <= getPrincipalGrace()) || (periodNumber > 0 && (((periodNumber - getPrincipalGrace()) % (this
- .getRecurringMoratoriumOnPrincipalPeriods() + 1)) != 1)));
+ boolean isPrincipalGraceApplicableForThisPeriod = false;
+ if (this.periodNumbersApplicableForPrincipalGrace.contains(periodNumber)) {
+ isPrincipalGraceApplicableForThisPeriod = true;
}
- return periodNumber > 0 && periodNumber <= getPrincipalGrace();
+ return isPrincipalGraceApplicableForThisPeriod;
}
- private boolean isInterestPaymentGraceApplicableForThisPeriod(final int periodNumber) {
- return periodNumber > 0 && periodNumber <= getInterestPaymentGrace();
+ public boolean isInterestPaymentGraceApplicableForThisPeriod(final int periodNumber) {
+ boolean isInterestPaymentGraceApplicableForThisPeriod = false;
+ if (this.periodNumbersApplicableForInterestGrace.contains(periodNumber)) {
+ isInterestPaymentGraceApplicableForThisPeriod = true;
+ }
+ return isInterestPaymentGraceApplicableForThisPeriod;
}
private boolean isFirstPeriodAfterInterestPaymentGracePeriod(final int periodNumber) {
@@ -1099,7 +1170,7 @@ public final class LoanApplicationTerms {
final double principalDouble = balance.getAmount().multiply(BigDecimal.valueOf(-1)).doubleValue();
final Integer periodsRemaining = calculateNumberOfRemainingPrincipalPaymentPeriods(this.actualNumberOfRepayments,
- this.getRecurringMoratoriumOnPrincipalPeriods(), this.getPrincipalGrace(), periodsElapsed);
+ periodsElapsed);
double installmentAmount = FinanicalFunctions.pmt(periodicInterestRate.doubleValue(), periodsRemaining.doubleValue(),
principalDouble, futureValue, false);
@@ -1165,7 +1236,7 @@ public final class LoanApplicationTerms {
Money principal = this.principal;
if (this.fixedPrincipalAmount == null) {
final Integer numberOfPrincipalPaymentPeriods = calculateNumberOfRemainingPrincipalPaymentPeriods(
- this.actualNumberOfRepayments, this.getRecurringMoratoriumOnPrincipalPeriods(), this.getPrincipalGrace(), periodNumber);
+ this.actualNumberOfRepayments, periodNumber);
principal = this.principal.dividedBy(numberOfPrincipalPaymentPeriods, mc.getRoundingMode());
this.fixedPrincipalAmount = principal.getAmount();
}
@@ -1179,21 +1250,19 @@ public final class LoanApplicationTerms {
public void updateFixedPrincipalAmount(final MathContext mc, final int periodNumber, final Money outstandingAmount) {
final Integer numberOfPrincipalPaymentPeriods = calculateNumberOfRemainingPrincipalPaymentPeriods(this.actualNumberOfRepayments,
- this.getRecurringMoratoriumOnPrincipalPeriods(), this.getPrincipalGrace(), periodNumber - 1);
+ periodNumber - 1);
Money principal = outstandingAmount.dividedBy(numberOfPrincipalPaymentPeriods, mc.getRoundingMode());
this.fixedPrincipalAmount = principal.getAmount();
}
- private static Integer calculateNumberOfRemainingPrincipalPaymentPeriods(final Integer totalNumberOfRepaymentPeriods,
- final int recurringMoratoriumOnPrincipalPeriods, final int PrincipalGrace, int periodsElapsed) {
- if (PrincipalGrace > periodsElapsed) {
- periodsElapsed = PrincipalGrace;
- }
- Integer periodsRemaining = totalNumberOfRepaymentPeriods - periodsElapsed;
- if (recurringMoratoriumOnPrincipalPeriods > 0) {
- double periodsRemainingDouble = ((double) periodsRemaining / ((double) (recurringMoratoriumOnPrincipalPeriods + 1)));
- periodsRemaining = (int) Math.ceil(periodsRemainingDouble);
+ private Integer calculateNumberOfRemainingPrincipalPaymentPeriods(final Integer totalNumberOfRepaymentPeriods, int periodsElapsed) {
+ int principalFeePeriods = 0;
+ for (Integer intNumber : this.periodNumbersApplicableForPrincipalGrace) {
+ if (intNumber > periodsElapsed) {
+ principalFeePeriods++;
+ }
}
+ Integer periodsRemaining = totalNumberOfRepaymentPeriods - periodsElapsed - principalFeePeriods;
return periodsRemaining;
}
@@ -1469,10 +1538,7 @@ public final class LoanApplicationTerms {
}
public void updateTotalInterestDue(Money totalInterestDue) {
-
- if (totalInterestDue != null) {
- this.totalInterestDue = totalInterestDue;
- }
+ this.totalInterestDue = totalInterestDue;
}
public ApplicationCurrency getApplicationCurrency() {
@@ -1576,4 +1642,81 @@ public final class LoanApplicationTerms {
}
return disbursedAmount;
}
+
+ public void updatePeriodNumberApplicableForPrincipalOrInterestGrace(final Integer periodsApplicationForGrace) {
+ int applicablePeriodNumber = periodsApplicationForGrace;
+ int graceOnPrincipal = defaultToZeroIfNull(this.principalGrace);
+ int graceOnInterest = defaultToZeroIfNull(this.interestPaymentGrace);
+
+ while (graceOnPrincipal > 0 || graceOnInterest > 0) {
+ if (graceOnPrincipal > 0) {
+ this.periodNumbersApplicableForPrincipalGrace.add(applicablePeriodNumber);
+ }
+ if (graceOnInterest > 0) {
+ this.periodNumbersApplicableForInterestGrace.add(applicablePeriodNumber);
+ }
+ applicablePeriodNumber++;
+ graceOnPrincipal--;
+ graceOnInterest--;
+ }
+ }
+
+ /**
+ * set the value to zero if the provided value is null
+ *
+ * @return integer value equal/greater than 0
+ **/
+ private Integer defaultToZeroIfNull(Integer value) {
+
+ return (value != null) ? value : 0;
+ }
+
+ public void updateExcludePeriodsForCalculation(Integer excludePeriodsForCalculation){
+ this.excludePeriodsForCalculation = excludePeriodsForCalculation;
+ this.extraPeriods = 0;
+ }
+
+ public Integer getActualNoOfRepaymnets() {
+ return this.actualNumberOfRepayments;
+ }
+
+ public Money getTotalInterestDue() {
+ return this.totalInterestDue;
+ }
+
+ private void updateRecurringMoratoriumOnPrincipalPeriods(Integer periodNumber) {
+ Boolean isPrincipalGraceApplicableForThisPeriod = false;
+ Integer numberOfRepayments = this.actualNumberOfRepayments;
+ if (this.getRecurringMoratoriumOnPrincipalPeriods() > 0) {
+ while (numberOfRepayments > 0) {
+ isPrincipalGraceApplicableForThisPeriod = ((periodNumber > 0 && periodNumber <= getPrincipalGrace()) || (periodNumber > 0 && (((periodNumber - getPrincipalGrace()) % (this
+ .getRecurringMoratoriumOnPrincipalPeriods() + 1)) != 1)));
+ if (isPrincipalGraceApplicableForThisPeriod) {
+ this.periodNumbersApplicableForPrincipalGrace.add(periodNumber);
+ }
+ numberOfRepayments--;
+ periodNumber++;
+ }
+ }
+
+ }
+
+
+ public void setTotalPrincipalAccounted(Money totalPrincipalAccounted) {
+ this.totalPrincipalAccountedForInterestCalcualtion = totalPrincipalAccounted;
+ }
+
+
+ //Used for FLAT loans to calculate principal and interest per installment
+ public void updateAccountedTillPeriod(int periodNumber, Money totalPrincipalAccounted,Money totalInterestAccounted, int extendPeriods){
+ this.periodsCompleted = periodNumber;
+ this.totalPrincipalAccounted = totalPrincipalAccounted;
+ this.totalInterestAccounted = totalInterestAccounted;
+ this.extraPeriods = this.extraPeriods + extendPeriods;
+ }
+
+ public void updateTotalInterestAccounted(Money totalInterestAccounted){
+ this.totalInterestAccounted = totalInterestAccounted;
+ }
+
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
index ae67451..9583ac4 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanScheduleGenerator.java
@@ -19,22 +19,15 @@
package org.apache.fineract.portfolio.loanaccount.loanschedule.domain;
import java.math.MathContext;
-import java.util.List;
import java.util.Set;
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
-import org.apache.fineract.portfolio.calendar.domain.Calendar;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
-import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
-import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
-import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
import org.joda.time.LocalDate;
public interface LoanScheduleGenerator {
@@ -42,18 +35,12 @@ public interface LoanScheduleGenerator {
LoanScheduleModel generate(MathContext mc, LoanApplicationTerms loanApplicationTerms, Set<LoanCharge> loanCharges,
final HolidayDetailDTO holidayDetailDTO);
- LoanScheduleDTO rescheduleNextInstallments(MathContext mc, LoanApplicationTerms loanApplicationTerms, Set<LoanCharge> loanCharges,
- final HolidayDetailDTO holidayDetailDTO, List<LoanTransaction> transactions,
- LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
- List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, LocalDate rescheduleFrom);
+ LoanScheduleDTO rescheduleNextInstallments(MathContext mc, LoanApplicationTerms loanApplicationTerms, Loan loan,
+ final HolidayDetailDTO holidayDetailDTO, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
+ LocalDate rescheduleFrom);
LoanRepaymentScheduleInstallment calculatePrepaymentAmount(MonetaryCurrency currency, LocalDate onDate,
- LoanApplicationTerms loanApplicationTerms, MathContext mc, Set<LoanCharge> charges, HolidayDetailDTO holidayDetailDTO,
- List<LoanTransaction> loanTransactions, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
- List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments);
+ LoanApplicationTerms loanApplicationTerms, MathContext mc, Loan loan, HolidayDetailDTO holidayDetailDTO,
+ LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor);
- LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
- final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance,
- CalendarInstance compoundingCalendarInstance, final Calendar loanCalendar, FloatingRateDTO floatingRateDTO,
- final boolean isSkipRepaymentonmonthFirst, final Integer numberofdays);
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
index ac4a368..9565ff3 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java
@@ -86,7 +86,6 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
import org.apache.fineract.portfolio.loanaccount.exception.LoanApplicationDateException;
import org.apache.fineract.portfolio.loanaccount.exception.MinDaysBetweenDisbursalAndFirstRepaymentViolationException;
@@ -621,9 +620,8 @@ public class LoanScheduleAssembler {
}
public LoanScheduleModel assembleForInterestRecalculation(final LoanApplicationTerms loanApplicationTerms, final Long officeId,
- List<LoanTransaction> transactions, final Set<LoanCharge> loanCharges,
- final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
- final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final LocalDate rescheduleFrom) {
+ Loan loan, final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
+ final LocalDate rescheduleFrom) {
final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
final MathContext mc = new MathContext(8, roundingMode);
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
@@ -634,15 +632,13 @@ public class LoanScheduleAssembler {
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
HolidayDetailDTO detailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
- return loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, loanCharges, detailDTO, transactions,
- loanRepaymentScheduleTransactionProcessor, repaymentScheduleInstallments, rescheduleFrom).getLoanScheduleModel();
+ return loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, loan, detailDTO,
+ loanRepaymentScheduleTransactionProcessor, rescheduleFrom).getLoanScheduleModel();
}
public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(MonetaryCurrency currency, LocalDate onDate,
- LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges, final Long officeId,
- List<LoanTransaction> loanTransactions,
- final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
- final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments) {
+ LoanApplicationTerms loanApplicationTerms, Loan loan, final Long officeId,
+ final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) {
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
final MathContext mc = new MathContext(8, roundingMode);
@@ -653,8 +649,8 @@ public class LoanScheduleAssembler {
final WorkingDays workingDays = this.workingDaysRepository.findOne();
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
- return loanScheduleGenerator.calculatePrepaymentAmount(currency, onDate, loanApplicationTerms, mc, loanCharges, holidayDetailDTO,
- loanTransactions, loanRepaymentScheduleTransactionProcessor, repaymentScheduleInstallments);
+ return loanScheduleGenerator.calculatePrepaymentAmount(currency, onDate, loanApplicationTerms, mc, loan, holidayDetailDTO,
+ loanRepaymentScheduleTransactionProcessor);
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java
index 41e8313..a8ea977 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java
@@ -171,9 +171,8 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
}
LoanApplicationTerms loanApplicationTerms = constructLoanApplicationTerms(loan);
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = this.loanScheduleAssembler.calculatePrepaymentAmount(currency,
- today, loanApplicationTerms, loan.charges(), loan.getOfficeId(),
- loan.retreiveListOfTransactionsPostDisbursementExcludeAccruals(), loanRepaymentScheduleTransactionProcessor,
- loan.getRepaymentScheduleInstallments());
+ today, loanApplicationTerms, loan, loan.getOfficeId(),
+ loanRepaymentScheduleTransactionProcessor);
Money totalAmount = totalPrincipal.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency)).plus(
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
Money interestDue = Money.zero(currency);
@@ -194,8 +193,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
}
LoanScheduleModel model = this.loanScheduleAssembler.assembleForInterestRecalculation(loanApplicationTerms, loan.getOfficeId(),
- modifiedTransactions, loan.charges(), loanRepaymentScheduleTransactionProcessor, loan.getRepaymentScheduleInstallments(),
- loan.fetchInterestRecalculateFromDate());
+ loan, loanRepaymentScheduleTransactionProcessor, loan.fetchInterestRecalculateFromDate());
LoanScheduleData scheduleDate = model.toData();
Collection<LoanSchedulePeriodData> periodDatas = scheduleDate.getPeriods();
for (LoanSchedulePeriodData periodData : periodDatas) {
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java
index 2094a05..591e21b 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/api/RescheduleLoansApiResource.java
@@ -42,9 +42,9 @@ import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSeria
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.data.LoanRescheduleRequestData;
-import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.service.LoanReschedulePreviewPlatformService;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.service.LoanRescheduleRequestReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -108,14 +108,14 @@ public class RescheduleLoansApiResource {
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
if (compareIgnoreCase(command, "previewLoanReschedule")) {
- final LoanRescheduleModel loanRescheduleModel = this.loanReschedulePreviewPlatformService.previewLoanReschedule(scheduleId);
+ final LoanScheduleModel loanRescheduleModel = this.loanReschedulePreviewPlatformService.previewLoanReschedule(scheduleId);
return this.loanRescheduleToApiJsonSerializer.serialize(settings, loanRescheduleModel.toData(), new HashSet<String>());
}
final LoanRescheduleRequestData loanRescheduleRequestData = this.loanRescheduleRequestReadPlatformService
.readLoanRescheduleRequest(scheduleId);
-
+
return this.loanRescheduleRequestToApiJsonSerializer.serialize(settings, loanRescheduleRequestData);
}
@@ -170,4 +170,20 @@ public class RescheduleLoansApiResource {
private boolean compareIgnoreCase(String firstString, String secondString) {
return StringUtils.isNotBlank(firstString) && firstString.trim().equalsIgnoreCase(secondString);
}
+
+ /*@GET
+ @Path("{scheduleId}")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public String retrieveTemplate(@Context final UriInfo uriInfo) {
+
+ this.platformSecurityContext.authenticatedUser().validateHasReadPermission(RescheduleLoansApiConstants.ENTITY_NAME);
+ final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
+
+ LoanRescheduleRequestData loanRescheduleReasons = null;
+ loanRescheduleReasons = this.loanRescheduleRequestReadPlatformService
+ .retrieveAllRescheduleReasons(RescheduleLoansApiConstants.LOAN_RESCHEDULE_REASON);
+
+ return this.loanRescheduleRequestToApiJsonSerializer.serialize(settings, loanRescheduleReasons);
+ }*/
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java
index b74388c..2a6dfbd 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestData.java
@@ -18,10 +18,10 @@
*/
package org.apache.fineract.portfolio.loanaccount.rescheduleloan.data;
-import java.math.BigDecimal;
import java.util.Collection;
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
+import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
import org.joda.time.LocalDate;
/**
@@ -36,59 +36,55 @@ public class LoanRescheduleRequestData {
private final String loanAccountNumber;
private final LoanRescheduleRequestStatusEnumData statusEnum;
private final Integer rescheduleFromInstallment;
- private final Integer graceOnPrincipal;
- private final Integer graceOnInterest;
private final LocalDate rescheduleFromDate;
- private final Integer extraTerms;
- private final BigDecimal interestRate;
private final Boolean recalculateInterest;
private final CodeValueData rescheduleReasonCodeValue;
private final LoanRescheduleRequestTimelineData timeline;
private final String rescheduleReasonComment;
- private final LocalDate adjustedDueDate;
+ @SuppressWarnings("unused")
private final Collection<CodeValueData> rescheduleReasons;
+ @SuppressWarnings("unused")
+ private final Collection<LoanTermVariationsData> loanTermVariationsData;
/**
* LoanRescheduleRequestData constructor
+ * @param loanTermVariationsData TODO
**/
private LoanRescheduleRequestData(Long id, Long loanId, LoanRescheduleRequestStatusEnumData statusEnum,
- Integer rescheduleFromInstallment, Integer graceOnPrincipal, Integer graceOnInterest, LocalDate rescheduleFromDate,
- LocalDate adjustedDueDate, Integer extraTerms, BigDecimal interestRate, CodeValueData rescheduleReasonCodeValue,
+ Integer rescheduleFromInstallment, LocalDate rescheduleFromDate, CodeValueData rescheduleReasonCodeValue,
String rescheduleReasonComment, LoanRescheduleRequestTimelineData timeline, final String clientName,
- final String loanAccountNumber, final Long clientId, final Boolean recalculateInterest, Collection<CodeValueData> rescheduleReasons) {
+ final String loanAccountNumber, final Long clientId, final Boolean recalculateInterest,
+ Collection<CodeValueData> rescheduleReasons, final Collection<LoanTermVariationsData> loanTermVariationsData) {
this.id = id;
this.loanId = loanId;
this.statusEnum = statusEnum;
this.rescheduleFromInstallment = rescheduleFromInstallment;
- this.graceOnPrincipal = graceOnPrincipal;
- this.graceOnInterest = graceOnInterest;
this.rescheduleFromDate = rescheduleFromDate;
- this.extraTerms = extraTerms;
- this.interestRate = interestRate;
this.rescheduleReasonCodeValue = rescheduleReasonCodeValue;
this.rescheduleReasonComment = rescheduleReasonComment;
- this.adjustedDueDate = adjustedDueDate;
this.timeline = timeline;
this.clientName = clientName;
this.loanAccountNumber = loanAccountNumber;
this.clientId = clientId;
this.recalculateInterest = recalculateInterest;
this.rescheduleReasons = rescheduleReasons ;
+ this.loanTermVariationsData = loanTermVariationsData;
}
/**
+ * @param loanTermVariationsData TODO
* @return an instance of the LoanRescheduleRequestData class
**/
public static LoanRescheduleRequestData instance(Long id, Long loanId, LoanRescheduleRequestStatusEnumData statusEnum,
- Integer rescheduleFromInstallment, Integer graceOnPrincipal, Integer graceOnInterest, LocalDate rescheduleFromDate,
- LocalDate adjustedDueDate, Integer extraTerms, BigDecimal interestRate, CodeValueData rescheduleReasonCodeValue,
+ Integer rescheduleFromInstallment, LocalDate rescheduleFromDate, CodeValueData rescheduleReasonCodeValue,
String rescheduleReasonComment, LoanRescheduleRequestTimelineData timeline, final String clientName,
- final String loanAccountNumber, final Long clientId, final Boolean recalculateInterest, Collection<CodeValueData> rescheduleReasons) {
+ final String loanAccountNumber, final Long clientId, final Boolean recalculateInterest,
+ Collection<CodeValueData> rescheduleReasons, final Collection<LoanTermVariationsData> loanTermVariationsData) {
- return new LoanRescheduleRequestData(id, loanId, statusEnum, rescheduleFromInstallment, graceOnPrincipal, graceOnInterest,
- rescheduleFromDate, adjustedDueDate, extraTerms, interestRate, rescheduleReasonCodeValue, rescheduleReasonComment,
- timeline, clientName, loanAccountNumber, clientId, recalculateInterest, rescheduleReasons);
+ return new LoanRescheduleRequestData(id, loanId, statusEnum, rescheduleFromInstallment, rescheduleFromDate,
+ rescheduleReasonCodeValue, rescheduleReasonComment, timeline, clientName, loanAccountNumber, clientId, recalculateInterest,
+ rescheduleReasons, loanTermVariationsData);
}
/**
@@ -120,20 +116,6 @@ public class LoanRescheduleRequestData {
}
/**
- * @return the graceOnPrincipal
- */
- public Integer getGraceOnPrincipal() {
- return graceOnPrincipal;
- }
-
- /**
- * @return the graceOnInterest
- */
- public Integer getGraceOnInterest() {
- return graceOnInterest;
- }
-
- /**
* @return the reschedule from date
*/
public LocalDate getRescheduleFromDate() {
@@ -141,20 +123,6 @@ public class LoanRescheduleRequestData {
}
/**
- * @return the extraTerms
- */
- public Integer getExtraTerms() {
- return extraTerms;
- }
-
- /**
- * @return the interestRate
- */
- public BigDecimal getInterestRate() {
- return interestRate;
- }
-
- /**
* @return the rescheduleReasonCodeValueId
*/
public CodeValueData getRescheduleReasonCodeValueId() {
@@ -176,13 +144,6 @@ public class LoanRescheduleRequestData {
}
/**
- * @return the adjustedDueDate
- */
- public LocalDate getAdjustedDueDate() {
- return adjustedDueDate;
- }
-
- /**
* @return the clientName
*/
public String getClientName() {
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
index 5254187..67e0f80 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/data/LoanRescheduleRequestDataValidator.java
@@ -32,10 +32,8 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
-import org.apache.fineract.portfolio.loanaccount.rescheduleloan.service.LoanRescheduleRequestReadPlatformService;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -47,13 +45,10 @@ import com.google.gson.reflect.TypeToken;
public class LoanRescheduleRequestDataValidator {
private final FromJsonHelper fromJsonHelper;
- private final LoanRescheduleRequestReadPlatformService loanRescheduleRequestReadPlatformService;
@Autowired
- public LoanRescheduleRequestDataValidator(FromJsonHelper fromJsonHelper,
- LoanRescheduleRequestReadPlatformService loanRescheduleRequestReadPlatformService) {
+ public LoanRescheduleRequestDataValidator(FromJsonHelper fromJsonHelper) {
this.fromJsonHelper = fromJsonHelper;
- this.loanRescheduleRequestReadPlatformService = loanRescheduleRequestReadPlatformService;
}
/**
@@ -159,21 +154,8 @@ public class LoanRescheduleRequestDataValidator {
.failWithCode("repayment.schedule.installment.obligation.met", "Repayment schedule installment obligation met");
}
- if (installment != null && installment.isPartlyPaid()) {
- dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.rescheduleFromDateParamName)
- .failWithCode("repayment.schedule.installment.partly.paid", "Repayment schedule installment is partly paid");
- }
}
- if (loanId != null) {
- List<LoanRescheduleRequestData> loanRescheduleRequestData = this.loanRescheduleRequestReadPlatformService
- .readLoanRescheduleRequests(loanId, LoanStatus.APPROVED.getValue());
-
- if (loanRescheduleRequestData.size() > 0) {
- dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode("loan.already.rescheduled",
- "The loan can only be rescheduled once.");
- }
- }
if(loan.isMultiDisburmentLoan()) {
dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode(RescheduleLoansApiConstants.resheduleForMultiDisbursementNotSupportedErrorCode,
"Loan rescheduling is not supported for multidisbursement loans");
@@ -232,7 +214,6 @@ public class LoanRescheduleRequestDataValidator {
final Loan loan = loanRescheduleRequest.getLoan();
if (loan != null) {
- Long loanId = loan.getId();
if (!loan.status().isActive()) {
dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode("loan.is.not.active", "Loan is not active");
@@ -251,16 +232,6 @@ public class LoanRescheduleRequestDataValidator {
"loan.repayment.schedule.installment." + "obligation.met", "Repayment schedule installment obligation met");
}
}
-
- if (loanId != null) {
- List<LoanRescheduleRequestData> loanRescheduleRequestData = this.loanRescheduleRequestReadPlatformService
- .readLoanRescheduleRequests(loanId, LoanStatus.APPROVED.getValue());
-
- if (loanRescheduleRequestData.size() > 0) {
- dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode("loan.already.rescheduled",
- "The loan can only be rescheduled once.");
- }
- }
}
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java
deleted file mode 100644
index bcb7bc4..0000000
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/DefaultLoanReschedulerFactory.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain;
-
-import java.math.MathContext;
-
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
-import org.apache.fineract.portfolio.calendar.domain.Calendar;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
-import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
-import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
-import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DecliningBalanceInterestLoanScheduleGenerator;
-import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.FlatInterestLoanScheduleGenerator;
-import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
-
-public class DefaultLoanReschedulerFactory implements LoanReschedulerFactory {
-
- @Override
- 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 Calendar loanCalendar, final FloatingRateDTO floatingRateDTO,
- final boolean isSkipRepaymentonmonthFirst, final Integer numberofdays) {
-
- LoanRescheduleModel loanRescheduleModel = null;
-
- switch (interestMethod) {
- case DECLINING_BALANCE:
- loanRescheduleModel = new DecliningBalanceInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
- applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, loanCalendar,
- floatingRateDTO, isSkipRepaymentonmonthFirst, numberofdays);
- break;
-
- case FLAT:
- loanRescheduleModel = new FlatInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
- applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, loanCalendar,
- floatingRateDTO, isSkipRepaymentonmonthFirst, numberofdays);
- break;
-
- case INVALID:
- break;
- }
-
- return loanRescheduleModel;
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java
index 8893054..8a0a844 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanRescheduleRequest.java
@@ -18,20 +18,27 @@
*/
package org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain;
-import java.math.BigDecimal;
import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
+import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRescheduleRequestToTermVariationMapping;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
import org.apache.fineract.useradministration.domain.AppUser;
import org.joda.time.LocalDate;
import org.springframework.data.jpa.domain.AbstractPersistable;
@@ -40,116 +47,97 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
@Table(name = "m_loan_reschedule_request")
public class LoanRescheduleRequest extends AbstractPersistable<Long> {
- @ManyToOne
+ @ManyToOne
@JoinColumn(name = "loan_id", nullable = false)
private Loan loan;
- @Column(name = "status_enum", nullable = false)
- private Integer statusEnum;
-
- @Column(name = "reschedule_from_installment")
- private Integer rescheduleFromInstallment;
-
- @Column(name = "grace_on_principal")
- private Integer graceOnPrincipal;
-
- @Column(name = "grace_on_interest")
- private Integer graceOnInterest;
-
- @Temporal(TemporalType.DATE)
+ @Column(name = "status_enum", nullable = false)
+ private Integer statusEnum;
+
+ @Column(name = "reschedule_from_installment")
+ private Integer rescheduleFromInstallment;
+
+ @Temporal(TemporalType.DATE)
@Column(name = "reschedule_from_date")
- private Date rescheduleFromDate;
-
- @Temporal(TemporalType.DATE)
- @Column(name = "adjusted_due_date")
- private Date adjustedDueDate;
-
- @Column(name = "extra_terms")
- private Integer extraTerms;
-
- @Column(name = "recalculate_interest")
- private Boolean recalculateInterest;
-
- @Column(name = "interest_rate", scale = 6, precision = 19)
- private BigDecimal interestRate;
-
- @ManyToOne
+ private Date rescheduleFromDate;
+
+ @Column(name = "recalculate_interest")
+ private Boolean recalculateInterest;
+
+ @ManyToOne
@JoinColumn(name = "reschedule_reason_cv_id")
- private CodeValue rescheduleReasonCodeValue;
-
- @Column(name = "reschedule_reason_comment")
- private String rescheduleReasonComment;
-
- @Temporal(TemporalType.DATE)
+ private CodeValue rescheduleReasonCodeValue;
+
+ @Column(name = "reschedule_reason_comment")
+ private String rescheduleReasonComment;
+
+ @Temporal(TemporalType.DATE)
@Column(name = "submitted_on_date")
- private Date submittedOnDate;
-
- @ManyToOne
+ private Date submittedOnDate;
+
+ @ManyToOne
@JoinColumn(name = "submitted_by_user_id")
- private AppUser submittedByUser;
-
- @Temporal(TemporalType.DATE)
+ private AppUser submittedByUser;
+
+ @Temporal(TemporalType.DATE)
@Column(name = "approved_on_date")
- private Date approvedOnDate;
+ private Date approvedOnDate;
- @ManyToOne
+ @ManyToOne
@JoinColumn(name = "approved_by_user_id")
- private AppUser approvedByUser;
+ private AppUser approvedByUser;
- @Temporal(TemporalType.DATE)
+ @Temporal(TemporalType.DATE)
@Column(name = "rejected_on_date")
- private Date rejectedOnDate;
+ private Date rejectedOnDate;
- @ManyToOne
+ @ManyToOne
@JoinColumn(name = "rejected_by_user_id")
- private AppUser rejectedByUser;
-
- /**
- * LoanRescheduleRequest constructor
- **/
- protected LoanRescheduleRequest() {}
-
- /**
- * LoanRescheduleRequest constructor
- **/
- private LoanRescheduleRequest(final Loan loan, final Integer statusEnum, final Integer rescheduleFromInstallment,
- final Integer graceOnPrincipal, final Integer graceOnInterest, final Date rescheduleFromDate, final Date adjustedDueDate,
- final Integer extraTerms, final Boolean recalculateInterest, final BigDecimal interestRate, final CodeValue rescheduleReasonCodeValue,
- final String rescheduleReasonComment, final Date submittedOnDate, final AppUser submittedByUser,
- final Date approvedOnDate, final AppUser approvedByUser, final Date rejectedOnDate, AppUser rejectedByUser) {
- this.loan = loan;
- this.statusEnum = statusEnum;
- this.rescheduleFromInstallment = rescheduleFromInstallment;
- this.graceOnPrincipal = graceOnPrincipal;
- this.graceOnInterest = graceOnInterest;
- this.rescheduleFromDate = rescheduleFromDate;
- this.extraTerms = extraTerms;
- this.interestRate = interestRate;
- this.rescheduleReasonCodeValue = rescheduleReasonCodeValue;
- this.rescheduleReasonComment = rescheduleReasonComment;
- this.submittedOnDate = submittedOnDate;
- this.submittedByUser = submittedByUser;
- this.approvedOnDate = approvedOnDate;
- this.approvedByUser = approvedByUser;
- this.rejectedOnDate = rejectedOnDate;
- this.rejectedByUser = rejectedByUser;
- this.adjustedDueDate = adjustedDueDate;
- this.recalculateInterest = recalculateInterest;
- }
-
- /**
- * @return a new instance of the LoanRescheduleRequest class
- **/
- public static LoanRescheduleRequest instance(final Loan loan, final Integer statusEnum, final Integer rescheduleFromInstallment,
- final Integer graceOnPrincipal, final Integer graceOnInterest, final Date rescheduleFromDate, final Date adjustedDueDate,
- final Integer extraTerms, final Boolean recalculateInterest, final BigDecimal interestRate, final CodeValue rescheduleReasonCodeValue,
- final String rescheduleReasonComment, final Date submittedOnDate, final AppUser submittedByUser,
- final Date approvedOnDate, final AppUser approvedByUser, final Date rejectedOnDate, AppUser rejectedByUser) {
-
- return new LoanRescheduleRequest(loan, statusEnum, rescheduleFromInstallment, graceOnPrincipal, graceOnInterest,
- rescheduleFromDate, adjustedDueDate, extraTerms, recalculateInterest, interestRate, rescheduleReasonCodeValue, rescheduleReasonComment, submittedOnDate,
- submittedByUser, approvedOnDate, approvedByUser, rejectedOnDate, rejectedByUser);
- }
+ private AppUser rejectedByUser;
+
+ @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch=FetchType.EAGER)
+ @JoinColumn(name = "loan_reschedule_request_id", nullable = false)
+ private Set<LoanRescheduleRequestToTermVariationMapping> loanRescheduleRequestToTermVariationMappings = new HashSet<>();
+
+ /**
+ * LoanRescheduleRequest constructor
+ **/
+ protected LoanRescheduleRequest() {}
+
+ /**
+ * LoanRescheduleRequest constructor
+ **/
+ private LoanRescheduleRequest(final Loan loan, final Integer statusEnum, final Integer rescheduleFromInstallment,
+ final Date rescheduleFromDate, final Boolean recalculateInterest, final CodeValue rescheduleReasonCodeValue,
+ final String rescheduleReasonComment, final Date submittedOnDate, final AppUser submittedByUser, final Date approvedOnDate,
+ final AppUser approvedByUser, final Date rejectedOnDate, AppUser rejectedByUser) {
+ this.loan = loan;
+ this.statusEnum = statusEnum;
+ this.rescheduleFromInstallment = rescheduleFromInstallment;
+ this.rescheduleFromDate = rescheduleFromDate;
+ this.rescheduleReasonCodeValue = rescheduleReasonCodeValue;
+ this.rescheduleReasonComment = rescheduleReasonComment;
+ this.submittedOnDate = submittedOnDate;
+ this.submittedByUser = submittedByUser;
+ this.approvedOnDate = approvedOnDate;
+ this.approvedByUser = approvedByUser;
+ this.rejectedOnDate = rejectedOnDate;
+ this.rejectedByUser = rejectedByUser;
+ this.recalculateInterest = recalculateInterest;
+ }
+
+ /**
+ * @return a new instance of the LoanRescheduleRequest class
+ **/
+ public static LoanRescheduleRequest instance(final Loan loan, final Integer statusEnum, final Integer rescheduleFromInstallment,
+ final Date rescheduleFromDate, final Boolean recalculateInterest, final CodeValue rescheduleReasonCodeValue,
+ final String rescheduleReasonComment, final Date submittedOnDate, final AppUser submittedByUser, final Date approvedOnDate,
+ final AppUser approvedByUser, final Date rejectedOnDate, AppUser rejectedByUser) {
+
+ return new LoanRescheduleRequest(loan, statusEnum, rescheduleFromInstallment, rescheduleFromDate, recalculateInterest,
+ rescheduleReasonCodeValue, rescheduleReasonComment, submittedOnDate, submittedByUser, approvedOnDate, approvedByUser,
+ rejectedOnDate, rejectedByUser);
+ }
/**
* @return the reschedule request loan object
@@ -173,20 +161,6 @@ public class LoanRescheduleRequest extends AbstractPersistable<Long> {
}
/**
- * @return the grace on principal
- **/
- public Integer getGraceOnPrincipal() {
- return this.graceOnPrincipal;
- }
-
- /**
- * @return the grace on interest
- **/
- public Integer getGraceOnInterest() {
- return this.graceOnInterest;
- }
-
- /**
* @return due date of the rescheduling start point
**/
public LocalDate getRescheduleFromDate() {
@@ -201,34 +175,6 @@ public class LoanRescheduleRequest extends AbstractPersistable<Long> {
}
/**
- * @return due date of the first rescheduled installment
- **/
- public LocalDate getAdjustedDueDate() {
-
- LocalDate localDate = null;
-
- if(this.adjustedDueDate != null) {
- localDate = new LocalDate(this.adjustedDueDate);
- }
-
- return localDate;
- }
-
- /**
- * @return extra terms to be added after the last loan installment
- **/
- public Integer getExtraTerms() {
- return this.extraTerms;
- }
-
- /**
- * @return the new interest rate to be applied to unpaid installments
- **/
- public BigDecimal getInterestRate() {
- return this.interestRate;
- }
-
- /**
* @return the reschedule reason code value object
**/
public CodeValue getRescheduleReasonCodeValue() {
@@ -348,4 +294,24 @@ public class LoanRescheduleRequest extends AbstractPersistable<Long> {
this.statusEnum = LoanStatus.REJECTED.getValue();
}
}
+
+ public void updateLoanRescheduleRequestToTermVariationMappings(final List<LoanRescheduleRequestToTermVariationMapping> mapping) {
+ this.loanRescheduleRequestToTermVariationMappings.addAll(mapping);
+ }
+
+ public Set<LoanRescheduleRequestToTermVariationMapping> getLoanRescheduleRequestToTermVariationMappings() {
+ return this.loanRescheduleRequestToTermVariationMappings;
+ }
+
+ public LoanTermVariations getDueDateTermVariationIfExists() {
+ if(this.loanRescheduleRequestToTermVariationMappings != null
+ && this.loanRescheduleRequestToTermVariationMappings.size() > 0){
+ for (LoanRescheduleRequestToTermVariationMapping mapping : this.loanRescheduleRequestToTermVariationMappings) {
+ if(mapping.getLoanTermVariations().getTermType().isDueDateVariation()){
+ return mapping.getLoanTermVariations();
+ }
+ }
+ }
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java
deleted file mode 100644
index f2e8bc7..0000000
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/domain/LoanReschedulerFactory.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain;
-
-import java.math.MathContext;
-
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
-import org.apache.fineract.portfolio.calendar.domain.Calendar;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
-import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
-import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
-import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
-
-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 Calendar loanCalendar, FloatingRateDTO floatingRateDTO, final boolean isSkipRepaymentonmonthFirst,
- final Integer numberofdays);
-}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java
index b300b4d..f91649e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformService.java
@@ -18,9 +18,9 @@
*/
package org.apache.fineract.portfolio.loanaccount.rescheduleloan.service;
-import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
public interface LoanReschedulePreviewPlatformService {
- public LoanRescheduleModel previewLoanReschedule(Long requestId);
+ public LoanScheduleModel previewLoanReschedule(Long requestId);
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java
index 64040af..f6a918d 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanReschedulePreviewPlatformServiceImpl.java
@@ -18,41 +18,33 @@
*/
package org.apache.fineract.portfolio.loanaccount.rescheduleloan.service;
-import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
-import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
-import org.apache.fineract.organisation.holiday.domain.Holiday;
-import org.apache.fineract.organisation.holiday.domain.HolidayRepository;
-import org.apache.fineract.organisation.holiday.domain.HolidayStatusType;
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
-import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
-import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
-import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
-import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
-import org.apache.fineract.portfolio.calendar.domain.Calendar;
-import org.apache.fineract.portfolio.calendar.domain.CalendarEntityType;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
-import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
-import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
-import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
-import org.apache.fineract.portfolio.floatingrates.exception.FloatingRateNotFoundException;
-import org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
-import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
+import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
+import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
-import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
-import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
-import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.DefaultLoanReschedulerFactory;
-import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRescheduleRequestToTermVariationMapping;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanSummaryWrapper;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariations;
+import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
+import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository;
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.exception.LoanRescheduleRequestNotFoundException;
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
-import org.apache.fineract.portfolio.loanproduct.domain.InterestMethod;
-import org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
+import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -60,103 +52,94 @@ import org.springframework.stereotype.Service;
public class LoanReschedulePreviewPlatformServiceImpl implements LoanReschedulePreviewPlatformService {
private final LoanRescheduleRequestRepository loanRescheduleRequestRepository;
- private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository;
- private final ConfigurationDomainService configurationDomainService;
- private final HolidayRepository holidayRepository;
- private final WorkingDaysRepositoryWrapper workingDaysRepository;
- private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService;
- private final CalendarInstanceRepository calendarInstanceRepository;
- private final FloatingRatesReadPlatformService floatingRatesReadPlatformService;
private final LoanUtilService loanUtilService;
+ private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
+ private final LoanScheduleGeneratorFactory loanScheduleFactory;
+ private final LoanSummaryWrapper loanSummaryWrapper;
+ private final DefaultScheduledDateGenerator scheduledDateGenerator = new DefaultScheduledDateGenerator();
@Autowired
public LoanReschedulePreviewPlatformServiceImpl(final LoanRescheduleRequestRepository loanRescheduleRequestRepository,
- final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository,
- final ConfigurationDomainService configurationDomainService, final HolidayRepository holidayRepository,
- final WorkingDaysRepositoryWrapper workingDaysRepository,
- final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService,
- final CalendarInstanceRepository calendarInstanceRepository,
- final FloatingRatesReadPlatformService floatingRatesReadPlatformService, final LoanUtilService loanUtilService) {
+ final LoanUtilService loanUtilService,
+ final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
+ final LoanScheduleGeneratorFactory loanScheduleFactory, final LoanSummaryWrapper loanSummaryWrapper) {
this.loanRescheduleRequestRepository = loanRescheduleRequestRepository;
- this.applicationCurrencyRepository = applicationCurrencyRepository;
- this.configurationDomainService = configurationDomainService;
- this.holidayRepository = holidayRepository;
- this.workingDaysRepository = workingDaysRepository;
- this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService;
- this.calendarInstanceRepository = calendarInstanceRepository;
- this.floatingRatesReadPlatformService = floatingRatesReadPlatformService;
this.loanUtilService = loanUtilService;
+ this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
+ this.loanScheduleFactory = loanScheduleFactory;
+ this.loanSummaryWrapper = loanSummaryWrapper;
}
@Override
- public LoanRescheduleModel previewLoanReschedule(Long requestId) {
+ public LoanScheduleModel previewLoanReschedule(Long requestId) {
final LoanRescheduleRequest loanRescheduleRequest = this.loanRescheduleRequestRepository.findOne(requestId);
if (loanRescheduleRequest == null) { throw new LoanRescheduleRequestNotFoundException(requestId); }
Loan loan = loanRescheduleRequest.getLoan();
- final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
- final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan
- .getDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
- final WorkingDays workingDays = this.workingDaysRepository.findOne();
- final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
- final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
- final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
-
- final InterestMethod interestMethod = loan.getLoanRepaymentScheduleDetail().getInterestMethod();
- final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
- final MathContext mathContext = new MathContext(8, roundingMode);
- List<LoanRepaymentScheduleHistory> oldPeriods = this.loanScheduleHistoryWritePlatformService.createLoanScheduleArchive(
- loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
- HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
- CalendarInstance restCalendarInstance = null;
- CalendarInstance compoundingCalendarInstance = null;
- if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
- restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
- CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
- compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
- loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
+ ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan,
+ loanRescheduleRequest.getRescheduleFromDate());
+ LocalDate rescheduleFromDate = null;
+ List<LoanTermVariationsData> removeLoanTermVariationsData = new ArrayList<>();
+ final LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(scheduleGeneratorDTO);
+ LoanTermVariations dueDateVariationInCurrentRequest = loanRescheduleRequest.getDueDateTermVariationIfExists();
+ if(dueDateVariationInCurrentRequest != null){
+ for (LoanTermVariationsData loanTermVariation : loanApplicationTerms.getLoanTermVariations().getDueDateVariation()) {
+ if (loanTermVariation.getDateValue().equals(dueDateVariationInCurrentRequest.fetchTermApplicaDate())) {
+ rescheduleFromDate = loanTermVariation.getTermApplicableFrom();
+ removeLoanTermVariationsData.add(loanTermVariation);
+ }
+ }
}
- final CalendarInstance loanCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
- CalendarEntityType.LOANS.getValue());
- Calendar loanCalendar = null;
- if (loanCalendarInstance != null) {
- loanCalendar = loanCalendarInstance.getCalendar();
+ loanApplicationTerms.getLoanTermVariations().getDueDateVariation().removeAll(removeLoanTermVariationsData);
+ if (rescheduleFromDate == null) {
+ rescheduleFromDate = loanRescheduleRequest.getRescheduleFromDate();
}
- final FloatingRateDTO floatingRateDTO = constructFloatingRateDTO(loan);
- Boolean isSkipRepaymentOnFirstMonth = false;
- Integer numberOfDays = 0;
- boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
- if(isSkipRepaymentOnFirstMonthEnabled){
- isSkipRepaymentOnFirstMonth = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), loanCalendar);
- if(isSkipRepaymentOnFirstMonth) { numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue(); }
-
+ List<LoanTermVariationsData> loanTermVariationsData = new ArrayList<>();
+ LocalDate adjustedApplicableDate = null;
+ Set<LoanRescheduleRequestToTermVariationMapping> loanRescheduleRequestToTermVariationMappings = loanRescheduleRequest.getLoanRescheduleRequestToTermVariationMappings();
+ if (!loanRescheduleRequestToTermVariationMappings.isEmpty()) {
+ for (LoanRescheduleRequestToTermVariationMapping loanRescheduleRequestToTermVariationMapping : loanRescheduleRequestToTermVariationMappings) {
+ if (loanRescheduleRequestToTermVariationMapping.getLoanTermVariations().getTermType().isDueDateVariation()
+ && rescheduleFromDate != null) {
+ adjustedApplicableDate = loanRescheduleRequestToTermVariationMapping.getLoanTermVariations().fetchDateValue();
+ loanRescheduleRequestToTermVariationMapping.getLoanTermVariations().setTermApplicableFrom(
+ rescheduleFromDate.toDate());
+ }
+ loanTermVariationsData.add(loanRescheduleRequestToTermVariationMapping.getLoanTermVariations().toData());
+ }
}
- LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
- loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
- loanCalendar, floatingRateDTO, isSkipRepaymentOnFirstMonth, numberOfDays);
- LoanRescheduleModel loanRescheduleModelWithOldPeriods = LoanRescheduleModel.createWithSchedulehistory(loanRescheduleModel,
- oldPeriods);
- return loanRescheduleModelWithOldPeriods;
- }
-
- private FloatingRateDTO constructFloatingRateDTO(final Loan loan) {
- FloatingRateDTO floatingRateDTO = null;
- if (loan.loanProduct().isLinkedToFloatingInterestRate()) {
- boolean isFloatingInterestRate = loan.getIsFloatingInterestRate();
- BigDecimal interestRateDiff = loan.getInterestRateDifferential();
- List<FloatingRatePeriodData> baseLendingRatePeriods = null;
- try{
- baseLendingRatePeriods = this.floatingRatesReadPlatformService.retrieveBaseLendingRate()
- .getRatePeriods();
- }catch(final FloatingRateNotFoundException ex){
- // Do not do anything
+
+ for (LoanTermVariationsData loanTermVariation : loanApplicationTerms.getLoanTermVariations().getDueDateVariation()) {
+ if (rescheduleFromDate.isBefore(loanTermVariation.getTermApplicableFrom())) {
+ LocalDate applicableDate = this.scheduledDateGenerator.generateNextRepaymentDate(rescheduleFromDate, loanApplicationTerms,
+ false, loanApplicationTerms.getHolidayDetailDTO());
+ if (loanTermVariation.getTermApplicableFrom().equals(applicableDate)) {
+ LocalDate adjustedDate = this.scheduledDateGenerator.generateNextRepaymentDate(adjustedApplicableDate,
+ loanApplicationTerms, false, loanApplicationTerms.getHolidayDetailDTO());
+ loanTermVariation.setApplicableFromDate(adjustedDate);
+ loanTermVariationsData.add(loanTermVariation);
+ }
}
- floatingRateDTO = new FloatingRateDTO(isFloatingInterestRate, loan.getDisbursementDate(), interestRateDiff,
- baseLendingRatePeriods);
}
- return floatingRateDTO;
+
+ loanApplicationTerms.getLoanTermVariations().updateLoanTermVariationsData(loanTermVariationsData);
+ final RoundingMode roundingMode = MoneyHelper.getRoundingMode();
+ final MathContext mathContext = new MathContext(8, roundingMode);
+ final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.loanRepaymentScheduleTransactionProcessorFactory
+ .determineProcessor(loan.transactionProcessingStrategy());
+ final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
+ final LoanLifecycleStateMachine loanLifecycleStateMachine = null;
+ loan.setHelpers(loanLifecycleStateMachine, this.loanSummaryWrapper, this.loanRepaymentScheduleTransactionProcessorFactory);
+ final LoanScheduleDTO loanSchedule = loanScheduleGenerator.rescheduleNextInstallments(mathContext, loanApplicationTerms,
+ loan, loanApplicationTerms.getHolidayDetailDTO(),
+ loanRepaymentScheduleTransactionProcessor, rescheduleFromDate);
+ final LoanScheduleModel loanScheduleModel = loanSchedule.getLoanScheduleModel();
+ LoanScheduleModel loanScheduleModels = LoanScheduleModel.withLoanScheduleModelPeriods(loanScheduleModel.getPeriods(),
+ loanScheduleModel);
+
+ return loanScheduleModels;
}
}
[4/5] incubator-fineract git commit: FINERACT-202 : enabling the
option for multi reshedule
Posted by na...@apache.org.
FINERACT-202 : enabling the option for multi reshedule
Project: http://git-wip-us.apache.org/repos/asf/incubator-fineract/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-fineract/commit/fe617123
Tree: http://git-wip-us.apache.org/repos/asf/incubator-fineract/tree/fe617123
Diff: http://git-wip-us.apache.org/repos/asf/incubator-fineract/diff/fe617123
Branch: refs/heads/develop
Commit: fe6171237e09cb1f347dc6577800ca4c665e361e
Parents: ada9ced
Author: venkatconflux <ve...@confluxtechnologies.com>
Authored: Fri Jul 29 18:22:46 2016 +0530
Committer: venkatconflux <ve...@confluxtechnologies.com>
Committed: Mon Aug 1 17:07:34 2016 +0530
----------------------------------------------------------------------
api-docs/apiLive.htm | 90 ++-
.../LoanRescheduleRequestTest.java | 2 +-
.../data/LoanTermVariationsData.java | 6 +-
.../data/LoanTermVariationsDataWrapper.java | 78 +-
.../portfolio/loanaccount/domain/Loan.java | 55 +-
.../domain/LoanAccountDomainService.java | 2 +
.../domain/LoanAccountDomainServiceJpa.java | 23 +-
.../LoanRepaymentScheduleInstallment.java | 6 +
...RescheduleRequestToTermVariationMapping.java | 53 ++
.../domain/LoanTermVariationType.java | 34 +-
.../loanaccount/domain/LoanTermVariations.java | 43 +-
.../loanaccount/domain/LoanTransaction.java | 6 +
.../domain/AbstractLoanScheduleGenerator.java | 750 ++++++++-----------
...ingBalanceInterestLoanScheduleGenerator.java | 6 +-
.../FlatInterestLoanScheduleGenerator.java | 8 +-
.../domain/LoanApplicationTerms.java | 217 +++++-
.../domain/LoanScheduleGenerator.java | 25 +-
.../service/LoanScheduleAssembler.java | 20 +-
...nScheduleCalculationPlatformServiceImpl.java | 8 +-
.../api/RescheduleLoansApiResource.java | 22 +-
.../data/LoanRescheduleRequestData.java | 71 +-
.../LoanRescheduleRequestDataValidator.java | 31 +-
.../domain/DefaultLoanReschedulerFactory.java | 62 --
.../domain/LoanRescheduleRequest.java | 244 +++---
.../domain/LoanReschedulerFactory.java | 37 -
.../LoanReschedulePreviewPlatformService.java | 4 +-
...oanReschedulePreviewPlatformServiceImpl.java | 187 +++--
...escheduleRequestReadPlatformServiceImpl.java | 71 +-
...scheduleRequestWritePlatformServiceImpl.java | 488 ++++++------
.../loanproduct/service/LoanEnumerations.java | 16 +
.../core_db/V313__multi_rescheduling_script.sql | 141 ++++
31 files changed, 1496 insertions(+), 1310 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/api-docs/apiLive.htm
----------------------------------------------------------------------
diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm
index 696e066..7fe3fc9 100644
--- a/api-docs/apiLive.htm
+++ b/api-docs/apiLive.htm
@@ -11877,11 +11877,11 @@ Content-Type: application/json Request Body:
{
"loanId": 1,
"graceOnPrincipal": 2,
- "rescheduleFromDate": "04 December 2014",
- "adjustedDueDate": "20 December 2014",
+ "rescheduleFromDate": "25 December 2013",
+ "adjustedDueDate": "31 December 2013",
"dateFormat": "dd MMMM yyyy",
"locale": "en",
- "submittedOnDate": "04 September 2014",
+ "submittedOnDate": "04 September 2013",
"rescheduleReasonComment" : "Client has gone AWOL",
"rescheduleReasonId": 1
}
@@ -11907,52 +11907,80 @@ GET https://DomainName/api/v1/rescheduleloans/{requestId}
</code>
<code class="method-response">
{
- "id": 2,
- "loanId": 17,
- "clientId": 4,
- "clientName": "Fernando Michael Torres",
- "loanAccountNumber": "000000017",
+ "id": 1,
+ "loanId": 1,
+ "clientId": 1,
+ "clientName": "test test",
+ "loanAccountNumber": "000000001",
"statusEnum": {
- "id": 500,
- "code": "loanStatusType.rejected",
- "value": "Rejected",
- "pendingApproval": false,
+ "id": 100,
+ "code": "loanStatusType.submitted.and.pending.approval",
+ "value": "Submitted and pending approval",
+ "pendingApproval": true,
"approved": false,
- "rejected": true
+ "rejected": false
},
"rescheduleFromInstallment": 5,
- "graceOnPrincipal": 3,
"rescheduleFromDate": [
2013,
12,
- 6
+ 25
],
"recalculateInterest": false,
"rescheduleReasonCodeValue": {
- "id": 239,
- "name": "client cannot pay on time"
+ "id": 1,
+ "name": "Passport",
+ "isActive": false
},
"timeline": {
"submittedOnDate": [
- 2014,
- 8,
+ 2013,
+ 9,
4
],
"submittedByUsername": "mifos",
"submittedByFirstname": "App",
- "submittedByLastname": "Administrator",
- "rejectedOnDate": [
- 2014,
- 8,
- 5
- ],
- "rejectedByUsername": "mifos",
- "rejectedByFirstname": "App",
- "rejectedByLastname": "Administrator"
+ "submittedByLastname": "Administrator"
},
- "rescheduleReasonComment": ""
-}
- </code>
+ "rescheduleReasonComment": "Client has gone AWOL",
+ "loanTermVariationsData": [
+ {
+ "id": 13,
+ "termType": {
+ "id": 4,
+ "code": "loanTermType.dueDate",
+ "value": "dueDate"
+ },
+ "termVariationApplicableFrom": [
+ 2013,
+ 12,
+ 25
+ ],
+ "dateValue": [
+ 2013,
+ 12,
+ 31
+ ],
+ "isSpecificToInstallment": false
+ },
+ {
+ "id": 14,
+ "termType": {
+ "id": 8,
+ "code": "loanTermType.graceOnPrincipal",
+ "value": "graceOnPrincipal"
+ },
+ "termVariationApplicableFrom": [
+ 2013,
+ 12,
+ 25
+ ],
+ "decimalValue": 2,
+ "isSpecificToInstallment": false
+ }
+ ]
+}
+</code>
</div>
</div>
<a id="loan_reschedule_preview_retrieve" name="loan_reschedule_preview_retrieve" class="old-syle-anchor"> </a>
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRescheduleRequestTest.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRescheduleRequestTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRescheduleRequestTest.java
index 2b00a98..ae39433 100644
--- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRescheduleRequestTest.java
+++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanRescheduleRequestTest.java
@@ -211,7 +211,7 @@ public class LoanRescheduleRequestTest {
final HashMap loanSummary = this.loanTransactionHelper.getLoanSummary(requestSpec, generalResponseSpec, loanId);
final Float totalExpectedRepayment = (Float) loanSummary.get("totalExpectedRepayment");
- assertEquals("NUMBER OF REPAYMENTS SHOULD BE 16, NOT 12", "16", numberOfRepayments.toString());
+ assertEquals("NUMBER OF REPAYMENTS SHOULD BE 16, NOT 12", "12", numberOfRepayments.toString());
assertEquals("TOTAL EXPECTED REPAYMENT MUST BE EQUAL TO 118000.0", "118000.0", totalExpectedRepayment.toString());
System.out.println("Successfully approved loan reschedule request (ID: " + this.loanRescheduleRequestId + ")");
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsData.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsData.java
index f5d2cc0..a19d3b1 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsData.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsData.java
@@ -29,7 +29,7 @@ public class LoanTermVariationsData implements Comparable<LoanTermVariationsData
@SuppressWarnings("unused")
private final Long id;
private final EnumOptionData termType;
- private final LocalDate termVariationApplicableFrom;
+ private LocalDate termVariationApplicableFrom;
private final BigDecimal decimalValue;
private final LocalDate dateValue;
private final boolean isSpecificToInstallment;
@@ -113,5 +113,9 @@ public class LoanTermVariationsData implements Comparable<LoanTermVariationsData
}
return comparsion;
}
+
+ public void setApplicableFromDate(final LocalDate applicableFromDate) {
+ this.termVariationApplicableFrom = applicableFromDate;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java
index 65730e7..ea784e3 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanTermVariationsDataWrapper.java
@@ -22,37 +22,27 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
-
import org.joda.time.LocalDate;
public class LoanTermVariationsDataWrapper {
private final List<LoanTermVariationsData> exceptionData;
- private final ListIterator<LoanTermVariationsData> iterator;
+ private ListIterator<LoanTermVariationsData> iterator;
private final List<LoanTermVariationsData> interestRateChanges;
+ private final List<LoanTermVariationsData> interestRateFromInstallment;
private final List<LoanTermVariationsData> dueDateVariation;
- private final ListIterator<LoanTermVariationsData> dueDateIterator;
+ private ListIterator<LoanTermVariationsData> dueDateIterator;
public LoanTermVariationsDataWrapper(final List<LoanTermVariationsData> exceptionData) {
if (exceptionData == null) {
this.exceptionData = new ArrayList<>(1);
} else {
this.exceptionData = exceptionData;
- Collections.sort(this.exceptionData);
}
this.interestRateChanges = new ArrayList<>();
this.dueDateVariation = new ArrayList<>();
- for (LoanTermVariationsData loanTermVariationsData : this.exceptionData) {
- if (loanTermVariationsData.getTermVariationType().isInterestRateVariation()) {
- this.interestRateChanges.add(loanTermVariationsData);
- } else if (loanTermVariationsData.getTermVariationType().isDueDateVariation()) {
- this.dueDateVariation.add(loanTermVariationsData);
- }
- }
- this.exceptionData.removeAll(this.interestRateChanges);
- this.exceptionData.removeAll(this.dueDateVariation);
- iterator = this.exceptionData.listIterator();
- dueDateIterator = this.dueDateVariation.listIterator();
+ this.interestRateFromInstallment = new ArrayList<>();
+ deriveLoanTermVariations();
}
public boolean hasVariation(final LocalDate date) {
@@ -84,6 +74,10 @@ public class LoanTermVariationsDataWrapper {
public LoanTermVariationsData nextDueDateVariation() {
return this.dueDateIterator.next();
}
+
+ public LoanTermVariationsData previousDueDateVariation() {
+ return this.dueDateIterator.previous();
+ }
public List<LoanTermVariationsData> getInterestRateChanges() {
return this.interestRateChanges;
@@ -96,6 +90,23 @@ public class LoanTermVariationsDataWrapper {
public List<LoanTermVariationsData> getExceptionData() {
return this.exceptionData;
}
+
+ public void setExceptionData(final List<LoanTermVariationsData> exceptionData) {
+ clearTerms();
+ this.exceptionData.addAll(exceptionData);
+ deriveLoanTermVariations();
+ }
+
+ public void clearTerms() {
+ this.exceptionData.clear();
+ this.interestRateChanges.clear();
+ this.dueDateVariation.clear();
+ this.interestRateFromInstallment.clear();
+ }
+
+ public List<LoanTermVariationsData> getInterestRateFromInstallment() {
+ return this.interestRateFromInstallment;
+ }
public int adjustNumberOfRepayments() {
int repaymetsForAdjust = 0;
@@ -108,7 +119,7 @@ public class LoanTermVariationsDataWrapper {
}
return repaymetsForAdjust;
}
-
+
public LoanTermVariationsData fetchLoanTermDueDateVariationsData(final LocalDate onDate) {
LoanTermVariationsData data = null;
for (LoanTermVariationsData termVariationsData : this.dueDateVariation) {
@@ -125,4 +136,39 @@ public class LoanTermVariationsDataWrapper {
return hasNext(date, iterator);
}
+ public void updateLoanTermVariationsData(final List<LoanTermVariationsData> exceptionData){
+ if(this.exceptionData != null && exceptionData != null && exceptionData.size() > 0){
+ this.exceptionData.addAll(exceptionData);
+ deriveLoanTermVariations();
+ }
+ }
+
+ private void deriveLoanTermVariations() {
+ Collections.sort(this.exceptionData);
+ for (LoanTermVariationsData loanTermVariationsData : this.exceptionData) {
+ if (loanTermVariationsData.getTermVariationType().isInterestRateVariation()) {
+ this.interestRateChanges.add(loanTermVariationsData);
+ } else if (loanTermVariationsData.getTermVariationType().isDueDateVariation()) {
+ this.dueDateVariation.add(loanTermVariationsData);
+ } else if (loanTermVariationsData.getTermVariationType().isInterestRateFromInstallment()) {
+ this.interestRateFromInstallment.add(loanTermVariationsData);
+ }
+ }
+ Collections.sort(this.dueDateVariation);
+ this.exceptionData.removeAll(this.interestRateChanges);
+ this.exceptionData.removeAll(this.dueDateVariation);
+ this.exceptionData.removeAll(this.interestRateFromInstallment);
+ this.iterator = this.exceptionData.listIterator();
+ this.dueDateIterator = this.dueDateVariation.listIterator();
+ }
+
+ public void resetVariations(){
+
+ for (LoanTermVariationsData loanTermVariationsData : this.exceptionData) {
+ loanTermVariationsData.setProcessed(false);
+ }
+ this.iterator = this.exceptionData.listIterator();
+ this.dueDateIterator = this.dueDateVariation.listIterator();
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index 5bd7a0b..adb516e 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -2734,6 +2734,8 @@ public class Loan extends AbstractPersistable<Long> {
final LoanStatus currentStatus = LoanStatus.fromInt(this.loanStatus);
final LoanStatus statusEnum = this.loanLifecycleStateMachine.transition(LoanEvent.LOAN_DISBURSAL_UNDO, currentStatus);
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_DISBURSAL_UNDO, getDisbursementDate());
+ existingTransactionIds.addAll(findExistingTransactionIds());
+ existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
if (!statusEnum.hasStateOf(currentStatus)) {
this.loanStatus = statusEnum.getValue();
actualChanges.put("status", LoanEnumerations.status(this.loanStatus));
@@ -2750,6 +2752,7 @@ public class Loan extends AbstractPersistable<Long> {
}
}
boolean isEmiAmountChanged = this.loanTermVariations.size() > 0;
+
updateLoanToPreDisbursalState();
if (isScheduleRegenerateRequired || isDisbursedAmountChanged || isEmiAmountChanged
|| this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
@@ -2760,14 +2763,14 @@ public class Loan extends AbstractPersistable<Long> {
if (isDisbursedAmountChanged) {
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
}
+ }else if(isPeriodicAccrualAccountingEnabledOnLoanProduct()){
+ for (final LoanRepaymentScheduleInstallment period : getRepaymentScheduleInstallments()) {
+ period.resetAccrualComponents();
+ }
}
actualChanges.put("actualDisbursementDate", "");
- existingTransactionIds.addAll(findExistingTransactionIds());
- existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
- this.accruedTill = null;
- reverseExistingTransactions();
updateLoanSummaryDerivedFields();
}
@@ -2776,14 +2779,22 @@ public class Loan extends AbstractPersistable<Long> {
}
private final void reverseExistingTransactions() {
-
+ Collection<LoanTransaction> retainTransactions = new ArrayList<>();
for (final LoanTransaction transaction : this.loanTransactions) {
transaction.reverse();
+ if(transaction.getId() != null){
+ retainTransactions.add(transaction);
+ }
}
+ this.loanTransactions.retainAll(retainTransactions);
+ isTransactionsListDirty = true ;
}
private void updateLoanToPreDisbursalState() {
this.actualDisbursementDate = null;
+
+ this.accruedTill = null;
+ reverseExistingTransactions();
for (final LoanCharge charge : charges()) {
if (charge.isOverdueInstallmentCharge()) {
@@ -2796,13 +2807,11 @@ public class Loan extends AbstractPersistable<Long> {
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
currentInstallment.resetDerivedComponents();
}
- final List<LoanTermVariations> removeTerms = new ArrayList<>(this.loanTermVariations.size());
for (LoanTermVariations variations : this.loanTermVariations) {
if (variations.getOnLoanStatus().equals(LoanStatus.ACTIVE.getValue())) {
- removeTerms.add(variations);
+ variations.markAsInactive();
}
}
- this.loanTermVariations.removeAll(removeTerms);
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
wrapper.reprocess(getCurrency(), getDisbursementDate(), getRepaymentScheduleInstallments(), charges());
@@ -5024,7 +5033,7 @@ public class Loan extends AbstractPersistable<Long> {
}
- private ChangedTransactionDetail processTransactions() {
+ public ChangedTransactionDetail processTransactions() {
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategy);
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
@@ -5292,9 +5301,8 @@ public class Loan extends AbstractPersistable<Long> {
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategy);
- return loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, charges(), generatorDTO.getHolidayDetailDTO(),
- retreiveListOfTransactionsPostDisbursementExcludeAccruals(), loanRepaymentScheduleTransactionProcessor,
- getRepaymentScheduleInstallments(), generatorDTO.getRecalculateFrom());
+ return loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, this, generatorDTO.getHolidayDetailDTO(),
+ loanRepaymentScheduleTransactionProcessor, generatorDTO.getRecalculateFrom());
}
public LoanRepaymentScheduleInstallment fetchPrepaymentDetail(final ScheduleGeneratorDTO scheduleGeneratorDTO, final LocalDate onDate) {
@@ -5310,9 +5318,8 @@ public class Loan extends AbstractPersistable<Long> {
final LoanScheduleGenerator loanScheduleGenerator = scheduleGeneratorDTO.getLoanScheduleFactory().create(interestMethod);
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategy);
- installment = loanScheduleGenerator.calculatePrepaymentAmount(getCurrency(), onDate, loanApplicationTerms, mc, charges(),
- scheduleGeneratorDTO.getHolidayDetailDTO(), retreiveListOfTransactionsPostDisbursementExcludeAccruals(),
- loanRepaymentScheduleTransactionProcessor, getRepaymentScheduleInstallments());
+ installment = loanScheduleGenerator.calculatePrepaymentAmount(getCurrency(), onDate, loanApplicationTerms, mc, this,
+ scheduleGeneratorDTO.getHolidayDetailDTO(), loanRepaymentScheduleTransactionProcessor);
} else {
installment = this.getTotalOutstandingOnLoan();
}
@@ -5377,10 +5384,12 @@ public class Loan extends AbstractPersistable<Long> {
return loanApplicationTerms;
}
- private BigDecimal constructLoanTermVariations(FloatingRateDTO floatingRateDTO, BigDecimal annualNominalInterestRate,
+ public BigDecimal constructLoanTermVariations(FloatingRateDTO floatingRateDTO, BigDecimal annualNominalInterestRate,
List<LoanTermVariationsData> loanTermVariations) {
for (LoanTermVariations variationTerms : this.loanTermVariations) {
- loanTermVariations.add(variationTerms.toData());
+ if(variationTerms.isActive()) {
+ loanTermVariations.add(variationTerms.toData());
+ }
}
annualNominalInterestRate = constructFloatingInterestRates(annualNominalInterestRate, floatingRateDTO, loanTermVariations);
return annualNominalInterestRate;
@@ -6332,4 +6341,16 @@ public class Loan extends AbstractPersistable<Long> {
return isForeClosure;
}
+ public Set<LoanTermVariations> getActiveLoanTermVariations() {
+ Set<LoanTermVariations> retData = new HashSet<>();
+ if(this.loanTermVariations != null && this.loanTermVariations.size() > 0){
+ for (LoanTermVariations loanTermVariations : this.loanTermVariations) {
+ if(loanTermVariations.isActive()){
+ retData.add(loanTermVariations);
+ }
+ }
+ }
+ return retData.size()>0?retData:null;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
index b1052c3..407a706 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainService.java
@@ -65,4 +65,6 @@ public interface LoanAccountDomainService {
* @param loan {@link Loan} object
*/
void disableStandingInstructionsLinkedToClosedLoan(Loan loan);
+
+ void recalculateAccruals(Loan loan, boolean isInterestCalcualtionHappened);
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
index a46b43f..f7b1a6b 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanAccountDomainServiceJpa.java
@@ -447,15 +447,21 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
*/
@Override
public void recalculateAccruals(Loan loan) {
+ boolean isInterestCalcualtionHappened = loan.repaymentScheduleDetail().isInterestRecalculationEnabled();
+ recalculateAccruals(loan, isInterestCalcualtionHappened);
+ }
+
+ @Override
+ public void recalculateAccruals(Loan loan, boolean isInterestCalcualtionHappened) {
LocalDate accruedTill = loan.getAccruedTill();
+ if (!loan.isPeriodicAccrualAccountingEnabledOnLoanProduct() || !isInterestCalcualtionHappened
+ || accruedTill == null || loan.isNpa() || !loan.status().isActive()) { return; }
+
boolean isOrganisationDateEnabled = this.configurationDomainService.isOrganisationstartDateEnabled();
Date organisationStartDate = new Date();
if(isOrganisationDateEnabled){
organisationStartDate = this.configurationDomainService.retrieveOrganisationStartDate();
}
-
- if (!loan.isPeriodicAccrualAccountingEnabledOnLoanProduct() || !loan.repaymentScheduleDetail().isInterestRecalculationEnabled()
- || accruedTill == null || loan.isNpa() || !loan.status().isActive()) { return; }
Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas = new ArrayList<>();
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
Long loanId = loan.getId();
@@ -697,17 +703,6 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
}
- private LoanRepaymentScheduleInstallment fetchLoanRepaymentScheduleInstallment(LocalDate fromDate, final Loan loan) {
- LoanRepaymentScheduleInstallment installment = null;
- for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : loan.getRepaymentScheduleInstallments()) {
- if (fromDate.equals(loanRepaymentScheduleInstallment.getFromDate())) {
- installment = loanRepaymentScheduleInstallment;
- break;
- }
- }
- return installment;
- }
-
private Map<BUSINESS_ENTITY, Object> constructEntityMap(final BUSINESS_ENTITY entityEvent, Object entity) {
Map<BUSINESS_ENTITY, Object> map = new HashMap<>(1);
map.put(entityEvent, entity);
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
index d95d741..c31d1ec 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
@@ -344,6 +344,12 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
this.obligationsMet = false;
this.obligationsMetOnDate = null;
}
+
+ public void resetAccrualComponents() {
+ this.interestAccrued = null;
+ this.feeAccrued = null;
+ this.penaltyAccrued = null;
+ }
public Money payPenaltyChargesComponent(final LocalDate transactionDate, final Money transactionAmountRemaining) {
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRescheduleRequestToTermVariationMapping.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRescheduleRequestToTermVariationMapping.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRescheduleRequestToTermVariationMapping.java
new file mode 100644
index 0000000..af9a8e2
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRescheduleRequestToTermVariationMapping.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.loanaccount.domain;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import org.springframework.data.jpa.domain.AbstractPersistable;
+
+@Entity
+@Table(name="m_loan_reschedule_request_term_variations_mapping")
+public class LoanRescheduleRequestToTermVariationMapping extends AbstractPersistable<Long> {
+
+
+ @ManyToOne(optional = false, cascade = CascadeType.PERSIST)
+ @JoinColumn(name = "loan_term_variations_id", nullable = false)
+ private LoanTermVariations loanTermVariations;
+
+ protected LoanRescheduleRequestToTermVariationMapping(){
+
+ }
+
+ private LoanRescheduleRequestToTermVariationMapping(final LoanTermVariations loanTermVariations) {
+ this.loanTermVariations = loanTermVariations;
+ }
+
+ public static LoanRescheduleRequestToTermVariationMapping createNew(final LoanTermVariations loanTermVariation) {
+ return new LoanRescheduleRequestToTermVariationMapping(loanTermVariation);
+ }
+
+ public LoanTermVariations getLoanTermVariations() {
+ return this.loanTermVariations;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariationType.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariationType.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariationType.java
index c0df3bb..0b12182 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariationType.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariationType.java
@@ -26,7 +26,11 @@ public enum LoanTermVariationType {
PRINCIPAL_AMOUNT(3, "loanTermType.principalAmount"), //
DUE_DATE(4, "loanTermType.dueDate"), //
INSERT_INSTALLMENT(5, "loanTermType.insertInstallment"), //
- DELETE_INSTALLMENT(6, "loanTermType.deleteInstallment");
+ DELETE_INSTALLMENT(6, "loanTermType.deleteInstallment"),
+ GRACE_ON_INTEREST(7, "loanTermType.graceOnInterest"),
+ GRACE_ON_PRINCIPAL(8, "loanTermType.graceOnPrincipal"),
+ EXTEND_REPAYMENT_PERIOD(9, "loanTermType.extendRepaymentPeriod"),
+ INTEREST_RATE_FROM_INSTALLMENT(10, "loanTermType.interestRateFromInstallment");
private final Integer value;
private final String code;
@@ -66,6 +70,18 @@ public enum LoanTermVariationType {
case 6:
enumeration = LoanTermVariationType.DELETE_INSTALLMENT;
break;
+ case 7:
+ enumeration = LoanTermVariationType.GRACE_ON_INTEREST;
+ break;
+ case 8:
+ enumeration = LoanTermVariationType.GRACE_ON_PRINCIPAL;
+ break;
+ case 9:
+ enumeration = LoanTermVariationType.EXTEND_REPAYMENT_PERIOD;
+ break;
+ case 10:
+ enumeration = LoanTermVariationType.INTEREST_RATE_FROM_INSTALLMENT;
+ break;
}
return enumeration;
}
@@ -93,4 +109,20 @@ public enum LoanTermVariationType {
public boolean isDeleteInstallment() {
return this.value.equals(LoanTermVariationType.DELETE_INSTALLMENT.getValue());
}
+
+ public boolean isGraceOnInterest() {
+ return this.value.equals(LoanTermVariationType.GRACE_ON_INTEREST.getValue());
+ }
+
+ public boolean isGraceOnPrincipal() {
+ return this.value.equals(LoanTermVariationType.GRACE_ON_PRINCIPAL.getValue());
+ }
+
+ public boolean isExtendRepaymentPeriod() {
+ return this.value.equals(LoanTermVariationType.EXTEND_REPAYMENT_PERIOD.getValue());
+ }
+
+ public boolean isInterestRateFromInstallment() {
+ return this.value.equals(LoanTermVariationType.INTEREST_RATE_FROM_INSTALLMENT.getValue());
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariations.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariations.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariations.java
index 01245b9..6dbadad 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariations.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTermVariations.java
@@ -23,12 +23,13 @@ import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
+import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
+import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
-
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
@@ -62,6 +63,13 @@ public class LoanTermVariations extends AbstractPersistable<Long> {
@Column(name = "applied_on_loan_status", nullable = false)
private Integer onLoanStatus;
+
+ @Column(name = "is_active", nullable = false)
+ private Boolean isActive;
+
+ @OneToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "parent_id")
+ private LoanTermVariations parent;
public LoanTermVariations(final Integer termType, final Date termApplicableFrom, final BigDecimal decimalValue, final Date dateValue,
final boolean isSpecificToInstallment, final Loan loan) {
@@ -72,6 +80,8 @@ public class LoanTermVariations extends AbstractPersistable<Long> {
this.dateValue = dateValue;
this.isSpecificToInstallment = isSpecificToInstallment;
this.onLoanStatus = loan.status().getValue();
+ this.isActive = true;
+ this.parent = null;
}
public LoanTermVariations(final Integer termType, final Date termApplicableFrom, final BigDecimal decimalValue, final Date dateValue,
@@ -83,6 +93,21 @@ public class LoanTermVariations extends AbstractPersistable<Long> {
this.dateValue = dateValue;
this.isSpecificToInstallment = isSpecificToInstallment;
this.onLoanStatus = loanStatus;
+ this.isActive = true;
+ this.parent = null;
+ }
+
+ public LoanTermVariations(final Integer termType, final Date termApplicableFrom, final BigDecimal decimalValue, final Date dateValue,
+ final boolean isSpecificToInstallment, final Loan loan, final Integer loanStatus, final Boolean isActive, final LoanTermVariations parent) {
+ this.loan = loan;
+ this.termApplicableFrom = termApplicableFrom;
+ this.termType = termType;
+ this.decimalValue = decimalValue;
+ this.dateValue = dateValue;
+ this.isSpecificToInstallment = isSpecificToInstallment;
+ this.onLoanStatus = loanStatus;
+ this.isActive = isActive;
+ this.parent = parent;
}
protected LoanTermVariations() {
@@ -135,5 +160,21 @@ public class LoanTermVariations extends AbstractPersistable<Long> {
public Integer getOnLoanStatus() {
return this.onLoanStatus;
}
+
+ public Boolean isActive() {
+ return this.isActive;
+ }
+
+ public LoanTermVariations parent() {
+ return this.parent;
+ }
+
+ public void updateIsActive(final Boolean isActive){
+ this.isActive = isActive;
+ }
+
+ public void markAsInactive() {
+ this.isActive = false;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
index 414ca14..7b16a5c 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransaction.java
@@ -777,4 +777,10 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
public boolean isAccrualTransaction() {
return isAccrual();
}
+
+ public boolean isPaymentTransaction() {
+ return this.isNotReversed()
+ && !(this.isDisbursement() || this.isAccrual() || this.isRepaymentAtDisbursement() || this.isNonMonetaryTransaction() || this
+ .isIncomePosting());
+ }
}
\ No newline at end of file
[3/5] incubator-fineract git commit: FINERACT-202 : enabling the
option for multi reshedule
Posted by na...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
index d9e57a0..b380b34 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java
@@ -22,7 +22,6 @@ 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;
@@ -36,11 +35,9 @@ import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.workingdays.domain.RepaymentRescheduleType;
-import org.apache.fineract.portfolio.calendar.domain.Calendar;
import org.apache.fineract.portfolio.calendar.domain.CalendarInstance;
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
-import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData;
@@ -48,7 +45,6 @@ import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
@@ -56,10 +52,6 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleP
import org.apache.fineract.portfolio.loanaccount.loanschedule.exception.MultiDisbursementEmiAmountException;
import org.apache.fineract.portfolio.loanaccount.loanschedule.exception.MultiDisbursementOutstandingAmoutException;
import org.apache.fineract.portfolio.loanaccount.loanschedule.exception.ScheduleDateException;
-import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModel;
-import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleModelRepaymentPeriod;
-import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
-import org.apache.fineract.portfolio.loanproduct.domain.LoanProductMinimumRepaymentScheduleRelatedDetail;
import org.joda.time.Days;
import org.joda.time.LocalDate;
@@ -96,7 +88,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
final MonetaryCurrency currency = loanApplicationTerms.getCurrency();
final int numberOfRepayments = loanApplicationTerms.fetchNumberOfRepaymentsAfterExceptions();
-
LoanScheduleParams scheduleParams = null;
if (loanScheduleParams == null) {
scheduleParams = LoanScheduleParams.createLoanScheduleParams(currency, Money.of(currency, chargesDueAtTimeOfDisbursement),
@@ -114,14 +105,20 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = scheduleParams
.getLoanRepaymentScheduleTransactionProcessor();
- final Collection<LoanScheduleModelPeriod> periods = createNewLoanScheduleListWithDisbursementDetails(numberOfRepayments,
- loanApplicationTerms, chargesDueAtTimeOfDisbursement);
+ Collection<LoanScheduleModelPeriod> periods = new ArrayList<>();
+ if(!scheduleParams.isPartialUpdate()) {
+ periods = createNewLoanScheduleListWithDisbursementDetails(numberOfRepayments,
+ loanApplicationTerms, chargesDueAtTimeOfDisbursement);
+ }
// Determine the total interest owed over the full loan for FLAT
// interest method .
- final Money totalInterestChargedForFullLoanTerm = loanApplicationTerms.calculateTotalInterestCharged(
- this.paymentPeriodsInOneYearCalculator, mc);
-
+ if (!scheduleParams.isPartialUpdate()) {
+ Money totalInterestChargedForFullLoanTerm = loanApplicationTerms.calculateTotalInterestCharged(
+ this.paymentPeriodsInOneYearCalculator, mc);
+ loanApplicationTerms.updateTotalInterestDue(totalInterestChargedForFullLoanTerm);
+ }
+
boolean isFirstRepayment = true;
LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(
loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms, isFirstRepayment, holidayDetailDTO);
@@ -167,6 +164,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
}
final Collection<LoanTermVariationsData> interestRates = loanApplicationTerms.getLoanTermVariations().getInterestRateChanges();
+ final Collection<LoanTermVariationsData> interestRatesForInstallments = loanApplicationTerms.getLoanTermVariations().getInterestRateFromInstallment();
// this block is to start the schedule generation from specified date
if (scheduleParams.isPartialUpdate()) {
@@ -174,7 +172,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
loanApplicationTerms.setPrincipal(scheduleParams.getPrincipalToBeScheduled());
}
- applyLoanVariationsForPartialScheduleGenerate(loanApplicationTerms, scheduleParams, interestRates);
+ applyLoanVariationsForPartialScheduleGenerate(loanApplicationTerms, scheduleParams, interestRates, interestRatesForInstallments);
isFirstRepayment = false;
}
@@ -185,7 +183,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
isFirstRepayment = false;
LocalDate scheduledDueDate = this.scheduledDateGenerator.adjustRepaymentDate(scheduleParams.getActualRepaymentDate(),
loanApplicationTerms, holidayDetailDTO);
-
+
// calculated interest start date for the period
LocalDate periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(loanApplicationTerms,
scheduleParams.getPeriodStartDate(), idealDisbursementDate, firstRepaymentdate,
@@ -194,7 +192,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// Loan Schedule Exceptions that need to be applied for Loan Account
LoanTermVariationParams termVariationParams = applyLoanTermVariations(loanApplicationTerms, scheduleParams,
- previousRepaymentDate, scheduledDueDate);
+ previousRepaymentDate, scheduledDueDate, interestRatesForInstallments, this.paymentPeriodsInOneYearCalculator, mc);
scheduledDueDate = termVariationParams.getScheduledDueDate();
// Updates total days in term
@@ -244,7 +242,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// for a loan repayment which falls between the
// two periods for interest first repayment strategies
handleRecalculationForNonDueDateTransactions(mc, loanApplicationTerms, loanCharges, holidayDetailDTO, scheduleParams, periods,
- totalInterestChargedForFullLoanTerm, idealDisbursementDate, firstRepaymentdate, lastRestDate, scheduledDueDate,
+ loanApplicationTerms.getTotalInterestDue(), idealDisbursementDate, firstRepaymentdate, lastRestDate, scheduledDueDate,
periodStartDateApplicableForInterest, applicableTransactions, currentPeriodParams);
if (currentPeriodParams.isSkipCurrentLoop()) {
@@ -262,10 +260,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
this.paymentPeriodsInOneYearCalculator, currentPeriodParams.getInterestCalculationGraceOnRepaymentPeriodFraction(),
scheduleParams.getTotalCumulativePrincipal().minus(scheduleParams.getReducePrincipal()),
- scheduleParams.getTotalCumulativeInterest(), totalInterestChargedForFullLoanTerm,
+ scheduleParams.getTotalCumulativeInterest(), loanApplicationTerms.getTotalInterestDue(),
scheduleParams.getTotalOutstandingInterestPaymentDueToGrace(), scheduleParams.getOutstandingBalanceAsPerRest(),
loanApplicationTerms, scheduleParams.getPeriodNumber(), mc, mergeVariationsToMap(scheduleParams),
scheduleParams.getCompoundingMap(), periodStartDateApplicableForInterest, scheduledDueDate, interestRates);
+
// will check for EMI amount greater than interest calculated
if (loanApplicationTerms.getFixedEmiAmount() != null
@@ -320,7 +319,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// apply loan transactions on installments to identify early/late
// payments for interest recalculation
installment = handleRecalculationForTransactions(mc, loanApplicationTerms, holidayDetailDTO, currency, scheduleParams,
- loanRepaymentScheduleTransactionProcessor, totalInterestChargedForFullLoanTerm, lastRestDate, scheduledDueDate,
+ loanRepaymentScheduleTransactionProcessor, loanApplicationTerms.getTotalInterestDue(), lastRestDate, scheduledDueDate,
periodStartDateApplicableForInterest, applicableTransactions, currentPeriodParams,
lastTotalOutstandingInterestPaymentDueToGrace, installment, loanCharges);
periods.add(installment);
@@ -960,11 +959,18 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
* @param priviousScheduledDueDate
* @param previousRepaymentDate
* @param scheduledDueDate
+ * @param interestRatesForInstallments
+ * @param mc
+ * @param paymentPeriodsInOneYearCalculator
+ * @param interestRates
+ * @param periodsApplicableForGrace
* @param scheduleDateForReversal
* @return
*/
private LoanTermVariationParams applyLoanTermVariations(final LoanApplicationTerms loanApplicationTerms,
- final LoanScheduleParams scheduleParams, final LocalDate previousRepaymentDate, final LocalDate scheduledDueDate) {
+ final LoanScheduleParams scheduleParams, final LocalDate previousRepaymentDate, final LocalDate scheduledDueDate,
+ Collection<LoanTermVariationsData> interestRatesForInstallments, PaymentPeriodsInOneYearCalculator calculator,
+ MathContext mc) {
boolean skipPeriod = false;
boolean recalculateAmounts = false;
LocalDate modifiedScheduledDueDate = scheduledDueDate;
@@ -981,7 +987,28 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
loanTermVariationsData.setProcessed(true);
}
}
+
+ for (LoanTermVariationsData variation : interestRatesForInstallments) {
+ if (variation.isApplicable(modifiedScheduledDueDate) && variation.getDecimalValue() != null && !variation.isProcessed()) {
+ loanApplicationTerms.updateAnnualNominalInterestRate(variation.getDecimalValue());
+ if (loanApplicationTerms.getInterestMethod().isDecliningBalnce()) {
+ if (loanApplicationTerms.getActualFixedEmiAmount() == null) {
+ loanApplicationTerms.setFixedEmiAmount(null);
+ }
+ } else {
+ Money totalInterestDueForLoan = Money.zero(loanApplicationTerms.getCurrency());
+ loanApplicationTerms.setTotalPrincipalAccounted(scheduleParams.getTotalCumulativePrincipal());
+ totalInterestDueForLoan = loanApplicationTerms.calculateTotalInterestCharged(calculator, mc);
+ totalInterestDueForLoan = totalInterestDueForLoan.plus(scheduleParams.getTotalCumulativeInterest());
+ loanApplicationTerms.updateTotalInterestDue(totalInterestDueForLoan);
+ // exclude till last period in calculations
+ loanApplicationTerms.updateExcludePeriodsForCalculation(scheduleParams.getPeriodNumber() - 1);
+ }
+ variation.setProcessed(true);
+ }
+ }
+
while (loanApplicationTerms.getLoanTermVariations().hasVariation(modifiedScheduledDueDate)) {
LoanTermVariationsData loanTermVariationsData = loanApplicationTerms.getLoanTermVariations().nextVariation();
if (loanTermVariationsData.isProcessed()) {
@@ -1026,6 +1053,33 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
}
loanTermVariationsData.setProcessed(true);
break;
+ case EXTEND_REPAYMENT_PERIOD:
+ Integer rescheduleNumberOfRepayments = loanApplicationTerms.getNumberOfRepayments();
+ rescheduleNumberOfRepayments += loanTermVariationsData.getDecimalValue().intValue();
+ loanApplicationTerms.updateNumberOfRepayments(rescheduleNumberOfRepayments);
+ LocalDate loanEndDate = this.scheduledDateGenerator.getLastRepaymentDate(loanApplicationTerms, loanApplicationTerms.getHolidayDetailDTO());
+ loanApplicationTerms.updateLoanEndDate(loanEndDate);
+ loanApplicationTerms.updateAccountedTillPeriod(scheduleParams.getPeriodNumber() - 1,
+ scheduleParams.getTotalCumulativePrincipal(), scheduleParams.getTotalCumulativeInterest(),
+ loanTermVariationsData.getDecimalValue().intValue());
+ loanApplicationTerms.setFixedEmiAmount(null);
+ loanTermVariationsData.setProcessed(true);
+ break;
+ case GRACE_ON_PRINCIPAL:
+ loanApplicationTerms.updatePrincipalGrace(loanTermVariationsData.getDecimalValue().intValue());
+ Integer interestPaymentGrace = 0;
+ loanApplicationTerms.updateInterestPaymentGrace(interestPaymentGrace);
+ loanApplicationTerms.updatePeriodNumberApplicableForPrincipalOrInterestGrace(scheduleParams.getPeriodNumber());
+ loanTermVariationsData.setProcessed(true);
+ break;
+ case GRACE_ON_INTEREST:
+ loanApplicationTerms.updateInterestPaymentGrace(loanTermVariationsData.getDecimalValue().intValue());
+ Integer principalGrace = 0;
+ loanApplicationTerms.updatePrincipalGrace(principalGrace);
+ loanApplicationTerms.updatePeriodNumberApplicableForPrincipalOrInterestGrace(scheduleParams.getPeriodNumber());
+ loanApplicationTerms.updateTotalInterestAccounted(scheduleParams.getTotalCumulativeInterest());
+ loanTermVariationsData.setProcessed(true);
+ break;
default:
break;
@@ -1040,14 +1094,33 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
* @param loanApplicationTerms
* @param scheduledDueDate
* @param exceptionDataListIterator
+ * @param instalmentNumber
+ * @param totalCumulativePrincipal TODO
+ * @param totalCumulativeInterest TODO
+ * @param mc TODO
+ * @param periodNumber
* @return
*/
private LoanTermVariationParams applyExceptionLoanTermVariations(final LoanApplicationTerms loanApplicationTerms,
- final LocalDate scheduledDueDate, final ListIterator<LoanTermVariationsData> exceptionDataListIterator) {
+ final LocalDate scheduledDueDate, final ListIterator<LoanTermVariationsData> exceptionDataListIterator, int instalmentNumber,
+ Money totalCumulativePrincipal, Money totalCumulativeInterest, MathContext mc) {
boolean skipPeriod = false;
boolean recalculateAmounts = false;
LocalDate modifiedScheduledDueDate = scheduledDueDate;
ArrayList<LoanTermVariationsData> variationsData = new ArrayList<>();
+
+ for (LoanTermVariationsData variation : loanApplicationTerms.getLoanTermVariations().getInterestRateFromInstallment()) {
+ if (variation.isApplicable(modifiedScheduledDueDate) && variation.getDecimalValue() != null && !variation.isProcessed()) {
+ loanApplicationTerms.updateAnnualNominalInterestRate(variation.getDecimalValue());
+ if (loanApplicationTerms.getInterestMethod().isDecliningBalnce()) {
+ adjustInstallmentOrPrincipalAmount(loanApplicationTerms, totalCumulativePrincipal, instalmentNumber, mc);
+ } else {
+ loanApplicationTerms.setTotalPrincipalAccounted(totalCumulativePrincipal);
+ loanApplicationTerms.updateExcludePeriodsForCalculation(instalmentNumber - 1);
+ }
+ variation.setProcessed(true);
+ }
+ }
while (loanApplicationTerms.getLoanTermVariations().hasExceptionVariation(modifiedScheduledDueDate, exceptionDataListIterator)) {
LoanTermVariationsData loanTermVariationsData = exceptionDataListIterator.next();
@@ -1057,14 +1130,40 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
switch (loanTermVariationsData.getTermVariationType()) {
case INSERT_INSTALLMENT:
modifiedScheduledDueDate = loanTermVariationsData.getTermApplicableFrom();
- variationsData.add(loanTermVariationsData) ;
+ variationsData.add(loanTermVariationsData);
break;
case DELETE_INSTALLMENT:
if (loanTermVariationsData.getTermApplicableFrom().isEqual(modifiedScheduledDueDate)) {
skipPeriod = true;
- variationsData.add(loanTermVariationsData) ;
+ variationsData.add(loanTermVariationsData);
}
-
+ break;
+ case GRACE_ON_PRINCIPAL:
+ loanApplicationTerms.updatePrincipalGrace(loanTermVariationsData.getDecimalValue().intValue());
+ Integer interestPaymentGrace = 0;
+ loanApplicationTerms.updateInterestPaymentGrace(interestPaymentGrace);
+ loanApplicationTerms.updatePeriodNumberApplicableForPrincipalOrInterestGrace(instalmentNumber);
+ variationsData.add(loanTermVariationsData);
+ break;
+ case GRACE_ON_INTEREST:
+ loanApplicationTerms.updateInterestPaymentGrace(loanTermVariationsData.getDecimalValue().intValue());
+ Integer principalGrace = 0;
+ loanApplicationTerms.updatePrincipalGrace(principalGrace);
+ loanApplicationTerms.updatePeriodNumberApplicableForPrincipalOrInterestGrace(instalmentNumber);
+ loanApplicationTerms.updateTotalInterestAccounted(totalCumulativeInterest);
+ variationsData.add(loanTermVariationsData);
+ break;
+ case EXTEND_REPAYMENT_PERIOD:
+ Integer rescheduleNumberOfRepayments = loanApplicationTerms.getNumberOfRepayments();
+ rescheduleNumberOfRepayments += loanTermVariationsData.getDecimalValue().intValue();
+ loanApplicationTerms.updateNumberOfRepayments(rescheduleNumberOfRepayments);
+ // generate list of proposed schedule due dates
+ LocalDate loanEndDate = this.scheduledDateGenerator.getLastRepaymentDate(loanApplicationTerms,
+ loanApplicationTerms.getHolidayDetailDTO());
+ loanApplicationTerms.updateLoanEndDate(loanEndDate);
+ adjustInstallmentOrPrincipalAmount(loanApplicationTerms, totalCumulativePrincipal, instalmentNumber, mc);
+ loanTermVariationsData.setProcessed(true);
+ loanApplicationTerms.updateAccountedTillPeriod(instalmentNumber-1, totalCumulativePrincipal, totalCumulativeInterest, loanTermVariationsData.getDecimalValue().intValue());
break;
default:
break;
@@ -1080,9 +1179,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
* @param loanApplicationTerms
* @param scheduleParams
* @param interestRates
+ * @param interestRatesForInstallments
+ * @param periodsApplicableForGrace
*/
private void applyLoanVariationsForPartialScheduleGenerate(final LoanApplicationTerms loanApplicationTerms,
- LoanScheduleParams scheduleParams, final Collection<LoanTermVariationsData> interestRates) {
+ LoanScheduleParams scheduleParams, final Collection<LoanTermVariationsData> interestRates,
+ final Collection<LoanTermVariationsData> interestRatesForInstallments) {
// Applies loan variations
while (loanApplicationTerms.getLoanTermVariations().hasVariation(scheduleParams.getPeriodStartDate())) {
LoanTermVariationsData variation = loanApplicationTerms.getLoanTermVariations().nextVariation();
@@ -1109,6 +1211,15 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
loanApplicationTerms.updateAnnualNominalInterestRate(variation.getDecimalValue());
}
}
+
+ // Applies interest rate changes for installments
+ for (LoanTermVariationsData variation : interestRatesForInstallments) {
+ if (variation.getTermVariationType().isInterestRateFromInstallment() && variation.isApplicable(scheduleParams.getPeriodStartDate())
+ && variation.getDecimalValue() != null) {
+ loanApplicationTerms.updateAnnualNominalInterestRate(variation.getDecimalValue());
+ variation.setProcessed(true);
+ }
+ }
}
/**
@@ -1189,6 +1300,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
Collection<LoanTermVariationsData> applicableVariations = loanApplicationTerms.getLoanTermVariations().getInterestRateChanges();
Money uncompoundedFromLastInstallment = params.getUnCompoundedAmount();
LocalDate additionalPeriodsStartDate = params.getPeriodStartDate();
+
do {
params.setActualRepaymentDate(this.scheduledDateGenerator.generateNextRepaymentDate(params.getActualRepaymentDate(),
@@ -1327,18 +1439,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
return applicableTransactions;
}
- private Collection<LoanTermVariationsData> getApplicableTermVariationsForPeriod(final LocalDate fromDate, final LocalDate dueDate,
- final Collection<LoanTermVariationsData> variations) {
- Collection<LoanTermVariationsData> applicableVariations = new ArrayList<>();
- for (LoanTermVariationsData detail : variations) {
- if (detail.isApplicable(fromDate, dueDate)) {
- applicableVariations.add(detail);
- }
- }
- variations.removeAll(applicableVariations);
- return applicableVariations;
- }
-
private List<LoanTransaction> createCurrentTransactionList(RecalculationDetail detail) {
List<LoanTransaction> currentTransactions = new ArrayList<>(2);
currentTransactions.add(detail.getTransaction());
@@ -1511,7 +1611,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
final boolean isPastDate = params.applyInterestRecalculation()
&& loanRepaymentScheduleInstallment.getDueDate().isBefore(DateUtils.getLocalDateOfTenant());
boolean periodHasCompoundingDate = false;
- Money amountCharged = getIncomeForCompounding(loanApplicationTerms, currency, loanRepaymentScheduleInstallment);
+ Money amountCharged = Money.zero(currency);
+ if (loanApplicationTerms.getInterestRecalculationCompoundingMethod() != null) {
+ amountCharged = getIncomeForCompounding(loanApplicationTerms, currency, loanRepaymentScheduleInstallment);
+ }
final Map<LocalDate, Money> compoundingMap = params.getCompoundingMap();
LocalDate effectiveStartDate = loanRepaymentScheduleInstallment.getFromDate();
if (loanApplicationTerms.allowCompoundingOnEod()) {
@@ -1756,316 +1859,6 @@ 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 Calendar loanCalendar,
- final FloatingRateDTO floatingRateDTO, final boolean isSkipRepaymentonmonthFirst, final Integer numberofdays) {
-
- final Loan loan = loanRescheduleRequest.getLoan();
- final LoanSummary loanSummary = loan.getSummary();
- final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
- final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
-
- // create an archive of the current loan schedule installments
- Collection<LoanRepaymentScheduleHistory> loanRepaymentScheduleHistoryList = null;
-
- // get the initial list of repayment installments
- List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
-
- // sort list by installment number in ASC order
- Collections.sort(repaymentScheduleInstallments, LoanRepaymentScheduleInstallment.installmentNumberComparator);
-
- final Collection<LoanRescheduleModelRepaymentPeriod> periods = new ArrayList<>();
-
- Money outstandingLoanBalance = loan.getPrincpal();
-
- for (LoanRepaymentScheduleInstallment repaymentScheduleInstallment : repaymentScheduleInstallments) {
-
- Integer oldPeriodNumber = repaymentScheduleInstallment.getInstallmentNumber();
- LocalDate fromDate = repaymentScheduleInstallment.getFromDate();
- LocalDate dueDate = repaymentScheduleInstallment.getDueDate();
- Money principalDue = repaymentScheduleInstallment.getPrincipal(currency);
- Money interestDue = repaymentScheduleInstallment.getInterestCharged(currency);
- Money feeChargesDue = repaymentScheduleInstallment.getFeeChargesCharged(currency);
- Money penaltyChargesDue = repaymentScheduleInstallment.getPenaltyChargesCharged(currency);
- Money totalDue = principalDue.plus(interestDue).plus(feeChargesDue).plus(penaltyChargesDue);
-
- outstandingLoanBalance = outstandingLoanBalance.minus(principalDue);
-
- LoanRescheduleModelRepaymentPeriod period = LoanRescheduleModelRepaymentPeriod
- .instance(oldPeriodNumber, oldPeriodNumber, fromDate, dueDate, principalDue, outstandingLoanBalance, interestDue,
- feeChargesDue, penaltyChargesDue, totalDue, false);
-
- periods.add(period);
- }
-
- Money outstandingBalance = loan.getPrincpal();
- Money totalCumulativePrincipal = Money.zero(currency);
- Money totalCumulativeInterest = Money.zero(currency);
- Money actualTotalCumulativeInterest = Money.zero(currency);
- Money totalOutstandingInterestPaymentDueToGrace = Money.zero(currency);
- Money totalPrincipalBeforeReschedulePeriod = Money.zero(currency);
-
- LocalDate installmentDueDate = null;
- LocalDate adjustedInstallmentDueDate = null;
- LocalDate installmentFromDate = null;
- Integer rescheduleFromInstallmentNo = defaultToZeroIfNull(loanRescheduleRequest.getRescheduleFromInstallment());
- Integer installmentNumber = rescheduleFromInstallmentNo;
- Integer graceOnPrincipal = defaultToZeroIfNull(loanRescheduleRequest.getGraceOnPrincipal());
- Integer graceOnInterest = defaultToZeroIfNull(loanRescheduleRequest.getGraceOnInterest());
- Integer extraTerms = defaultToZeroIfNull(loanRescheduleRequest.getExtraTerms());
- final boolean recalculateInterest = loanRescheduleRequest.getRecalculateInterest();
- Integer numberOfRepayments = repaymentScheduleInstallments.size();
- Integer rescheduleNumberOfRepayments = numberOfRepayments;
- final Money principal = loan.getPrincpal();
- final Money totalPrincipalOutstanding = Money.of(currency, loanSummary.getTotalPrincipalOutstanding());
- LocalDate adjustedDueDate = loanRescheduleRequest.getAdjustedDueDate();
- BigDecimal newInterestRate = loanRescheduleRequest.getInterestRate();
- int loanTermInDays = Integer.valueOf(0);
-
- if (rescheduleFromInstallmentNo > 0) {
- // this will hold the loan repayment installment that is before the
- // reschedule start installment
- // (rescheduleFrominstallment)
- LoanRepaymentScheduleInstallment previousInstallment = null;
-
- // get the install number of the previous installment
- int previousInstallmentNo = rescheduleFromInstallmentNo - 1;
-
- // only fetch the installment if the number is greater than 0
- if (previousInstallmentNo > 0) {
- previousInstallment = loan.fetchRepaymentScheduleInstallment(previousInstallmentNo);
- }
-
- LoanRepaymentScheduleInstallment firstInstallment = loan.fetchRepaymentScheduleInstallment(1);
-
- // the "installment from date" is equal to the due date of the
- // previous installment, if it exists
- if (previousInstallment != null) {
- installmentFromDate = previousInstallment.getDueDate();
- }
-
- else {
- installmentFromDate = firstInstallment.getFromDate();
- }
-
- installmentDueDate = installmentFromDate;
- LocalDate periodStartDateApplicableForInterest = installmentFromDate;
- Integer periodNumber = 1;
- outstandingLoanBalance = loan.getPrincpal();
-
- for (LoanRescheduleModelRepaymentPeriod period : periods) {
-
- if (period.periodDueDate().isBefore(loanRescheduleRequest.getRescheduleFromDate())) {
-
- totalPrincipalBeforeReschedulePeriod = totalPrincipalBeforeReschedulePeriod.plus(period.principalDue());
- actualTotalCumulativeInterest = actualTotalCumulativeInterest.plus(period.interestDue());
- rescheduleNumberOfRepayments--;
- outstandingLoanBalance = outstandingLoanBalance.minus(period.principalDue());
- outstandingBalance = outstandingBalance.minus(period.principalDue());
- }
- }
-
- while (graceOnPrincipal > 0 || graceOnInterest > 0) {
-
- LoanRescheduleModelRepaymentPeriod period = LoanRescheduleModelRepaymentPeriod.instance(0, 0, new LocalDate(),
- new LocalDate(), Money.zero(currency), Money.zero(currency), Money.zero(currency), Money.zero(currency),
- Money.zero(currency), Money.zero(currency), true);
-
- periods.add(period);
-
- if (graceOnPrincipal > 0) {
- graceOnPrincipal--;
- }
-
- if (graceOnInterest > 0) {
- graceOnInterest--;
- }
-
- rescheduleNumberOfRepayments++;
- numberOfRepayments++;
- }
-
- while (extraTerms > 0) {
-
- LoanRescheduleModelRepaymentPeriod period = LoanRescheduleModelRepaymentPeriod.instance(0, 0, new LocalDate(),
- new LocalDate(), Money.zero(currency), Money.zero(currency), Money.zero(currency), Money.zero(currency),
- Money.zero(currency), Money.zero(currency), true);
-
- periods.add(period);
-
- extraTerms--;
- rescheduleNumberOfRepayments++;
- numberOfRepayments++;
- }
-
- // get the loan application terms from the Loan object
- final LoanApplicationTerms loanApplicationTerms = loan
- .getLoanApplicationTerms(applicationCurrency, restCalendarInstance, compoundingCalendarInstance, loanCalendar,
- floatingRateDTO, isSkipRepaymentonmonthFirst, numberofdays, holidayDetailDTO);
-
- // for applying variations
- Collection<LoanTermVariationsData> loanTermVariations = loanApplicationTerms.getLoanTermVariations().getInterestRateChanges();
-
- // update the number of repayments
- loanApplicationTerms.updateNumberOfRepayments(numberOfRepayments);
-
- LocalDate loanEndDate = this.scheduledDateGenerator.getLastRepaymentDate(loanApplicationTerms, holidayDetailDTO);
- LoanTermVariationsData lastDueDateVariation = loanApplicationTerms.getLoanTermVariations().fetchLoanTermDueDateVariationsData(
- loanEndDate);
- if (lastDueDateVariation != null) {
- loanEndDate = lastDueDateVariation.getDateValue();
- }
- loanApplicationTerms.updateLoanEndDate(loanEndDate);
-
- if (newInterestRate != null) {
- loanApplicationTerms.updateAnnualNominalInterestRate(newInterestRate);
- loanApplicationTerms.updateInterestRatePerPeriod(newInterestRate);
- }
-
- graceOnPrincipal = defaultToZeroIfNull(loanRescheduleRequest.getGraceOnPrincipal());
- graceOnInterest = defaultToZeroIfNull(loanRescheduleRequest.getGraceOnInterest());
-
- loanApplicationTerms.updateInterestPaymentGrace(graceOnInterest);
- loanApplicationTerms.updatePrincipalGrace(graceOnPrincipal);
-
- loanApplicationTerms.setPrincipal(totalPrincipalOutstanding);
- loanApplicationTerms.updateNumberOfRepayments(rescheduleNumberOfRepayments);
- loanApplicationTerms.updateLoanTermFrequency(rescheduleNumberOfRepayments);
- loanApplicationTerms.updateInterestChargedFromDate(periodStartDateApplicableForInterest);
-
- Money totalInterestChargedForFullLoanTerm = loanApplicationTerms.calculateTotalInterestCharged(
- this.paymentPeriodsInOneYearCalculator, mathContext);
-
- if (!recalculateInterest && newInterestRate == null) {
- totalInterestChargedForFullLoanTerm = Money.of(currency, loanSummary.getTotalInterestCharged());
- totalInterestChargedForFullLoanTerm = totalInterestChargedForFullLoanTerm.minus(actualTotalCumulativeInterest);
-
- loanApplicationTerms.updateTotalInterestDue(totalInterestChargedForFullLoanTerm);
- }
-
- for (LoanRescheduleModelRepaymentPeriod period : periods) {
-
- if (period.periodDueDate().isEqual(loanRescheduleRequest.getRescheduleFromDate())
- || period.periodDueDate().isAfter(loanRescheduleRequest.getRescheduleFromDate()) || period.isNew()) {
-
- installmentDueDate = this.scheduledDateGenerator.generateNextRepaymentDate(installmentDueDate, loanApplicationTerms,
- false, holidayDetailDTO);
-
- if (adjustedDueDate != null && periodNumber == 1) {
- installmentDueDate = adjustedDueDate;
- }
-
- adjustedInstallmentDueDate = this.scheduledDateGenerator.adjustRepaymentDate(installmentDueDate, loanApplicationTerms,
- holidayDetailDTO);
-
- final int daysInInstallment = Days.daysBetween(installmentFromDate, adjustedInstallmentDueDate).getDays();
-
- period.updatePeriodNumber(installmentNumber);
- period.updatePeriodFromDate(installmentFromDate);
- period.updatePeriodDueDate(adjustedInstallmentDueDate);
-
- double interestCalculationGraceOnRepaymentPeriodFraction = this.paymentPeriodsInOneYearCalculator
- .calculatePortionOfRepaymentPeriodInterestChargingGrace(periodStartDateApplicableForInterest,
- adjustedInstallmentDueDate, periodStartDateApplicableForInterest,
- loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery());
-
- // ========================= Calculate the interest due
- // ========================================
-
- // change the principal to => Principal Disbursed - Total
- // Principal Paid
- // interest calculation is always based on the total
- // principal outstanding
- loanApplicationTerms.setPrincipal(totalPrincipalOutstanding);
-
- // for applying variations
- Collection<LoanTermVariationsData> applicableVariations = getApplicableTermVariationsForPeriod(installmentFromDate,
- adjustedInstallmentDueDate, loanTermVariations);
-
- // determine the interest & principal for the period
- PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
- this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
- totalCumulativePrincipal, totalCumulativeInterest, totalInterestChargedForFullLoanTerm,
- totalOutstandingInterestPaymentDueToGrace, outstandingBalance, loanApplicationTerms, periodNumber, mathContext,
- null, null, installmentFromDate, adjustedInstallmentDueDate, applicableVariations);
-
- // update the interest due for the period
- period.updateInterestDue(principalInterestForThisPeriod.interest());
-
- // =============================================================================================
-
- // ========================== Calculate the principal due
- // ======================================
-
- // change the principal to => Principal Disbursed - Total
- // cumulative Principal Amount before the reschedule
- // installment
- loanApplicationTerms.setPrincipal(principal.minus(totalPrincipalBeforeReschedulePeriod));
-
- principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(this.paymentPeriodsInOneYearCalculator,
- interestCalculationGraceOnRepaymentPeriodFraction, totalCumulativePrincipal, totalCumulativeInterest,
- totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace, outstandingBalance,
- loanApplicationTerms, periodNumber, mathContext, null, null, installmentFromDate, adjustedInstallmentDueDate,
- applicableVariations);
-
- period.updatePrincipalDue(principalInterestForThisPeriod.principal());
-
- // ==============================================================================================
-
- outstandingLoanBalance = outstandingLoanBalance.minus(period.principalDue());
- period.updateOutstandingLoanBalance(outstandingLoanBalance);
-
- Money principalDue = Money.of(currency, period.principalDue());
- Money interestDue = Money.of(currency, period.interestDue());
-
- if (principalDue.isZero() && interestDue.isZero()) {
- period.updateFeeChargesDue(Money.zero(currency));
- period.updatePenaltyChargesDue(Money.zero(currency));
- }
-
- Money feeChargesDue = Money.of(currency, period.feeChargesDue());
- Money penaltyChargesDue = Money.of(currency, period.penaltyChargesDue());
-
- Money totalDue = principalDue.plus(interestDue).plus(feeChargesDue).plus(penaltyChargesDue);
-
- period.updateTotalDue(totalDue);
-
- // update cumulative fields for principal & interest
- totalCumulativePrincipal = totalCumulativePrincipal.plus(period.principalDue());
- totalCumulativeInterest = totalCumulativeInterest.plus(period.interestDue());
- actualTotalCumulativeInterest = actualTotalCumulativeInterest.plus(period.interestDue());
- totalOutstandingInterestPaymentDueToGrace = principalInterestForThisPeriod.interestPaymentDueToGrace();
-
- installmentFromDate = adjustedInstallmentDueDate;
- installmentNumber++;
- periodNumber++;
- loanTermInDays += daysInInstallment;
-
- outstandingBalance = outstandingBalance.minus(period.principalDue());
- }
- }
- }
-
- final Money totalRepaymentExpected = principal // get the loan Principal
- // amount
- .plus(actualTotalCumulativeInterest) // add the actual total
- // cumulative interest
- .plus(loanSummary.getTotalFeeChargesCharged()) // add the total
- // fees charged
- .plus(loanSummary.getTotalPenaltyChargesCharged()); // finally
- // add the
- // total
- // penalty
- // charged
-
- return LoanRescheduleModel.instance(periods, loanRepaymentScheduleHistoryList, applicationCurrency, loanTermInDays,
- loan.getPrincpal(), loan.getPrincpal().getAmount(), loanSummary.getTotalPrincipalRepaid(),
- actualTotalCumulativeInterest.getAmount(), loanSummary.getTotalFeeChargesCharged(),
- loanSummary.getTotalPenaltyChargesCharged(), totalRepaymentExpected.getAmount(), loanSummary.getTotalOutstanding());
- }
-
public abstract PrincipalInterest calculatePrincipalInterestComponentsForPeriod(PaymentPeriodsInOneYearCalculator calculator,
double interestCalculationGraceOnRepaymentPeriodFraction, Money totalCumulativePrincipal, Money totalCumulativeInterest,
Money totalInterestDueForLoan, Money cumulatingInterestPaymentDueToGrace, Money outstandingBalance,
@@ -2230,28 +2023,28 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
* fields to generate the schedule
*/
@Override
- public LoanScheduleDTO rescheduleNextInstallments(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
- final Set<LoanCharge> loanCharges, final HolidayDetailDTO holidayDetailDTO, final List<LoanTransaction> transactions,
- final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
- final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final LocalDate rescheduleFrom) {
+ public LoanScheduleDTO rescheduleNextInstallments(final MathContext mc, final LoanApplicationTerms loanApplicationTerms, Loan loan,
+ final HolidayDetailDTO holidayDetailDTO,
+ final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate rescheduleFrom) {
// Fixed schedule End Date for generating schedule
final LocalDate scheduleTillDate = null;
- return rescheduleNextInstallments(mc, loanApplicationTerms, loanCharges, holidayDetailDTO, transactions,
- loanRepaymentScheduleTransactionProcessor, repaymentScheduleInstallments, rescheduleFrom, scheduleTillDate);
+ return rescheduleNextInstallments(mc, loanApplicationTerms, loan, holidayDetailDTO, loanRepaymentScheduleTransactionProcessor,
+ rescheduleFrom, scheduleTillDate);
}
private LoanScheduleDTO rescheduleNextInstallments(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
- final Set<LoanCharge> loanCharges, final HolidayDetailDTO holidayDetailDTO, final List<LoanTransaction> transactions,
- final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
- final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final LocalDate rescheduleFrom,
+ Loan loan, final HolidayDetailDTO holidayDetailDTO, final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
+ final LocalDate rescheduleFrom,
final LocalDate scheduleTillDate) {
// Loan transactions to process and find the variation on payments
Collection<RecalculationDetail> recalculationDetails = new ArrayList<>();
- for (LoanTransaction loanTransaction : transactions) {
- recalculationDetails.add(new RecalculationDetail(loanTransaction.getTransactionDate(), LoanTransaction
- .copyTransactionProperties(loanTransaction)));
+ for (LoanTransaction loanTransaction : loan.getLoanTransactions()) {
+ if (loanTransaction.isPaymentTransaction()) {
+ recalculationDetails.add(new RecalculationDetail(loanTransaction.getTransactionDate(), LoanTransaction
+ .copyTransactionProperties(loanTransaction)));
+ }
}
final boolean applyInterestRecalculation = loanApplicationTerms.isInterestRecalculationEnabled();
@@ -2271,10 +2064,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
// this is required to update total fee amounts in the
// LoanScheduleModel
- final BigDecimal chargesDueAtTimeOfDisbursement = deriveTotalChargesDueAtTimeOfDisbursement(loanCharges);
+ final BigDecimal chargesDueAtTimeOfDisbursement = deriveTotalChargesDueAtTimeOfDisbursement(loan.charges());
periods = createNewLoanScheduleListWithDisbursementDetails(loanApplicationTerms.fetchNumberOfRepaymentsAfterExceptions(),
loanApplicationTerms, chargesDueAtTimeOfDisbursement);
- final List<LoanRepaymentScheduleInstallment> newRepaymentScheduleInstallments = new ArrayList<>();
MonetaryCurrency currency = outstandingBalance.getCurrency();
// early payments will be added here and as per the selected
@@ -2302,7 +2094,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
final Map<LocalDate, Map<LocalDate, Money>> compoundingDateVariations = new HashMap<>();
LocalDate currentDate = DateUtils.getLocalDateOfTenant();
LocalDate lastRestDate = currentDate;
- if (loanApplicationTerms.getRestCalendarInstance() != null) {
+ if (loanApplicationTerms.isInterestRecalculationEnabled()) {
lastRestDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms, holidayDetailDTO);
}
LocalDate actualRepaymentDate = loanApplicationTerms.getExpectedDisbursementDate();
@@ -2323,6 +2115,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
LocalDate periodStartDate = loanApplicationTerms.getExpectedDisbursementDate();
// Set fixed Amortization Amounts(either EMI or Principal )
updateAmortization(mc, loanApplicationTerms, periodNumber, outstandingBalance);
+
+ // count periods without interest grace to exclude for flat loan calculations
final Map<LocalDate, Money> disburseDetailMap = new HashMap<>();
if (loanApplicationTerms.isMultiDisburseLoan()) {
@@ -2340,12 +2134,17 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
List<LoanTermVariationsData> exceptionDataList = loanApplicationTerms.getLoanTermVariations().getExceptionData();
final ListIterator<LoanTermVariationsData> exceptionDataListIterator = exceptionDataList.listIterator();
LoanTermVariationParams loanTermVariationParams = null;
+
+ // identify retain installments
+ final List<LoanRepaymentScheduleInstallment> processInstallmentsInstallments = fetchRetainedInstallments(
+ loan.getRepaymentScheduleInstallments(), rescheduleFrom, currency);
+ final List<LoanRepaymentScheduleInstallment> newRepaymentScheduleInstallments = new ArrayList<>();
// Block process the installment and creates the period if it falls
// before reschedule from date
// This will create the recalculation details by applying the
// transactions
- for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
+ for (LoanRepaymentScheduleInstallment installment : processInstallmentsInstallments) {
// this will generate the next schedule due date and allows to
// process the installment only if recalculate from date is
// greater than due date
@@ -2353,32 +2152,44 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
if (totalCumulativePrincipal.isGreaterThanOrEqualTo(loanApplicationTerms.getTotalDisbursedAmount())) {
break;
}
- LocalDate previousRepaymentDate = actualRepaymentDate;
ArrayList<LoanTermVariationsData> dueDateVariationsDataList = new ArrayList<>();
+
// check for date changes
- while (loanApplicationTerms.getLoanTermVariations().hasDueDateVariation(lastInstallmentDate)) {
- LoanTermVariationsData variation = loanApplicationTerms.getLoanTermVariations().nextDueDateVariation();
- if (!variation.isSpecificToInstallment()) {
- actualRepaymentDate = variation.getDateValue();
- }
- dueDateVariationsDataList.add(variation);
- }
-
+
do {
actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate,
loanApplicationTerms, isFirstRepayment, holidayDetailDTO);
isFirstRepayment = false;
lastInstallmentDate = this.scheduledDateGenerator.adjustRepaymentDate(actualRepaymentDate, loanApplicationTerms,
holidayDetailDTO);
+ while (loanApplicationTerms.getLoanTermVariations().hasDueDateVariation(lastInstallmentDate)) {
+ LoanTermVariationsData variation = loanApplicationTerms.getLoanTermVariations().nextDueDateVariation();
+ if (!variation.isSpecificToInstallment()) {
+ actualRepaymentDate = variation.getDateValue();
+ /*if (!isDueDateChangeApplied) {
+ previousRepaymentDate = actualRepaymentDate;
+ isDueDateChangeApplied = true;
+ }*/
+ lastInstallmentDate = actualRepaymentDate;
+ }
+ dueDateVariationsDataList.add(variation);
+ }
loanTermVariationParams = applyExceptionLoanTermVariations(loanApplicationTerms, lastInstallmentDate,
- exceptionDataListIterator);
+ exceptionDataListIterator, instalmentNumber, totalCumulativePrincipal, totalCumulativeInterest, mc);
} while (loanTermVariationParams != null && loanTermVariationParams.isSkipPeriod());
- if (!lastInstallmentDate.isBefore(rescheduleFrom)) {
+ /*if (!lastInstallmentDate.isBefore(rescheduleFrom)) {
actualRepaymentDate = previousRepaymentDate;
+ if(isDueDateChangeApplied){
+ int numberOfDateChangesApplied = dueDateVariationsDataList.size();
+ while(numberOfDateChangesApplied >0 ){
+ loanApplicationTerms.getLoanTermVariations().previousDueDateVariation();
+ numberOfDateChangesApplied--;
+ }
+ }
break;
- }
+ }*/
periodNumber++;
for (LoanTermVariationsData dueDateVariation : dueDateVariationsDataList) {
@@ -2422,66 +2233,81 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
totalPenaltyChargesCharged = totalPenaltyChargesCharged.plus(installment.getPenaltyChargesCharged(currency));
instalmentNumber++;
loanTermInDays = Days.daysBetween(installment.getFromDate(), installment.getDueDate()).getDays();
+
+
+ if (loanApplicationTerms.isInterestRecalculationEnabled()) {
+
+ // populates the collection with transactions till the due
+ // date
+ // of
+ // the period for interest recalculation enabled loans
+ Collection<RecalculationDetail> applicableTransactions = getApplicableTransactionsForPeriod(applyInterestRecalculation,
+ installment.getDueDate(), recalculationDetails);
+
+ // calculates the expected principal value for this
+ // repayment
+ // schedule
+ Money principalPortionCalculated = principalToBeScheduled.zero();
+ if (!installment.isRecalculatedInterestComponent()) {
+ principalPortionCalculated = calculateExpectedPrincipalPortion(installment.getInterestCharged(currency),
+ loanApplicationTerms);
+ }
- // populates the collection with transactions till the due date
- // of
- // the period for interest recalculation enabled loans
- Collection<RecalculationDetail> applicableTransactions = getApplicableTransactionsForPeriod(applyInterestRecalculation,
- installment.getDueDate(), recalculationDetails);
-
- // calculates the expected principal value for this repayment
- // schedule
- Money principalPortionCalculated = principalToBeScheduled.zero();
- if (!installment.isRecalculatedInterestComponent()) {
- principalPortionCalculated = calculateExpectedPrincipalPortion(installment.getInterestCharged(currency),
- loanApplicationTerms);
- }
+ // expected principal considering the previously paid excess
+ // amount
+ Money actualPrincipalPortion = principalPortionCalculated.minus(reducePrincipal);
+ if (actualPrincipalPortion.isLessThanZero()) {
+ actualPrincipalPortion = principalPortionCalculated.zero();
+ }
- // expected principal considering the previously paid excess
- // amount
- Money actualPrincipalPortion = principalPortionCalculated.minus(reducePrincipal);
- if (actualPrincipalPortion.isLessThanZero()) {
- actualPrincipalPortion = principalPortionCalculated.zero();
- }
+ Money unprocessed = updateEarlyPaidAmountsToMap(loanApplicationTerms, holidayDetailDTO,
+ loanRepaymentScheduleTransactionProcessor, newRepaymentScheduleInstallments, currency, principalPortionMap,
+ installment, applicableTransactions, actualPrincipalPortion);
+
+ // this block is to adjust the period number based on the
+ // actual
+ // schedule due date and installment due date
+ // recalculatedInterestComponent installment shouldn't be
+ // considered while calculating fixed EMI amounts
+ int period = periodNumber;
+ if (!lastInstallmentDate.isEqual(installment.getDueDate())) {
+ period--;
+ }
+ reducePrincipal = fetchEarlyPaidAmount(installment.getPrincipal(currency), principalPortionCalculated, reducePrincipal,
+ loanApplicationTerms, totalCumulativePrincipal, period, mc);
+ // Updates principal paid map with efective date for
+ // reducing
+ // the amount from outstanding balance(interest calculation)
+ LocalDate amountApplicableDate = null;
+ if (loanApplicationTerms.getRestCalendarInstance() != null) {
+ amountApplicableDate = getNextRestScheduleDate(installment.getDueDate().minusDays(1), loanApplicationTerms,
+ holidayDetailDTO);
+ }
- Money unprocessed = updateEarlyPaidAmountsToMap(loanApplicationTerms, holidayDetailDTO,
- loanRepaymentScheduleTransactionProcessor, newRepaymentScheduleInstallments, currency, principalPortionMap,
- installment, applicableTransactions, actualPrincipalPortion);
-
- // this block is to adjust the period number based on the actual
- // schedule due date and installment due date
- // recalculatedInterestComponent installment shouldn't be
- // considered while calculating fixed EMI amounts
- int period = periodNumber;
- if (!lastInstallmentDate.isEqual(installment.getDueDate())) {
- period--;
- }
- reducePrincipal = fetchEarlyPaidAmount(installment.getPrincipal(currency), principalPortionCalculated, reducePrincipal,
- loanApplicationTerms, totalCumulativePrincipal, period, mc);
- // Updates principal paid map with efective date for reducing
- // the amount from outstanding balance(interest calculation)
- LocalDate amountApplicableDate = getNextRestScheduleDate(installment.getDueDate().minusDays(1), loanApplicationTerms,
- holidayDetailDTO);
- // updates map with the installment principal amount excluding
- // unprocessed amount since this amount is already accounted.
- updateMapWithAmount(principalPortionMap, installment.getPrincipal(currency).minus(unprocessed), amountApplicableDate);
- uncompoundedAmount = updateCompoundingDetailsForPartialScheduleGeneration(installment, loanApplicationTerms,
- principalPortionMap, compoundingDateVariations, uncompoundedAmount, applicableTransactions, lastRestDate,
- holidayDetailDTO);
- // update outstanding balance for interest calculation
- outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(principalPortionMap, installment.getDueDate(),
- outstandingBalanceAsPerRest, false);
- outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(disburseDetailMap, installment.getDueDate(),
- outstandingBalanceAsPerRest, true);
+ // updates map with the installment principal amount
+ // excluding
+ // unprocessed amount since this amount is already
+ // accounted.
+ updateMapWithAmount(principalPortionMap, installment.getPrincipal(currency).minus(unprocessed), amountApplicableDate);
+ uncompoundedAmount = updateCompoundingDetailsForPartialScheduleGeneration(installment, loanApplicationTerms,
+ principalPortionMap, compoundingDateVariations, uncompoundedAmount, applicableTransactions, lastRestDate,
+ holidayDetailDTO);
+ // update outstanding balance for interest calculation
+ outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(principalPortionMap, installment.getDueDate(),
+ outstandingBalanceAsPerRest, false);
+ outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(disburseDetailMap, installment.getDueDate(),
+ outstandingBalanceAsPerRest, true);
+ // updates the map with over due amounts
+ updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, lastInstallmentDate,
+ newRepaymentScheduleInstallments, true, lastRestDate);
+ } else {
+ outstandingBalanceAsPerRest = outstandingBalance;
+ }
}
totalRepaymentExpected = totalCumulativePrincipal.plus(totalCumulativeInterest).plus(totalFeeChargesCharged)
.plus(totalPenaltyChargesCharged);
- // updates the map with over due amounts
- updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, lastInstallmentDate,
- newRepaymentScheduleInstallments, true, lastRestDate);
-
// for partial schedule generation
if (!newRepaymentScheduleInstallments.isEmpty() && totalCumulativeInterest.isGreaterThanZero()) {
Money totalOutstandingInterestPaymentDueToGrace = Money.zero(currency);
@@ -2494,6 +2320,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
scheduleTillDate, currency, applyInterestRecalculation);
retainedInstallments.addAll(newRepaymentScheduleInstallments);
loanScheduleParams.getCompoundingDateVariations().putAll(compoundingDateVariations);
+ loanApplicationTerms.updateTotalInterestDue(Money.of(currency, loan.getLoanSummary().getTotalInterestCharged()));
+ }else{
+ loanApplicationTerms.getLoanTermVariations().resetVariations();
}
}
@@ -2501,9 +2330,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
if (loanScheduleParams == null) {
loanScheduleParams = LoanScheduleParams.createLoanScheduleParamsForCompleteUpdate(recalculationDetails,
loanRepaymentScheduleTransactionProcessor, scheduleTillDate, applyInterestRecalculation);
+ periods.clear();
}
-
- LoanScheduleModel loanScheduleModel = generate(mc, loanApplicationTerms, loanCharges, holidayDetailDTO, loanScheduleParams);
+ LoanScheduleModel loanScheduleModel = generate(mc, loanApplicationTerms, loan.charges(), holidayDetailDTO, loanScheduleParams);
for (LoanScheduleModelPeriod loanScheduleModelPeriod : loanScheduleModel.getPeriods()) {
if (loanScheduleModelPeriod.isRepaymentPeriod()) {
// adding newly created repayment periods to installments
@@ -2515,6 +2344,41 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
return LoanScheduleDTO.from(retainedInstallments, loanScheduleModelwithPeriodChanges);
}
+ public List<LoanRepaymentScheduleInstallment> fetchRetainedInstallments(
+ final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final LocalDate rescheduleFrom,
+ MonetaryCurrency currency) {
+ List<LoanRepaymentScheduleInstallment> newRepaymentScheduleInstallments = new ArrayList<>();
+ int lastInterestAvilablePeriod = 0;
+ int processedPeriod = 0;
+ for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) {
+ if (installment.getDueDate().isBefore(rescheduleFrom)) {
+ newRepaymentScheduleInstallments.add(installment);
+ if(installment.getInterestCharged(currency).isGreaterThanZero()){
+ lastInterestAvilablePeriod = installment.getInstallmentNumber();
+ }
+ processedPeriod = installment.getInstallmentNumber();
+ } else {
+ break;
+ }
+ }
+
+ // this block is to remove the periods till last interest available
+ // period.
+ // if the last retained period is interest grace period then we
+ // can't get the interest of last period without calculating again
+ // to fix this adjusting retained periods
+ if(lastInterestAvilablePeriod != processedPeriod){
+ final List<LoanRepaymentScheduleInstallment> retainRepaymentScheduleInstallments = new ArrayList<>();
+ for (LoanRepaymentScheduleInstallment installment : newRepaymentScheduleInstallments) {
+ if(installment.getInstallmentNumber() <= lastInterestAvilablePeriod){
+ retainRepaymentScheduleInstallments.add(installment);
+ }
+ }
+ newRepaymentScheduleInstallments.retainAll(retainRepaymentScheduleInstallments);
+ }
+ return newRepaymentScheduleInstallments;
+ }
+
/**
* Method identifies the early paid amounts for a installment and update the
* principal map for further calculations
@@ -2630,7 +2494,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
earlyPaidAmount = earlyPaidAmount.zero();
}
- if (isEarlyPaid) {
+ if (isEarlyPaid && applicationTerms.getRescheduleStrategyMethod() != null) {
switch (applicationTerms.getRescheduleStrategyMethod()) {
case REDUCE_EMI_AMOUNT:
adjustInstallmentOrPrincipalAmount(applicationTerms, totalCumulativePrincipal, periodNumber, mc);
@@ -2727,21 +2591,20 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
*/
@Override
public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(final MonetaryCurrency currency, final LocalDate onDate,
- final LoanApplicationTerms loanApplicationTerms, final MathContext mc, final Set<LoanCharge> charges,
- final HolidayDetailDTO holidayDetailDTO, final List<LoanTransaction> loanTransactions,
- final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
- final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments) {
+ final LoanApplicationTerms loanApplicationTerms, final MathContext mc, Loan loan, final HolidayDetailDTO holidayDetailDTO,
+ final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) {
LocalDate calculateTill = onDate;
if (loanApplicationTerms.getPreClosureInterestCalculationStrategy().calculateTillRestFrequencyEnabled()) {
calculateTill = getNextRestScheduleDate(onDate.minusDays(1), loanApplicationTerms, holidayDetailDTO);
}
- LoanScheduleDTO loanScheduleDTO = rescheduleNextInstallments(mc, loanApplicationTerms, charges, holidayDetailDTO, loanTransactions,
- loanRepaymentScheduleTransactionProcessor, repaymentScheduleInstallments, onDate, calculateTill);
+ LoanScheduleDTO loanScheduleDTO = rescheduleNextInstallments(mc, loanApplicationTerms, loan, holidayDetailDTO, loanRepaymentScheduleTransactionProcessor,
+ onDate, calculateTill);
+ List<LoanTransaction> loanTransactions = loan.retreiveListOfTransactionsPostDisbursementExcludeAccruals();
loanRepaymentScheduleTransactionProcessor.handleTransaction(loanApplicationTerms.getExpectedDisbursementDate(), loanTransactions,
- currency, loanScheduleDTO.getInstallments(), charges);
+ currency, loanScheduleDTO.getInstallments(), loan.charges());
Money feeCharges = Money.zero(currency);
Money penaltyCharges = Money.zero(currency);
Money totalPrincipal = Money.zero(currency);
@@ -2759,15 +2622,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
feeCharges.getAmount(), penaltyCharges.getAmount(), false, compoundingDetails);
}
- /**
- * set the value to zero if the provided value is null
- *
- * @return integer value equal/greater than 0
- **/
- private Integer defaultToZeroIfNull(Integer value) {
-
- return (value != null) ? value : 0;
- }
private final class LoanTermVariationParams {
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DecliningBalanceInterestLoanScheduleGenerator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DecliningBalanceInterestLoanScheduleGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DecliningBalanceInterestLoanScheduleGenerator.java
index 1bbefa4..1bbf261 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DecliningBalanceInterestLoanScheduleGenerator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DecliningBalanceInterestLoanScheduleGenerator.java
@@ -73,6 +73,7 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
Money balanceForInterestCalculation = outstandingBalance;
Money cumulatingInterestDueToGrace = cumulatingInterestPaymentDueToGrace;
Map<LocalDate, BigDecimal> interestRates = new HashMap<>(termVariations.size());
+
for (LoanTermVariationsData loanTermVariation : termVariations) {
if (loanTermVariation.getTermVariationType().isInterestRateVariation()
&& loanTermVariation.isApplicable(periodStartDate, periodEndDate)) {
@@ -86,6 +87,7 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
}
}
}
+
if (principalVariation != null) {
for (Map.Entry<LocalDate, Money> principal : principalVariation.entrySet()) {
@@ -99,6 +101,7 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
interestForThisInstallment = interestForThisInstallment.plus(result.interest());
cumulatingInterestDueToGrace = result.interestPaymentDueToGrace();
interestStartDate = principal.getKey();
+
}
Money compoundFee = totalCumulativePrincipal.zero();
if (compoundingMap.containsKey(principal.getKey())) {
@@ -118,13 +121,14 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
loanApplicationTerms.updateAnnualNominalInterestRate(interestRates.get(principal.getKey()));
}
}
-
}
}
+
final PrincipalInterest result = loanApplicationTerms.calculateTotalInterestForPeriod(calculator,
interestCalculationGraceOnRepaymentPeriodFraction, periodNumber, mc, cumulatingInterestDueToGrace,
balanceForInterestCalculation, interestStartDate, periodEndDate);
+
interestForThisInstallment = interestForThisInstallment.plus(result.interest());
cumulatingInterestDueToGrace = result.interestPaymentDueToGrace();
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/fe617123/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/FlatInterestLoanScheduleGenerator.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/FlatInterestLoanScheduleGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/FlatInterestLoanScheduleGenerator.java
index 31cdbe5..5f3d8d7 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/FlatInterestLoanScheduleGenerator.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/FlatInterestLoanScheduleGenerator.java
@@ -32,11 +32,12 @@ public class FlatInterestLoanScheduleGenerator extends AbstractLoanScheduleGener
@Override
public PrincipalInterest calculatePrincipalInterestComponentsForPeriod(final PaymentPeriodsInOneYearCalculator calculator,
final double interestCalculationGraceOnRepaymentPeriodFraction, final Money totalCumulativePrincipal,
- final Money totalCumulativeInterest, final Money totalInterestDueForLoan, final Money cumulatingInterestPaymentDueToGrace,
+ Money totalCumulativeInterest, Money totalInterestDueForLoan, final Money cumulatingInterestPaymentDueToGrace,
final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms, final int periodNumber, final MathContext mc,
@SuppressWarnings("unused") TreeMap<LocalDate, Money> principalVariation,
@SuppressWarnings("unused") Map<LocalDate, Money> compoundingMap, LocalDate periodStartDate, LocalDate periodEndDate,
@SuppressWarnings("unused") Collection<LoanTermVariationsData> termVariations) {
+
Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator, outstandingBalance,
periodNumber, mc, null);
@@ -54,6 +55,11 @@ public class FlatInterestLoanScheduleGenerator extends AbstractLoanScheduleGener
principalForThisInstallment = loanApplicationTerms.adjustPrincipalIfLastRepaymentPeriod(principalForThisInstallment,
totalCumulativePrincipalToDate, periodNumber);
+ // totalCumulativeInterest from partial schedule generation for multi rescheduling
+ /*if (loanApplicationTerms.getPartialTotalCumulativeInterest() != null && loanApplicationTerms.getTotalInterestDue() != null) {
+ totalInterestDueForLoan = loanApplicationTerms.getTotalInterestDue();
+ totalInterestDueForLoan = totalInterestDueForLoan.plus(loanApplicationTerms.getPartialTotalCumulativeInterest());
+ }*/
interestForThisInstallment = loanApplicationTerms.adjustInterestIfLastRepaymentPeriod(interestForThisInstallment,
totalCumulativeInterestToDate, totalInterestDueForLoan, periodNumber);
[5/5] incubator-fineract git commit: Adding Apache License Text in
V313__multi_rescheduling_script.sql
Posted by na...@apache.org.
Adding Apache License Text in V313__multi_rescheduling_script.sql
Project: http://git-wip-us.apache.org/repos/asf/incubator-fineract/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-fineract/commit/c44cf55f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-fineract/tree/c44cf55f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-fineract/diff/c44cf55f
Branch: refs/heads/develop
Commit: c44cf55fcee7422671422dd94f2462637d254170
Parents: fe61712
Author: Nazeer Hussain Shaik <na...@confluxtechnologies.com>
Authored: Mon Aug 1 19:08:21 2016 +0530
Committer: Nazeer Hussain Shaik <na...@confluxtechnologies.com>
Committed: Mon Aug 1 19:08:21 2016 +0530
----------------------------------------------------------------------
.../core_db/V313__multi_rescheduling_script.sql | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/c44cf55f/fineract-provider/src/main/resources/sql/migrations/core_db/V313__multi_rescheduling_script.sql
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V313__multi_rescheduling_script.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V313__multi_rescheduling_script.sql
index 1fca1d1..367ee0c 100644
--- a/fineract-provider/src/main/resources/sql/migrations/core_db/V313__multi_rescheduling_script.sql
+++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V313__multi_rescheduling_script.sql
@@ -1,3 +1,22 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied. See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
ALTER TABLE `m_loan_term_variations`
ADD COLUMN `is_active` TINYINT(1) NOT NULL DEFAULT '1' AFTER `applied_on_loan_status`;