FINERACT-2317: Add new endpoints to indirectly modify loan approved amount
This commit is contained in:
+37
@@ -924,6 +924,34 @@ public class LoansApiResource {
|
||||
return getLoanApprovedAmountHistory(null, ExternalIdFactory.produce(loanExternalId));
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("{loanId}/available-disbursement-amount")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Modifies the available disbursement amount of the loan", description = "Modifies the available disbursement amount of the loan, this indirectly modifies the approved amount that can be disbursed on the loan")
|
||||
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = LoansApiResourceSwagger.PutLoansAvailableDisbursementAmountRequest.class)))
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoansApiResourceSwagger.PutLoansAvailableDisbursementAmountResponse.class))) })
|
||||
public CommandProcessingResult modifyLoanAvailableDisbursementAmount(
|
||||
@PathParam("loanId") @Parameter(description = "loanId", required = true) final Long loanId, @Context final UriInfo uriInfo,
|
||||
@Parameter(hidden = true) final String apiRequestBodyAsJson) {
|
||||
return modifyLoanAvailableDisbursementAmount(loanId, ExternalId.empty(), apiRequestBodyAsJson);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("external-id/{loanExternalId}/available-disbursement-amount")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Modifies the available disbursement amount of the loan", description = "Modifies the available disbursement amount of the loan, this indirectly modifies the approved amount that can be disbursed on the loan")
|
||||
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = LoansApiResourceSwagger.PutLoansAvailableDisbursementAmountRequest.class)))
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoansApiResourceSwagger.PutLoansAvailableDisbursementAmountResponse.class))) })
|
||||
public CommandProcessingResult modifyLoanAvailableDisbursementAmount(
|
||||
@PathParam("loanExternalId") @Parameter(description = "loanExternalId", required = true) final String loanExternalId,
|
||||
@Context final UriInfo uriInfo, @Parameter(hidden = true) final String apiRequestBodyAsJson) {
|
||||
return modifyLoanAvailableDisbursementAmount(null, ExternalIdFactory.produce(loanExternalId), apiRequestBodyAsJson);
|
||||
}
|
||||
|
||||
private String retrieveApprovalTemplate(final Long loanId, final String loanExternalIdStr, final String templateType,
|
||||
final UriInfo uriInfo) {
|
||||
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
|
||||
@@ -1350,4 +1378,13 @@ public class LoansApiResource {
|
||||
return loanApprovedAmountHistoryRepository.findAllByLoanId(resolvedLoanId, sortedByCreationDate);
|
||||
}
|
||||
|
||||
private CommandProcessingResult modifyLoanAvailableDisbursementAmount(Long loanId, ExternalId loanExternalId,
|
||||
String apiRequestBodyAsJson) {
|
||||
Long resolvedLoanId = loanId == null ? loanReadPlatformService.getResolvedLoanId(loanExternalId) : loanId;
|
||||
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
|
||||
CommandWrapper commandRequest = builder.updateLoanAvailableDisbursementAmount(resolvedLoanId).build();
|
||||
|
||||
return this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+47
@@ -1814,4 +1814,51 @@ final class LoansApiResourceSwagger {
|
||||
@Schema(description = "PutLoansApprovedAmountChanges")
|
||||
public PutLoansApprovedAmountChanges changes;
|
||||
}
|
||||
|
||||
@Schema(description = "PutLoansAvailableDisbursementAmountRequest")
|
||||
public static final class PutLoansAvailableDisbursementAmountRequest {
|
||||
|
||||
private PutLoansAvailableDisbursementAmountRequest() {}
|
||||
|
||||
@Schema(example = "1000")
|
||||
public BigDecimal amount;
|
||||
@Schema(example = "en")
|
||||
public String locale;
|
||||
}
|
||||
|
||||
@Schema(description = "PutLoansAvailableDisbursementAmountResponse")
|
||||
public static final class PutLoansAvailableDisbursementAmountResponse {
|
||||
|
||||
private PutLoansAvailableDisbursementAmountResponse() {}
|
||||
|
||||
static final class PutLoansAvailableDisbursementAmountChanges {
|
||||
|
||||
private PutLoansAvailableDisbursementAmountChanges() {}
|
||||
|
||||
@Schema(example = "1000")
|
||||
public BigDecimal oldApprovedAmount;
|
||||
@Schema(example = "1000")
|
||||
public BigDecimal newApprovedAmount;
|
||||
@Schema(example = "1000")
|
||||
public BigDecimal oldAvailableDisbursementAmount;
|
||||
@Schema(example = "1000")
|
||||
public BigDecimal newAvailableDisbursementAmount;
|
||||
@Schema(example = "en_GB")
|
||||
public String locale;
|
||||
}
|
||||
|
||||
@Schema(example = "3")
|
||||
public Long resourceId;
|
||||
@Schema(example = "95174ff9-1a75-4d72-a413-6f9b1cb988b7")
|
||||
public String resourceExternalId;
|
||||
@Schema(example = "2")
|
||||
public Long officeId;
|
||||
@Schema(example = "6")
|
||||
public Long clientId;
|
||||
@Schema(example = "10")
|
||||
public Long groupId;
|
||||
|
||||
@Schema(description = "PutLoansAvailableDisbursementAmountChanges")
|
||||
public PutLoansAvailableDisbursementAmountChanges changes;
|
||||
}
|
||||
}
|
||||
|
||||
+56
-1
@@ -35,6 +35,7 @@ import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||
import org.apache.fineract.portfolio.common.service.Validator;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
|
||||
@@ -95,10 +96,64 @@ public final class LoanApprovedAmountValidatorImpl implements LoanApprovedAmount
|
||||
}
|
||||
|
||||
BigDecimal totalPrincipalOnLoan = loan.getSummary().getTotalPrincipal();
|
||||
if (MathUtil.isLessThan(newApprovedAmount, totalPrincipalOnLoan)) {
|
||||
BigDecimal totalExpectedPrincipal = loan.getDisbursementDetails().stream().filter(t -> t.actualDisbursementDate() == null)
|
||||
.map(LoanDisbursementDetails::principal).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
if (MathUtil.isLessThan(newApprovedAmount, totalPrincipalOnLoan.add(totalExpectedPrincipal))) {
|
||||
baseDataValidator.reset().parameter(LoanApiConstants.amountParameterName)
|
||||
.failWithCode("less.than.disbursed.principal.and.capitalized.income");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateLoanAvailableDisbursementAmountModification(JsonCommand command) {
|
||||
String json = command.json();
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
|
||||
final Set<String> supportedParameters = new HashSet<>(
|
||||
Arrays.asList(LoanApiConstants.amountParameterName, LoanApiConstants.localeParameterName));
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
|
||||
|
||||
final BigDecimal newAvailableDisbursementAmount = this.fromApiJsonHelper
|
||||
.extractBigDecimalWithLocaleNamed(LoanApiConstants.amountParameterName, element);
|
||||
|
||||
Validator.validateOrThrow("loan.available.disbursement.amount", baseDataValidator -> {
|
||||
baseDataValidator.reset().parameter(LoanApiConstants.amountParameterName).value(newAvailableDisbursementAmount).notNull();
|
||||
});
|
||||
|
||||
Validator.validateOrThrowDomainViolation("loan.available.disbursement.amount", baseDataValidator -> {
|
||||
baseDataValidator.reset().parameter(LoanApiConstants.amountParameterName).value(newAvailableDisbursementAmount)
|
||||
.zeroOrPositiveAmount();
|
||||
|
||||
final Long loanId = command.getLoanId();
|
||||
Loan loan = this.loanRepository.findById(loanId).orElseThrow(() -> new LoanNotFoundException(loanId));
|
||||
|
||||
if (INVALID_LOAN_STATUSES_FOR_APPROVED_AMOUNT_MODIFICATION.contains(loan.getStatus())) {
|
||||
baseDataValidator.reset()
|
||||
.failWithCodeNoParameterAddedToErrorCode("loan.status.not.valid.for.available.disbursement.amount.modification");
|
||||
}
|
||||
|
||||
BigDecimal maximumThresholdForApprovedAmount;
|
||||
if (loan.loanProduct().isAllowApprovedDisbursedAmountsOverApplied()) {
|
||||
maximumThresholdForApprovedAmount = loanApplicationValidator.getOverAppliedMax(loan);
|
||||
} else {
|
||||
maximumThresholdForApprovedAmount = loan.getProposedPrincipal();
|
||||
}
|
||||
|
||||
BigDecimal expectedDisbursementAmount = loan.getDisbursementDetails().stream().filter(t -> t.actualDisbursementDate() == null)
|
||||
.map(LoanDisbursementDetails::principal).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
BigDecimal maximumAvailableDisbursementThreshold = maximumThresholdForApprovedAmount
|
||||
.subtract(loan.getSummary().getTotalPrincipal()).subtract(expectedDisbursementAmount);
|
||||
if (MathUtil.isGreaterThan(newAvailableDisbursementAmount, maximumAvailableDisbursementThreshold)) {
|
||||
baseDataValidator.reset().parameter(LoanApiConstants.amountParameterName)
|
||||
.failWithCode("can't.be.greater.than.maximum.available.disbursement.amount.calculation");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user