diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java index 6b947db27..7c66482c9 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java @@ -3230,6 +3230,101 @@ public class ClientLoanIntegrationTest { LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap); } + @Test + public void testLoanScheduleWithInterestRecalculation_WITH_REST_SAME_AS_REPAYMENT_INTEREST_COMPOUND_NONE_STRATEGY_REDUCE_EMI_WITH_INSTALLMENT_CHARGE() { + this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); + + DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy"); + + Calendar todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -14); + final String LOAN_DISBURSEMENT_DATE = dateFormat.format(todaysDate.getTime()); + + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); + ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID); + final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.MIFOS_STANDARD_STRATEGY, + LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE, + LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN, + LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null, null); + + List charges = new ArrayList(); + Integer installmentCharge = ChargesHelper.createCharges(requestSpec, responseSpec, + ChargesHelper.getLoanInstallmentJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_PERCENTAGE_INTEREST, "10", false)); + addCharges(charges, installmentCharge, "10", null); + final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE, null, + LoanApplicationTestBuilder.MIFOS_STANDARD_STRATEGY, charges); + + Assert.assertNotNull(loanID); + HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); + LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); + + ArrayList loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); + List> expectedvalues = new ArrayList<>(); + todaysDate = Calendar.getInstance(); + addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "4.62", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "3.47", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "2.32", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "1.16", "0.0"); + verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); + + System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, loanID); + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + + System.out.println("-------------------------------DISBURSE LOAN-------------------------------------------"); + loanStatusHashMap = this.loanTransactionHelper.disburseLoan(LOAN_DISBURSEMENT_DATE, loanID); + LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap); + + loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); + expectedvalues = new ArrayList<>(); + todaysDate = Calendar.getInstance(); + addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "4.62", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "2482.76", "46.15", "4.62", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "2.32", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "2528.81", "11.67", "1.17", "0.0"); + + verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); + + todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -7); + final String LOAN_FIRST_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime()); + Float totalDueForCurrentPeriod = (Float) loanSchedule.get(1).get("totalDueForPeriod"); + this.loanTransactionHelper.makeRepayment(LOAN_FIRST_REPAYMENT_DATE, totalDueForCurrentPeriod, loanID); + + loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); + expectedvalues = new ArrayList<>(); + todaysDate = Calendar.getInstance(); + addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "4.62", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "3.47", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "2.32", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "1.16", "0.0"); + verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); + + Float earlyPayment = new Float("4000"); + todaysDate = Calendar.getInstance(); + todaysDate.add(Calendar.DAY_OF_MONTH, -5); + final String LOAN_SECOND_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime()); + this.loanTransactionHelper.makeRepayment(LOAN_SECOND_REPAYMENT_DATE, earlyPayment, loanID); + loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); + expectedvalues = new ArrayList<>(); + todaysDate = Calendar.getInstance(); + addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "4.62", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "3961.84", "34.69", "3.47", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "1773.61", "16.41", "1.64", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "1781.79", "8.22", "0.82", "0.0"); + verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); + + HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID); + String prepayAmount = String.valueOf(prepayDetail.get("amount")); + todaysDate = Calendar.getInstance(); + String LOAN_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime()); + this.loanTransactionHelper.makeRepayment(LOAN_REPAYMENT_DATE, new Float(prepayAmount), loanID); + loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); + LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap); + } + + @Test public void testLoanScheduleWithInterestRecalculation_WITH_REST_DAILY_INTEREST_COMPOUND_INTEREST_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS() { this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); @@ -3359,11 +3454,11 @@ public class ClientLoanIntegrationTest { List charges = new ArrayList<>(2); Integer flat = ChargesHelper.createCharges(requestSpec, responseSpec, ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "100", false)); - Integer interestPercentage = ChargesHelper.createCharges(requestSpec, responseSpec, - ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_PERCENTAGE_INTEREST, "1", false)); + Integer principalPercentage = ChargesHelper.createCharges(requestSpec, responseSpec, + ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_PERCENTAGE_AMOUNT, "2", false)); addCharges(charges, flat, "100", LOAN_FLAT_CHARGE_DATE); - addCharges(charges, interestPercentage, "10", LOAN_INTEREST_CHARGE_DATE); + addCharges(charges, principalPercentage, "2", LOAN_INTEREST_CHARGE_DATE); final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec); ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID); @@ -3384,7 +3479,7 @@ public class ClientLoanIntegrationTest { todaysDate = Calendar.getInstance(); addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "0.0", "0.0"); - addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "11.56", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "200", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0"); verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); @@ -3402,7 +3497,7 @@ public class ClientLoanIntegrationTest { todaysDate = Calendar.getInstance(); addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2490.75", "38.16", "0.0", "0.0"); - addRepaymentValues(expectedvalues, todaysDate, 1, "2505.71", "23.2", "11.91", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "2505.71", "23.2", "200", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2520.78", "11.63", "0.0", "0.0"); verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); @@ -3418,7 +3513,7 @@ public class ClientLoanIntegrationTest { todaysDate = Calendar.getInstance(); addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "0.0", "0.0"); - addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "11.56", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "200", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0"); verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); @@ -3433,7 +3528,7 @@ public class ClientLoanIntegrationTest { todaysDate = Calendar.getInstance(); addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "5100", "27.96", "0.0", "0.0"); - addRepaymentValues(expectedvalues, todaysDate, 1, "0", "11.16", "9.64", "0.0"); + addRepaymentValues(expectedvalues, todaysDate, 1, "0", "11.16", "200", "0.0"); addRepaymentValues(expectedvalues, todaysDate, 1, "2417.24", "11.16", "0.0", "0.0"); verifyLoanRepaymentSchedule(loanSchedule, expectedvalues); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanApiConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanApiConstants.java index 24e998af1..dec97b8bc 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanApiConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoanApiConstants.java @@ -28,6 +28,10 @@ public interface LoanApiConstants { public static final String principalDisbursedParameterName = "transactionAmount"; public static final String ALREADY_DISBURSED = "can.not.change.disbursement.date"; + + public static final String LOAN_CHARGE_CAN_NOT_BE_ADDED_WITH_INTEREST_CALCULATION_TYPE= "loancharge.with.calculation.type.interest.not.allowed"; + + public static final String LOAN_CHARGE_CAN_NOT_BE_ADDED_WITH_PRINCIPAL_CALCULATION_TYPE= "loancharge.with.calculation.type.principal.not.allowed"; // Interest recalculation related public static final String isInterestRecalculationEnabledParameterName = "isInterestRecalculationEnabled"; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java index e38db157c..dfb64d2e4 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java @@ -4377,7 +4377,8 @@ public class Loan extends AbstractPersistable { if (!loanCharge.isDueAtDisbursement()) { updateOverdueScheduleInstallment(loanCharge); if (loanCharge.getDueLocalDate() == null || (!lastRepaymentDate.isBefore(loanCharge.getDueLocalDate()))) { - if (!loanCharge.isWaived() && !lastTransactionDate.isAfter(loanCharge.getDueLocalDate())) { + if (!loanCharge.isWaived() + && (loanCharge.getDueLocalDate() == null || !lastTransactionDate.isAfter(loanCharge.getDueLocalDate()))) { recalculateLoanCharge(loanCharge, generatorDTO.getPenaltyWaitPeriod()); loanCharge.updateWaivedAmount(getCurrency()); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java index ee2d9c7af..c9bc84ef2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java @@ -25,6 +25,7 @@ import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.portfolio.accountdetails.domain.AccountType; import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants; import org.mifosplatform.portfolio.loanaccount.domain.Loan; +import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge; import org.mifosplatform.portfolio.loanproduct.LoanProductConstants; import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod; import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct; @@ -836,11 +837,53 @@ public final class LoanApplicationCommandFromApiJsonHelper { } - public void validateRecalcuationFrequency(final LocalDate recalculationFrequencyDate, final LocalDate expectedDisbursementDate) { - final List dataValidationErrors = new ArrayList<>(); + public void validateRecalcuationFrequency(final LocalDate recalculationFrequencyDate, final LocalDate expectedDisbursementDate, + final List dataValidationErrors) { + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan"); baseDataValidator.reset().parameter(LoanProductConstants.recalculationRestFrequencyDateParamName).value(recalculationFrequencyDate) .notNull().validateDateBeforeOrEqual(expectedDisbursementDate); + } + + public void validateLoanCharges(final Set charges, final List dataValidationErrors) { + if (charges == null) { return; } + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan"); + for (LoanCharge loanCharge : charges) { + String errorcode = null; + switch (loanCharge.getChargeCalculation()) { + case PERCENT_OF_AMOUNT: + if (loanCharge.isInstalmentFee()) { + errorcode = "installment." + LoanApiConstants.LOAN_CHARGE_CAN_NOT_BE_ADDED_WITH_PRINCIPAL_CALCULATION_TYPE; + + } + break; + case PERCENT_OF_AMOUNT_AND_INTEREST: + if (loanCharge.isInstalmentFee()) { + errorcode = "installment." + LoanApiConstants.LOAN_CHARGE_CAN_NOT_BE_ADDED_WITH_PRINCIPAL_CALCULATION_TYPE; + } else if (loanCharge.isSpecifiedDueDate()) { + errorcode = "specific." + LoanApiConstants.LOAN_CHARGE_CAN_NOT_BE_ADDED_WITH_INTEREST_CALCULATION_TYPE; + } + break; + case PERCENT_OF_INTEREST: + if (loanCharge.isSpecifiedDueDate()) { + errorcode = "specific." + LoanApiConstants.LOAN_CHARGE_CAN_NOT_BE_ADDED_WITH_INTEREST_CALCULATION_TYPE; + } + break; + + default: + break; + } + if (errorcode != null) { + baseDataValidator.reset().parameter("charges").failWithCode(errorcode); + } + } + } + + public void validateLoanForInterestRecalculation(final LocalDate recalculationFrequencyDate, final LocalDate expectedDisbursementDate, + final Set charges) { + final List dataValidationErrors = new ArrayList<>(); + validateRecalcuationFrequency(recalculationFrequencyDate, expectedDisbursementDate, dataValidationErrors); + validateLoanCharges(charges, dataValidationErrors); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java index e7d7c561f..f77e17cd3 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java @@ -216,8 +216,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa final LocalDate recalculationFrequencyDate = this.fromJsonHelper.extractLocalDateNamed( LoanProductConstants.recalculationRestFrequencyDateParamName, command.parsedJson()); if (!newLoanApplication.loanInterestRecalculationDetails().getRestFrequencyType().isSameAsRepayment()) { - this.fromApiJsonDeserializer.validateRecalcuationFrequency(recalculationFrequencyDate, - newLoanApplication.getExpectedDisbursedOnLocalDate()); + this.fromApiJsonDeserializer.validateLoanForInterestRecalculation(recalculationFrequencyDate, + newLoanApplication.getExpectedDisbursedOnLocalDate(), newLoanApplication.charges()); } createAndPersistCalendarInstanceForInterestRecalculation(newLoanApplication); } @@ -624,8 +624,8 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa recalculationFrequencyDate = this.fromJsonHelper.extractLocalDateNamed( LoanProductConstants.recalculationRestFrequencyDateParamName, command.parsedJson()); if (!existingLoanApplication.loanInterestRecalculationDetails().getRestFrequencyType().isSameAsRepayment()) { - this.fromApiJsonDeserializer.validateRecalcuationFrequency(recalculationFrequencyDate, - existingLoanApplication.getExpectedDisbursedOnLocalDate()); + this.fromApiJsonDeserializer.validateLoanForInterestRecalculation(recalculationFrequencyDate, + existingLoanApplication.getExpectedDisbursedOnLocalDate(), existingLoanApplication.charges()); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index 2d51fa75b..eeb1b395a 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -10,6 +10,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; @@ -120,6 +121,7 @@ import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleM import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod; import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.ScheduledDateGenerator; import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService; +import org.mifosplatform.portfolio.loanaccount.serialization.LoanApplicationCommandFromApiJsonHelper; import org.mifosplatform.portfolio.loanaccount.serialization.LoanEventApiJsonValidator; import org.mifosplatform.portfolio.loanaccount.serialization.LoanUpdateCommandFromApiJsonDeserializer; import org.mifosplatform.portfolio.loanproduct.data.LoanOverdueDTO; @@ -178,6 +180,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf private final CalendarRepository calendarRepository; private final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository; private final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService; + private final LoanApplicationCommandFromApiJsonHelper loanApplicationCommandFromApiJsonHelper; @Autowired public LoanWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, @@ -199,7 +202,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final FromJsonHelper fromApiJsonHelper, final AccountTransferRepository accountTransferRepository, final CalendarRepository calendarRepository, final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository, - final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService) { + final LoanScheduleHistoryWritePlatformService loanScheduleHistoryWritePlatformService, + final LoanApplicationCommandFromApiJsonHelper loanApplicationCommandFromApiJsonHelper) { this.context = context; this.loanEventApiJsonValidator = loanEventApiJsonValidator; this.loanAssembler = loanAssembler; @@ -229,6 +233,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf this.calendarRepository = calendarRepository; this.repaymentScheduleInstallmentRepository = repaymentScheduleInstallmentRepository; this.loanScheduleHistoryWritePlatformService = loanScheduleHistoryWritePlatformService; + this.loanApplicationCommandFromApiJsonHelper = loanApplicationCommandFromApiJsonHelper; } private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() { @@ -1179,14 +1184,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final LoanCharge loanCharge = LoanCharge.createNewFromJson(loan, chargeDefinition, command); - if (chargeDefinition.isOverdueInstallment()) { - - final String defaultUserMessage = "Installment charge cannot be added to the loan."; - throw new LoanChargeCannotBeAddedException("loanCharge", "overdue.charge", defaultUserMessage, null, chargeDefinition.getName()); - } else if(loanCharge.getDueLocalDate() != null && loanCharge.getDueLocalDate().isBefore(loan.getLastUserTransactionForChargeCalc())){ - final String defaultUserMessage = "charge after last transaction date can not be added to loan."; - throw new LoanChargeCannotBeAddedException("loanCharge", "date.is.after.last.transaction.date", defaultUserMessage, null, chargeDefinition.getName()); - } + validateAddLoanCharge(loan, chargeDefinition, loanCharge); final List existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds()); final List existingReversedTransactionIds = new ArrayList<>(loan.findExistingReversedTransactionIds()); @@ -1217,6 +1215,31 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf .build(); } + private void validateAddLoanCharge(final Loan loan, final Charge chargeDefinition, final LoanCharge loanCharge) { + if (chargeDefinition.isOverdueInstallment()) { + final String defaultUserMessage = "Installment charge cannot be added to the loan."; + throw new LoanChargeCannotBeAddedException("loanCharge", "overdue.charge", defaultUserMessage, null, chargeDefinition.getName()); + } else if (loanCharge.getDueLocalDate() != null + && loanCharge.getDueLocalDate().isBefore(loan.getLastUserTransactionForChargeCalc())) { + final String defaultUserMessage = "charge with date before last transaction date can not be added to loan."; + throw new LoanChargeCannotBeAddedException("loanCharge", "date.is.before.last.transaction.date", defaultUserMessage, null, + chargeDefinition.getName()); + } else if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) { + + if (loanCharge.isInstalmentFee() && loan.status().isActive()) { + final String defaultUserMessage = "installment charge addition not allowed after disbursement"; + throw new LoanChargeCannotBeAddedException("loanCharge", "installment.charge", defaultUserMessage, null, + chargeDefinition.getName()); + } + final List dataValidationErrors = new ArrayList<>(); + final Set loanCharges = new HashSet<>(1); + loanCharges.add(loanCharge); + this.loanApplicationCommandFromApiJsonHelper.validateLoanCharges(loanCharges, dataValidationErrors); + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } + } + + } + public void runScheduleRecalculation(Loan loan) { if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) { CalendarInstance restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(