MIFOSX-1631 : added constrains for charges with interest recalculation

This commit is contained in:
Pramod Nuthakki
2014-10-31 23:43:53 +05:30
parent c7cd28c340
commit 784c180154
6 changed files with 189 additions and 23 deletions
@@ -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";
@@ -4377,7 +4377,8 @@ public class Loan extends AbstractPersistable<Long> {
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());
}
@@ -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<ApiParameterError> dataValidationErrors = new ArrayList<>();
public void validateRecalcuationFrequency(final LocalDate recalculationFrequencyDate, final LocalDate expectedDisbursementDate,
final List<ApiParameterError> dataValidationErrors) {
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
baseDataValidator.reset().parameter(LoanProductConstants.recalculationRestFrequencyDateParamName).value(recalculationFrequencyDate)
.notNull().validateDateBeforeOrEqual(expectedDisbursementDate);
}
public void validateLoanCharges(final Set<LoanCharge> charges, final List<ApiParameterError> 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<LoanCharge> charges) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
validateRecalcuationFrequency(recalculationFrequencyDate, expectedDisbursementDate, dataValidationErrors);
validateLoanCharges(charges, dataValidationErrors);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
@@ -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());
}
}
@@ -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<Long> existingTransactionIds = new ArrayList<>(loan.findExistingTransactionIds());
final List<Long> 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<ApiParameterError> dataValidationErrors = new ArrayList<>();
final Set<LoanCharge> 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(