try {
final AppUser currentUser = this.context.authenticatedUser();
this.fromApiJsonDeserializer.validateClose(command);
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
final LocalDate closureDate = command.localDateValueOfParameterNamed(ClientApiConstants.closureDateParamName);
final Long closureReasonId = command.longValueOfParameterNamed(ClientApiConstants.closureReasonIdParamName);
final CodeValue closureReason = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
ClientApiConstants.CLIENT_CLOSURE_REASON, closureReasonId);
if (ClientStatus.fromInt(client.getStatus()).isClosed()) {
final String errorMessage = "Client is already closed.";
throw new InvalidClientStateTransitionException("close", "is.already.closed", errorMessage);
} else if (ClientStatus.fromInt(client.getStatus()).isUnderTransfer()) {
final String errorMessage = "Cannot Close a Client under Transfer";
throw new InvalidClientStateTransitionException("close", "is.under.transfer", errorMessage);
}
if (client.isNotPending() && client.getActivationLocalDate().isAfter(closureDate)) {
final String errorMessage = "The client closureDate cannot be before the client ActivationDate.";
throw new InvalidClientStateTransitionException("close", "date.cannot.before.client.actvation.date", errorMessage,
closureDate, client.getActivationLocalDate());
}
final List<Loan> clientLoans = this.loanRepository.findLoanByClientId(clientId);
for (final Loan loan : clientLoans) {
final LoanStatusMapper loanStatus = new LoanStatusMapper(loan.status().getValue());
if (loanStatus.isOpen() || loanStatus.isPendingApproval() || loanStatus.isAwaitingDisbursal()) {
final String errorMessage = "Client cannot be closed because of non-closed loans.";
throw new InvalidClientStateTransitionException("close", "loan.non-closed", errorMessage);
} else if (loanStatus.isClosed() && loan.getClosedOnDate().after(closureDate.toDate())) {
final String errorMessage = "The client closureDate cannot be before the loan closedOnDate.";
throw new InvalidClientStateTransitionException("close", "date.cannot.before.loan.closed.date", errorMessage,
closureDate, loan.getClosedOnDate());
} else if (loanStatus.isOverpaid()) {
final String errorMessage = "Client cannot be closed because of overpaid loans.";
throw new InvalidClientStateTransitionException("close", "loan.overpaid", errorMessage);
}
}
final List<SavingsAccount> clientSavingAccounts = this.savingsRepository.findSavingAccountByClientId(clientId);
for (final SavingsAccount saving : clientSavingAccounts) {
if (saving.isActive() || saving.isSubmittedAndPendingApproval() || saving.isApproved()) {
final String errorMessage = "Client cannot be closed because of non-closed savings account.";
throw new InvalidClientStateTransitionException("close", "non-closed.savings.account", errorMessage);
}
}
client.close(currentUser, closureReason, closureDate.toDate());
this.clientRepository.saveAndFlush(client);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withClientId(clientId) //