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
