Skip to content

Commit

Permalink
refactoring approveApplication
Browse files Browse the repository at this point in the history
  • Loading branch information
kjozsa committed Jun 5, 2024
1 parent c4b014b commit dbd256c
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1945,7 +1945,6 @@ public Map<String, Object> loanApplicationWithdrawnByApplicant(final AppUser cur

public Map<String, Object> loanApplicationApproval(final AppUser currentUser, final JsonCommand command,
final JsonArray disbursementDataArray, final LoanLifecycleStateMachine loanLifecycleStateMachine) {

validateAccountStatus(LoanEvent.LOAN_APPROVED);

final Map<String, Object> actualChanges = new LinkedHashMap<>();
Expand Down Expand Up @@ -2001,18 +2000,7 @@ public Map<String, Object> loanApplicationApproval(final AppUser currentUser, fi
recalculateAllCharges();

if (loanProduct.isMultiDisburseLoan()) {
List<LoanDisbursementDetails> currentDisbursementDetails = getDisbursementDetails();
if (loanProduct.isDisallowExpectedDisbursements()) {
if (!currentDisbursementDetails.isEmpty()) {
final String errorMessage = "For this loan product, disbursement details are not allowed";
throw new MultiDisbursementDataNotAllowedException(LoanApiConstants.disbursementDataParameterName, errorMessage);
}
} else {
if (currentDisbursementDetails.isEmpty()) {
final String errorMessage = "For this loan product, disbursement details must be provided";
throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
}
}
List<LoanDisbursementDetails> currentDisbursementDetails = getLoanDisbursementDetails();

if (currentDisbursementDetails.size() > loanProduct.maxTrancheCount()) {
final String errorMessage = "Number of tranche shouldn't be greter than " + loanProduct.maxTrancheCount();
Expand Down Expand Up @@ -2064,6 +2052,22 @@ public Map<String, Object> loanApplicationApproval(final AppUser currentUser, fi

}

private List<LoanDisbursementDetails> getLoanDisbursementDetails() {
List<LoanDisbursementDetails> currentDisbursementDetails = getDisbursementDetails();
if (loanProduct.isDisallowExpectedDisbursements()) {
if (!currentDisbursementDetails.isEmpty()) {
final String errorMessage = "For this loan product, disbursement details are not allowed";
throw new MultiDisbursementDataNotAllowedException(LoanApiConstants.disbursementDataParameterName, errorMessage);
}
} else {
if (currentDisbursementDetails.isEmpty()) {
final String errorMessage = "For this loan product, disbursement details must be provided";
throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage);
}
}
return currentDisbursementDetails;
}

private void compareApprovedToProposedPrincipal(BigDecimal approvedLoanAmount) {

if (this.loanProduct().isDisallowExpectedDisbursements() && this.loanProduct().isAllowApprovedDisbursedAmountsOverApplied()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -547,98 +547,55 @@ public CommandProcessingResult approveGLIMLoanAppication(final Long loanId, fina
@Transactional
@Override
public CommandProcessingResult approveApplication(final Long loanId, final JsonCommand command) {

final AppUser currentUser = getAppUserIfPresent();
LocalDate expectedDisbursementDate = null;

this.loanApplicationTransitionApiJsonValidator.validateApproval(command.json());
loanApplicationTransitionApiJsonValidator.validateApproval(command.json());

Loan loan = retrieveLoanBy(loanId);
checkClientOrGroupActive(loan);

final JsonArray disbursementDataArray = command.arrayOfParameterNamed(LoanApiConstants.disbursementDataParameterName);

expectedDisbursementDate = command.localDateValueOfParameterNamed(LoanApiConstants.expectedDisbursementDateParameterName);
LocalDate expectedDisbursementDate = command.localDateValueOfParameterNamed(LoanApiConstants.expectedDisbursementDateParameterName);
if (expectedDisbursementDate == null) {
expectedDisbursementDate = loan.getExpectedDisbursedOnLocalDate();
}

if (loan.loanProduct().isMultiDisburseLoan()) {
this.validateMultiDisbursementData(command, expectedDisbursementDate);
validateMultiDisbursementData(command, expectedDisbursementDate);
}

checkClientOrGroupActive(loan);
Boolean isSkipRepaymentOnFirstMonth = false;
Integer numberOfDays = 0;
// validate expected disbursement date against meeting date
final JsonArray disbursementDataArray = command.arrayOfParameterNamed(LoanApiConstants.disbursementDataParameterName);

boolean isSkipRepaymentOnFirstMonth = false;
int numberOfDays = 0;
if (loan.isSyncDisbursementWithMeeting() && (loan.isGroupLoan() || loan.isJLGLoan())) {
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
CalendarEntityType.LOANS.getValue());
Calendar calendar = null;
if (calendarInstance != null) {
calendar = calendarInstance.getCalendar();
Calendar calendar = getCalendarInstance(loan);
isSkipRepaymentOnFirstMonth = isLoanRepaymentsSyncWithMeeting(loan, calendar);
if (isSkipRepaymentOnFirstMonth) {
numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
}
// final Calendar calendar = calendarInstance.getCalendar();
boolean isSkipRepaymentOnFirstMonthEnabled = this.configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
if (isSkipRepaymentOnFirstMonthEnabled) {
isSkipRepaymentOnFirstMonth = this.loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
if (isSkipRepaymentOnFirstMonth) {
numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue();
}
}
this.loanScheduleAssembler.validateDisbursementDateWithMeetingDates(expectedDisbursementDate, calendar,
isSkipRepaymentOnFirstMonth, numberOfDays);

}

final Map<String, Object> changes = loan.loanApplicationApproval(currentUser, command, disbursementDataArray,
defaultLoanLifecycleStateMachine);
loanScheduleAssembler.validateDisbursementDateWithMeetingDates(expectedDisbursementDate, getCalendarInstance(loan), isSkipRepaymentOnFirstMonth, numberOfDays);

entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
StatusEnum.APPROVE.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
final Map<String, Object> changes = loan.loanApplicationApproval(currentUser, command, disbursementDataArray, defaultLoanLifecycleStateMachine);

if (!changes.isEmpty()) {
entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(), StatusEnum.APPROVE.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());

// If loan approved amount less than loan demanded amount, then need
// to recompute the schedule
if (changes.containsKey(LoanApiConstants.approvedLoanAmountParameterName) || changes.containsKey("recalculateLoanSchedule")
|| changes.containsKey("expectedDisbursementDate")) {
LocalDate recalculateFrom = null;
ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
loan.regenerateRepaymentSchedule(scheduleGeneratorDTO);
if (!changes.isEmpty()) {
if (changes.containsKey(LoanApiConstants.approvedLoanAmountParameterName) || changes.containsKey("recalculateLoanSchedule") || changes.containsKey("expectedDisbursementDate")) {
loan.regenerateRepaymentSchedule(loanUtilService.buildScheduleGeneratorDTO(loan, null));
}

if (loan.isTopup() && loan.getClientId() != null) {
final Long loanIdToClose = loan.getTopupLoanDetails().getLoanIdToClose();
final Loan loanToClose = this.loanRepositoryWrapper.findNonClosedLoanThatBelongsToClient(loanIdToClose, loan.getClientId());
if (loanToClose == null) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.to.be.closed.with.topup.is.not.active",
"Loan to be closed with this topup is not active.");
}

final LocalDate lastUserTransactionOnLoanToClose = loanToClose.getLastUserTransactionDate();
if (DateUtils.isBefore(loan.getDisbursementDate(), lastUserTransactionOnLoanToClose)) {
throw new GeneralPlatformDomainRuleException(
"error.msg.loan.disbursal.date.should.be.after.last.transaction.date.of.loan.to.be.closed",
"Disbursal date of this loan application " + loan.getDisbursementDate()
+ " should be after last transaction date of loan to be closed " + lastUserTransactionOnLoanToClose);
}
BigDecimal loanOutstanding = this.loanReadPlatformService
.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, expectedDisbursementDate).getAmount();
final BigDecimal firstDisbursalAmount = loan.getFirstDisbursalAmount();
if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
"Topup loan amount should be greater than outstanding amount of loan to be closed.");
}
BigDecimal netDisbursalAmount = loan.getApprovedPrincipal().subtract(loanOutstanding);
loan.adjustNetDisbursalAmount(netDisbursalAmount);
validateTopupLoan(loan);
}

loan = loanRepository.saveAndFlush(loan);
loan = this.loanRepository.saveAndFlush(loan);

final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
final Note note = Note.loanNote(loan, noteText);
changes.put("note", noteText);
this.noteRepository.save(note);
noteRepository.save(note);
}

businessEventNotifierService.notifyPostBusinessEvent(new LoanApprovedBusinessEvent(loan));
Expand All @@ -656,6 +613,40 @@ public CommandProcessingResult approveApplication(final Long loanId, final JsonC
.build();
}

private Calendar getCalendarInstance(Loan loan) {
CalendarInstance calendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(), CalendarEntityType.LOANS.getValue());
return calendarInstance != null ? calendarInstance.getCalendar() : null;
}

private boolean isLoanRepaymentsSyncWithMeeting(Loan loan, Calendar calendar) {
return configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled() && loanUtilService.isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
}

private void validateTopupLoan(Loan loan) {
final Long loanIdToClose = loan.getTopupLoanDetails().getLoanIdToClose();
final Loan loanToClose = loanRepositoryWrapper.findNonClosedLoanThatBelongsToClient(loanIdToClose, loan.getClientId());
if (loanToClose == null) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.to.be.closed.with.topup.is.not.active", "Loan to be closed with this topup is not active.");
}

final LocalDate lastUserTransactionOnLoanToClose = loanToClose.getLastUserTransactionDate();
if (DateUtils.isBefore(loan.getDisbursementDate(), lastUserTransactionOnLoanToClose)) {
throw new GeneralPlatformDomainRuleException(
"error.msg.loan.disbursal.date.should.be.after.last.transaction.date.of.loan.to.be.closed",
"Disbursal date of this loan application " + loan.getDisbursementDate() + " should be after last transaction date of loan to be closed " + lastUserTransactionOnLoanToClose);
}

BigDecimal loanOutstanding = loanReadPlatformService.retrieveLoanPrePaymentTemplate(LoanTransactionType.REPAYMENT, loanIdToClose, expectedDisbursementDate).getAmount();
final BigDecimal firstDisbursalAmount = loan.getFirstDisbursalAmount();
if (loanOutstanding.compareTo(firstDisbursalAmount) > 0) {
throw new GeneralPlatformDomainRuleException("error.msg.loan.amount.less.than.outstanding.of.loan.to.be.closed",
"Topup loan amount should be greater than outstanding amount of loan to be closed.");
}

BigDecimal netDisbursalAmount = loan.getApprovedPrincipal().subtract(loanOutstanding);
loan.adjustNetDisbursalAmount(netDisbursalAmount);
}

@Transactional
@Override
public CommandProcessingResult undoGLIMLoanApplicationApproval(final Long loanId, final JsonCommand command) {
Expand Down Expand Up @@ -853,16 +844,12 @@ private Loan retrieveLoanBy(final Long loanId) {

private void checkClientOrGroupActive(final Loan loan) {
final Client client = loan.client();
if (client != null) {
if (client.isNotActive()) {
throw new ClientNotActiveException(client.getId());
}
if (client != null && client.isNotActive()) {
throw new ClientNotActiveException(client.getId());
}
final Group group = loan.group();
if (group != null) {
if (group.isNotActive()) {
throw new GroupNotActiveException(group.getId());
}
if (group != null && group.isNotActive()) {
throw new GroupNotActiveException(group.getId());
}
}

Expand Down

0 comments on commit dbd256c

Please sign in to comment.