FINERACT-2090: Restructure Withdraw Loan Application Logic
This commit is contained in:
committed by
Adam Saghy
parent
0292171f6f
commit
1c53fe2136
-62
@@ -42,7 +42,6 @@ import jakarta.validation.constraints.NotNull;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -1741,54 +1740,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
return maturityDate;
|
return maturityDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> loanApplicationWithdrawnByApplicant(final AppUser currentUser, final JsonCommand command,
|
|
||||||
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
|
||||||
final Map<String, Object> actualChanges = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
final LoanStatus statusEnum = loanLifecycleStateMachine.dryTransition(LoanEvent.LOAN_WITHDRAWN, this);
|
|
||||||
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
|
|
||||||
loanLifecycleStateMachine.transition(LoanEvent.LOAN_WITHDRAWN, this);
|
|
||||||
actualChanges.put(PARAM_STATUS, LoanEnumerations.status(this.loanStatus));
|
|
||||||
|
|
||||||
LocalDate withdrawnOn = command.localDateValueOfParameterNamed(WITHDRAWN_ON_DATE);
|
|
||||||
if (withdrawnOn == null) {
|
|
||||||
withdrawnOn = command.localDateValueOfParameterNamed(EVENT_DATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Locale locale = new Locale(command.locale());
|
|
||||||
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
|
|
||||||
|
|
||||||
this.withdrawnOnDate = withdrawnOn;
|
|
||||||
this.withdrawnBy = currentUser;
|
|
||||||
this.closedOnDate = withdrawnOn;
|
|
||||||
this.closedBy = currentUser;
|
|
||||||
|
|
||||||
actualChanges.put(LOCALE, command.locale());
|
|
||||||
actualChanges.put(DATE_FORMAT, command.dateFormat());
|
|
||||||
actualChanges.put(WITHDRAWN_ON_DATE, withdrawnOn.format(fmt));
|
|
||||||
actualChanges.put(CLOSED_ON_DATE, withdrawnOn.format(fmt));
|
|
||||||
|
|
||||||
if (DateUtils.isBefore(withdrawnOn, getSubmittedOnDate())) {
|
|
||||||
final String errorMessage = "The date on which a loan is withdrawn cannot be before its submittal date: "
|
|
||||||
+ getSubmittedOnDate().toString();
|
|
||||||
throw new InvalidLoanStateTransitionException("withdraw", "cannot.be.before.submittal.date", errorMessage, command,
|
|
||||||
getSubmittedOnDate());
|
|
||||||
}
|
|
||||||
|
|
||||||
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_WITHDRAWN, withdrawnOn);
|
|
||||||
|
|
||||||
if (DateUtils.isDateInTheFuture(withdrawnOn)) {
|
|
||||||
final String errorMessage = "The date on which a loan is withdrawn cannot be in the future.";
|
|
||||||
throw new InvalidLoanStateTransitionException("withdraw", "cannot.be.a.future.date", errorMessage, command);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
final String errorMessage = "Only the loan applications with status 'Submitted and pending approval' are allowed to be withdrawn by applicant.";
|
|
||||||
throw new InvalidLoanStateTransitionException("withdraw", "cannot.withdraw", errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
return actualChanges;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Object> loanApplicationApproval(final AppUser currentUser, final JsonCommand command,
|
public Map<String, Object> loanApplicationApproval(final AppUser currentUser, final JsonCommand command,
|
||||||
final JsonArray disbursementDataArray, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
final JsonArray disbursementDataArray, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
||||||
validateAccountStatus(LoanEvent.LOAN_APPROVED);
|
validateAccountStatus(LoanEvent.LOAN_APPROVED);
|
||||||
@@ -4278,11 +4229,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
action = "repayment.or.waiver";
|
action = "repayment.or.waiver";
|
||||||
postfix = "cannot.be.made.before.client.transfer.date";
|
postfix = "cannot.be.made.before.client.transfer.date";
|
||||||
}
|
}
|
||||||
case LOAN_WITHDRAWN -> {
|
|
||||||
errorMessage = "The date on which a loan is withdrawn cannot be earlier than client's transfer date to this office";
|
|
||||||
action = "withdraw";
|
|
||||||
postfix = "cannot.be.before.client.transfer.date";
|
|
||||||
}
|
|
||||||
case WRITE_OFF_OUTSTANDING -> {
|
case WRITE_OFF_OUTSTANDING -> {
|
||||||
errorMessage = "The date on which a write off is made cannot be earlier than client's transfer date to this office";
|
errorMessage = "The date on which a write off is made cannot be earlier than client's transfer date to this office";
|
||||||
action = "writeoff";
|
action = "writeoff";
|
||||||
@@ -4478,14 +4424,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
|||||||
dataValidationErrors.add(error);
|
dataValidationErrors.add(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case LOAN_WITHDRAWN -> {
|
|
||||||
if (!isSubmittedAndPendingApproval()) {
|
|
||||||
final String defaultUserMessage = "Loan application cannot be withdrawn. Loan Account is not in Submitted and Pending approval state.";
|
|
||||||
final ApiParameterError error = ApiParameterError
|
|
||||||
.generalError("error.msg.loan.withdrawn.account.is.not.submitted.pending.approval.state", defaultUserMessage);
|
|
||||||
dataValidationErrors.add(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case WRITE_OFF_OUTSTANDING -> {
|
case WRITE_OFF_OUTSTANDING -> {
|
||||||
if (!isOpen()) {
|
if (!isOpen()) {
|
||||||
final String defaultUserMessage = "Loan Written off is not allowed. Loan Account is not active.";
|
final String defaultUserMessage = "Loan Written off is not allowed. Loan Account is not active.";
|
||||||
|
|||||||
+52
-12
@@ -29,6 +29,7 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||||
@@ -47,18 +48,14 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent;
|
|||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||||
import org.apache.fineract.portfolio.loanaccount.exception.InvalidLoanStateTransitionException;
|
import org.apache.fineract.portfolio.loanaccount.exception.InvalidLoanStateTransitionException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
public final class LoanApplicationTransitionValidator {
|
public final class LoanApplicationTransitionValidator {
|
||||||
|
|
||||||
private final FromJsonHelper fromApiJsonHelper;
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
|
private final LoanLifecycleStateMachine defaultLoanLifecycleStateMachine;
|
||||||
@Autowired
|
|
||||||
public LoanApplicationTransitionValidator(final FromJsonHelper fromApiJsonHelper) {
|
|
||||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||||
if (!dataValidationErrors.isEmpty()) {
|
if (!dataValidationErrors.isEmpty()) {
|
||||||
@@ -112,13 +109,13 @@ public final class LoanApplicationTransitionValidator {
|
|||||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateRejection(final JsonCommand command, final Loan loan, final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
public void validateRejection(final JsonCommand command, final Loan loan) {
|
||||||
// validate request body
|
// validate request body
|
||||||
final String json = command.json();
|
final String json = command.json();
|
||||||
validateLoanRejectionRequestBody(json);
|
validateLoanRejectionRequestBody(json);
|
||||||
|
|
||||||
// validate loan rejection
|
// validate loan rejection
|
||||||
validateLoanRejection(command, loan, loanLifecycleStateMachine);
|
validateLoanRejection(command, loan);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateLoanRejectionRequestBody(String json) {
|
private void validateLoanRejectionRequestBody(String json) {
|
||||||
@@ -146,8 +143,7 @@ public final class LoanApplicationTransitionValidator {
|
|||||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateLoanRejection(final JsonCommand command, final Loan loan,
|
private void validateLoanRejection(final JsonCommand command, final Loan loan) {
|
||||||
final LoanLifecycleStateMachine loanLifecycleStateMachine) {
|
|
||||||
// validate client or group is active
|
// validate client or group is active
|
||||||
checkClientOrGroupActive(loan);
|
checkClientOrGroupActive(loan);
|
||||||
|
|
||||||
@@ -156,7 +152,7 @@ public final class LoanApplicationTransitionValidator {
|
|||||||
|
|
||||||
// validate loan state transition
|
// validate loan state transition
|
||||||
|
|
||||||
final LoanStatus statusEnum = loanLifecycleStateMachine.dryTransition(LoanEvent.LOAN_REJECTED, loan);
|
final LoanStatus statusEnum = defaultLoanLifecycleStateMachine.dryTransition(LoanEvent.LOAN_REJECTED, loan);
|
||||||
if (!statusEnum.hasStateOf(LoanStatus.fromInt(loan.getLoanStatus()))) {
|
if (!statusEnum.hasStateOf(LoanStatus.fromInt(loan.getLoanStatus()))) {
|
||||||
final LocalDate rejectedOn = command.localDateValueOfParameterNamed(Loan.REJECTED_ON_DATE);
|
final LocalDate rejectedOn = command.localDateValueOfParameterNamed(Loan.REJECTED_ON_DATE);
|
||||||
if (DateUtils.isBefore(rejectedOn, loan.getSubmittedOnDate())) {
|
if (DateUtils.isBefore(rejectedOn, loan.getSubmittedOnDate())) {
|
||||||
@@ -178,8 +174,16 @@ public final class LoanApplicationTransitionValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateApplicantWithdrawal(final String json) {
|
public void validateApplicantWithdrawal(final JsonCommand command, final Loan loan) {
|
||||||
|
// validate request body
|
||||||
|
final String json = command.json();
|
||||||
|
validateApplicantWithdrawalRequestBody(json);
|
||||||
|
|
||||||
|
// validate Loan application withdrawal by applicant
|
||||||
|
validateLoanApplicantWithdrawal(command, loan);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateApplicantWithdrawalRequestBody(String json) {
|
||||||
if (StringUtils.isBlank(json)) {
|
if (StringUtils.isBlank(json)) {
|
||||||
throw new InvalidJsonException();
|
throw new InvalidJsonException();
|
||||||
}
|
}
|
||||||
@@ -204,6 +208,37 @@ public final class LoanApplicationTransitionValidator {
|
|||||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateLoanApplicantWithdrawal(final JsonCommand command, final Loan loan) {
|
||||||
|
// validate client or group is active
|
||||||
|
checkClientOrGroupActive(loan);
|
||||||
|
|
||||||
|
// validate loan state transition
|
||||||
|
final LoanStatus statusEnum = defaultLoanLifecycleStateMachine.dryTransition(LoanEvent.LOAN_WITHDRAWN, loan);
|
||||||
|
if (!statusEnum.hasStateOf(LoanStatus.fromInt(loan.getLoanStatus()))) {
|
||||||
|
LocalDate withdrawnOn = command.localDateValueOfParameterNamed(Loan.WITHDRAWN_ON_DATE);
|
||||||
|
if (withdrawnOn == null) {
|
||||||
|
withdrawnOn = command.localDateValueOfParameterNamed(Loan.EVENT_DATE);
|
||||||
|
}
|
||||||
|
if (DateUtils.isBefore(withdrawnOn, loan.getSubmittedOnDate())) {
|
||||||
|
final String errorMessage = "The date on which a loan is withdrawn cannot be before its submittal date: "
|
||||||
|
+ loan.getSubmittedOnDate().toString();
|
||||||
|
throw new InvalidLoanStateTransitionException("withdraw", "cannot.be.before.submittal.date", errorMessage, command,
|
||||||
|
loan.getSubmittedOnDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
validateActivityNotBeforeClientOrGroupTransferDate(loan, LoanEvent.LOAN_WITHDRAWN, withdrawnOn);
|
||||||
|
|
||||||
|
if (DateUtils.isDateInTheFuture(withdrawnOn)) {
|
||||||
|
final String errorMessage = "The date on which a loan is withdrawn cannot be in the future.";
|
||||||
|
throw new InvalidLoanStateTransitionException("withdraw", "cannot.be.a.future.date", errorMessage, command);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final String errorMessage = "Only the loan applications with status 'Submitted and pending approval' are allowed to be withdrawn by applicant.";
|
||||||
|
throw new InvalidLoanStateTransitionException("withdraw", "cannot.withdraw", errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void validateActivityNotBeforeClientOrGroupTransferDate(final Loan loan, final LoanEvent event, final LocalDate activityDate) {
|
private void validateActivityNotBeforeClientOrGroupTransferDate(final Loan loan, final LoanEvent event, final LocalDate activityDate) {
|
||||||
if (loan.getClient() != null && loan.getClient().getOfficeJoiningDate() != null) {
|
if (loan.getClient() != null && loan.getClient().getOfficeJoiningDate() != null) {
|
||||||
final LocalDate clientOfficeJoiningDate = loan.getClient().getOfficeJoiningDate();
|
final LocalDate clientOfficeJoiningDate = loan.getClient().getOfficeJoiningDate();
|
||||||
@@ -217,6 +252,11 @@ public final class LoanApplicationTransitionValidator {
|
|||||||
action = "reject";
|
action = "reject";
|
||||||
postfix = "cannot.be.before.client.transfer.date";
|
postfix = "cannot.be.before.client.transfer.date";
|
||||||
}
|
}
|
||||||
|
case LOAN_WITHDRAWN -> {
|
||||||
|
errorMessage = "The date on which a loan is withdrawn cannot be earlier than client's transfer date to this office";
|
||||||
|
action = "withdraw";
|
||||||
|
postfix = "cannot.be.before.client.transfer.date";
|
||||||
|
}
|
||||||
default -> {
|
default -> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-49
@@ -26,13 +26,10 @@ import com.google.gson.JsonObject;
|
|||||||
import jakarta.persistence.PersistenceException;
|
import jakarta.persistence.PersistenceException;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.time.temporal.ChronoField;
|
import java.time.temporal.ChronoField;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -96,7 +93,6 @@ import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationTr
|
|||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationValidator;
|
||||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
import org.apache.fineract.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||||
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
|
||||||
import org.apache.fineract.portfolio.note.domain.Note;
|
import org.apache.fineract.portfolio.note.domain.Note;
|
||||||
import org.apache.fineract.portfolio.note.domain.NoteRepository;
|
import org.apache.fineract.portfolio.note.domain.NoteRepository;
|
||||||
import org.apache.fineract.portfolio.savings.data.GroupSavingsIndividualMonitoringAccountData;
|
import org.apache.fineract.portfolio.savings.data.GroupSavingsIndividualMonitoringAccountData;
|
||||||
@@ -492,6 +488,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
this.accountAssociationsRepository.delete(accountAssociations);
|
this.accountAssociationsRepository.delete(accountAssociations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: check if releaseAttachedCollaterals method can be used here
|
||||||
Set<LoanCollateralManagement> loanCollateralManagements = loan.getLoanCollateralManagements();
|
Set<LoanCollateralManagement> loanCollateralManagements = loan.getLoanCollateralManagements();
|
||||||
for (LoanCollateralManagement loanCollateralManagement : loanCollateralManagements) {
|
for (LoanCollateralManagement loanCollateralManagement : loanCollateralManagements) {
|
||||||
BigDecimal quantity = loanCollateralManagement.getQuantity();
|
BigDecimal quantity = loanCollateralManagement.getQuantity();
|
||||||
@@ -797,20 +794,23 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
Loan loan = retrieveLoanBy(loanId);
|
Loan loan = retrieveLoanBy(loanId);
|
||||||
|
|
||||||
// validate loan rejection
|
// validate loan rejection
|
||||||
loanApplicationTransitionValidator.validateRejection(command, loan, defaultLoanLifecycleStateMachine);
|
loanApplicationTransitionValidator.validateRejection(command, loan);
|
||||||
|
|
||||||
// check for mandatory entities
|
// check for mandatory entities
|
||||||
entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
|
entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
|
||||||
StatusEnum.REJECTED.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
|
StatusEnum.REJECTED.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
|
||||||
|
|
||||||
// loan application rejection
|
// loan application rejection
|
||||||
final Map<String, Object> changes = loanApplicationRejection(loan, command);
|
final AppUser currentUser = getAppUserIfPresent();
|
||||||
|
defaultLoanLifecycleStateMachine.transition(LoanEvent.LOAN_REJECTED, loan);
|
||||||
|
final Map<String, Object> changes = loanAssembler.updateLoanApplicationAttributesForRejection(loan, command, currentUser);
|
||||||
|
|
||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
loanRepositoryWrapper.saveAndFlush(loan);
|
loanRepositoryWrapper.saveAndFlush(loan);
|
||||||
final String noteText = command.stringValueOfParameterNamed("note");
|
final String noteText = command.stringValueOfParameterNamed("note");
|
||||||
createNote(noteText, loan);
|
createNote(noteText, loan);
|
||||||
}
|
}
|
||||||
|
|
||||||
businessEventNotifierService.notifyPostBusinessEvent(new LoanRejectedBusinessEvent(loan));
|
businessEventNotifierService.notifyPostBusinessEvent(new LoanRejectedBusinessEvent(loan));
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(command.commandId()) //
|
.withCommandId(command.commandId()) //
|
||||||
@@ -824,63 +824,31 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Object> loanApplicationRejection(Loan loan, final JsonCommand command) {
|
|
||||||
|
|
||||||
final AppUser currentUser = getAppUserIfPresent();
|
|
||||||
final LocalDate rejectedOn = command.localDateValueOfParameterNamed(Loan.REJECTED_ON_DATE);
|
|
||||||
|
|
||||||
loan.setRejectedOnDate(rejectedOn);
|
|
||||||
loan.setRejectedBy(currentUser);
|
|
||||||
loan.setClosedOnDate(rejectedOn);
|
|
||||||
loan.setClosedBy(currentUser);
|
|
||||||
|
|
||||||
defaultLoanLifecycleStateMachine.transition(LoanEvent.LOAN_REJECTED, loan);
|
|
||||||
|
|
||||||
final Map<String, Object> actualChanges = new LinkedHashMap<>();
|
|
||||||
final Locale locale = new Locale(command.locale());
|
|
||||||
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
|
|
||||||
|
|
||||||
actualChanges.put(Loan.PARAM_STATUS, LoanEnumerations.status(loan.getStatus()));
|
|
||||||
actualChanges.put(Loan.LOCALE, command.locale());
|
|
||||||
actualChanges.put(Loan.DATE_FORMAT, command.dateFormat());
|
|
||||||
actualChanges.put(Loan.REJECTED_ON_DATE, rejectedOn.format(fmt));
|
|
||||||
actualChanges.put(Loan.CLOSED_ON_DATE, rejectedOn.format(fmt));
|
|
||||||
|
|
||||||
return actualChanges;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult applicantWithdrawsFromApplication(final Long loanId, final JsonCommand command) {
|
public CommandProcessingResult applicantWithdrawsFromApplication(final Long loanId, final JsonCommand command) {
|
||||||
|
|
||||||
final AppUser currentUser = getAppUserIfPresent();
|
// retrieve loan
|
||||||
|
|
||||||
this.loanApplicationTransitionValidator.validateApplicantWithdrawal(command.json());
|
|
||||||
|
|
||||||
final Loan loan = retrieveLoanBy(loanId);
|
final Loan loan = retrieveLoanBy(loanId);
|
||||||
loanApplicationTransitionValidator.checkClientOrGroupActive(loan);
|
|
||||||
|
|
||||||
|
// validate withdrawal
|
||||||
|
loanApplicationTransitionValidator.validateApplicantWithdrawal(command, loan);
|
||||||
|
|
||||||
|
// check for mandatory entities
|
||||||
entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
|
entityDatatableChecksWritePlatformService.runTheCheckForProduct(loanId, EntityTables.LOAN.getName(),
|
||||||
StatusEnum.WITHDRAWN.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
|
StatusEnum.WITHDRAWN.getCode().longValue(), EntityTables.LOAN.getForeignKeyColumnNameOnDatatable(), loan.productId());
|
||||||
|
|
||||||
final Map<String, Object> changes = loan.loanApplicationWithdrawnByApplicant(currentUser, command,
|
// loan application withdrawal
|
||||||
defaultLoanLifecycleStateMachine);
|
final AppUser currentUser = getAppUserIfPresent();
|
||||||
|
defaultLoanLifecycleStateMachine.transition(LoanEvent.LOAN_WITHDRAWN, loan);
|
||||||
|
final Map<String, Object> changes = loanAssembler.updateLoanApplicationAttributesForWithdrawal(loan, command, currentUser);
|
||||||
// Release attached collaterals
|
// Release attached collaterals
|
||||||
if (loan.getLoanType().isIndividualAccount()) {
|
if (loan.getLoanType().isIndividualAccount()) {
|
||||||
Set<LoanCollateralManagement> loanCollateralManagements = loan.getLoanCollateralManagements();
|
releaseAttachedCollaterals(loan);
|
||||||
for (LoanCollateralManagement loanCollateralManagement : loanCollateralManagements) {
|
|
||||||
ClientCollateralManagement clientCollateralManagement = loanCollateralManagement.getClientCollateralManagement();
|
|
||||||
clientCollateralManagement
|
|
||||||
.updateQuantity(clientCollateralManagement.getQuantity().add(loanCollateralManagement.getQuantity()));
|
|
||||||
loanCollateralManagement.setClientCollateralManagement(clientCollateralManagement);
|
|
||||||
loanCollateralManagement.setIsReleased(true);
|
|
||||||
}
|
|
||||||
loan.updateLoanCollateral(loanCollateralManagements);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
this.loanRepositoryWrapper.saveAndFlush(loan);
|
loanRepositoryWrapper.saveAndFlush(loan);
|
||||||
|
|
||||||
final String noteText = command.stringValueOfParameterNamed("note");
|
final String noteText = command.stringValueOfParameterNamed("note");
|
||||||
createNote(noteText, loan);
|
createNote(noteText, loan);
|
||||||
@@ -983,4 +951,15 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void releaseAttachedCollaterals(Loan loan) {
|
||||||
|
Set<LoanCollateralManagement> loanCollateralManagements = loan.getLoanCollateralManagements();
|
||||||
|
for (LoanCollateralManagement loanCollateralManagement : loanCollateralManagements) {
|
||||||
|
ClientCollateralManagement clientCollateralManagement = loanCollateralManagement.getClientCollateralManagement();
|
||||||
|
clientCollateralManagement.updateQuantity(clientCollateralManagement.getQuantity().add(loanCollateralManagement.getQuantity()));
|
||||||
|
loanCollateralManagement.setClientCollateralManagement(clientCollateralManagement);
|
||||||
|
loanCollateralManagement.setIsReleased(true);
|
||||||
|
}
|
||||||
|
loan.updateLoanCollateral(loanCollateralManagements);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+49
@@ -22,9 +22,11 @@ import com.google.gson.JsonArray;
|
|||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -96,8 +98,10 @@ import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
|
|||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
|
||||||
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations;
|
||||||
import org.apache.fineract.portfolio.rate.domain.Rate;
|
import org.apache.fineract.portfolio.rate.domain.Rate;
|
||||||
import org.apache.fineract.portfolio.rate.service.RateAssembler;
|
import org.apache.fineract.portfolio.rate.service.RateAssembler;
|
||||||
|
import org.apache.fineract.useradministration.domain.AppUser;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class LoanAssembler {
|
public class LoanAssembler {
|
||||||
@@ -833,4 +837,49 @@ public class LoanAssembler {
|
|||||||
|
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> updateLoanApplicationAttributesForWithdrawal(Loan loan, JsonCommand command, AppUser currentUser) {
|
||||||
|
final Map<String, Object> actualChanges = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
LocalDate withdrawnOn = command.localDateValueOfParameterNamed(Loan.WITHDRAWN_ON_DATE);
|
||||||
|
if (withdrawnOn == null) {
|
||||||
|
withdrawnOn = command.localDateValueOfParameterNamed(Loan.EVENT_DATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
loan.setWithdrawnOnDate(withdrawnOn);
|
||||||
|
loan.setWithdrawnBy(currentUser);
|
||||||
|
loan.setClosedOnDate(withdrawnOn);
|
||||||
|
loan.setClosedBy(currentUser);
|
||||||
|
|
||||||
|
final Locale locale = new Locale(command.locale());
|
||||||
|
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
|
||||||
|
|
||||||
|
actualChanges.put(Loan.PARAM_STATUS, LoanEnumerations.status(loan.getStatus()));
|
||||||
|
actualChanges.put(Loan.LOCALE, command.locale());
|
||||||
|
actualChanges.put(Loan.DATE_FORMAT, command.dateFormat());
|
||||||
|
actualChanges.put(Loan.WITHDRAWN_ON_DATE, withdrawnOn.format(fmt));
|
||||||
|
actualChanges.put(Loan.CLOSED_ON_DATE, withdrawnOn.format(fmt));
|
||||||
|
return actualChanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> updateLoanApplicationAttributesForRejection(Loan loan, JsonCommand command, AppUser currentUser) {
|
||||||
|
final Map<String, Object> actualChanges = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
final LocalDate rejectedOn = command.localDateValueOfParameterNamed(Loan.REJECTED_ON_DATE);
|
||||||
|
|
||||||
|
loan.setRejectedOnDate(rejectedOn);
|
||||||
|
loan.setRejectedBy(currentUser);
|
||||||
|
loan.setClosedOnDate(rejectedOn);
|
||||||
|
loan.setClosedBy(currentUser);
|
||||||
|
|
||||||
|
final Locale locale = new Locale(command.locale());
|
||||||
|
final DateTimeFormatter fmt = DateTimeFormatter.ofPattern(command.dateFormat()).withLocale(locale);
|
||||||
|
|
||||||
|
actualChanges.put(Loan.PARAM_STATUS, LoanEnumerations.status(loan.getStatus()));
|
||||||
|
actualChanges.put(Loan.LOCALE, command.locale());
|
||||||
|
actualChanges.put(Loan.DATE_FORMAT, command.dateFormat());
|
||||||
|
actualChanges.put(Loan.REJECTED_ON_DATE, rejectedOn.format(fmt));
|
||||||
|
actualChanges.put(Loan.CLOSED_ON_DATE, rejectedOn.format(fmt));
|
||||||
|
return actualChanges;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user