Delinquency buckets management for Loans (#2442)
Co-authored-by: Jose Alberto Hernandez <alberto@MacBook-Pro.local>
This commit is contained in:
co-authored by
Jose Alberto Hernandez
parent
f78a596878
commit
9e949887b9
+46
@@ -3494,4 +3494,50 @@ public class CommandWrapperBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CommandWrapperBuilder createDelinquencyRange() {
|
||||||
|
this.actionName = "CREATE";
|
||||||
|
this.entityName = "DELINQUENCY_RANGE";
|
||||||
|
this.href = "/delinquency/range";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandWrapperBuilder updateDelinquencyRange(final Long delinquencyRangeId) {
|
||||||
|
this.actionName = "UPDATE";
|
||||||
|
this.entityName = "DELINQUENCY_RANGE";
|
||||||
|
this.entityId = delinquencyRangeId;
|
||||||
|
this.href = "/delinquency/range";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandWrapperBuilder deleteDelinquencyRange(final Long delinquencyRangeId) {
|
||||||
|
this.actionName = "DELETE";
|
||||||
|
this.entityName = "DELINQUENCY_RANGE";
|
||||||
|
this.entityId = delinquencyRangeId;
|
||||||
|
this.href = "/delinquency/range";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandWrapperBuilder createDelinquencyBucket() {
|
||||||
|
this.actionName = "CREATE";
|
||||||
|
this.entityName = "DELINQUENCY_BUCKET";
|
||||||
|
this.href = "/delinquency/bucket";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandWrapperBuilder updateDelinquencyBucket(final Long delinquencyBucketId) {
|
||||||
|
this.actionName = "UPDATE";
|
||||||
|
this.entityName = "DELINQUENCY_BUCKET";
|
||||||
|
this.entityId = delinquencyBucketId;
|
||||||
|
this.href = "/delinquency/bucket";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandWrapperBuilder deleteDelinquencyBucket(final Long delinquencyBucketId) {
|
||||||
|
this.actionName = "DELETE";
|
||||||
|
this.entityName = "DELINQUENCY_BUCKET";
|
||||||
|
this.entityId = delinquencyBucketId;
|
||||||
|
this.href = "/delinquency/bucket";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.infrastructure.core.validator;
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||||
|
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
|
||||||
|
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||||
|
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class ParseAndValidator {
|
||||||
|
|
||||||
|
protected JsonObject extractJsonObject(final FromJsonHelper jsonHelper, final JsonCommand command) {
|
||||||
|
String json = command.json();
|
||||||
|
if (StringUtils.isBlank(json)) {
|
||||||
|
throw new InvalidJsonException();
|
||||||
|
}
|
||||||
|
|
||||||
|
final JsonElement element = jsonHelper.parse(json);
|
||||||
|
return element.getAsJsonObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void throwExceptionIfValidationWarningsExist(DataValidatorBuilder dataValidator) {
|
||||||
|
if (dataValidator.hasError()) {
|
||||||
|
log.error("Validation errors: {}", dataValidator.getDataValidationErrors());
|
||||||
|
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||||
|
dataValidator.getDataValidationErrors());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.api;
|
||||||
|
|
||||||
|
public final class DelinquencyApiConstants {
|
||||||
|
|
||||||
|
private DelinquencyApiConstants() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String NAME_PARAM_NAME = "name";
|
||||||
|
public static final String CLASSIFICATION_PARAM_NAME = "classification";
|
||||||
|
public static final String RANGES_PARAM_NAME = "ranges";
|
||||||
|
public static final String MINIMUMAGEDAYS_PARAM_NAME = "minimumAgeDays";
|
||||||
|
public static final String MAXIMUMAGEDAYS_PARAM_NAME = "maximumAgeDays";
|
||||||
|
public static final String LOCALE_PARAM_NAME = "locale";
|
||||||
|
|
||||||
|
}
|
||||||
+235
@@ -0,0 +1,235 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.api;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import java.util.Collection;
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.DELETE;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.PUT;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.Context;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.commands.domain.CommandWrapper;
|
||||||
|
import org.apache.fineract.commands.service.CommandWrapperBuilder;
|
||||||
|
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||||
|
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||||
|
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||||
|
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Path("delinquency")
|
||||||
|
@Component
|
||||||
|
@Tag(name = "Delinquency Range and Buckets Management", description = "Delinquency Range and Buckets management enables you to set up, fetch and adjust Delinquency overdue ranges")
|
||||||
|
public class DelinquencyApiResource {
|
||||||
|
|
||||||
|
private final ApiRequestParameterHelper parameterHelper;
|
||||||
|
private final PlatformSecurityContext securityContext;
|
||||||
|
private final DefaultToApiJsonSerializer<DelinquencyBucketData> jsonSerializerBucket;
|
||||||
|
private final DefaultToApiJsonSerializer<DelinquencyRangeData> jsonSerializerRange;
|
||||||
|
private final DelinquencyReadPlatformService readPlatformService;
|
||||||
|
private final PortfolioCommandSourceWritePlatformService commandWritePlatformService;
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("ranges")
|
||||||
|
@Consumes({ MediaType.TEXT_HTML, MediaType.APPLICATION_JSON })
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Operation(summary = "List all Delinquency Ranges", description = "")
|
||||||
|
@ApiResponses({
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = DelinquencyApiResourceSwagger.GetDelinquencyRangesResponse.class)))) })
|
||||||
|
public String getDelinquencyRanges(@Context final UriInfo uriInfo) {
|
||||||
|
securityContext.authenticatedUser().validateHasReadPermission("DELINQUENCY_BUCKET");
|
||||||
|
final Collection<DelinquencyRangeData> delinquencyRangeData = this.readPlatformService.retrieveAllDelinquencyRanges();
|
||||||
|
ApiRequestJsonSerializationSettings settings = parameterHelper.process(uriInfo.getQueryParameters());
|
||||||
|
return this.jsonSerializerRange.serialize(settings, delinquencyRangeData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("ranges/{delinquencyRangeId}")
|
||||||
|
@Consumes({ MediaType.TEXT_HTML, MediaType.APPLICATION_JSON })
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Operation(summary = "Retrieve a specific Delinquency Range based on the Id", description = "")
|
||||||
|
@ApiResponses({
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.GetDelinquencyRangesResponse.class))) })
|
||||||
|
public String getDelinquencyRange(
|
||||||
|
@PathParam("delinquencyRangeId") @Parameter(description = "delinquencyRangeId") final Long delinquencyRangeId,
|
||||||
|
@Context final UriInfo uriInfo) {
|
||||||
|
securityContext.authenticatedUser().validateHasReadPermission("DELINQUENCY_BUCKET");
|
||||||
|
final DelinquencyRangeData delinquencyRangeData = this.readPlatformService.retrieveDelinquencyRange(delinquencyRangeId);
|
||||||
|
ApiRequestJsonSerializationSettings settings = parameterHelper.process(uriInfo.getQueryParameters());
|
||||||
|
return this.jsonSerializerRange.serialize(settings, delinquencyRangeData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("ranges")
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
@Operation(summary = "Create Delinquency Range", description = "")
|
||||||
|
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PostDelinquencyRangeRequest.class)))
|
||||||
|
@ApiResponses({
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PostDelinquencyRangeResponse.class))) })
|
||||||
|
public String createDelinquencyRange(final String jsonRequestBody, @Context UriInfo uriInfo) {
|
||||||
|
securityContext.authenticatedUser().validateHasCreatePermission("DELINQUENCY_BUCKET");
|
||||||
|
final CommandWrapper commandRequest = new CommandWrapperBuilder().createDelinquencyRange().withJson(jsonRequestBody).build();
|
||||||
|
|
||||||
|
CommandProcessingResult result = commandWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
return jsonSerializerRange.serialize(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("ranges/{delinquencyRangeId}")
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
@Operation(summary = "Update Delinquency Range based on the Id", description = "")
|
||||||
|
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PostDelinquencyRangeRequest.class)))
|
||||||
|
@ApiResponses({
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PutDelinquencyRangeResponse.class))) })
|
||||||
|
public String updateDelinquencyRange(
|
||||||
|
@PathParam("delinquencyRangeId") @Parameter(description = "delinquencyRangeId") final Long delinquencyRangeId,
|
||||||
|
final String jsonRequestBody, @Context UriInfo uriInfo) {
|
||||||
|
securityContext.authenticatedUser().validateHasUpdatePermission("DELINQUENCY_BUCKET");
|
||||||
|
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateDelinquencyRange(delinquencyRangeId)
|
||||||
|
.withJson(jsonRequestBody).build();
|
||||||
|
|
||||||
|
CommandProcessingResult result = commandWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
return jsonSerializerRange.serialize(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Path("ranges/{delinquencyRangeId}")
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
@Operation(summary = "Update Delinquency Range based on the Id", description = "")
|
||||||
|
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PostDelinquencyRangeRequest.class)))
|
||||||
|
@ApiResponses({
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.DeleteDelinquencyRangeResponse.class))) })
|
||||||
|
public String deleteDelinquencyRange(
|
||||||
|
@PathParam("delinquencyRangeId") @Parameter(description = "delinquencyRangeId") final Long delinquencyRangeId,
|
||||||
|
@Context UriInfo uriInfo) {
|
||||||
|
securityContext.authenticatedUser().validateHasDeletePermission("DELINQUENCY_BUCKET");
|
||||||
|
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteDelinquencyRange(delinquencyRangeId).build();
|
||||||
|
|
||||||
|
CommandProcessingResult result = commandWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
return jsonSerializerRange.serialize(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("buckets")
|
||||||
|
@Consumes({ MediaType.TEXT_HTML, MediaType.APPLICATION_JSON })
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Operation(summary = "List all Delinquency Buckets", description = "")
|
||||||
|
@ApiResponses({
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = DelinquencyApiResourceSwagger.GetDelinquencyBucketsResponse.class)))) })
|
||||||
|
public String getDelinquencyBuckets(@Context final UriInfo uriInfo) {
|
||||||
|
securityContext.authenticatedUser().validateHasReadPermission("DELINQUENCY_BUCKET");
|
||||||
|
final Collection<DelinquencyBucketData> delinquencyBucketData = this.readPlatformService.retrieveAllDelinquencyBuckets();
|
||||||
|
ApiRequestJsonSerializationSettings settings = parameterHelper.process(uriInfo.getQueryParameters());
|
||||||
|
return this.jsonSerializerBucket.serialize(settings, delinquencyBucketData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("buckets/{delinquencyBucketId}")
|
||||||
|
@Consumes({ MediaType.TEXT_HTML, MediaType.APPLICATION_JSON })
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Operation(summary = "Retrieve a specific Delinquency Bucket based on the Id", description = "")
|
||||||
|
@ApiResponses({
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.GetDelinquencyBucketsResponse.class))) })
|
||||||
|
public String getDelinquencyBucket(
|
||||||
|
@PathParam("delinquencyBucketId") @Parameter(description = "delinquencyBucketId") final Long delinquencyBucketId,
|
||||||
|
@Context final UriInfo uriInfo) {
|
||||||
|
securityContext.authenticatedUser().validateHasReadPermission("DELINQUENCY_BUCKET");
|
||||||
|
final DelinquencyBucketData delinquencyBucketData = this.readPlatformService.retrieveDelinquencyBucket(delinquencyBucketId);
|
||||||
|
ApiRequestJsonSerializationSettings settings = parameterHelper.process(uriInfo.getQueryParameters());
|
||||||
|
return this.jsonSerializerBucket.serialize(settings, delinquencyBucketData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("buckets")
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
@Operation(summary = "Create Delinquency Bucket", description = "")
|
||||||
|
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PostDelinquencyBucketRequest.class)))
|
||||||
|
@ApiResponses({
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PostDelinquencyBucketResponse.class))) })
|
||||||
|
public String createDelinquencyBucket(final String jsonRequestBody, @Context UriInfo uriInfo) {
|
||||||
|
securityContext.authenticatedUser().validateHasCreatePermission("DELINQUENCY_BUCKET");
|
||||||
|
final CommandWrapper commandRequest = new CommandWrapperBuilder().createDelinquencyBucket().withJson(jsonRequestBody).build();
|
||||||
|
|
||||||
|
CommandProcessingResult result = commandWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
return jsonSerializerRange.serialize(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("buckets/{delinquencyBucketId}")
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
@Operation(summary = "Update Delinquency Bucket based on the Id", description = "")
|
||||||
|
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PostDelinquencyBucketRequest.class)))
|
||||||
|
@ApiResponses({
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PutDelinquencyBucketResponse.class))) })
|
||||||
|
public String updateDelinquencyBucket(
|
||||||
|
@PathParam("delinquencyBucketId") @Parameter(description = "delinquencyBucketId") final Long delinquencyBucketId,
|
||||||
|
final String jsonRequestBody, @Context UriInfo uriInfo) {
|
||||||
|
securityContext.authenticatedUser().validateHasUpdatePermission("DELINQUENCY_BUCKET");
|
||||||
|
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateDelinquencyBucket(delinquencyBucketId)
|
||||||
|
.withJson(jsonRequestBody).build();
|
||||||
|
|
||||||
|
CommandProcessingResult result = commandWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
return jsonSerializerRange.serialize(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Path("buckets/{delinquencyBucketId}")
|
||||||
|
@Consumes({ MediaType.APPLICATION_JSON })
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON })
|
||||||
|
@Operation(summary = "Delete Delinquency Bucket based on the Id", description = "")
|
||||||
|
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PostDelinquencyBucketRequest.class)))
|
||||||
|
@ApiResponses({
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.DeleteDelinquencyBucketResponse.class))) })
|
||||||
|
public String deleteDelinquencyBucket(
|
||||||
|
@PathParam("delinquencyBucketId") @Parameter(description = "delinquencyBucketId") final Long delinquencyBucketId,
|
||||||
|
@Context UriInfo uriInfo) {
|
||||||
|
securityContext.authenticatedUser().validateHasDeletePermission("DELINQUENCY_BUCKET");
|
||||||
|
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteDelinquencyBucket(delinquencyBucketId).build();
|
||||||
|
|
||||||
|
CommandProcessingResult result = commandWritePlatformService.logCommandSource(commandRequest);
|
||||||
|
return jsonSerializerRange.serialize(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+136
@@ -0,0 +1,136 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.api;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
public final class DelinquencyApiResourceSwagger {
|
||||||
|
|
||||||
|
private DelinquencyApiResourceSwagger() {}
|
||||||
|
|
||||||
|
@Schema(description = "GetDelinquencyRangesResponse")
|
||||||
|
public static final class GetDelinquencyRangesResponse {
|
||||||
|
|
||||||
|
private GetDelinquencyRangesResponse() {}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Integer id;
|
||||||
|
@Schema(example = "Delinquent 1")
|
||||||
|
public String classification;
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Long minimumAgeDays;
|
||||||
|
@Schema(example = "3")
|
||||||
|
public Long maximumAgeDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Schema(description = "GetDelinquencyBucketsResponse")
|
||||||
|
public static final class GetDelinquencyBucketsResponse {
|
||||||
|
|
||||||
|
private GetDelinquencyBucketsResponse() {}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Integer id;
|
||||||
|
@Schema(example = "Delinquent Bucket Set 1")
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
public GetDelinquencyRangesResponse[] ranges;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Schema(description = "PostDelinquencyRangeRequest")
|
||||||
|
public static final class PostDelinquencyRangeRequest {
|
||||||
|
|
||||||
|
private PostDelinquencyRangeRequest() {}
|
||||||
|
|
||||||
|
@Schema(example = "Delinquent 1")
|
||||||
|
public String classification;
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Integer minimumAgeDays;
|
||||||
|
@Schema(example = "3")
|
||||||
|
public Integer maximumAgeDays;
|
||||||
|
@Schema(example = "en")
|
||||||
|
public String locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Schema(description = "PostDelinquencyRangeResponse")
|
||||||
|
public static final class PostDelinquencyRangeResponse {
|
||||||
|
|
||||||
|
private PostDelinquencyRangeResponse() {}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Integer resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Schema(description = "PutDelinquencyRangeResponse")
|
||||||
|
public static final class PutDelinquencyRangeResponse {
|
||||||
|
|
||||||
|
private PutDelinquencyRangeResponse() {}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Integer resourceId;
|
||||||
|
public PostDelinquencyRangeRequest changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Schema(description = "DeleteDelinquencyRangeResponse")
|
||||||
|
public static final class DeleteDelinquencyRangeResponse {
|
||||||
|
|
||||||
|
private DeleteDelinquencyRangeResponse() {}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Integer resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Schema(description = "PostDelinquencyBucketRequest")
|
||||||
|
public static final class PostDelinquencyBucketRequest {
|
||||||
|
|
||||||
|
private PostDelinquencyBucketRequest() {}
|
||||||
|
|
||||||
|
@Schema(example = "Delinquent 1")
|
||||||
|
public String name;
|
||||||
|
@Schema(example = "[1,2,3]")
|
||||||
|
public Long[] ranges;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Schema(description = "PostDelinquencyBucketResponse")
|
||||||
|
public static final class PostDelinquencyBucketResponse {
|
||||||
|
|
||||||
|
private PostDelinquencyBucketResponse() {}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Integer resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Schema(description = "PutDelinquencyBucketResponse")
|
||||||
|
public static final class PutDelinquencyBucketResponse {
|
||||||
|
|
||||||
|
private PutDelinquencyBucketResponse() {}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Integer resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Schema(description = "DeleteDelinquencyBucketResponse")
|
||||||
|
public static final class DeleteDelinquencyBucketResponse {
|
||||||
|
|
||||||
|
private DeleteDelinquencyBucketResponse() {}
|
||||||
|
|
||||||
|
@Schema(example = "1")
|
||||||
|
public Integer resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@ToString
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class DelinquencyBucketData implements Serializable {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
private List<DelinquencyRangeData> ranges;
|
||||||
|
|
||||||
|
}
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@ToString
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class DelinquencyRangeData implements Serializable {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String classification;
|
||||||
|
private Integer minimumAgeDays;
|
||||||
|
private Integer maximumAgeDays;
|
||||||
|
|
||||||
|
public static DelinquencyRangeData instance(String classification, Integer minimumAgeDays, Integer maximumAgeDays) {
|
||||||
|
return new DelinquencyRangeData(null, classification, minimumAgeDays, maximumAgeDays);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DelinquencyRangeData reference(Long id) {
|
||||||
|
return new DelinquencyRangeData(id, "", 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+58
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.domain;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.JoinTable;
|
||||||
|
import javax.persistence.ManyToMany;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.UniqueConstraint;
|
||||||
|
import javax.persistence.Version;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Entity
|
||||||
|
@Table(name = "m_delinquency_bucket", uniqueConstraints = {
|
||||||
|
@UniqueConstraint(name = "uq_delinquency_bucket_name", columnNames = { "name" }) })
|
||||||
|
public class DelinquencyBucket extends AbstractAuditableWithUTCDateTimeCustom {
|
||||||
|
|
||||||
|
@Column(name = "name", nullable = false)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ManyToMany(fetch = FetchType.LAZY)
|
||||||
|
@JoinTable(name = "m_delinquency_bucket_mappings", joinColumns = @JoinColumn(name = "delinquency_bucket_id"), inverseJoinColumns = @JoinColumn(name = "delinquency_range_id"))
|
||||||
|
private Set<DelinquencyRange> ranges;
|
||||||
|
|
||||||
|
@Version
|
||||||
|
private Long version;
|
||||||
|
|
||||||
|
public DelinquencyBucket(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.domain;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.UniqueConstraint;
|
||||||
|
import javax.persistence.Version;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Entity
|
||||||
|
@Table(name = "m_delinquency_bucket_mappings", uniqueConstraints = {
|
||||||
|
@UniqueConstraint(name = "uq_delinquency_bucket_mapping", columnNames = { "delinquencyBucket", "delinquencyRange" }) })
|
||||||
|
public class DelinquencyBucketMappings extends AbstractAuditableWithUTCDateTimeCustom {
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "delinquency_bucket_id", nullable = false)
|
||||||
|
private DelinquencyBucket delinquencyBucket;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "delinquency_range_id", nullable = false)
|
||||||
|
private DelinquencyRange delinquencyRange;
|
||||||
|
|
||||||
|
@Version
|
||||||
|
private Long version;
|
||||||
|
|
||||||
|
public DelinquencyBucketMappings(DelinquencyBucket delinquencyBucket, DelinquencyRange delinquencyRange) {
|
||||||
|
this.delinquencyBucket = delinquencyBucket;
|
||||||
|
this.delinquencyRange = delinquencyRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DelinquencyBucketMappings instance(DelinquencyBucket delinquencyBucket, DelinquencyRange delinquencyRange) {
|
||||||
|
return new DelinquencyBucketMappings(delinquencyBucket, delinquencyRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.domain;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
|
||||||
|
public interface DelinquencyBucketMappingsRepository
|
||||||
|
extends JpaRepository<DelinquencyBucketMappings, Long>, JpaSpecificationExecutor<DelinquencyBucketMappings> {
|
||||||
|
|
||||||
|
List<DelinquencyBucketMappings> findByDelinquencyBucket(DelinquencyBucket delinquencyBucket);
|
||||||
|
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.domain;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
|
||||||
|
public interface DelinquencyBucketRepository extends JpaRepository<DelinquencyBucket, Long>, JpaSpecificationExecutor<DelinquencyBucket> {
|
||||||
|
|
||||||
|
Optional<DelinquencyBucket> findByName(String name);
|
||||||
|
}
|
||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.domain;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.UniqueConstraint;
|
||||||
|
import javax.persistence.Version;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Entity
|
||||||
|
@Table(name = "m_delinquency_range", uniqueConstraints = {
|
||||||
|
@UniqueConstraint(name = "uq_delinquency_range_classification", columnNames = { "classification" }) })
|
||||||
|
public class DelinquencyRange extends AbstractAuditableWithUTCDateTimeCustom {
|
||||||
|
|
||||||
|
@Column(name = "classification", nullable = false)
|
||||||
|
private String classification;
|
||||||
|
|
||||||
|
@Column(name = "min_age_days", nullable = false)
|
||||||
|
private Integer minimumAgeDays;
|
||||||
|
|
||||||
|
@Column(name = "max_age_days", nullable = true)
|
||||||
|
private Integer maximumAgeDays;
|
||||||
|
|
||||||
|
@Version
|
||||||
|
private Long version;
|
||||||
|
|
||||||
|
protected DelinquencyRange(@NotNull String classification, @NotNull Integer minimumAgeDays, Integer maximumAgeDays) {
|
||||||
|
this.classification = classification;
|
||||||
|
this.minimumAgeDays = minimumAgeDays;
|
||||||
|
this.maximumAgeDays = maximumAgeDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DelinquencyRange instance(@NotNull String classification, @NotNull Integer minimumAge, Integer maximumAge) {
|
||||||
|
return new DelinquencyRange(classification, minimumAge, maximumAge);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.domain;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
|
||||||
|
public interface DelinquencyRangeRepository extends JpaRepository<DelinquencyRange, Long>, JpaSpecificationExecutor<DelinquencyRange> {
|
||||||
|
|
||||||
|
Optional<DelinquencyRange> findByClassification(String classification);
|
||||||
|
}
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.domain;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.Version;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Entity
|
||||||
|
@Table(name = "m_loan_delinquency_tag_history")
|
||||||
|
public class LoanDelinquencyTagHistory extends AbstractAuditableWithUTCDateTimeCustom {
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "delinquency_range_id", nullable = false)
|
||||||
|
private DelinquencyRange delinquencyRange;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "loan_id", nullable = false)
|
||||||
|
private Loan loan;
|
||||||
|
|
||||||
|
@Column(name = "addedon_date", nullable = false)
|
||||||
|
private LocalDate addedOnDate;
|
||||||
|
|
||||||
|
@Column(name = "liftedon_date", nullable = true)
|
||||||
|
private LocalDate liftedOnDate;
|
||||||
|
|
||||||
|
@Version
|
||||||
|
private Long version;
|
||||||
|
|
||||||
|
public LoanDelinquencyTagHistory(DelinquencyRange delinquencyRange, Loan loan, LocalDate addedOnDate, LocalDate liftedOnDate) {
|
||||||
|
this.delinquencyRange = delinquencyRange;
|
||||||
|
this.loan = loan;
|
||||||
|
this.addedOnDate = addedOnDate;
|
||||||
|
this.liftedOnDate = liftedOnDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.domain;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
|
||||||
|
public interface LoanDelinquencyTagHistoryRepository
|
||||||
|
extends JpaRepository<LoanDelinquencyTagHistory, Long>, JpaSpecificationExecutor<LoanDelinquencyTagHistory> {
|
||||||
|
|
||||||
|
List<LoanDelinquencyTagHistory> findByLoanOrderByAddedOnDateDesc(Loan loan);
|
||||||
|
|
||||||
|
Optional<LoanDelinquencyTagHistory> findByLoanAndLiftedOnDate(Loan loan, LocalDate liftedOnDate);
|
||||||
|
|
||||||
|
Long countByDelinquencyRangeAndLiftedOnDate(DelinquencyRange delinquencyRange, LocalDate liftedOnDate);
|
||||||
|
|
||||||
|
Long countByDelinquencyRange(DelinquencyRange delinquencyRange);
|
||||||
|
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.exception;
|
||||||
|
|
||||||
|
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||||
|
|
||||||
|
public class DelinquencyBucketAgesOverlapedException extends AbstractPlatformDomainRuleException {
|
||||||
|
|
||||||
|
public DelinquencyBucketAgesOverlapedException(final String defaultUserMessage, final Object... defaultUserMessageArgs) {
|
||||||
|
super("error.msg.loan.delinquency.bucket.ages.overlaped", defaultUserMessage, defaultUserMessageArgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.exception;
|
||||||
|
|
||||||
|
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||||
|
|
||||||
|
public class DelinquencyBucketNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||||
|
|
||||||
|
public DelinquencyBucketNotFoundException(String globalisationMessageCode, String defaultUserMessage,
|
||||||
|
Object... defaultUserMessageArgs) {
|
||||||
|
super(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DelinquencyBucketNotFoundException notExist(final Long id, Throwable... e) {
|
||||||
|
return new DelinquencyBucketNotFoundException("error.msg.delinquency.bucket.id.not.exist",
|
||||||
|
"Delinquency bucket with id `" + id + "` does not exist.", id, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DelinquencyBucketNotFoundException notFound(final Long id, Throwable... e) {
|
||||||
|
return new DelinquencyBucketNotFoundException("error.msg.delinquency.bucket.not.found",
|
||||||
|
"Delinquency bucket with id `" + id + "` does not found.", id, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.exception;
|
||||||
|
|
||||||
|
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||||
|
|
||||||
|
public class DelinquencyRangeInvalidAgesException extends AbstractPlatformDomainRuleException {
|
||||||
|
|
||||||
|
public DelinquencyRangeInvalidAgesException(final String defaultUserMessage, final Object... defaultUserMessageArgs) {
|
||||||
|
super("error.msg.loan.delinquency.age.days,invalid", defaultUserMessage, defaultUserMessageArgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.exception;
|
||||||
|
|
||||||
|
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||||
|
|
||||||
|
public class DelinquencyRangeNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||||
|
|
||||||
|
public DelinquencyRangeNotFoundException(String globalisationMessageCode, String defaultUserMessage, Object... defaultUserMessageArgs) {
|
||||||
|
super(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DelinquencyRangeNotFoundException notExist(final Long id, Throwable... e) {
|
||||||
|
return new DelinquencyRangeNotFoundException("error.msg.delinquency.range.id.not.exist",
|
||||||
|
"Delinquency range with id `" + id + "` does not exist.", id, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DelinquencyRangeNotFoundException notFound(final Long id, Throwable... e) {
|
||||||
|
return new DelinquencyRangeNotFoundException("error.msg.delinquency.range.not.found",
|
||||||
|
"Delinquency range with id `" + id + "` does not found.", id, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.handler;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.commands.annotation.CommandType;
|
||||||
|
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@CommandType(entity = "DELINQUENCY_BUCKET", action = "CREATE")
|
||||||
|
public class CreateDelinquencyBucketCommandHandler implements NewCommandSourceHandler {
|
||||||
|
|
||||||
|
private final DelinquencyWritePlatformService writePlatformService;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
|
return this.writePlatformService.createDelinquencyBucket(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.handler;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.commands.annotation.CommandType;
|
||||||
|
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@CommandType(entity = "DELINQUENCY_RANGE", action = "CREATE")
|
||||||
|
public class CreateDelinquencyRangeCommandHandler implements NewCommandSourceHandler {
|
||||||
|
|
||||||
|
private final DelinquencyWritePlatformService writePlatformService;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
|
return this.writePlatformService.createDelinquencyRange(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.handler;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.commands.annotation.CommandType;
|
||||||
|
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@CommandType(entity = "DELINQUENCY_BUCKET", action = "DELETE")
|
||||||
|
public class DeleteDelinquencyBucketCommandHandler implements NewCommandSourceHandler {
|
||||||
|
|
||||||
|
private final DelinquencyWritePlatformService writePlatformService;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
|
return this.writePlatformService.deleteDelinquencyBucket(command.entityId(), command);
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.handler;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.commands.annotation.CommandType;
|
||||||
|
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@CommandType(entity = "DELINQUENCY_RANGE", action = "DELETE")
|
||||||
|
public class DeleteDelinquencyRangeCommandHandler implements NewCommandSourceHandler {
|
||||||
|
|
||||||
|
private final DelinquencyWritePlatformService writePlatformService;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
|
return this.writePlatformService.deleteDelinquencyRange(command.entityId(), command);
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.handler;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.commands.annotation.CommandType;
|
||||||
|
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@CommandType(entity = "DELINQUENCY_BUCKET", action = "UPDATE")
|
||||||
|
public class UpdateDelinquencyBucketCommandHandler implements NewCommandSourceHandler {
|
||||||
|
|
||||||
|
private final DelinquencyWritePlatformService writePlatformService;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
|
return this.writePlatformService.updateDelinquencyBucket(command.entityId(), command);
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.handler;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.commands.annotation.CommandType;
|
||||||
|
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyWritePlatformService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@CommandType(entity = "DELINQUENCY_RANGE", action = "UPDATE")
|
||||||
|
public class UpdateDelinquencyRangeCommandHandler implements NewCommandSourceHandler {
|
||||||
|
|
||||||
|
private final DelinquencyWritePlatformService writePlatformService;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||||
|
return this.writePlatformService.updateDelinquencyRange(command.entityId(), command);
|
||||||
|
}
|
||||||
|
}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.Mappings;
|
||||||
|
|
||||||
|
@Mapper(componentModel = "spring")
|
||||||
|
public interface DelinquencyBucketMapper {
|
||||||
|
|
||||||
|
@Mappings({ @Mapping(target = "id", source = "source.id"), @Mapping(target = "name", source = "source.name") })
|
||||||
|
DelinquencyBucketData map(DelinquencyBucket source);
|
||||||
|
|
||||||
|
List<DelinquencyBucketData> map(List<DelinquencyBucket> sources);
|
||||||
|
|
||||||
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.Mappings;
|
||||||
|
|
||||||
|
@Mapper(componentModel = "spring")
|
||||||
|
public interface DelinquencyRangeMapper {
|
||||||
|
|
||||||
|
@Mappings({ @Mapping(target = "id", source = "source.id"), @Mapping(target = "classification", source = "source.classification"),
|
||||||
|
@Mapping(target = "minimumAgeDays", source = "source.minimumAgeDays"),
|
||||||
|
@Mapping(target = "maximumAgeDays", source = "source.maximumAgeDays") })
|
||||||
|
DelinquencyRangeData map(DelinquencyRange source);
|
||||||
|
|
||||||
|
List<DelinquencyRangeData> map(List<DelinquencyRange> sources);
|
||||||
|
|
||||||
|
}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||||
|
|
||||||
|
public interface DelinquencyReadPlatformService {
|
||||||
|
|
||||||
|
Collection<DelinquencyRangeData> retrieveAllDelinquencyRanges();
|
||||||
|
|
||||||
|
DelinquencyRangeData retrieveDelinquencyRange(Long delinquencyRangeId);
|
||||||
|
|
||||||
|
Collection<DelinquencyBucketData> retrieveAllDelinquencyBuckets();
|
||||||
|
|
||||||
|
DelinquencyBucketData retrieveDelinquencyBucket(Long delinquencyBucketId);
|
||||||
|
|
||||||
|
DelinquencyRangeData retrieveCurrentDelinquencyTag(Long loanId);
|
||||||
|
}
|
||||||
+125
@@ -0,0 +1,125 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.service;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketRepository;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyRangeRepository;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistory;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistoryRepository;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.exception.DelinquencyBucketNotFoundException;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.mapper.DelinquencyBucketMapper;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.mapper.DelinquencyRangeMapper;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
|
||||||
|
import org.springframework.dao.EmptyResultDataAccessException;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.jdbc.core.RowMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatformService {
|
||||||
|
|
||||||
|
private final JdbcTemplate jdbcTemplate;
|
||||||
|
private final DelinquencyRangeRepository repositoryRange;
|
||||||
|
private final DelinquencyBucketRepository repositoryBucket;
|
||||||
|
private final LoanDelinquencyTagHistoryRepository repositoryLoanDelinquencyTagHistory;
|
||||||
|
private final DelinquencyRangeMapper mapperRange;
|
||||||
|
private final DelinquencyBucketMapper mapperBucket;
|
||||||
|
private final LoanAssembler loanAssembler;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<DelinquencyRangeData> retrieveAllDelinquencyRanges() {
|
||||||
|
final List<DelinquencyRange> delinquencyRangeList = repositoryRange.findAll();
|
||||||
|
return mapperRange.map(delinquencyRangeList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DelinquencyRangeData retrieveDelinquencyRange(Long delinquencyRangeId) {
|
||||||
|
DelinquencyRange delinquencyRangeList = repositoryRange.getReferenceById(delinquencyRangeId);
|
||||||
|
return mapperRange.map(delinquencyRangeList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<DelinquencyBucketData> retrieveAllDelinquencyBuckets() {
|
||||||
|
final List<DelinquencyBucket> delinquencyRangeList = repositoryBucket.findAll();
|
||||||
|
return mapperBucket.map(delinquencyRangeList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DelinquencyBucketData retrieveDelinquencyBucket(Long delinquencyBucketId) {
|
||||||
|
try {
|
||||||
|
final DelinquencyBucket delinquencyBucket = repositoryBucket.getReferenceById(delinquencyBucketId);
|
||||||
|
final DelinquencyBucketData delinquencyBucketData = mapperBucket.map(delinquencyBucket);
|
||||||
|
|
||||||
|
final DelinquencyBucketMappingMapper rmMappings = new DelinquencyBucketMappingMapper();
|
||||||
|
final String sql = "select " + rmMappings.schema() + " where buc.id = ? order by dran.min_age_days";
|
||||||
|
List<DelinquencyRangeData> ranges = this.jdbcTemplate.query(sql, rmMappings, delinquencyBucketId); // NOSONAR
|
||||||
|
delinquencyBucketData.setRanges(ranges);
|
||||||
|
|
||||||
|
return delinquencyBucketData;
|
||||||
|
} catch (final EmptyResultDataAccessException e) {
|
||||||
|
throw DelinquencyBucketNotFoundException.notFound(delinquencyBucketId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DelinquencyRangeData retrieveCurrentDelinquencyTag(Long loanId) {
|
||||||
|
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||||
|
Optional<LoanDelinquencyTagHistory> optLoanDelinquencyTag = this.repositoryLoanDelinquencyTagHistory.findByLoanAndLiftedOnDate(loan,
|
||||||
|
null);
|
||||||
|
if (optLoanDelinquencyTag.isPresent()) {
|
||||||
|
return mapperRange.map(optLoanDelinquencyTag.get().getDelinquencyRange());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class DelinquencyBucketMappingMapper implements RowMapper<DelinquencyRangeData> {
|
||||||
|
|
||||||
|
public String schema() {
|
||||||
|
return " dran.id as id, dran.classification as classification, dran.min_age_days as minimumAgeDays, dran.max_age_days as maximumAgeDays from m_delinquency_bucket buc "
|
||||||
|
+ " inner join m_delinquency_bucket_mappings dmap on dmap.delinquency_bucket_id = buc.id "
|
||||||
|
+ " inner join m_delinquency_range dran on dran.id = dmap.delinquency_range_id ";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DelinquencyRangeData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||||
|
|
||||||
|
final Long id = rs.getLong("id");
|
||||||
|
final String classification = rs.getString("classification");
|
||||||
|
final Integer minimumAgeDays = rs.getInt("minimumAgeDays");
|
||||||
|
final Integer maximumAgeDays = rs.getInt("maximumAgeDays");
|
||||||
|
|
||||||
|
return new DelinquencyRangeData(id, classification, minimumAgeDays, maximumAgeDays);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.service;
|
||||||
|
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
|
||||||
|
public interface DelinquencyWritePlatformService {
|
||||||
|
|
||||||
|
CommandProcessingResult createDelinquencyRange(JsonCommand command);
|
||||||
|
|
||||||
|
CommandProcessingResult updateDelinquencyRange(Long delinquencyRangeId, JsonCommand command);
|
||||||
|
|
||||||
|
CommandProcessingResult deleteDelinquencyRange(Long delinquencyRangeId, JsonCommand command);
|
||||||
|
|
||||||
|
CommandProcessingResult setLoanDelinquencyTag(Long loanId, Long delinquencyRangeId, JsonCommand command);
|
||||||
|
|
||||||
|
CommandProcessingResult createDelinquencyBucket(JsonCommand command);
|
||||||
|
|
||||||
|
CommandProcessingResult updateDelinquencyBucket(Long delinquencyBucketId, JsonCommand command);
|
||||||
|
|
||||||
|
CommandProcessingResult deleteDelinquencyBucket(Long delinquencyBucketId, JsonCommand command);
|
||||||
|
|
||||||
|
}
|
||||||
+278
@@ -0,0 +1,278 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.service;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||||
|
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.api.DelinquencyApiConstants;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketMappings;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketMappingsRepository;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketRepository;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyRangeRepository;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistory;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistoryRepository;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.exception.DelinquencyBucketAgesOverlapedException;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.exception.DelinquencyRangeInvalidAgesException;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyBucketParseAndValidator;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.validator.DelinquencyRangeParseAndValidator;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||||
|
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class DelinquencyWritePlatformServiceImpl implements DelinquencyWritePlatformService {
|
||||||
|
|
||||||
|
private final DelinquencyBucketParseAndValidator dataValidatorBucket;
|
||||||
|
private final DelinquencyRangeParseAndValidator dataValidatorRange;
|
||||||
|
|
||||||
|
private final DelinquencyRangeRepository repositoryRange;
|
||||||
|
private final DelinquencyBucketRepository repositoryBucket;
|
||||||
|
private final DelinquencyBucketMappingsRepository repositoryBucketMappings;
|
||||||
|
private final LoanDelinquencyTagHistoryRepository loanDelinquencyTagRepository;
|
||||||
|
private final LoanRepositoryWrapper loanRepository;
|
||||||
|
private final LoanProductRepository loanProductRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult createDelinquencyRange(JsonCommand command) {
|
||||||
|
DelinquencyRangeData data = dataValidatorRange.validateAndParseUpdate(command);
|
||||||
|
Map<String, Object> changes = new HashMap<>();
|
||||||
|
DelinquencyRange delinquencyRange = createDelinquencyRange(data, changes);
|
||||||
|
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(delinquencyRange.getId()).with(changes)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult updateDelinquencyRange(Long delinquencyRangeId, JsonCommand command) {
|
||||||
|
DelinquencyRangeData data = dataValidatorRange.validateAndParseUpdate(command);
|
||||||
|
DelinquencyRange delinquencyRange = this.repositoryRange.getReferenceById(delinquencyRangeId);
|
||||||
|
Map<String, Object> changes = new HashMap<>();
|
||||||
|
delinquencyRange = updateDelinquencyRange(delinquencyRange, data, changes);
|
||||||
|
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(delinquencyRange.getId()).with(changes)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult deleteDelinquencyRange(Long delinquencyRangeId, JsonCommand command) {
|
||||||
|
final DelinquencyRange delinquencyRange = repositoryRange.getReferenceById(delinquencyRangeId);
|
||||||
|
if (delinquencyRange != null) {
|
||||||
|
final Long delinquencyRangeLinked = this.loanDelinquencyTagRepository.countByDelinquencyRange(delinquencyRange);
|
||||||
|
if (delinquencyRangeLinked > 0) {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.data.integrity.issue.entity.linked",
|
||||||
|
"Data integrity issue with resource: " + delinquencyRange.getId());
|
||||||
|
}
|
||||||
|
repositoryRange.delete(delinquencyRange);
|
||||||
|
}
|
||||||
|
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(delinquencyRange.getId()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult setLoanDelinquencyTag(Long loanId, Long delinquencyRangeId, JsonCommand command) {
|
||||||
|
setLoanDelinquencyTag(loanId, delinquencyRangeId);
|
||||||
|
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(loanId).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult createDelinquencyBucket(JsonCommand command) {
|
||||||
|
DelinquencyBucketData data = dataValidatorBucket.validateAndParseUpdate(command);
|
||||||
|
Map<String, Object> changes = new HashMap<>();
|
||||||
|
DelinquencyBucket delinquencyBucket = createDelinquencyBucket(data, changes);
|
||||||
|
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(delinquencyBucket.getId()).with(changes)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult updateDelinquencyBucket(Long delinquencyBucketId, JsonCommand command) {
|
||||||
|
DelinquencyBucketData data = dataValidatorBucket.validateAndParseUpdate(command);
|
||||||
|
DelinquencyBucket delinquencyBucket = this.repositoryBucket.getReferenceById(delinquencyBucketId);
|
||||||
|
|
||||||
|
Map<String, Object> changes = new HashMap<>();
|
||||||
|
delinquencyBucket = updateDelinquencyBucket(delinquencyBucket, data, changes);
|
||||||
|
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(delinquencyBucket.getId()).with(changes)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandProcessingResult deleteDelinquencyBucket(Long delinquencyBucketId, JsonCommand command) {
|
||||||
|
final DelinquencyBucket delinquencyBucket = repositoryBucket.getReferenceById(delinquencyBucketId);
|
||||||
|
if (delinquencyBucket != null) {
|
||||||
|
Long delinquencyBucketLinked = this.loanProductRepository.countByDelinquencyBucket(delinquencyBucket);
|
||||||
|
if (delinquencyBucketLinked > 0) {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.data.integrity.issue.entity.linked",
|
||||||
|
"Data integrity issue with resource: " + delinquencyBucket.getId());
|
||||||
|
}
|
||||||
|
repositoryBucket.delete(delinquencyBucket);
|
||||||
|
}
|
||||||
|
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(delinquencyBucket.getId()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DelinquencyRange createDelinquencyRange(DelinquencyRangeData data, Map<String, Object> changes) {
|
||||||
|
Optional<DelinquencyRange> delinquencyRange = repositoryRange.findByClassification(data.getClassification());
|
||||||
|
|
||||||
|
if (delinquencyRange.isEmpty()) {
|
||||||
|
if (data.getMinimumAgeDays() > data.getMaximumAgeDays()) {
|
||||||
|
final String errorMessage = "The age days values are invalid, the maximum age days can't be lower than minimum age days";
|
||||||
|
throw new DelinquencyRangeInvalidAgesException(errorMessage, data.getMinimumAgeDays(), data.getMaximumAgeDays());
|
||||||
|
}
|
||||||
|
DelinquencyRange newDelinquencyRange = DelinquencyRange.instance(data.getClassification(), data.getMinimumAgeDays(),
|
||||||
|
data.getMaximumAgeDays());
|
||||||
|
return repositoryRange.saveAndFlush(newDelinquencyRange);
|
||||||
|
} else {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.data.integrity.issue.entity.duplicated",
|
||||||
|
"Data integrity issue with resource: " + delinquencyRange.get().getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DelinquencyRange updateDelinquencyRange(DelinquencyRange delinquencyRange, DelinquencyRangeData data,
|
||||||
|
Map<String, Object> changes) {
|
||||||
|
if (!data.getClassification().equalsIgnoreCase(delinquencyRange.getClassification())) {
|
||||||
|
delinquencyRange.setClassification(data.getClassification());
|
||||||
|
changes.put(DelinquencyApiConstants.CLASSIFICATION_PARAM_NAME, data.getClassification());
|
||||||
|
}
|
||||||
|
if (!data.getMinimumAgeDays().equals(delinquencyRange.getMinimumAgeDays())) {
|
||||||
|
delinquencyRange.setMinimumAgeDays(data.getMinimumAgeDays());
|
||||||
|
changes.put(DelinquencyApiConstants.MINIMUMAGEDAYS_PARAM_NAME, data.getMinimumAgeDays());
|
||||||
|
}
|
||||||
|
if (!data.getMaximumAgeDays().equals(delinquencyRange.getMaximumAgeDays())) {
|
||||||
|
delinquencyRange.setMaximumAgeDays(data.getMaximumAgeDays());
|
||||||
|
changes.put(DelinquencyApiConstants.MAXIMUMAGEDAYS_PARAM_NAME, data.getMaximumAgeDays());
|
||||||
|
}
|
||||||
|
if (!changes.isEmpty()) {
|
||||||
|
delinquencyRange = repositoryRange.saveAndFlush(delinquencyRange);
|
||||||
|
}
|
||||||
|
return delinquencyRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DelinquencyBucket createDelinquencyBucket(DelinquencyBucketData data, Map<String, Object> changes) {
|
||||||
|
Optional<DelinquencyBucket> delinquencyBucket = repositoryBucket.findByName(data.getName());
|
||||||
|
|
||||||
|
if (delinquencyBucket.isEmpty()) {
|
||||||
|
DelinquencyBucket newDelinquencyBucket = new DelinquencyBucket(data.getName());
|
||||||
|
repositoryBucket.save(newDelinquencyBucket);
|
||||||
|
setDelinquencyBucketMappings(newDelinquencyBucket, data);
|
||||||
|
return newDelinquencyBucket;
|
||||||
|
} else {
|
||||||
|
throw new PlatformDataIntegrityException("error.msg.data.integrity.issue.entity.duplicated",
|
||||||
|
"Data integrity issue with resource: " + delinquencyBucket.get().getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DelinquencyBucket updateDelinquencyBucket(DelinquencyBucket delinquencyBucket, DelinquencyBucketData data,
|
||||||
|
Map<String, Object> changes) {
|
||||||
|
if (!data.getName().equalsIgnoreCase(delinquencyBucket.getName())) {
|
||||||
|
delinquencyBucket.setName(data.getName());
|
||||||
|
changes.put(DelinquencyApiConstants.NAME_PARAM_NAME, data.getName());
|
||||||
|
}
|
||||||
|
if (!changes.isEmpty()) {
|
||||||
|
delinquencyBucket = repositoryBucket.save(delinquencyBucket);
|
||||||
|
}
|
||||||
|
setDelinquencyBucketMappings(delinquencyBucket, data);
|
||||||
|
return delinquencyBucket;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDelinquencyBucketMappings(DelinquencyBucket delinquencyBucket, DelinquencyBucketData data) {
|
||||||
|
List<Long> rangeIds = new ArrayList<>();
|
||||||
|
data.getRanges().forEach(dataRange -> {
|
||||||
|
rangeIds.add(dataRange.getId());
|
||||||
|
});
|
||||||
|
|
||||||
|
List<DelinquencyRange> ranges = repositoryRange.findAllById(rangeIds);
|
||||||
|
validateDelinquencyRanges(ranges);
|
||||||
|
List<DelinquencyBucketMappings> bucketMappings = repositoryBucketMappings.findByDelinquencyBucket(delinquencyBucket);
|
||||||
|
repositoryBucketMappings.deleteAll(bucketMappings);
|
||||||
|
bucketMappings.clear();
|
||||||
|
for (DelinquencyRange delinquencyRange : ranges) {
|
||||||
|
bucketMappings.add(DelinquencyBucketMappings.instance(delinquencyBucket, delinquencyRange));
|
||||||
|
}
|
||||||
|
repositoryBucketMappings.saveAllAndFlush(bucketMappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateDelinquencyRanges(List<DelinquencyRange> ranges) {
|
||||||
|
// Sort the ranges based on the minAgeDays
|
||||||
|
final Comparator<DelinquencyRange> orderByMinAge = new Comparator<DelinquencyRange>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(DelinquencyRange o1, DelinquencyRange o2) {
|
||||||
|
return o1.getMinimumAgeDays().compareTo(o2.getMinimumAgeDays());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Collections.sort(ranges, orderByMinAge);
|
||||||
|
DelinquencyRange prevDelinquencyRange = null;
|
||||||
|
for (DelinquencyRange delinquencyRange : ranges) {
|
||||||
|
if (prevDelinquencyRange != null) {
|
||||||
|
if (isOverlaped(prevDelinquencyRange, delinquencyRange)) {
|
||||||
|
final String errorMessage = "The delinquency ranges age days values are overlaped";
|
||||||
|
throw new DelinquencyBucketAgesOverlapedException(errorMessage, prevDelinquencyRange, delinquencyRange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevDelinquencyRange = delinquencyRange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isOverlaped(DelinquencyRange o1, DelinquencyRange o2) {
|
||||||
|
return Math.max(o1.getMinimumAgeDays(), o2.getMinimumAgeDays()) <= Math.min(o1.getMaximumAgeDays(), o2.getMaximumAgeDays());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLoanDelinquencyTag(Long loanId, Long delinquencyRangeId) {
|
||||||
|
final Loan loan = this.loanRepository.findOneWithNotFoundDetection(loanId);
|
||||||
|
|
||||||
|
final LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
|
||||||
|
List<LoanDelinquencyTagHistory> loanDelinquencyTagHistory = this.loanDelinquencyTagRepository
|
||||||
|
.findByLoanOrderByAddedOnDateDesc(loan);
|
||||||
|
// The delinquencyRangeId in null means just goes out from Delinquency
|
||||||
|
if (delinquencyRangeId == null) {
|
||||||
|
// The Loan will go out from Delinquency
|
||||||
|
if (!loanDelinquencyTagHistory.isEmpty()) {
|
||||||
|
LoanDelinquencyTagHistory loanDelinquencyTagPrev = loanDelinquencyTagHistory.get(0);
|
||||||
|
loanDelinquencyTagPrev.setLiftedOnDate(transactionDate);
|
||||||
|
this.loanDelinquencyTagRepository.saveAndFlush(loanDelinquencyTagPrev);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The previous Loan Delinquency Tag will set as Lifted
|
||||||
|
if (!loanDelinquencyTagHistory.isEmpty()) {
|
||||||
|
LoanDelinquencyTagHistory loanDelinquencyTagPrev = loanDelinquencyTagHistory.get(0);
|
||||||
|
loanDelinquencyTagPrev.setLiftedOnDate(transactionDate);
|
||||||
|
this.loanDelinquencyTagRepository.save(loanDelinquencyTagPrev);
|
||||||
|
}
|
||||||
|
|
||||||
|
final DelinquencyRange delinquencyRange = repositoryRange.getReferenceById(delinquencyRangeId);
|
||||||
|
LoanDelinquencyTagHistory loanDelinquencyTag = new LoanDelinquencyTagHistory(delinquencyRange, loan, transactionDate, null);
|
||||||
|
loanDelinquencyTagHistory.add(loanDelinquencyTag);
|
||||||
|
this.loanDelinquencyTagRepository.saveAndFlush(loanDelinquencyTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+76
@@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.validator;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||||
|
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||||
|
import org.apache.fineract.infrastructure.core.validator.ParseAndValidator;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.api.DelinquencyApiConstants;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Component
|
||||||
|
public class DelinquencyBucketParseAndValidator extends ParseAndValidator {
|
||||||
|
|
||||||
|
private final FromJsonHelper jsonHelper;
|
||||||
|
|
||||||
|
public DelinquencyBucketData validateAndParseUpdate(@NotNull final JsonCommand command) {
|
||||||
|
final DataValidatorBuilder dataValidator = new DataValidatorBuilder(new ArrayList<>()).resource("delinquencyBucket.create");
|
||||||
|
JsonObject element = extractJsonObject(jsonHelper, command);
|
||||||
|
|
||||||
|
DelinquencyBucketData result = validateAndParseUpdate(dataValidator, element, jsonHelper);
|
||||||
|
throwExceptionIfValidationWarningsExist(dataValidator);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DelinquencyBucketData validateAndParseUpdate(final DataValidatorBuilder dataValidator, JsonObject element,
|
||||||
|
FromJsonHelper jsonHelper) {
|
||||||
|
if (element == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonHelper.checkForUnsupportedParameters(element,
|
||||||
|
List.of(DelinquencyApiConstants.NAME_PARAM_NAME, DelinquencyApiConstants.RANGES_PARAM_NAME));
|
||||||
|
|
||||||
|
final String name = jsonHelper.extractStringNamed(DelinquencyApiConstants.NAME_PARAM_NAME, element);
|
||||||
|
|
||||||
|
dataValidator.reset().parameter(DelinquencyApiConstants.NAME_PARAM_NAME).value(name).notBlank();
|
||||||
|
|
||||||
|
final String[] rangeIds = jsonHelper.extractArrayNamed(DelinquencyApiConstants.RANGES_PARAM_NAME, element);
|
||||||
|
dataValidator.reset().parameter(DelinquencyApiConstants.RANGES_PARAM_NAME).value(rangeIds).notNull().arrayNotEmpty();
|
||||||
|
|
||||||
|
ArrayList<DelinquencyRangeData> ranges = new ArrayList<>();
|
||||||
|
if (rangeIds != null) {
|
||||||
|
for (String rangeId : rangeIds) {
|
||||||
|
ranges.add(DelinquencyRangeData.reference(Long.parseLong(rangeId)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dataValidator.hasError() ? null : new DelinquencyBucketData(null, name, ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.delinquency.validator;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
|
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||||
|
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||||
|
import org.apache.fineract.infrastructure.core.validator.ParseAndValidator;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.api.DelinquencyApiConstants;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Component
|
||||||
|
public class DelinquencyRangeParseAndValidator extends ParseAndValidator {
|
||||||
|
|
||||||
|
private final FromJsonHelper jsonHelper;
|
||||||
|
|
||||||
|
public DelinquencyRangeData validateAndParseUpdate(@NotNull final JsonCommand command) {
|
||||||
|
final DataValidatorBuilder dataValidator = new DataValidatorBuilder(new ArrayList<>()).resource("delinquencyrange.create");
|
||||||
|
JsonObject element = extractJsonObject(jsonHelper, command);
|
||||||
|
|
||||||
|
DelinquencyRangeData result = validateAndParseUpdate(dataValidator, element, jsonHelper);
|
||||||
|
throwExceptionIfValidationWarningsExist(dataValidator);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DelinquencyRangeData validateAndParseUpdate(final DataValidatorBuilder dataValidator, JsonObject element,
|
||||||
|
FromJsonHelper jsonHelper) {
|
||||||
|
if (element == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonHelper.checkForUnsupportedParameters(element,
|
||||||
|
List.of(DelinquencyApiConstants.CLASSIFICATION_PARAM_NAME, DelinquencyApiConstants.MINIMUMAGEDAYS_PARAM_NAME,
|
||||||
|
DelinquencyApiConstants.MAXIMUMAGEDAYS_PARAM_NAME, DelinquencyApiConstants.LOCALE_PARAM_NAME));
|
||||||
|
|
||||||
|
final String localeValue = jsonHelper.extractStringNamed(DelinquencyApiConstants.LOCALE_PARAM_NAME, element);
|
||||||
|
dataValidator.reset().parameter(DelinquencyApiConstants.LOCALE_PARAM_NAME).value(localeValue).notBlank();
|
||||||
|
final Locale locale = jsonHelper.extractLocaleParameter(element);
|
||||||
|
|
||||||
|
final String classification = jsonHelper.extractStringNamed(DelinquencyApiConstants.CLASSIFICATION_PARAM_NAME, element);
|
||||||
|
final Integer minimumAge = jsonHelper.extractIntegerNamed(DelinquencyApiConstants.MINIMUMAGEDAYS_PARAM_NAME, element, locale);
|
||||||
|
final Integer maximumAge = jsonHelper.extractIntegerNamed(DelinquencyApiConstants.MAXIMUMAGEDAYS_PARAM_NAME, element, locale);
|
||||||
|
dataValidator.reset().parameter(DelinquencyApiConstants.CLASSIFICATION_PARAM_NAME).value(classification).notBlank();
|
||||||
|
dataValidator.reset().parameter(DelinquencyApiConstants.MINIMUMAGEDAYS_PARAM_NAME).value(minimumAge).notBlank()
|
||||||
|
.integerGreaterThanNumber(0);
|
||||||
|
dataValidator.reset().parameter(DelinquencyApiConstants.MAXIMUMAGEDAYS_PARAM_NAME).value(maximumAge).ignoreIfNull()
|
||||||
|
.integerGreaterThanNumber(0);
|
||||||
|
|
||||||
|
return dataValidator.hasError() ? null : DelinquencyRangeData.instance(classification, minimumAge, maximumAge);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+27
-16
@@ -38,6 +38,7 @@ import org.apache.fineract.portfolio.accountdetails.data.LoanAccountSummaryData;
|
|||||||
import org.apache.fineract.portfolio.calendar.data.CalendarData;
|
import org.apache.fineract.portfolio.calendar.data.CalendarData;
|
||||||
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||||
import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData;
|
import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData;
|
||||||
import org.apache.fineract.portfolio.fund.data.FundData;
|
import org.apache.fineract.portfolio.fund.data.FundData;
|
||||||
import org.apache.fineract.portfolio.group.data.GroupGeneralData;
|
import org.apache.fineract.portfolio.group.data.GroupGeneralData;
|
||||||
@@ -239,6 +240,7 @@ public final class LoanAccountData {
|
|||||||
private LocalDate expectedDisbursementDate;
|
private LocalDate expectedDisbursementDate;
|
||||||
|
|
||||||
private final CollectionData delinquent;
|
private final CollectionData delinquent;
|
||||||
|
private final DelinquencyRangeData delinquencyRange;
|
||||||
|
|
||||||
public static LoanAccountData importInstanceIndividual(EnumOptionData loanTypeEnumOption, Long clientId, Long productId,
|
public static LoanAccountData importInstanceIndividual(EnumOptionData loanTypeEnumOption, Long clientId, Long productId,
|
||||||
Long loanOfficerId, LocalDate submittedOnDate, Long fundId, BigDecimal principal, Integer numberOfRepayments,
|
Long loanOfficerId, LocalDate submittedOnDate, Long fundId, BigDecimal principal, Integer numberOfRepayments,
|
||||||
@@ -426,6 +428,7 @@ public final class LoanAccountData {
|
|||||||
this.isRatesEnabled = false;
|
this.isRatesEnabled = false;
|
||||||
this.fixedPrincipalPercentagePerInstallment = null;
|
this.fixedPrincipalPercentagePerInstallment = null;
|
||||||
this.delinquent = null;
|
this.delinquent = null;
|
||||||
|
this.delinquencyRange = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getRowIndex() {
|
public Integer getRowIndex() {
|
||||||
@@ -592,6 +595,7 @@ public final class LoanAccountData {
|
|||||||
final Boolean isRatesEnabled = false;
|
final Boolean isRatesEnabled = false;
|
||||||
final BigDecimal fixedPrincipalPercentagePerInstallment = null;
|
final BigDecimal fixedPrincipalPercentagePerInstallment = null;
|
||||||
final CollectionData delinquent = CollectionData.template();
|
final CollectionData delinquent = CollectionData.template();
|
||||||
|
final DelinquencyRangeData delinquencyRange = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
|
||||||
loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
|
loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
|
||||||
@@ -613,7 +617,7 @@ public final class LoanAccountData {
|
|||||||
interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
|
interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
|
||||||
isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
|
isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
|
||||||
closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled,
|
closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment, delinquent);
|
fixedPrincipalPercentagePerInstallment, delinquent, delinquencyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -738,6 +742,7 @@ public final class LoanAccountData {
|
|||||||
final Boolean isRatesEnabled = false;
|
final Boolean isRatesEnabled = false;
|
||||||
final BigDecimal fixedPrincipalPercentagePerInstallment = null;
|
final BigDecimal fixedPrincipalPercentagePerInstallment = null;
|
||||||
final CollectionData delinquent = CollectionData.template();
|
final CollectionData delinquent = CollectionData.template();
|
||||||
|
final DelinquencyRangeData delinquencyRange = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
|
||||||
loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
|
loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
|
||||||
@@ -759,7 +764,7 @@ public final class LoanAccountData {
|
|||||||
originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
|
originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
|
||||||
isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
|
isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
|
||||||
closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled,
|
closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment, delinquent);
|
fixedPrincipalPercentagePerInstallment, delinquent, delinquencyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) {
|
public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) {
|
||||||
@@ -790,7 +795,7 @@ public final class LoanAccountData {
|
|||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
||||||
acc.fixedPrincipalPercentagePerInstallment, acc.delinquent);
|
acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.delinquencyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -917,6 +922,7 @@ public final class LoanAccountData {
|
|||||||
final Boolean isRatesEnabled = false;
|
final Boolean isRatesEnabled = false;
|
||||||
final BigDecimal fixedPrincipalPercentagePerInstallment = null;
|
final BigDecimal fixedPrincipalPercentagePerInstallment = null;
|
||||||
final CollectionData delinquent = CollectionData.template();
|
final CollectionData delinquent = CollectionData.template();
|
||||||
|
final DelinquencyRangeData delinquencyRange = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
|
||||||
loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
|
loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
|
||||||
@@ -938,7 +944,7 @@ public final class LoanAccountData {
|
|||||||
originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
|
originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
|
||||||
isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
|
isVariableInstallmentsAllowed, minimumGap, maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup,
|
||||||
closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled,
|
closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment, delinquent);
|
fixedPrincipalPercentagePerInstallment, delinquent, delinquencyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) {
|
public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) {
|
||||||
@@ -968,7 +974,7 @@ public final class LoanAccountData {
|
|||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
||||||
acc.fixedPrincipalPercentagePerInstallment, acc.delinquent);
|
acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.delinquencyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product,
|
public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product,
|
||||||
@@ -1110,6 +1116,7 @@ public final class LoanAccountData {
|
|||||||
final List<RateData> rates = null;
|
final List<RateData> rates = null;
|
||||||
final Boolean isRatesEnabled = false;
|
final Boolean isRatesEnabled = false;
|
||||||
final CollectionData delinquent = CollectionData.template();
|
final CollectionData delinquent = CollectionData.template();
|
||||||
|
final DelinquencyRangeData delinquencyRange = null;
|
||||||
|
|
||||||
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
|
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
|
||||||
loanType, product.getId(), product.getName(), product.getDescription(), product.isLinkedToFloatingInterestRates(),
|
loanType, product.getId(), product.getName(), product.getDescription(), product.isLinkedToFloatingInterestRates(),
|
||||||
@@ -1136,7 +1143,7 @@ public final class LoanAccountData {
|
|||||||
product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(),
|
product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(),
|
||||||
product.getMaximumGapBetweenInstallments(), subStatus, canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId,
|
product.getMaximumGapBetweenInstallments(), subStatus, canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId,
|
||||||
closureLoanAccountNo, topupAmount, product.isEqualAmortization(), rates, isRatesEnabled,
|
closureLoanAccountNo, topupAmount, product.isEqualAmortization(), rates, isRatesEnabled,
|
||||||
product.getFixedPrincipalPercentagePerInstallment(), delinquent);
|
product.getFixedPrincipalPercentagePerInstallment(), delinquent, delinquencyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
|
public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) {
|
||||||
@@ -1179,6 +1186,7 @@ public final class LoanAccountData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
final CollectionData delinquent = CollectionData.template();
|
final CollectionData delinquent = CollectionData.template();
|
||||||
|
final DelinquencyRangeData delinquencyRange = null;
|
||||||
|
|
||||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
|
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
|
||||||
acc.clientOfficeId, acc.group, acc.loanType, product.getId(), product.getName(), product.getDescription(),
|
acc.clientOfficeId, acc.group, acc.loanType, product.getId(), product.getName(), product.getDescription(),
|
||||||
@@ -1206,7 +1214,7 @@ public final class LoanAccountData {
|
|||||||
product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(),
|
product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(),
|
||||||
product.getMaximumGapBetweenInstallments(), acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
product.getMaximumGapBetweenInstallments(), acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, product.isEqualAmortization(), acc.rates, acc.isRatesEnabled,
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, product.isEqualAmortization(), acc.rates, acc.isRatesEnabled,
|
||||||
product.getFixedPrincipalPercentagePerInstallment(), delinquent);
|
product.getFixedPrincipalPercentagePerInstallment(), delinquent, delinquencyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1237,7 +1245,8 @@ public final class LoanAccountData {
|
|||||||
final LoanInterestRecalculationData interestRecalculationData, final Boolean createStandingInstructionAtDisbursement,
|
final LoanInterestRecalculationData interestRecalculationData, final Boolean createStandingInstructionAtDisbursement,
|
||||||
final Boolean isVariableInstallmentsAllowed, Integer minimumGap, Integer maximumGap, final EnumOptionData subStatus,
|
final Boolean isVariableInstallmentsAllowed, Integer minimumGap, Integer maximumGap, final EnumOptionData subStatus,
|
||||||
final boolean canUseForTopup, final boolean isTopup, final Long closureLoanId, final String closureLoanAccountNo,
|
final boolean canUseForTopup, final boolean isTopup, final Long closureLoanId, final String closureLoanAccountNo,
|
||||||
final BigDecimal topupAmount, final boolean isEqualAmortization, final BigDecimal fixedPrincipalPercentagePerInstallment) {
|
final BigDecimal topupAmount, final boolean isEqualAmortization, final BigDecimal fixedPrincipalPercentagePerInstallment,
|
||||||
|
final DelinquencyRangeData delinquencyRange) {
|
||||||
|
|
||||||
final LoanScheduleData repaymentSchedule = null;
|
final LoanScheduleData repaymentSchedule = null;
|
||||||
final Collection<LoanTransactionData> transactions = null;
|
final Collection<LoanTransactionData> transactions = null;
|
||||||
@@ -1297,7 +1306,7 @@ public final class LoanAccountData {
|
|||||||
isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
||||||
createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap,
|
createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap,
|
||||||
maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId, closureLoanAccountNo, topupAmount,
|
maximumGap, subStatus, canUseForTopup, clientActiveLoanOptions, isTopup, closureLoanId, closureLoanAccountNo, topupAmount,
|
||||||
isEqualAmortization, rates, isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquent);
|
isEqualAmortization, rates, isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquent, delinquencyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1351,7 +1360,7 @@ public final class LoanAccountData {
|
|||||||
acc.createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, clientActiveLoanOptions, acc.isTopup, acc.closureLoanId,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, clientActiveLoanOptions, acc.isTopup, acc.closureLoanId,
|
||||||
acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, rates, isRatesEnabled,
|
acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, rates, isRatesEnabled,
|
||||||
acc.fixedPrincipalPercentagePerInstallment, delinquent);
|
acc.fixedPrincipalPercentagePerInstallment, delinquent, acc.delinquencyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions,
|
public static LoanAccountData associationsAndTemplate(final LoanAccountData acc, final Collection<LoanProductData> productOptions,
|
||||||
@@ -1394,7 +1403,7 @@ public final class LoanAccountData {
|
|||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
||||||
acc.fixedPrincipalPercentagePerInstallment, acc.delinquent);
|
acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.delinquencyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map<Long, Integer> memberLoanCycle) {
|
public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map<Long, Integer> memberLoanCycle) {
|
||||||
@@ -1460,7 +1469,7 @@ public final class LoanAccountData {
|
|||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
||||||
acc.fixedPrincipalPercentagePerInstallment, acc.delinquent);
|
acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.delinquencyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData withInterestRecalculationCalendarData(final LoanAccountData acc, final CalendarData calendarData,
|
public static LoanAccountData withInterestRecalculationCalendarData(final LoanAccountData acc, final CalendarData calendarData,
|
||||||
@@ -1494,7 +1503,7 @@ public final class LoanAccountData {
|
|||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
||||||
acc.fixedPrincipalPercentagePerInstallment, acc.delinquent);
|
acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.delinquencyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData withLoanCalendarData(final LoanAccountData acc, final CalendarData calendarData) {
|
public static LoanAccountData withLoanCalendarData(final LoanAccountData acc, final CalendarData calendarData) {
|
||||||
@@ -1523,7 +1532,7 @@ public final class LoanAccountData {
|
|||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
||||||
acc.fixedPrincipalPercentagePerInstallment, acc.delinquent);
|
acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.delinquencyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) {
|
public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) {
|
||||||
@@ -1553,7 +1562,7 @@ public final class LoanAccountData {
|
|||||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance, acc.interestRatesPeriods, acc.isVariableInstallmentsAllowed,
|
||||||
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
acc.minimumGap, acc.maximumGap, acc.subStatus, acc.canUseForTopup, acc.clientActiveLoanOptions, acc.isTopup,
|
||||||
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
acc.closureLoanId, acc.closureLoanAccountNo, acc.topupAmount, acc.isEqualAmortization, acc.rates, acc.isRatesEnabled,
|
||||||
acc.fixedPrincipalPercentagePerInstallment, acc.delinquent);
|
acc.fixedPrincipalPercentagePerInstallment, acc.delinquent, acc.delinquencyRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoanAccountData(final Long id, //
|
private LoanAccountData(final Long id, //
|
||||||
@@ -1606,7 +1615,8 @@ public final class LoanAccountData {
|
|||||||
final Integer minimumGap, final Integer maximumGap, final EnumOptionData subStatus, final Boolean canUseForTopup,
|
final Integer minimumGap, final Integer maximumGap, final EnumOptionData subStatus, final Boolean canUseForTopup,
|
||||||
final Collection<LoanAccountSummaryData> clientActiveLoanOptions, final boolean isTopup, final Long closureLoanId,
|
final Collection<LoanAccountSummaryData> clientActiveLoanOptions, final boolean isTopup, final Long closureLoanId,
|
||||||
final String closureLoanAccountNo, final BigDecimal topupAmount, final boolean isEqualAmortization, final List<RateData> rates,
|
final String closureLoanAccountNo, final BigDecimal topupAmount, final boolean isEqualAmortization, final List<RateData> rates,
|
||||||
final Boolean isRatesEnabled, final BigDecimal fixedPrincipalPercentagePerInstallment, final CollectionData delinquent) {
|
final Boolean isRatesEnabled, final BigDecimal fixedPrincipalPercentagePerInstallment, final CollectionData delinquent,
|
||||||
|
final DelinquencyRangeData delinquencyRange) {
|
||||||
|
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.accountNo = accountNo;
|
this.accountNo = accountNo;
|
||||||
@@ -1794,6 +1804,7 @@ public final class LoanAccountData {
|
|||||||
this.rates = rates;
|
this.rates = rates;
|
||||||
this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment;
|
this.fixedPrincipalPercentagePerInstallment = fixedPrincipalPercentagePerInstallment;
|
||||||
this.delinquent = delinquent;
|
this.delinquent = delinquent;
|
||||||
|
this.delinquencyRange = delinquencyRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
|
public RepaymentScheduleRelatedLoanData repaymentScheduleRelatedData() {
|
||||||
|
|||||||
+1
-1
@@ -151,7 +151,7 @@ public class RecalculateInterestForLoanTasklet implements Tasklet {
|
|||||||
List<Callable<Void>> posters = new ArrayList<>();
|
List<Callable<Void>> posters = new ArrayList<>();
|
||||||
int fromIndex = 0;
|
int fromIndex = 0;
|
||||||
int size = loanIds.size();
|
int size = loanIds.size();
|
||||||
double toGetCeilValue = size / threadPoolSize;
|
double toGetCeilValue = size / ((double) threadPoolSize);
|
||||||
batchSize = (int) Math.ceil(toGetCeilValue);
|
batchSize = (int) Math.ceil(toGetCeilValue);
|
||||||
|
|
||||||
if (batchSize == 0) {
|
if (batchSize == 0) {
|
||||||
|
|||||||
+15
-8
@@ -70,6 +70,8 @@ import org.apache.fineract.portfolio.client.domain.ClientEnumerations;
|
|||||||
import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
|
import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
import org.apache.fineract.portfolio.common.service.CommonEnumerations;
|
import org.apache.fineract.portfolio.common.service.CommonEnumerations;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyRangeData;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData;
|
import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData;
|
||||||
import org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
import org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.fund.data.FundData;
|
import org.apache.fineract.portfolio.fund.data.FundData;
|
||||||
@@ -157,6 +159,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
|
private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
|
||||||
private final ColumnValidator columnValidator;
|
private final ColumnValidator columnValidator;
|
||||||
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
||||||
|
private final DelinquencyReadPlatformService delinquencyReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanReadPlatformServiceImpl(final PlatformSecurityContext context,
|
public LoanReadPlatformServiceImpl(final PlatformSecurityContext context,
|
||||||
@@ -170,6 +173,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory,
|
||||||
final FloatingRatesReadPlatformService floatingRatesReadPlatformService, final LoanUtilService loanUtilService,
|
final FloatingRatesReadPlatformService floatingRatesReadPlatformService, final LoanUtilService loanUtilService,
|
||||||
final ConfigurationDomainService configurationDomainService,
|
final ConfigurationDomainService configurationDomainService,
|
||||||
|
final DelinquencyReadPlatformService delinquencyReadPlatformService,
|
||||||
final AccountDetailsReadPlatformService accountDetailsReadPlatformService, final LoanRepositoryWrapper loanRepositoryWrapper,
|
final AccountDetailsReadPlatformService accountDetailsReadPlatformService, final LoanRepositoryWrapper loanRepositoryWrapper,
|
||||||
final ColumnValidator columnValidator, DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
|
final ColumnValidator columnValidator, DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@@ -193,9 +197,10 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
this.configurationDomainService = configurationDomainService;
|
this.configurationDomainService = configurationDomainService;
|
||||||
this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
|
this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
|
||||||
this.columnValidator = columnValidator;
|
this.columnValidator = columnValidator;
|
||||||
this.loaanLoanMapper = new LoanMapper(sqlGenerator);
|
this.loaanLoanMapper = new LoanMapper(sqlGenerator, delinquencyReadPlatformService);
|
||||||
this.sqlGenerator = sqlGenerator;
|
this.sqlGenerator = sqlGenerator;
|
||||||
this.paginationHelper = paginationHelper;
|
this.paginationHelper = paginationHelper;
|
||||||
|
this.delinquencyReadPlatformService = delinquencyReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -206,7 +211,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
final String hierarchy = currentUser.getOffice().getHierarchy();
|
final String hierarchy = currentUser.getOffice().getHierarchy();
|
||||||
final String hierarchySearchString = hierarchy + "%";
|
final String hierarchySearchString = hierarchy + "%";
|
||||||
|
|
||||||
final LoanMapper rm = new LoanMapper(sqlGenerator);
|
final LoanMapper rm = new LoanMapper(sqlGenerator, delinquencyReadPlatformService);
|
||||||
|
|
||||||
final StringBuilder sqlBuilder = new StringBuilder();
|
final StringBuilder sqlBuilder = new StringBuilder();
|
||||||
sqlBuilder.append("select ");
|
sqlBuilder.append("select ");
|
||||||
@@ -226,7 +231,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
|
|
||||||
// final AppUser currentUser = this.context.authenticatedUser();
|
// final AppUser currentUser = this.context.authenticatedUser();
|
||||||
this.context.authenticatedUser();
|
this.context.authenticatedUser();
|
||||||
final LoanMapper rm = new LoanMapper(sqlGenerator);
|
final LoanMapper rm = new LoanMapper(sqlGenerator, delinquencyReadPlatformService);
|
||||||
|
|
||||||
final String sql = "select " + rm.loanSchema() + " where l.account_no=?";
|
final String sql = "select " + rm.loanSchema() + " where l.account_no=?";
|
||||||
|
|
||||||
@@ -237,7 +242,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
@Override
|
@Override
|
||||||
public List<LoanAccountData> retrieveGLIMChildLoansByGLIMParentAccount(String parentloanAccountNumber) {
|
public List<LoanAccountData> retrieveGLIMChildLoansByGLIMParentAccount(String parentloanAccountNumber) {
|
||||||
this.context.authenticatedUser();
|
this.context.authenticatedUser();
|
||||||
final LoanMapper rm = new LoanMapper(sqlGenerator);
|
final LoanMapper rm = new LoanMapper(sqlGenerator, delinquencyReadPlatformService);
|
||||||
|
|
||||||
final String sql = "select " + rm.loanSchema()
|
final String sql = "select " + rm.loanSchema()
|
||||||
+ " left join glim_parent_child_mapping as glim on glim.glim_child_account_id=l.account_no "
|
+ " left join glim_parent_child_mapping as glim on glim.glim_child_account_id=l.account_no "
|
||||||
@@ -490,8 +495,6 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
@Override
|
@Override
|
||||||
public LoanTransactionData retrieveWaiveInterestDetails(final Long loanId) {
|
public LoanTransactionData retrieveWaiveInterestDetails(final Long loanId) {
|
||||||
|
|
||||||
AppUser currentUser = this.context.authenticatedUser();
|
|
||||||
|
|
||||||
// TODO - KW -OPTIMIZE - write simple sql query to fetch back overdue
|
// TODO - KW -OPTIMIZE - write simple sql query to fetch back overdue
|
||||||
// interest that can be waived along with the date of repayment period
|
// interest that can be waived along with the date of repayment period
|
||||||
// interest is overdue.
|
// interest is overdue.
|
||||||
@@ -582,9 +585,11 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
private static final class LoanMapper implements RowMapper<LoanAccountData> {
|
private static final class LoanMapper implements RowMapper<LoanAccountData> {
|
||||||
|
|
||||||
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
||||||
|
private final DelinquencyReadPlatformService delinquencyReadPlatformService;
|
||||||
|
|
||||||
LoanMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
|
LoanMapper(DatabaseSpecificSQLGenerator sqlGenerator, DelinquencyReadPlatformService delinquencyReadPlatformService) {
|
||||||
this.sqlGenerator = sqlGenerator;
|
this.sqlGenerator = sqlGenerator;
|
||||||
|
this.delinquencyReadPlatformService = delinquencyReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String loanSchema() {
|
public String loanSchema() {
|
||||||
@@ -989,6 +994,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
final Long closureLoanId = rs.getLong("closureLoanId");
|
final Long closureLoanId = rs.getLong("closureLoanId");
|
||||||
final String closureLoanAccountNo = rs.getString("closureLoanAccountNo");
|
final String closureLoanAccountNo = rs.getString("closureLoanAccountNo");
|
||||||
final BigDecimal topupAmount = rs.getBigDecimal("topupAmount");
|
final BigDecimal topupAmount = rs.getBigDecimal("topupAmount");
|
||||||
|
// Current Delinquency Range Data
|
||||||
|
DelinquencyRangeData delinquencyRange = this.delinquencyReadPlatformService.retrieveCurrentDelinquencyTag(id);
|
||||||
|
|
||||||
return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientAccountNo, clientName,
|
return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientAccountNo, clientName,
|
||||||
clientOfficeId, groupData, loanType, loanProductId, loanProductName, loanProductDescription,
|
clientOfficeId, groupData, loanType, loanProductId, loanProductName, loanProductDescription,
|
||||||
@@ -1004,7 +1011,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData,
|
isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData,
|
||||||
createStandingInstructionAtDisbursement, isvariableInstallmentsAllowed, minimumGap, maximumGap, loanSubStatus,
|
createStandingInstructionAtDisbursement, isvariableInstallmentsAllowed, minimumGap, maximumGap, loanSubStatus,
|
||||||
canUseForTopup, isTopup, closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization,
|
canUseForTopup, isTopup, closureLoanId, closureLoanAccountNo, topupAmount, isEqualAmortization,
|
||||||
fixedPrincipalPercentagePerInstallment);
|
fixedPrincipalPercentagePerInstallment, delinquencyRange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -141,5 +141,6 @@ public interface LoanProductConstants {
|
|||||||
String ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED = "allowApprovedDisbursedAmountsOverApplied";
|
String ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED = "allowApprovedDisbursedAmountsOverApplied";
|
||||||
String OVER_APPLIED_CALCULATION_TYPE = "overAppliedCalculationType";
|
String OVER_APPLIED_CALCULATION_TYPE = "overAppliedCalculationType";
|
||||||
String OVER_APPLIED_NUMBER = "overAppliedNumber";
|
String OVER_APPLIED_NUMBER = "overAppliedNumber";
|
||||||
|
String DELINQUENCY_BUCKET_PARAM_NAME = "delinquencyBucketId";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-2
@@ -65,6 +65,8 @@ import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformSer
|
|||||||
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
||||||
import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
|
import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.common.service.DropdownReadPlatformService;
|
import org.apache.fineract.portfolio.common.service.DropdownReadPlatformService;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateData;
|
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateData;
|
||||||
import org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
import org.apache.fineract.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.fund.data.FundData;
|
import org.apache.fineract.portfolio.fund.data.FundData;
|
||||||
@@ -130,6 +132,7 @@ public class LoanProductsApiResource {
|
|||||||
private final FloatingRatesReadPlatformService floatingRateReadPlatformService;
|
private final FloatingRatesReadPlatformService floatingRateReadPlatformService;
|
||||||
private final RateReadService rateReadService;
|
private final RateReadService rateReadService;
|
||||||
private final ConfigurationDomainService configurationDomainService;
|
private final ConfigurationDomainService configurationDomainService;
|
||||||
|
private final DelinquencyReadPlatformService delinquencyReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanProductsApiResource(final PlatformSecurityContext context, final LoanProductReadPlatformService readPlatformService,
|
public LoanProductsApiResource(final PlatformSecurityContext context, final LoanProductReadPlatformService readPlatformService,
|
||||||
@@ -145,7 +148,8 @@ public class LoanProductsApiResource {
|
|||||||
final DropdownReadPlatformService commonDropdownReadPlatformService,
|
final DropdownReadPlatformService commonDropdownReadPlatformService,
|
||||||
PaymentTypeReadPlatformService paymentTypeReadPlatformService,
|
PaymentTypeReadPlatformService paymentTypeReadPlatformService,
|
||||||
final FloatingRatesReadPlatformService floatingRateReadPlatformService, final RateReadService rateReadService,
|
final FloatingRatesReadPlatformService floatingRateReadPlatformService, final RateReadService rateReadService,
|
||||||
final ConfigurationDomainService configurationDomainService) {
|
final ConfigurationDomainService configurationDomainService,
|
||||||
|
final DelinquencyReadPlatformService delinquencyReadPlatformService) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.loanProductReadPlatformService = readPlatformService;
|
this.loanProductReadPlatformService = readPlatformService;
|
||||||
this.chargeReadPlatformService = chargeReadPlatformService;
|
this.chargeReadPlatformService = chargeReadPlatformService;
|
||||||
@@ -164,6 +168,7 @@ public class LoanProductsApiResource {
|
|||||||
this.floatingRateReadPlatformService = floatingRateReadPlatformService;
|
this.floatingRateReadPlatformService = floatingRateReadPlatformService;
|
||||||
this.rateReadService = rateReadService;
|
this.rateReadService = rateReadService;
|
||||||
this.configurationDomainService = configurationDomainService;
|
this.configurationDomainService = configurationDomainService;
|
||||||
|
this.delinquencyReadPlatformService = delinquencyReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@@ -339,6 +344,12 @@ public class LoanProductsApiResource {
|
|||||||
if (fundOptions.isEmpty()) {
|
if (fundOptions.isEmpty()) {
|
||||||
fundOptions = null;
|
fundOptions = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Collection<DelinquencyBucketData> delinquencyBucketOptions = this.delinquencyReadPlatformService.retrieveAllDelinquencyBuckets();
|
||||||
|
if (delinquencyBucketOptions.isEmpty()) {
|
||||||
|
delinquencyBucketOptions = null;
|
||||||
|
}
|
||||||
|
|
||||||
final Collection<TransactionProcessingStrategyData> transactionProcessingStrategyOptions = this.dropdownReadPlatformService
|
final Collection<TransactionProcessingStrategyData> transactionProcessingStrategyOptions = this.dropdownReadPlatformService
|
||||||
.retreiveTransactionProcessingStrategies();
|
.retreiveTransactionProcessingStrategies();
|
||||||
|
|
||||||
@@ -372,7 +383,7 @@ public class LoanProductsApiResource {
|
|||||||
loanCycleValueConditionTypeOptions, daysInMonthTypeOptions, daysInYearTypeOptions,
|
loanCycleValueConditionTypeOptions, daysInMonthTypeOptions, daysInYearTypeOptions,
|
||||||
interestRecalculationCompoundingTypeOptions, rescheduleStrategyTypeOptions, interestRecalculationFrequencyTypeOptions,
|
interestRecalculationCompoundingTypeOptions, rescheduleStrategyTypeOptions, interestRecalculationFrequencyTypeOptions,
|
||||||
preCloseInterestCalculationStrategyOptions, floatingRateOptions, interestRecalculationNthDayTypeOptions,
|
preCloseInterestCalculationStrategyOptions, floatingRateOptions, interestRecalculationNthDayTypeOptions,
|
||||||
interestRecalculationDayOfWeekTypeOptions, isRatesEnabled);
|
interestRecalculationDayOfWeekTypeOptions, isRatesEnabled, delinquencyBucketOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-22
@@ -39,6 +39,7 @@ import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
|||||||
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
|
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
import org.apache.fineract.portfolio.common.service.CommonEnumerations;
|
import org.apache.fineract.portfolio.common.service.CommonEnumerations;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
||||||
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateData;
|
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateData;
|
||||||
import org.apache.fineract.portfolio.fund.data.FundData;
|
import org.apache.fineract.portfolio.fund.data.FundData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.data.LoanInterestRecalculationData;
|
import org.apache.fineract.portfolio.loanaccount.data.LoanInterestRecalculationData;
|
||||||
@@ -51,6 +52,7 @@ import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
|
|||||||
import org.apache.fineract.portfolio.rate.data.RateData;
|
import org.apache.fineract.portfolio.rate.data.RateData;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
/**
|
/**
|
||||||
* Immutable data object to represent loan products.
|
* Immutable data object to represent loan products.
|
||||||
*/
|
*/
|
||||||
@@ -140,9 +142,7 @@ public class LoanProductData implements Serializable {
|
|||||||
|
|
||||||
// template related
|
// template related
|
||||||
private final Collection<FundData> fundOptions;
|
private final Collection<FundData> fundOptions;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final Collection<PaymentTypeData> paymentTypeOptions;
|
private final Collection<PaymentTypeData> paymentTypeOptions;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final Collection<CurrencyData> currencyOptions;
|
private final Collection<CurrencyData> currencyOptions;
|
||||||
private final List<EnumOptionData> repaymentFrequencyTypeOptions;
|
private final List<EnumOptionData> repaymentFrequencyTypeOptions;
|
||||||
private final List<EnumOptionData> interestRateFrequencyTypeOptions;
|
private final List<EnumOptionData> interestRateFrequencyTypeOptions;
|
||||||
@@ -152,32 +152,19 @@ public class LoanProductData implements Serializable {
|
|||||||
private final Collection<TransactionProcessingStrategyData> transactionProcessingStrategyOptions;
|
private final Collection<TransactionProcessingStrategyData> transactionProcessingStrategyOptions;
|
||||||
private final Collection<ChargeData> chargeOptions;
|
private final Collection<ChargeData> chargeOptions;
|
||||||
private final Collection<RateData> rateOptions;
|
private final Collection<RateData> rateOptions;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final Collection<ChargeData> penaltyOptions;
|
private final Collection<ChargeData> penaltyOptions;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final List<EnumOptionData> accountingRuleOptions;
|
private final List<EnumOptionData> accountingRuleOptions;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final Map<String, List<GLAccountData>> accountingMappingOptions;
|
private final Map<String, List<GLAccountData>> accountingMappingOptions;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final List<EnumOptionData> valueConditionTypeOptions;
|
private final List<EnumOptionData> valueConditionTypeOptions;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final List<EnumOptionData> daysInMonthTypeOptions;
|
private final List<EnumOptionData> daysInMonthTypeOptions;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final List<EnumOptionData> daysInYearTypeOptions;
|
private final List<EnumOptionData> daysInYearTypeOptions;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final List<EnumOptionData> interestRecalculationCompoundingTypeOptions;
|
private final List<EnumOptionData> interestRecalculationCompoundingTypeOptions;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final List<EnumOptionData> interestRecalculationNthDayTypeOptions;
|
private final List<EnumOptionData> interestRecalculationNthDayTypeOptions;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final List<EnumOptionData> interestRecalculationDayOfWeekTypeOptions;
|
private final List<EnumOptionData> interestRecalculationDayOfWeekTypeOptions;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final List<EnumOptionData> rescheduleStrategyTypeOptions;
|
private final List<EnumOptionData> rescheduleStrategyTypeOptions;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final List<EnumOptionData> preClosureInterestCalculationStrategyOptions;
|
private final List<EnumOptionData> preClosureInterestCalculationStrategyOptions;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final List<EnumOptionData> interestRecalculationFrequencyTypeOptions;
|
private final List<EnumOptionData> interestRecalculationFrequencyTypeOptions;
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private final List<FloatingRateData> floatingRateOptions;
|
private final List<FloatingRateData> floatingRateOptions;
|
||||||
|
|
||||||
private final Boolean multiDisburseLoan;
|
private final Boolean multiDisburseLoan;
|
||||||
@@ -198,6 +185,10 @@ public class LoanProductData implements Serializable {
|
|||||||
private final boolean isEqualAmortization;
|
private final boolean isEqualAmortization;
|
||||||
private final BigDecimal fixedPrincipalPercentagePerInstallment;
|
private final BigDecimal fixedPrincipalPercentagePerInstallment;
|
||||||
|
|
||||||
|
// Delinquency Buckets
|
||||||
|
private final Collection<DelinquencyBucketData> delinquencyBucketOptions;
|
||||||
|
private final DelinquencyBucketData delinquencyBucket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used when returning lookup information about loan product for dropdowns.
|
* Used when returning lookup information about loan product for dropdowns.
|
||||||
*/
|
*/
|
||||||
@@ -282,6 +273,9 @@ public class LoanProductData implements Serializable {
|
|||||||
final Collection<RateData> rateOptions = null;
|
final Collection<RateData> rateOptions = null;
|
||||||
final Collection<RateData> rates = null;
|
final Collection<RateData> rates = null;
|
||||||
final boolean isRatesEnabled = false;
|
final boolean isRatesEnabled = false;
|
||||||
|
final Collection<DelinquencyBucketData> delinquencyBucketOptions = null;
|
||||||
|
final DelinquencyBucketData delinquencyBucket = null;
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType,
|
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType,
|
||||||
@@ -298,7 +292,7 @@ public class LoanProductData implements Serializable {
|
|||||||
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment);
|
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,6 +378,8 @@ public class LoanProductData implements Serializable {
|
|||||||
final Collection<RateData> rateOptions = null;
|
final Collection<RateData> rateOptions = null;
|
||||||
final Collection<RateData> rates = null;
|
final Collection<RateData> rates = null;
|
||||||
final boolean isRatesEnabled = false;
|
final boolean isRatesEnabled = false;
|
||||||
|
final Collection<DelinquencyBucketData> delinquencyBucketOptions = null;
|
||||||
|
final DelinquencyBucketData delinquencyBucket = null;
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
@@ -401,7 +397,7 @@ public class LoanProductData implements Serializable {
|
|||||||
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment);
|
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,6 +490,8 @@ public class LoanProductData implements Serializable {
|
|||||||
final Collection<RateData> rateOptions = null;
|
final Collection<RateData> rateOptions = null;
|
||||||
final Collection<RateData> rates = null;
|
final Collection<RateData> rates = null;
|
||||||
final boolean isRatesEnabled = false;
|
final boolean isRatesEnabled = false;
|
||||||
|
final Collection<DelinquencyBucketData> delinquencyBucketOptions = null;
|
||||||
|
final DelinquencyBucketData delinquencyBucket = null;
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
@@ -511,7 +509,7 @@ public class LoanProductData implements Serializable {
|
|||||||
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment);
|
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -598,6 +596,8 @@ public class LoanProductData implements Serializable {
|
|||||||
final Collection<RateData> rateOptions = null;
|
final Collection<RateData> rateOptions = null;
|
||||||
final Collection<RateData> rates = null;
|
final Collection<RateData> rates = null;
|
||||||
final boolean isRatesEnabled = false;
|
final boolean isRatesEnabled = false;
|
||||||
|
final Collection<DelinquencyBucketData> delinquencyBucketOptions = null;
|
||||||
|
final DelinquencyBucketData delinquencyBucket = null;
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
@@ -615,7 +615,7 @@ public class LoanProductData implements Serializable {
|
|||||||
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap,
|
||||||
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, rates, isRatesEnabled,
|
||||||
fixedPrincipalPercentagePerInstallment);
|
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,7 +660,8 @@ public class LoanProductData implements Serializable {
|
|||||||
final Integer minimumGapBetweenInstallments, final Integer maximumGapBetweenInstallments,
|
final Integer minimumGapBetweenInstallments, final Integer maximumGapBetweenInstallments,
|
||||||
final boolean syncExpectedWithDisbursementDate, final boolean canUseForTopup, final boolean isEqualAmortization,
|
final boolean syncExpectedWithDisbursementDate, final boolean canUseForTopup, final boolean isEqualAmortization,
|
||||||
Collection<RateData> rateOptions, Collection<RateData> rates, final boolean isRatesEnabled,
|
Collection<RateData> rateOptions, Collection<RateData> rates, final boolean isRatesEnabled,
|
||||||
final BigDecimal fixedPrincipalPercentagePerInstallment) {
|
final BigDecimal fixedPrincipalPercentagePerInstallment, final Collection<DelinquencyBucketData> delinquencyBucketOptions,
|
||||||
|
final DelinquencyBucketData delinquencyBucket) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.shortName = shortName;
|
this.shortName = shortName;
|
||||||
@@ -774,7 +775,8 @@ public class LoanProductData implements Serializable {
|
|||||||
this.syncExpectedWithDisbursementDate = syncExpectedWithDisbursementDate;
|
this.syncExpectedWithDisbursementDate = syncExpectedWithDisbursementDate;
|
||||||
this.canUseForTopup = canUseForTopup;
|
this.canUseForTopup = canUseForTopup;
|
||||||
this.isEqualAmortization = isEqualAmortization;
|
this.isEqualAmortization = isEqualAmortization;
|
||||||
|
this.delinquencyBucketOptions = delinquencyBucketOptions;
|
||||||
|
this.delinquencyBucket = delinquencyBucket;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
|
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
|
||||||
@@ -790,7 +792,8 @@ public class LoanProductData implements Serializable {
|
|||||||
final List<EnumOptionData> rescheduleStrategyTypeOptions, final List<EnumOptionData> interestRecalculationFrequencyTypeOptions,
|
final List<EnumOptionData> rescheduleStrategyTypeOptions, final List<EnumOptionData> interestRecalculationFrequencyTypeOptions,
|
||||||
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions, final List<FloatingRateData> floatingRateOptions,
|
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions, final List<FloatingRateData> floatingRateOptions,
|
||||||
final List<EnumOptionData> interestRecalculationNthDayTypeOptions,
|
final List<EnumOptionData> interestRecalculationNthDayTypeOptions,
|
||||||
final List<EnumOptionData> interestRecalculationDayOfWeekTypeOptions, final boolean isRatesEnabled) {
|
final List<EnumOptionData> interestRecalculationDayOfWeekTypeOptions, final boolean isRatesEnabled,
|
||||||
|
final Collection<DelinquencyBucketData> delinquencyBucketOptions) {
|
||||||
this.id = productData.id;
|
this.id = productData.id;
|
||||||
this.name = productData.name;
|
this.name = productData.name;
|
||||||
this.shortName = productData.shortName;
|
this.shortName = productData.shortName;
|
||||||
@@ -921,6 +924,8 @@ public class LoanProductData implements Serializable {
|
|||||||
this.isEqualAmortization = productData.isEqualAmortization;
|
this.isEqualAmortization = productData.isEqualAmortization;
|
||||||
this.rates = productData.rates;
|
this.rates = productData.rates;
|
||||||
this.isRatesEnabled = isRatesEnabled;
|
this.isRatesEnabled = isRatesEnabled;
|
||||||
|
this.delinquencyBucketOptions = delinquencyBucketOptions;
|
||||||
|
this.delinquencyBucket = productData.delinquencyBucket;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {
|
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {
|
||||||
@@ -1051,6 +1056,10 @@ public class LoanProductData implements Serializable {
|
|||||||
return this.fundOptions;
|
return this.fundOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<DelinquencyBucketData> getDelinquencyBucketOptions() {
|
||||||
|
return delinquencyBucketOptions;
|
||||||
|
}
|
||||||
|
|
||||||
public List<EnumOptionData> getAmortizationTypeOptions() {
|
public List<EnumOptionData> getAmortizationTypeOptions() {
|
||||||
return this.amortizationTypeOptions;
|
return this.amortizationTypeOptions;
|
||||||
}
|
}
|
||||||
|
|||||||
+22
@@ -54,6 +54,7 @@ import org.apache.fineract.portfolio.charge.domain.Charge;
|
|||||||
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
import org.apache.fineract.portfolio.common.domain.DaysInMonthType;
|
||||||
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
|
import org.apache.fineract.portfolio.common.domain.DaysInYearType;
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket;
|
||||||
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
|
import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO;
|
||||||
import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
|
import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData;
|
||||||
import org.apache.fineract.portfolio.floatingrates.domain.FloatingRate;
|
import org.apache.fineract.portfolio.floatingrates.domain.FloatingRate;
|
||||||
@@ -195,6 +196,10 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
@Column(name = "over_applied_number", nullable = true)
|
@Column(name = "over_applied_number", nullable = true)
|
||||||
private Integer overAppliedNumber;
|
private Integer overAppliedNumber;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "delinquency_bucket_id", nullable = true)
|
||||||
|
private DelinquencyBucket delinquencyBucket;
|
||||||
|
|
||||||
public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy,
|
public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy,
|
||||||
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate,
|
final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate,
|
||||||
final List<Rate> productRates) {
|
final List<Rate> productRates) {
|
||||||
@@ -1001,6 +1006,15 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
this.syncExpectedWithDisbursementDate = newValue;
|
this.syncExpectedWithDisbursementDate = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Long delinquencyBucketId = null;
|
||||||
|
if (this.delinquencyBucket != null) {
|
||||||
|
delinquencyBucketId = this.delinquencyBucket.getId();
|
||||||
|
}
|
||||||
|
if (command.isChangeInLongParameterNamed(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME, delinquencyBucketId)) {
|
||||||
|
final Long newValue = command.longValueOfParameterNamed(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME);
|
||||||
|
actualChanges.put(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update interest recalculation settings
|
* Update interest recalculation settings
|
||||||
*/
|
*/
|
||||||
@@ -1578,4 +1592,12 @@ public class LoanProduct extends AbstractPersistableCustom {
|
|||||||
this.loanProducTrancheDetails = loanProducTrancheDetails;
|
this.loanProducTrancheDetails = loanProducTrancheDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DelinquencyBucket getDelinquencyBucket() {
|
||||||
|
return delinquencyBucket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDelinquencyBucket(DelinquencyBucket delinquencyBucket) {
|
||||||
|
this.delinquencyBucket = delinquencyBucket;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
@@ -19,6 +19,7 @@
|
|||||||
package org.apache.fineract.portfolio.loanproduct.domain;
|
package org.apache.fineract.portfolio.loanproduct.domain;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
@@ -28,4 +29,6 @@ public interface LoanProductRepository extends JpaRepository<LoanProduct, Long>,
|
|||||||
|
|
||||||
@Query("select loanProduct from LoanProduct loanProduct, IN(loanProduct.charges) charge where charge.id = :chargeId")
|
@Query("select loanProduct from LoanProduct loanProduct, IN(loanProduct.charges) charge where charge.id = :chargeId")
|
||||||
List<LoanProduct> retrieveLoanProductsByChargeId(@Param("chargeId") Long chargeId);
|
List<LoanProduct> retrieveLoanProductsByChargeId(@Param("chargeId") Long chargeId);
|
||||||
|
|
||||||
|
Long countByDelinquencyBucket(DelinquencyBucket delinquencyBucket);
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-1
@@ -111,7 +111,7 @@ public final class LoanProductDataValidator {
|
|||||||
LoanProductConstants.CAN_USE_FOR_TOPUP, LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, LoanProductConstants.RATES_PARAM_NAME,
|
LoanProductConstants.CAN_USE_FOR_TOPUP, LoanProductConstants.IS_EQUAL_AMORTIZATION_PARAM, LoanProductConstants.RATES_PARAM_NAME,
|
||||||
LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName, LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS,
|
LoanProductConstants.fixedPrincipalPercentagePerInstallmentParamName, LoanProductConstants.DISALLOW_EXPECTED_DISBURSEMENTS,
|
||||||
LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED, LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE,
|
LoanProductConstants.ALLOW_APPROVED_DISBURSED_AMOUNTS_OVER_APPLIED, LoanProductConstants.OVER_APPLIED_CALCULATION_TYPE,
|
||||||
LoanProductConstants.OVER_APPLIED_NUMBER));
|
LoanProductConstants.OVER_APPLIED_NUMBER, LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME));
|
||||||
|
|
||||||
private static final String[] supportedloanConfigurableAttributes = { LoanProductConstants.amortizationTypeParamName,
|
private static final String[] supportedloanConfigurableAttributes = { LoanProductConstants.amortizationTypeParamName,
|
||||||
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyIdParamName,
|
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyIdParamName,
|
||||||
@@ -274,6 +274,13 @@ public final class LoanProductDataValidator {
|
|||||||
baseDataValidator.reset().parameter("transactionProcessingStrategyId").value(transactionProcessingStrategyId).notNull()
|
baseDataValidator.reset().parameter("transactionProcessingStrategyId").value(transactionProcessingStrategyId).notNull()
|
||||||
.integerGreaterThanZero();
|
.integerGreaterThanZero();
|
||||||
|
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME, element)) {
|
||||||
|
final Long delinquencyBucketId = this.fromApiJsonHelper.extractLongNamed(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME).value(delinquencyBucketId)
|
||||||
|
.ignoreIfNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
// grace validation
|
// grace validation
|
||||||
final Integer graceOnPrincipalPayment = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnPrincipalPayment", element);
|
final Integer graceOnPrincipalPayment = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnPrincipalPayment", element);
|
||||||
baseDataValidator.reset().parameter("graceOnPrincipalPayment").value(graceOnPrincipalPayment).zeroOrPositiveAmount();
|
baseDataValidator.reset().parameter("graceOnPrincipalPayment").value(graceOnPrincipalPayment).zeroOrPositiveAmount();
|
||||||
@@ -1087,6 +1094,13 @@ public final class LoanProductDataValidator {
|
|||||||
.integerZeroOrGreater();
|
.integerZeroOrGreater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME, element)) {
|
||||||
|
final Long delinquencyBucketId = this.fromApiJsonHelper.extractLongNamed(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME,
|
||||||
|
element);
|
||||||
|
baseDataValidator.reset().parameter(LoanProductConstants.DELINQUENCY_BUCKET_PARAM_NAME).value(delinquencyBucketId)
|
||||||
|
.ignoreIfNull().integerGreaterThanZero();
|
||||||
|
}
|
||||||
|
|
||||||
Integer amortizationType = null;
|
Integer amortizationType = null;
|
||||||
if (this.fromApiJsonHelper.parameterExists("amortizationType", element)) {
|
if (this.fromApiJsonHelper.parameterExists("amortizationType", element)) {
|
||||||
amortizationType = this.fromApiJsonHelper.extractIntegerNamed("amortizationType", element, Locale.getDefault());
|
amortizationType = this.fromApiJsonHelper.extractIntegerNamed("amortizationType", element, Locale.getDefault());
|
||||||
|
|||||||
+24
-7
@@ -36,6 +36,8 @@ import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
|||||||
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
||||||
import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
|
import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.common.service.CommonEnumerations;
|
import org.apache.fineract.portfolio.common.service.CommonEnumerations;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.loanproduct.data.LoanProductBorrowerCycleVariationData;
|
import org.apache.fineract.portfolio.loanproduct.data.LoanProductBorrowerCycleVariationData;
|
||||||
import org.apache.fineract.portfolio.loanproduct.data.LoanProductData;
|
import org.apache.fineract.portfolio.loanproduct.data.LoanProductData;
|
||||||
import org.apache.fineract.portfolio.loanproduct.data.LoanProductGuaranteeData;
|
import org.apache.fineract.portfolio.loanproduct.data.LoanProductGuaranteeData;
|
||||||
@@ -60,18 +62,20 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
private final RateReadService rateReadService;
|
private final RateReadService rateReadService;
|
||||||
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
||||||
private final FineractEntityAccessUtil fineractEntityAccessUtil;
|
private final FineractEntityAccessUtil fineractEntityAccessUtil;
|
||||||
|
private final DelinquencyReadPlatformService delinquencyReadPlatformService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanProductReadPlatformServiceImpl(final PlatformSecurityContext context,
|
public LoanProductReadPlatformServiceImpl(final PlatformSecurityContext context,
|
||||||
final ChargeReadPlatformService chargeReadPlatformService, final JdbcTemplate jdbcTemplate,
|
final ChargeReadPlatformService chargeReadPlatformService, final JdbcTemplate jdbcTemplate,
|
||||||
final FineractEntityAccessUtil fineractEntityAccessUtil, final RateReadService rateReadService,
|
final FineractEntityAccessUtil fineractEntityAccessUtil, final RateReadService rateReadService,
|
||||||
DatabaseSpecificSQLGenerator sqlGenerator) {
|
final DelinquencyReadPlatformService delinquencyReadPlatformService, final DatabaseSpecificSQLGenerator sqlGenerator) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.chargeReadPlatformService = chargeReadPlatformService;
|
this.chargeReadPlatformService = chargeReadPlatformService;
|
||||||
this.jdbcTemplate = jdbcTemplate;
|
this.jdbcTemplate = jdbcTemplate;
|
||||||
this.fineractEntityAccessUtil = fineractEntityAccessUtil;
|
this.fineractEntityAccessUtil = fineractEntityAccessUtil;
|
||||||
this.rateReadService = rateReadService;
|
this.rateReadService = rateReadService;
|
||||||
this.sqlGenerator = sqlGenerator;
|
this.sqlGenerator = sqlGenerator;
|
||||||
|
this.delinquencyReadPlatformService = delinquencyReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -82,7 +86,9 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
final Collection<RateData> rates = this.rateReadService.retrieveProductLoanRates(loanProductId);
|
final Collection<RateData> rates = this.rateReadService.retrieveProductLoanRates(loanProductId);
|
||||||
final Collection<LoanProductBorrowerCycleVariationData> borrowerCycleVariationDatas = retrieveLoanProductBorrowerCycleVariations(
|
final Collection<LoanProductBorrowerCycleVariationData> borrowerCycleVariationDatas = retrieveLoanProductBorrowerCycleVariations(
|
||||||
loanProductId);
|
loanProductId);
|
||||||
final LoanProductMapper rm = new LoanProductMapper(charges, borrowerCycleVariationDatas, rates);
|
final Collection<DelinquencyBucketData> delinquencyBucketOptions = this.delinquencyReadPlatformService
|
||||||
|
.retrieveAllDelinquencyBuckets();
|
||||||
|
final LoanProductMapper rm = new LoanProductMapper(charges, borrowerCycleVariationDatas, rates, delinquencyBucketOptions);
|
||||||
final String sql = "select " + rm.loanProductSchema() + " where lp.id = ?";
|
final String sql = "select " + rm.loanProductSchema() + " where lp.id = ?";
|
||||||
|
|
||||||
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { loanProductId }); // NOSONAR
|
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { loanProductId }); // NOSONAR
|
||||||
@@ -104,7 +110,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
|
|
||||||
this.context.authenticatedUser();
|
this.context.authenticatedUser();
|
||||||
|
|
||||||
final LoanProductMapper rm = new LoanProductMapper(null, null, null);
|
final LoanProductMapper rm = new LoanProductMapper(null, null, null, null);
|
||||||
|
|
||||||
String sql = "select " + rm.loanProductSchema();
|
String sql = "select " + rm.loanProductSchema();
|
||||||
|
|
||||||
@@ -183,11 +189,15 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
|
|
||||||
private final Collection<RateData> rates;
|
private final Collection<RateData> rates;
|
||||||
|
|
||||||
|
private final Collection<DelinquencyBucketData> delinquencyBucketOptions;
|
||||||
|
|
||||||
LoanProductMapper(final Collection<ChargeData> charges,
|
LoanProductMapper(final Collection<ChargeData> charges,
|
||||||
final Collection<LoanProductBorrowerCycleVariationData> borrowerCycleVariationDatas, final Collection<RateData> rates) {
|
final Collection<LoanProductBorrowerCycleVariationData> borrowerCycleVariationDatas, final Collection<RateData> rates,
|
||||||
|
final Collection<DelinquencyBucketData> delinquencyBucketOptions) {
|
||||||
this.charges = charges;
|
this.charges = charges;
|
||||||
this.borrowerCycleVariationDatas = borrowerCycleVariationDatas;
|
this.borrowerCycleVariationDatas = borrowerCycleVariationDatas;
|
||||||
this.rates = rates;
|
this.rates = rates;
|
||||||
|
this.delinquencyBucketOptions = delinquencyBucketOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String loanProductSchema() {
|
public String loanProductSchema() {
|
||||||
@@ -235,7 +245,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
+ "lfr.max_differential_lending_rate as maxDifferentialLendingRate, "
|
+ "lfr.max_differential_lending_rate as maxDifferentialLendingRate, "
|
||||||
+ "lfr.is_floating_interest_rate_calculation_allowed as isFloatingInterestRateCalculationAllowed, "
|
+ "lfr.is_floating_interest_rate_calculation_allowed as isFloatingInterestRateCalculationAllowed, "
|
||||||
+ "lp.allow_variabe_installments as isVariableIntallmentsAllowed, " + "lvi.minimum_gap as minimumGap, "
|
+ "lp.allow_variabe_installments as isVariableIntallmentsAllowed, " + "lvi.minimum_gap as minimumGap, "
|
||||||
+ "lvi.maximum_gap as maximumGap, "
|
+ "lvi.maximum_gap as maximumGap, dbuc.id as delinquencyBucketId, dbuc.name as delinquencyBucketName, "
|
||||||
+ "lp.can_use_for_topup as canUseForTopup, lp.is_equal_amortization as isEqualAmortization "
|
+ "lp.can_use_for_topup as canUseForTopup, lp.is_equal_amortization as isEqualAmortization "
|
||||||
+ " from m_product_loan lp " + " left join m_fund f on f.id = lp.fund_id "
|
+ " from m_product_loan lp " + " left join m_fund f on f.id = lp.fund_id "
|
||||||
+ " left join m_product_loan_recalculation_details lpr on lpr.product_id=lp.id "
|
+ " left join m_product_loan_recalculation_details lpr on lpr.product_id=lp.id "
|
||||||
@@ -245,6 +255,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
+ " left join m_product_loan_floating_rates as lfr on lfr.loan_product_id = lp.id "
|
+ " left join m_product_loan_floating_rates as lfr on lfr.loan_product_id = lp.id "
|
||||||
+ " left join m_floating_rates as fr on lfr.floating_rates_id = fr.id "
|
+ " left join m_floating_rates as fr on lfr.floating_rates_id = fr.id "
|
||||||
+ " left join m_product_loan_variable_installment_config as lvi on lvi.loan_product_id = lp.id "
|
+ " left join m_product_loan_variable_installment_config as lvi on lvi.loan_product_id = lp.id "
|
||||||
|
+ " left join m_delinquency_bucket as dbuc on dbuc.id = lp.delinquency_bucket_id "
|
||||||
+ " join m_currency curr on curr.code = lp.currency_code";
|
+ " join m_currency curr on curr.code = lp.currency_code";
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -465,6 +476,12 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
final Collection<RateData> rateOptions = null;
|
final Collection<RateData> rateOptions = null;
|
||||||
final boolean isRatesEnabled = false;
|
final boolean isRatesEnabled = false;
|
||||||
|
|
||||||
|
// Delinquency Buckets
|
||||||
|
final Long delinquencyBucketId = rs.getLong("delinquencyBucketId");
|
||||||
|
final String delinquencyBucketName = rs.getString("delinquencyBucketName");
|
||||||
|
final DelinquencyBucketData delinquencyBucket = new DelinquencyBucketData(delinquencyBucketId, delinquencyBucketName,
|
||||||
|
new ArrayList<>());
|
||||||
|
|
||||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||||
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType,
|
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType,
|
||||||
@@ -482,7 +499,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
|
||||||
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableIntallmentsAllowed, minimumGap,
|
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableIntallmentsAllowed, minimumGap,
|
||||||
maximumGap, syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, this.rates,
|
maximumGap, syncExpectedWithDisbursementDate, canUseForTopup, isEqualAmortization, rateOptions, this.rates,
|
||||||
isRatesEnabled, fixedPrincipalPercentagePerInstallment);
|
isRatesEnabled, fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,7 +575,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
|||||||
public Collection<LoanProductData> retrieveAllLoanProductsForCurrency(String currencyCode) {
|
public Collection<LoanProductData> retrieveAllLoanProductsForCurrency(String currencyCode) {
|
||||||
this.context.authenticatedUser();
|
this.context.authenticatedUser();
|
||||||
|
|
||||||
final LoanProductMapper rm = new LoanProductMapper(null, null, null);
|
final LoanProductMapper rm = new LoanProductMapper(null, null, null, null);
|
||||||
|
|
||||||
String sql = "select " + rm.loanProductSchema() + " where lp.currency_code= ? ";
|
String sql = "select " + rm.loanProductSchema() + " where lp.currency_code= ? ";
|
||||||
|
|
||||||
|
|||||||
+12
-1
@@ -38,6 +38,8 @@ import org.apache.fineract.portfolio.businessevent.domain.loan.product.LoanProdu
|
|||||||
import org.apache.fineract.portfolio.businessevent.service.BusinessEventNotifierService;
|
import org.apache.fineract.portfolio.businessevent.service.BusinessEventNotifierService;
|
||||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||||
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket;
|
||||||
|
import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketRepository;
|
||||||
import org.apache.fineract.portfolio.floatingrates.domain.FloatingRate;
|
import org.apache.fineract.portfolio.floatingrates.domain.FloatingRate;
|
||||||
import org.apache.fineract.portfolio.floatingrates.domain.FloatingRateRepositoryWrapper;
|
import org.apache.fineract.portfolio.floatingrates.domain.FloatingRateRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.fund.domain.Fund;
|
import org.apache.fineract.portfolio.fund.domain.Fund;
|
||||||
@@ -83,6 +85,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
|||||||
private final FloatingRateRepositoryWrapper floatingRateRepository;
|
private final FloatingRateRepositoryWrapper floatingRateRepository;
|
||||||
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
||||||
private final BusinessEventNotifierService businessEventNotifierService;
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
|
private final DelinquencyBucketRepository delinquencyBucketRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LoanProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
public LoanProductWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||||
@@ -92,7 +95,8 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
|||||||
final ChargeRepositoryWrapper chargeRepository, final RateRepositoryWrapper rateRepository,
|
final ChargeRepositoryWrapper chargeRepository, final RateRepositoryWrapper rateRepository,
|
||||||
final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService,
|
final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService,
|
||||||
final FineractEntityAccessUtil fineractEntityAccessUtil, final FloatingRateRepositoryWrapper floatingRateRepository,
|
final FineractEntityAccessUtil fineractEntityAccessUtil, final FloatingRateRepositoryWrapper floatingRateRepository,
|
||||||
final LoanRepositoryWrapper loanRepositoryWrapper, final BusinessEventNotifierService businessEventNotifierService) {
|
final LoanRepositoryWrapper loanRepositoryWrapper, final BusinessEventNotifierService businessEventNotifierService,
|
||||||
|
final DelinquencyBucketRepository delinquencyBucketRepository) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||||
this.loanProductRepository = loanProductRepository;
|
this.loanProductRepository = loanProductRepository;
|
||||||
@@ -106,6 +110,7 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
|||||||
this.floatingRateRepository = floatingRateRepository;
|
this.floatingRateRepository = floatingRateRepository;
|
||||||
this.loanRepositoryWrapper = loanRepositoryWrapper;
|
this.loanRepositoryWrapper = loanRepositoryWrapper;
|
||||||
this.businessEventNotifierService = businessEventNotifierService;
|
this.businessEventNotifierService = businessEventNotifierService;
|
||||||
|
this.delinquencyBucketRepository = delinquencyBucketRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@@ -215,6 +220,12 @@ public class LoanProductWritePlatformServiceJpaRepositoryImpl implements LoanPro
|
|||||||
product.update(fund);
|
product.update(fund);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changes.containsKey("delinquencyBucketId")) {
|
||||||
|
final Long delinquencyBucketId = (Long) changes.get("delinquencyBucketId");
|
||||||
|
final DelinquencyBucket delinquencyBucket = this.delinquencyBucketRepository.getReferenceById(delinquencyBucketId);
|
||||||
|
product.setDelinquencyBucket(delinquencyBucket);
|
||||||
|
}
|
||||||
|
|
||||||
if (changes.containsKey("transactionProcessingStrategyId")) {
|
if (changes.containsKey("transactionProcessingStrategyId")) {
|
||||||
final Long transactionProcessingStrategyId = (Long) changes.get("transactionProcessingStrategyId");
|
final Long transactionProcessingStrategyId = (Long) changes.get("transactionProcessingStrategyId");
|
||||||
final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(
|
final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy = findStrategyByIdIfProvided(
|
||||||
|
|||||||
+1
-1
@@ -72,7 +72,7 @@ public class GenerateAdhocClientScheduleTasklet implements Tasklet {
|
|||||||
run = Math.toIntExact(ChronoUnit.YEARS.between(start, end)) >= 1;
|
run = Math.toIntExact(ChronoUnit.YEARS.between(start, end)) >= 1;
|
||||||
}
|
}
|
||||||
case CUSTOM -> {
|
case CUSTOM -> {
|
||||||
next = start.plusDays((int) (long) adhoc.getReportRunEvery());
|
next = start.plusDays((long) adhoc.getReportRunEvery());
|
||||||
run = Math.toIntExact(ChronoUnit.DAYS.between(start, end)) >= adhoc.getReportRunEvery();
|
run = Math.toIntExact(ChronoUnit.DAYS.between(start, end)) >= adhoc.getReportRunEvery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -560,6 +560,10 @@ public class AppUser extends AbstractPersistableCustom implements PlatformUser {
|
|||||||
validateHasPermission("UPDATE", resourceType);
|
validateHasPermission("UPDATE", resourceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void validateHasDeletePermission(final String resourceType) {
|
||||||
|
validateHasPermission("DELETE", resourceType);
|
||||||
|
}
|
||||||
|
|
||||||
private void validateHasPermission(final String prefix, final String resourceType) {
|
private void validateHasPermission(final String prefix, final String resourceType) {
|
||||||
final String authorizationMessage = "User has no authority to " + prefix + " " + resourceType.toLowerCase() + "s";
|
final String authorizationMessage = "User has no authority to " + prefix + " " + resourceType.toLowerCase() + "s";
|
||||||
final String matchPermission = prefix + "_" + resourceType.toUpperCase();
|
final String matchPermission = prefix + "_" + resourceType.toUpperCase();
|
||||||
|
|||||||
@@ -48,4 +48,5 @@
|
|||||||
<include file="parts/0026_reversals_for_reversed_transactions.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0026_reversals_for_reversed_transactions.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="parts/0027_add_charge_refund_permission.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0027_add_charge_refund_permission.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="parts/0028_add_charge_refund_charge_type_to_loan_transaction.xml" relativeToChangelogFile="true"/>
|
<include file="parts/0028_add_charge_refund_charge_type_to_loan_transaction.xml" relativeToChangelogFile="true"/>
|
||||||
|
<include file="parts/0029_add_delinquency_buckets.xml" relativeToChangelogFile="true"/>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
|||||||
+325
@@ -0,0 +1,325 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance
|
||||||
|
with the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing,
|
||||||
|
software distributed under the License is distributed on an
|
||||||
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, either express or implied. See the License for the
|
||||||
|
specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||||
|
<changeSet author="fineract" id="1" context="mysql">
|
||||||
|
<createTable tableName="m_delinquency_range">
|
||||||
|
<column autoIncrement="true" name="id" type="BIGINT">
|
||||||
|
<constraints nullable="false" primaryKey="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="classification" type="VARCHAR(100)">
|
||||||
|
<constraints unique="true" nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="min_age_days" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="max_age_days" type="BIGINT">
|
||||||
|
<constraints nullable="true" />
|
||||||
|
</column>
|
||||||
|
<column name="created_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="created_on_utc" type="DATETIME">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="version" type="BIGINT">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_on_utc" type="DATETIME">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
</createTable>
|
||||||
|
<createTable tableName="m_delinquency_bucket">
|
||||||
|
<column autoIncrement="true" name="id" type="BIGINT">
|
||||||
|
<constraints nullable="false" primaryKey="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="name" type="VARCHAR(100)">
|
||||||
|
<constraints unique="true" nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="created_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="created_on_utc" type="DATETIME">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="version" type="BIGINT">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_on_utc" type="DATETIME">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
</createTable>
|
||||||
|
<createTable tableName="m_delinquency_bucket_mappings">
|
||||||
|
<column autoIncrement="true" name="id" type="BIGINT">
|
||||||
|
<constraints nullable="false" primaryKey="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="delinquency_range_id" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="delinquency_bucket_id" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="created_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="created_on_utc" type="DATETIME">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="version" type="BIGINT">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_on_utc" type="DATETIME">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
</createTable>
|
||||||
|
<createTable tableName="m_loan_delinquency_tag_history">
|
||||||
|
<column autoIncrement="true" name="id" type="BIGINT">
|
||||||
|
<constraints nullable="false" primaryKey="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="delinquency_range_id" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="loan_id" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="addedon_date" type="DATE">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column defaultValueComputed="NULL" name="liftedon_date" type="DATE" />
|
||||||
|
<column name="created_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="created_on_utc" type="DATETIME">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="version" type="BIGINT">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_on_utc" type="DATETIME">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
</createTable>
|
||||||
|
</changeSet>
|
||||||
|
<changeSet author="fineract" id="1" context="postgresql">
|
||||||
|
<createTable tableName="m_delinquency_range">
|
||||||
|
<column autoIncrement="true" name="id" type="BIGINT">
|
||||||
|
<constraints nullable="false" primaryKey="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="classification" type="VARCHAR(100)">
|
||||||
|
<constraints unique="true" nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="min_age_days" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="max_age_days" type="BIGINT">
|
||||||
|
<constraints nullable="true" />
|
||||||
|
</column>
|
||||||
|
<column name="created_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="version" type="BIGINT">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
</createTable>
|
||||||
|
<createTable tableName="m_delinquency_bucket">
|
||||||
|
<column autoIncrement="true" name="id" type="BIGINT">
|
||||||
|
<constraints nullable="false" primaryKey="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="name" type="VARCHAR(100)">
|
||||||
|
<constraints unique="true" nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="created_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="version" type="BIGINT">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
</createTable>
|
||||||
|
<createTable tableName="m_delinquency_bucket_mappings">
|
||||||
|
<column autoIncrement="true" name="id" type="BIGINT">
|
||||||
|
<constraints nullable="false" primaryKey="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="delinquency_range_id" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="delinquency_bucket_id" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="created_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="version" type="BIGINT">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
</createTable>
|
||||||
|
<createTable tableName="m_loan_delinquency_tag_history">
|
||||||
|
<column autoIncrement="true" name="id" type="BIGINT">
|
||||||
|
<constraints nullable="false" primaryKey="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="delinquency_range_id" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="loan_id" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="addedon_date" type="DATE">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column defaultValueComputed="NULL" name="liftedon_date" type="DATE" />
|
||||||
|
<column name="created_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="version" type="BIGINT">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_by" type="BIGINT">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE">
|
||||||
|
<constraints nullable="false" />
|
||||||
|
</column>
|
||||||
|
</createTable>
|
||||||
|
</changeSet>
|
||||||
|
<changeSet author="fineract" id="2">
|
||||||
|
<addForeignKeyConstraint baseColumnNames="delinquency_range_id" baseTableName="m_delinquency_bucket_mappings"
|
||||||
|
constraintName="FK_m_delinquency_range_mapping" deferrable="false"
|
||||||
|
initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT"
|
||||||
|
referencedColumnNames="id" referencedTableName="m_delinquency_range" validate="true"/>
|
||||||
|
<addForeignKeyConstraint baseColumnNames="delinquency_bucket_id" baseTableName="m_delinquency_bucket_mappings"
|
||||||
|
constraintName="FK_m_delinquency_bucket_mapping" deferrable="false"
|
||||||
|
initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT"
|
||||||
|
referencedColumnNames="id" referencedTableName="m_delinquency_bucket" validate="true"/>
|
||||||
|
</changeSet>
|
||||||
|
<changeSet author="fineract" id="3">
|
||||||
|
<addColumn tableName="m_product_loan">
|
||||||
|
<column name="delinquency_bucket_id" type="BIGINT" defaultValueComputed="NULL"/>
|
||||||
|
</addColumn>
|
||||||
|
<addForeignKeyConstraint baseColumnNames="delinquency_bucket_id" baseTableName="m_product_loan"
|
||||||
|
constraintName="FK_m_product_loan_m_delinquency_bucket" deferrable="false"
|
||||||
|
initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT"
|
||||||
|
referencedColumnNames="id" referencedTableName="m_delinquency_bucket" validate="true"/>
|
||||||
|
</changeSet>
|
||||||
|
<changeSet author="fineract" id="4">
|
||||||
|
<addForeignKeyConstraint baseColumnNames="delinquency_range_id" baseTableName="m_loan_delinquency_tag_history"
|
||||||
|
constraintName="FK_m_delinquency_tags_range" deferrable="false"
|
||||||
|
initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT"
|
||||||
|
referencedColumnNames="id" referencedTableName="m_delinquency_range" validate="true"/>
|
||||||
|
<addForeignKeyConstraint baseColumnNames="loan_id" baseTableName="m_loan_delinquency_tag_history"
|
||||||
|
constraintName="FK_m_delinquency_tags_loan" deferrable="false"
|
||||||
|
initiallyDeferred="false" onDelete="RESTRICT" onUpdate="RESTRICT"
|
||||||
|
referencedColumnNames="id" referencedTableName="m_loan" validate="true"/>
|
||||||
|
</changeSet>
|
||||||
|
<changeSet author="fineract" id="5">
|
||||||
|
<insert tableName="m_permission">
|
||||||
|
<column name="grouping" value="organisation"/>
|
||||||
|
<column name="code" value="READ_DELINQUENCY_BUCKET"/>
|
||||||
|
<column name="entity_name" value="DELINQUENCY_BUCKET"/>
|
||||||
|
<column name="action_name" value="READ"/>
|
||||||
|
<column name="can_maker_checker" valueBoolean="false"/>
|
||||||
|
</insert>
|
||||||
|
<insert tableName="m_permission">
|
||||||
|
<column name="grouping" value="organisation"/>
|
||||||
|
<column name="code" value="CREATE_DELINQUENCY_BUCKET"/>
|
||||||
|
<column name="entity_name" value="DELINQUENCY_BUCKET"/>
|
||||||
|
<column name="action_name" value="CREATE"/>
|
||||||
|
<column name="can_maker_checker" valueBoolean="false"/>
|
||||||
|
</insert>
|
||||||
|
<insert tableName="m_permission">
|
||||||
|
<column name="grouping" value="organisation"/>
|
||||||
|
<column name="code" value="UPDATE_DELINQUENCY_BUCKET"/>
|
||||||
|
<column name="entity_name" value="DELINQUENCY_BUCKET"/>
|
||||||
|
<column name="action_name" value="UPDATE"/>
|
||||||
|
<column name="can_maker_checker" valueBoolean="false"/>
|
||||||
|
</insert>
|
||||||
|
<insert tableName="m_permission">
|
||||||
|
<column name="grouping" value="organisation"/>
|
||||||
|
<column name="code" value="DELETE_DELINQUENCY_BUCKET"/>
|
||||||
|
<column name="entity_name" value="DELINQUENCY_BUCKET"/>
|
||||||
|
<column name="action_name" value="DELETE"/>
|
||||||
|
<column name="can_maker_checker" valueBoolean="false"/>
|
||||||
|
</insert>
|
||||||
|
<insert tableName="m_permission">
|
||||||
|
<column name="grouping" value="organisation"/>
|
||||||
|
<column name="code" value="CREATE_DELINQUENCY_RANGE"/>
|
||||||
|
<column name="entity_name" value="DELINQUENCY_RANGE"/>
|
||||||
|
<column name="action_name" value="CREATE"/>
|
||||||
|
<column name="can_maker_checker" valueBoolean="false"/>
|
||||||
|
</insert>
|
||||||
|
<insert tableName="m_permission">
|
||||||
|
<column name="grouping" value="organisation"/>
|
||||||
|
<column name="code" value="UPDATE_DELINQUENCY_RANGE"/>
|
||||||
|
<column name="entity_name" value="DELINQUENCY_RANGE"/>
|
||||||
|
<column name="action_name" value="UPDATE"/>
|
||||||
|
<column name="can_maker_checker" valueBoolean="false"/>
|
||||||
|
</insert>
|
||||||
|
<insert tableName="m_permission">
|
||||||
|
<column name="grouping" value="organisation"/>
|
||||||
|
<column name="code" value="DELETE_DELINQUENCY_RANGE"/>
|
||||||
|
<column name="entity_name" value="DELINQUENCY_RANGE"/>
|
||||||
|
<column name="action_name" value="DELETE"/>
|
||||||
|
<column name="can_maker_checker" valueBoolean="false"/>
|
||||||
|
</insert>
|
||||||
|
</changeSet>
|
||||||
|
</databaseChangeLog>
|
||||||
+211
@@ -0,0 +1,211 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.integrationtests;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
import io.restassured.builder.RequestSpecBuilder;
|
||||||
|
import io.restassured.builder.ResponseSpecBuilder;
|
||||||
|
import io.restassured.http.ContentType;
|
||||||
|
import io.restassured.specification.RequestSpecification;
|
||||||
|
import io.restassured.specification.ResponseSpecification;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import org.apache.fineract.client.models.DeleteDelinquencyBucketResponse;
|
||||||
|
import org.apache.fineract.client.models.DeleteDelinquencyRangeResponse;
|
||||||
|
import org.apache.fineract.client.models.GetDelinquencyBucketsResponse;
|
||||||
|
import org.apache.fineract.client.models.GetDelinquencyRangesResponse;
|
||||||
|
import org.apache.fineract.client.models.PostDelinquencyBucketResponse;
|
||||||
|
import org.apache.fineract.client.models.PostDelinquencyRangeResponse;
|
||||||
|
import org.apache.fineract.client.models.PutDelinquencyBucketResponse;
|
||||||
|
import org.apache.fineract.client.models.PutDelinquencyRangeResponse;
|
||||||
|
import org.apache.fineract.integrationtests.common.Utils;
|
||||||
|
import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.products.DelinquencyRangesHelper;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
public class DelinquencyBucketsIntegrationTest {
|
||||||
|
|
||||||
|
private ResponseSpecification responseSpec;
|
||||||
|
private RequestSpecification requestSpec;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
Utils.initializeRESTAssured();
|
||||||
|
|
||||||
|
requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
|
||||||
|
requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
|
||||||
|
responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateDelinquencyRanges() {
|
||||||
|
// given
|
||||||
|
final String jsonRange = DelinquencyRangesHelper.getAsJSON(1, 3);
|
||||||
|
|
||||||
|
// when
|
||||||
|
final PostDelinquencyRangeResponse delinquencyRangeResponse01 = DelinquencyRangesHelper.createDelinquencyRange(requestSpec,
|
||||||
|
responseSpec, jsonRange);
|
||||||
|
final ArrayList<GetDelinquencyRangesResponse> ranges = DelinquencyRangesHelper.getDelinquencyRanges(requestSpec, responseSpec);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertNotNull(delinquencyRangeResponse01);
|
||||||
|
assertNotNull(ranges);
|
||||||
|
assertEquals(1, ranges.get(0).getMinimumAgeDays(), "Expected Min Age Days to 1");
|
||||||
|
assertEquals(3, ranges.get(0).getMaximumAgeDays(), "Expected Max Age Days to 3");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateDelinquencyRanges() {
|
||||||
|
// given
|
||||||
|
String jsonRange = DelinquencyRangesHelper.getAsJSON(1, 3);
|
||||||
|
final PostDelinquencyRangeResponse delinquencyRangeResponse01 = DelinquencyRangesHelper.createDelinquencyRange(requestSpec,
|
||||||
|
responseSpec, jsonRange);
|
||||||
|
jsonRange = DelinquencyRangesHelper.getAsJSON(1, 7);
|
||||||
|
assertNotNull(delinquencyRangeResponse01);
|
||||||
|
|
||||||
|
// when
|
||||||
|
final PutDelinquencyRangeResponse delinquencyRangeResponse02 = DelinquencyRangesHelper.updateDelinquencyRange(requestSpec,
|
||||||
|
responseSpec, delinquencyRangeResponse01.getResourceId(), jsonRange);
|
||||||
|
final GetDelinquencyRangesResponse range = DelinquencyRangesHelper.getDelinquencyRange(requestSpec, responseSpec,
|
||||||
|
delinquencyRangeResponse01.getResourceId());
|
||||||
|
final DeleteDelinquencyRangeResponse deleteDelinquencyRangeResponse = DelinquencyRangesHelper.deleteDelinquencyRange(requestSpec,
|
||||||
|
responseSpec, delinquencyRangeResponse01.getResourceId());
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertNotNull(delinquencyRangeResponse02);
|
||||||
|
assertNotNull(deleteDelinquencyRangeResponse);
|
||||||
|
assertNotNull(range);
|
||||||
|
assertNotEquals(3, range.getMaximumAgeDays());
|
||||||
|
assertEquals(1, range.getMinimumAgeDays());
|
||||||
|
assertEquals(7, range.getMaximumAgeDays());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelinquencyBuckets() {
|
||||||
|
// given
|
||||||
|
ArrayList<Integer> rangeIds = new ArrayList<>();
|
||||||
|
String jsonRange = DelinquencyRangesHelper.getAsJSON(1, 3);
|
||||||
|
PostDelinquencyRangeResponse delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec,
|
||||||
|
jsonRange);
|
||||||
|
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||||
|
jsonRange = DelinquencyRangesHelper.getAsJSON(4, 30);
|
||||||
|
// Create
|
||||||
|
delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec, jsonRange);
|
||||||
|
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||||
|
String jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds);
|
||||||
|
PostDelinquencyBucketResponse delinquencyBucketResponse = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec,
|
||||||
|
responseSpec, jsonBucket);
|
||||||
|
// Update
|
||||||
|
jsonRange = DelinquencyRangesHelper.getAsJSON(31, 60);
|
||||||
|
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||||
|
jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds);
|
||||||
|
PutDelinquencyBucketResponse updateDelinquencyBucketResponse = DelinquencyBucketsHelper.updateDelinquencyBucket(requestSpec,
|
||||||
|
responseSpec, delinquencyBucketResponse.getResourceId(), jsonBucket);
|
||||||
|
delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec, jsonRange);
|
||||||
|
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||||
|
// Read
|
||||||
|
final GetDelinquencyBucketsResponse delinquencyBucket = DelinquencyBucketsHelper.getDelinquencyBucket(requestSpec, responseSpec,
|
||||||
|
delinquencyBucketResponse.getResourceId());
|
||||||
|
|
||||||
|
// when
|
||||||
|
final ArrayList<GetDelinquencyBucketsResponse> bucketList = DelinquencyBucketsHelper.getDelinquencyBuckets(requestSpec,
|
||||||
|
responseSpec);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertNotNull(bucketList);
|
||||||
|
assertNotNull(delinquencyBucket);
|
||||||
|
assertEquals(2, delinquencyBucket.getRanges().size());
|
||||||
|
assertNotNull(delinquencyBucketResponse);
|
||||||
|
assertNotNull(updateDelinquencyBucketResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelinquencyBucketDelete() {
|
||||||
|
// given
|
||||||
|
ArrayList<Integer> rangeIds = new ArrayList<>();
|
||||||
|
String jsonRange = DelinquencyRangesHelper.getAsJSON(1, 3);
|
||||||
|
PostDelinquencyRangeResponse delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec,
|
||||||
|
jsonRange);
|
||||||
|
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||||
|
jsonRange = DelinquencyRangesHelper.getAsJSON(4, 30);
|
||||||
|
// Create
|
||||||
|
delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec, jsonRange);
|
||||||
|
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||||
|
String jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds);
|
||||||
|
PostDelinquencyBucketResponse delinquencyBucketResponse = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec,
|
||||||
|
responseSpec, jsonBucket);
|
||||||
|
// Delete
|
||||||
|
DeleteDelinquencyBucketResponse deleteDelinquencyBucketResponse = DelinquencyBucketsHelper.deleteDelinquencyBucket(requestSpec,
|
||||||
|
responseSpec, delinquencyBucketResponse.getResourceId());
|
||||||
|
|
||||||
|
// when
|
||||||
|
final ArrayList<GetDelinquencyBucketsResponse> bucketList = DelinquencyBucketsHelper.getDelinquencyBuckets(requestSpec,
|
||||||
|
responseSpec);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertNotNull(bucketList);
|
||||||
|
assertNotNull(delinquencyBucketResponse);
|
||||||
|
assertNotNull(deleteDelinquencyBucketResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelinquencyBucketsRangeAgeOverlaped() {
|
||||||
|
// Given
|
||||||
|
ArrayList<Integer> rangeIds = new ArrayList<>();
|
||||||
|
String jsonRange = DelinquencyRangesHelper.getAsJSON(1, 3);
|
||||||
|
PostDelinquencyRangeResponse delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec,
|
||||||
|
jsonRange);
|
||||||
|
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||||
|
jsonRange = DelinquencyRangesHelper.getAsJSON(3, 30);
|
||||||
|
// Create
|
||||||
|
delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec, jsonRange);
|
||||||
|
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||||
|
String jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds);
|
||||||
|
final ResponseSpecification response403Spec = new ResponseSpecBuilder().expectStatusCode(403).build();
|
||||||
|
|
||||||
|
// When
|
||||||
|
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, response403Spec, jsonBucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelinquencyBucketsNameDuplication() {
|
||||||
|
// Given
|
||||||
|
ArrayList<Integer> rangeIds = new ArrayList<>();
|
||||||
|
String jsonRange = DelinquencyRangesHelper.getAsJSON(1, 3);
|
||||||
|
PostDelinquencyRangeResponse delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec,
|
||||||
|
jsonRange);
|
||||||
|
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||||
|
jsonRange = DelinquencyRangesHelper.getAsJSON(4, 30);
|
||||||
|
// Create
|
||||||
|
delinquencyRangeResponse = DelinquencyRangesHelper.createDelinquencyRange(requestSpec, responseSpec, jsonRange);
|
||||||
|
rangeIds.add(delinquencyRangeResponse.getResourceId());
|
||||||
|
String jsonBucket = DelinquencyBucketsHelper.getAsJSON(rangeIds);
|
||||||
|
final ResponseSpecification response403Spec = new ResponseSpecBuilder().expectStatusCode(403).build();
|
||||||
|
|
||||||
|
// When
|
||||||
|
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec, jsonBucket);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, response403Spec, jsonBucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -338,4 +338,9 @@ public final class Utils {
|
|||||||
.spec(responseSpec).log().ifError().when().get(getURL).andReturn().asString();
|
.spec(responseSpec).log().ifError().when().get(getURL).andReturn().asString();
|
||||||
return templateLocation.substring(1, templateLocation.length() - 1);
|
return templateLocation.substring(1, templateLocation.length() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String emptyJson() {
|
||||||
|
return "{}";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+91
@@ -0,0 +1,91 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.integrationtests.common.products;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.linecorp.armeria.internal.shaded.guava.reflect.TypeToken;
|
||||||
|
import io.restassured.specification.RequestSpecification;
|
||||||
|
import io.restassured.specification.ResponseSpecification;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import org.apache.fineract.client.models.DeleteDelinquencyBucketResponse;
|
||||||
|
import org.apache.fineract.client.models.GetDelinquencyBucketsResponse;
|
||||||
|
import org.apache.fineract.client.models.PostDelinquencyBucketResponse;
|
||||||
|
import org.apache.fineract.client.models.PutDelinquencyBucketResponse;
|
||||||
|
import org.apache.fineract.client.util.JSON;
|
||||||
|
import org.apache.fineract.integrationtests.common.Utils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class DelinquencyBucketsHelper {
|
||||||
|
|
||||||
|
private static final String DELINQUENCY_BUCKETS_URL = "/fineract-provider/api/v1/delinquency/buckets";
|
||||||
|
private static final Gson GSON = new JSON().getGson();
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(DelinquencyBucketsHelper.class);
|
||||||
|
|
||||||
|
protected DelinquencyBucketsHelper() {}
|
||||||
|
|
||||||
|
public static ArrayList<GetDelinquencyBucketsResponse> getDelinquencyBuckets(final RequestSpecification requestSpec,
|
||||||
|
final ResponseSpecification responseSpec) {
|
||||||
|
String response = Utils.performServerGet(requestSpec, responseSpec, DELINQUENCY_BUCKETS_URL + "?" + Utils.TENANT_IDENTIFIER);
|
||||||
|
|
||||||
|
Type delinquencyBucketListType = new TypeToken<ArrayList<GetDelinquencyBucketsResponse>>() {}.getType();
|
||||||
|
return GSON.fromJson(response, delinquencyBucketListType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GetDelinquencyBucketsResponse getDelinquencyBucket(final RequestSpecification requestSpec,
|
||||||
|
final ResponseSpecification responseSpec, final Integer resourceId) {
|
||||||
|
String response = Utils.performServerGet(requestSpec, responseSpec,
|
||||||
|
DELINQUENCY_BUCKETS_URL + "/" + resourceId + "?" + Utils.TENANT_IDENTIFIER);
|
||||||
|
return GSON.fromJson(response, GetDelinquencyBucketsResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PostDelinquencyBucketResponse createDelinquencyBucket(final RequestSpecification requestSpec,
|
||||||
|
final ResponseSpecification responseSpec, final String json) {
|
||||||
|
LOG.info("JSON: {}", json);
|
||||||
|
final String response = Utils.performServerPost(requestSpec, responseSpec, DELINQUENCY_BUCKETS_URL + "?" + Utils.TENANT_IDENTIFIER,
|
||||||
|
json, null);
|
||||||
|
return GSON.fromJson(response, PostDelinquencyBucketResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PutDelinquencyBucketResponse updateDelinquencyBucket(final RequestSpecification requestSpec,
|
||||||
|
final ResponseSpecification responseSpec, final Integer resourceId, final String json) {
|
||||||
|
LOG.info("JSON: {}", json);
|
||||||
|
final String response = Utils.performServerPut(requestSpec, responseSpec,
|
||||||
|
DELINQUENCY_BUCKETS_URL + "/" + resourceId + "?" + Utils.TENANT_IDENTIFIER, json, null);
|
||||||
|
return GSON.fromJson(response, PutDelinquencyBucketResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DeleteDelinquencyBucketResponse deleteDelinquencyBucket(final RequestSpecification requestSpec,
|
||||||
|
final ResponseSpecification responseSpec, final Integer resourceId) {
|
||||||
|
final String response = Utils.performServerDelete(requestSpec, responseSpec,
|
||||||
|
DELINQUENCY_BUCKETS_URL + "/" + resourceId + "?" + Utils.TENANT_IDENTIFIER, Utils.emptyJson(), null);
|
||||||
|
return GSON.fromJson(response, DeleteDelinquencyBucketResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getAsJSON(final ArrayList<Integer> rangeIds) {
|
||||||
|
final HashMap<String, Object> map = new HashMap<>();
|
||||||
|
map.put("name", Utils.randomNameGenerator("Delinquency_Bucket_", 4));
|
||||||
|
map.put("ranges", rangeIds.toArray());
|
||||||
|
return new Gson().toJson(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.integrationtests.common.products;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.linecorp.armeria.internal.shaded.guava.reflect.TypeToken;
|
||||||
|
import io.restassured.specification.RequestSpecification;
|
||||||
|
import io.restassured.specification.ResponseSpecification;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import org.apache.fineract.client.models.DeleteDelinquencyRangeResponse;
|
||||||
|
import org.apache.fineract.client.models.GetDelinquencyRangesResponse;
|
||||||
|
import org.apache.fineract.client.models.PostDelinquencyRangeResponse;
|
||||||
|
import org.apache.fineract.client.models.PutDelinquencyRangeResponse;
|
||||||
|
import org.apache.fineract.client.util.JSON;
|
||||||
|
import org.apache.fineract.integrationtests.common.Utils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class DelinquencyRangesHelper {
|
||||||
|
|
||||||
|
private static final String DELINQUENCY_RANGES_URL = "/fineract-provider/api/v1/delinquency/ranges";
|
||||||
|
private static final Gson GSON = new JSON().getGson();
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(DelinquencyRangesHelper.class);
|
||||||
|
|
||||||
|
protected DelinquencyRangesHelper() {}
|
||||||
|
|
||||||
|
public static ArrayList<GetDelinquencyRangesResponse> getDelinquencyRanges(final RequestSpecification requestSpec,
|
||||||
|
final ResponseSpecification responseSpec) {
|
||||||
|
String response = Utils.performServerGet(requestSpec, responseSpec, DELINQUENCY_RANGES_URL + "?" + Utils.TENANT_IDENTIFIER);
|
||||||
|
|
||||||
|
Type delinquencyRangeListType = new TypeToken<ArrayList<GetDelinquencyRangesResponse>>() {}.getType();
|
||||||
|
return GSON.fromJson(response, delinquencyRangeListType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GetDelinquencyRangesResponse getDelinquencyRange(final RequestSpecification requestSpec,
|
||||||
|
final ResponseSpecification responseSpec, final Integer resourceId) {
|
||||||
|
String response = Utils.performServerGet(requestSpec, responseSpec,
|
||||||
|
DELINQUENCY_RANGES_URL + "/" + resourceId + "?" + Utils.TENANT_IDENTIFIER);
|
||||||
|
LOG.info("----- {}", response);
|
||||||
|
return GSON.fromJson(response, GetDelinquencyRangesResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PostDelinquencyRangeResponse createDelinquencyRange(final RequestSpecification requestSpec,
|
||||||
|
final ResponseSpecification responseSpec, final String json) {
|
||||||
|
final String response = Utils.performServerPost(requestSpec, responseSpec, DELINQUENCY_RANGES_URL + "?" + Utils.TENANT_IDENTIFIER,
|
||||||
|
json, null);
|
||||||
|
LOG.info("----- {}", response);
|
||||||
|
return GSON.fromJson(response, PostDelinquencyRangeResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PutDelinquencyRangeResponse updateDelinquencyRange(final RequestSpecification requestSpec,
|
||||||
|
final ResponseSpecification responseSpec, final Integer resourceId, final String json) {
|
||||||
|
final String response = Utils.performServerPut(requestSpec, responseSpec,
|
||||||
|
DELINQUENCY_RANGES_URL + "/" + resourceId + "?" + Utils.TENANT_IDENTIFIER, json, null);
|
||||||
|
LOG.info("----- {}", response);
|
||||||
|
return GSON.fromJson(response, PutDelinquencyRangeResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DeleteDelinquencyRangeResponse deleteDelinquencyRange(final RequestSpecification requestSpec,
|
||||||
|
final ResponseSpecification responseSpec, final Integer resourceId) {
|
||||||
|
final String response = Utils.performServerDelete(requestSpec, responseSpec,
|
||||||
|
DELINQUENCY_RANGES_URL + "/" + resourceId + "?" + Utils.TENANT_IDENTIFIER, Utils.emptyJson(), null);
|
||||||
|
LOG.info("----- {}", response);
|
||||||
|
return GSON.fromJson(response, DeleteDelinquencyRangeResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getAsJSON(int minimumAgeDays, int maximumAgeDays) {
|
||||||
|
final HashMap<String, Object> map = new HashMap<>();
|
||||||
|
map.put("classification", Utils.randomNameGenerator("Delinquency_", 4));
|
||||||
|
map.put("minimumAgeDays", minimumAgeDays);
|
||||||
|
map.put("maximumAgeDays", maximumAgeDays);
|
||||||
|
map.put("locale", "en");
|
||||||
|
return new Gson().toJson(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user