FINERACT-2421: Allow ProgressiveLoanInterestScheduleModel recalculation
Co-authored-by: Soma Sörös <soma.soros@dpc.hu>
This commit is contained in:
+13
-2
@@ -32,6 +32,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.cob.COBBusinessStepService;
|
||||
import org.apache.fineract.cob.data.BusinessStepNameAndOrder;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ProgressiveLoanModelProcessingService;
|
||||
import org.apache.fineract.portfolio.loanproduct.calc.data.ProgressiveLoanInterestScheduleModel;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.annotation.AfterStep;
|
||||
@@ -44,6 +46,7 @@ import org.springframework.lang.NonNull;
|
||||
public abstract class AbstractLoanItemProcessor implements ItemProcessor<Loan, Loan> {
|
||||
|
||||
private final COBBusinessStepService cobBusinessStepService;
|
||||
private final ProgressiveLoanModelProcessingService progressiveLoanModelProcessingService;
|
||||
|
||||
@Setter(AccessLevel.PROTECTED)
|
||||
private ExecutionContext executionContext;
|
||||
@@ -51,18 +54,26 @@ public abstract class AbstractLoanItemProcessor implements ItemProcessor<Loan, L
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
@Override
|
||||
public Loan process(@NonNull Loan item) throws Exception {
|
||||
public Loan process(@NonNull Loan loan) throws Exception {
|
||||
if (needToRebuildModel(loan)) {
|
||||
progressiveLoanModelProcessingService.recalculateModelAndSave(loan.getId());
|
||||
}
|
||||
Set<BusinessStepNameAndOrder> businessSteps = (Set<BusinessStepNameAndOrder>) executionContext.get(LoanCOBConstant.BUSINESS_STEPS);
|
||||
if (businessSteps == null) {
|
||||
throw new IllegalStateException("No business steps found in the execution context");
|
||||
}
|
||||
TreeMap<Long, String> businessStepMap = getBusinessStepMap(businessSteps);
|
||||
|
||||
Loan alreadyProcessedLoan = cobBusinessStepService.run(businessStepMap, item);
|
||||
Loan alreadyProcessedLoan = cobBusinessStepService.run(businessStepMap, loan);
|
||||
alreadyProcessedLoan.setLastClosedBusinessDate(businessDate);
|
||||
return alreadyProcessedLoan;
|
||||
}
|
||||
|
||||
private boolean needToRebuildModel(Loan loan) {
|
||||
return loan.isProgressiveSchedule() && !progressiveLoanModelProcessingService.hasValidModel(loan.getId(),
|
||||
ProgressiveLoanInterestScheduleModel.getModelVersion());
|
||||
}
|
||||
|
||||
private TreeMap<Long, String> getBusinessStepMap(Set<BusinessStepNameAndOrder> businessSteps) {
|
||||
Map<Long, String> businessStepMap = businessSteps.stream()
|
||||
.collect(Collectors.toMap(BusinessStepNameAndOrder::getStepOrder, BusinessStepNameAndOrder::getStepName));
|
||||
|
||||
+4
-2
@@ -19,13 +19,15 @@
|
||||
package org.apache.fineract.cob.loan;
|
||||
|
||||
import org.apache.fineract.cob.COBBusinessStepService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ProgressiveLoanModelProcessingService;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.annotation.BeforeStep;
|
||||
|
||||
public class InlineCOBLoanItemProcessor extends AbstractLoanItemProcessor {
|
||||
|
||||
public InlineCOBLoanItemProcessor(COBBusinessStepService cobBusinessStepService) {
|
||||
super(cobBusinessStepService);
|
||||
public InlineCOBLoanItemProcessor(COBBusinessStepService cobBusinessStepService,
|
||||
ProgressiveLoanModelProcessingService progressiveLoanModelProcessingService) {
|
||||
super(cobBusinessStepService, progressiveLoanModelProcessingService);
|
||||
}
|
||||
|
||||
@BeforeStep
|
||||
|
||||
+5
-1
@@ -28,6 +28,7 @@ import org.apache.fineract.infrastructure.jobs.service.JobName;
|
||||
import org.apache.fineract.infrastructure.springbatch.PropertyService;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ProgressiveLoanModelProcessingService;
|
||||
import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.configuration.annotation.StepScope;
|
||||
@@ -80,6 +81,9 @@ public class LoanCOBWorkerConfiguration {
|
||||
@Autowired
|
||||
private LoanLockingService loanLockingService;
|
||||
|
||||
@Autowired
|
||||
private ProgressiveLoanModelProcessingService progressiveLoanModelProcessingService;
|
||||
|
||||
@Bean(name = LoanCOBConstant.LOAN_COB_WORKER_STEP)
|
||||
public Step loanCOBWorkerStep(Flow cobFlow) {
|
||||
return stepBuilderFactory.get("Loan COB worker - Step").inputChannel(inboundRequests).flow(cobFlow).build();
|
||||
@@ -178,7 +182,7 @@ public class LoanCOBWorkerConfiguration {
|
||||
@Bean
|
||||
@StepScope
|
||||
public LoanItemProcessor cobWorkerItemProcessor() {
|
||||
return new LoanItemProcessor(cobBusinessStepService);
|
||||
return new LoanItemProcessor(cobBusinessStepService, progressiveLoanModelProcessingService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+4
-2
@@ -28,6 +28,7 @@ import org.apache.fineract.infrastructure.jobs.service.JobName;
|
||||
import org.apache.fineract.infrastructure.springbatch.PropertyService;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ProgressiveLoanModelProcessingService;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.configuration.annotation.JobScope;
|
||||
@@ -65,9 +66,10 @@ public class LoanInlineCOBConfig {
|
||||
private CustomJobParameterRepository customJobParameterRepository;
|
||||
@Autowired
|
||||
private CustomJobParameterResolver customJobParameterResolver;
|
||||
|
||||
@Autowired
|
||||
private LoanLockingService loanLockingService;
|
||||
@Autowired
|
||||
private ProgressiveLoanModelProcessingService progressiveLoanModelProcessingService;
|
||||
|
||||
@Bean
|
||||
public InlineLoanCOBBuildExecutionContextTasklet inlineLoanCOBBuildExecutionContextTasklet() {
|
||||
@@ -106,7 +108,7 @@ public class LoanInlineCOBConfig {
|
||||
@JobScope
|
||||
@Bean
|
||||
public InlineCOBLoanItemProcessor inlineCobWorkerItemProcessor() {
|
||||
return new InlineCOBLoanItemProcessor(cobBusinessStepService);
|
||||
return new InlineCOBLoanItemProcessor(cobBusinessStepService, progressiveLoanModelProcessingService);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -19,13 +19,15 @@
|
||||
package org.apache.fineract.cob.loan;
|
||||
|
||||
import org.apache.fineract.cob.COBBusinessStepService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ProgressiveLoanModelProcessingService;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.annotation.BeforeStep;
|
||||
|
||||
public class LoanItemProcessor extends AbstractLoanItemProcessor {
|
||||
|
||||
public LoanItemProcessor(COBBusinessStepService cobBusinessStepService) {
|
||||
super(cobBusinessStepService);
|
||||
public LoanItemProcessor(COBBusinessStepService cobBusinessStepService,
|
||||
ProgressiveLoanModelProcessingService progressiveLoanModelProcessingService) {
|
||||
super(cobBusinessStepService, progressiveLoanModelProcessingService);
|
||||
}
|
||||
|
||||
@BeforeStep
|
||||
|
||||
+5
@@ -40,6 +40,7 @@ import org.apache.fineract.infrastructure.core.service.MDCWrapper;
|
||||
import org.apache.fineract.infrastructure.instancemode.filter.FineractInstanceModeApiFilter;
|
||||
import org.apache.fineract.infrastructure.jobs.filter.LoanCOBApiFilter;
|
||||
import org.apache.fineract.infrastructure.jobs.filter.LoanCOBFilterHelper;
|
||||
import org.apache.fineract.infrastructure.jobs.filter.ProgressiveLoanModelCheckerFilter;
|
||||
import org.apache.fineract.infrastructure.security.data.PlatformRequestLog;
|
||||
import org.apache.fineract.infrastructure.security.filter.TenantAwareBasicAuthenticationFilter;
|
||||
import org.apache.fineract.infrastructure.security.filter.TwoFactorAuthenticationFilter;
|
||||
@@ -113,6 +114,8 @@ public class SecurityConfig {
|
||||
private LoanCOBFilterHelper loanCOBFilterHelper;
|
||||
@Autowired
|
||||
private IdempotencyStoreHelper idempotencyStoreHelper;
|
||||
@Autowired
|
||||
ProgressiveLoanModelCheckerFilter progressiveLoanModelCheckerFilter;
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
@@ -216,8 +219,10 @@ public class SecurityConfig {
|
||||
if (loanCOBFilterHelper != null) {
|
||||
http.addFilterAfter(loanCOBApiFilter(), FineractInstanceModeApiFilter.class).addFilterAfter(idempotencyStoreFilter(),
|
||||
LoanCOBApiFilter.class);
|
||||
http.addFilterBefore(progressiveLoanModelCheckerFilter, LoanCOBApiFilter.class);
|
||||
} else {
|
||||
http.addFilterAfter(idempotencyStoreFilter(), FineractInstanceModeApiFilter.class);
|
||||
http.addFilterAfter(progressiveLoanModelCheckerFilter, FineractInstanceModeApiFilter.class);
|
||||
}
|
||||
if (fineractProperties.getIpTracking().isEnabled()) {
|
||||
http.addFilterAfter(callerIpTrackingFilter(), RequestResponseFilter.class);
|
||||
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* 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.jobs.filter;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.http.BodyCachingHttpServletRequestWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ProgressiveLoanModelProcessingService;
|
||||
import org.apache.fineract.portfolio.loanproduct.calc.data.ProgressiveLoanInterestScheduleModel;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ProgressiveLoanModelCheckerFilter extends OncePerRequestFilter {
|
||||
|
||||
private final LoanRepository loanRepository;
|
||||
private final ProgressiveLoanModelProcessingService progressiveLoanModelProcessingService;
|
||||
private final ProgressiveLoanModelCheckerHelper helper;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
request = new BodyCachingHttpServletRequestWrapper(request);
|
||||
|
||||
if (!helper.isOnApiList((BodyCachingHttpServletRequestWrapper) request)) {
|
||||
proceed(filterChain, request, response);
|
||||
} else {
|
||||
List<Long> loanIds = helper.calculateRelevantLoanIds((BodyCachingHttpServletRequestWrapper) request);
|
||||
if (!loanIds.isEmpty()) {
|
||||
loanIds.forEach(loanId -> {
|
||||
if (isProgressiveLoan(loanId) && allowedLoanStatuses(loanId) && !hasValidModel(loanId)) {
|
||||
progressiveLoanModelProcessingService.recalculateModelAndSave(loanId);
|
||||
}
|
||||
});
|
||||
}
|
||||
proceed(filterChain, request, response);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isProgressiveLoan(Long loanId) {
|
||||
return loanRepository.isProgressiveLoan(loanId);
|
||||
}
|
||||
|
||||
private boolean allowedLoanStatuses(Long loanId) {
|
||||
return progressiveLoanModelProcessingService.allowedLoanStatuses(loanId);
|
||||
}
|
||||
|
||||
private boolean hasValidModel(Long loanId) {
|
||||
return progressiveLoanModelProcessingService.hasValidModel(loanId, ProgressiveLoanInterestScheduleModel.getModelVersion());
|
||||
}
|
||||
|
||||
private void proceed(FilterChain filterChain, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException {
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
|
||||
}
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* 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.jobs.filter;
|
||||
|
||||
import static org.apache.fineract.batch.command.CommandStrategyUtils.isRelativeUrlVersioned;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.json.JsonReadFeature;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.batch.domain.BatchRequest;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.infrastructure.core.http.BodyCachingHttpServletRequestWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.GLIMAccountInfoRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.GroupLoanIndividualMonitoringAccount;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
public class ProgressiveLoanModelCheckerHelper implements InitializingBean {
|
||||
|
||||
private final GLIMAccountInfoRepository glimAccountInfoRepository;
|
||||
private final LoanRepository loanRepository;
|
||||
|
||||
private final LoanRescheduleRequestRepository loanRescheduleRequestRepository;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private static final List<HttpMethod> HTTP_METHODS = List.of(HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE);
|
||||
|
||||
public static final Pattern IGNORE_LOAN_PATH_PATTERN = Pattern.compile("/v[1-9][0-9]*/loans/catch-up");
|
||||
public static final Pattern LOAN_PATH_PATTERN = Pattern.compile("/v[1-9][0-9]*/(?:reschedule)?loans/(?:external-id/)?([^/?]+).*");
|
||||
|
||||
public static final Pattern LOAN_GLIMACCOUNT_PATH_PATTERN = Pattern.compile("/v[1-9][0-9]*/loans/glimAccount/(\\d+).*");
|
||||
private static final Predicate<String> URL_FUNCTION = s -> LOAN_PATH_PATTERN.matcher(s).find()
|
||||
|| LOAN_GLIMACCOUNT_PATH_PATTERN.matcher(s).find();
|
||||
|
||||
private Long getLoanId(boolean isGlim, String pathInfo) {
|
||||
if (!isGlim) {
|
||||
String id = LOAN_PATH_PATTERN.matcher(pathInfo).replaceAll("$1");
|
||||
if (isExternal(pathInfo)) {
|
||||
String externalId = id;
|
||||
return loanRepository.findIdByExternalId(new ExternalId(externalId));
|
||||
} else if (isRescheduleLoans(pathInfo)) {
|
||||
return loanRescheduleRequestRepository.getLoanIdByRescheduleRequestId(Long.valueOf(id)).orElse(null);
|
||||
} else if (StringUtils.isNumeric(id)) {
|
||||
return Long.valueOf(id);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return Long.valueOf(LOAN_GLIMACCOUNT_PATH_PATTERN.matcher(pathInfo).replaceAll("$1"));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isExternal(String pathInfo) {
|
||||
return LOAN_PATH_PATTERN.matcher(pathInfo).matches() && pathInfo.contains("external-id");
|
||||
}
|
||||
|
||||
private boolean isRescheduleLoans(String pathInfo) {
|
||||
return LOAN_PATH_PATTERN.matcher(pathInfo).matches() && pathInfo.contains("/v1/rescheduleloans/");
|
||||
}
|
||||
|
||||
public boolean isOnApiList(BodyCachingHttpServletRequestWrapper request) throws IOException {
|
||||
String pathInfo = request.getPathInfo();
|
||||
String method = request.getMethod();
|
||||
if (StringUtils.isBlank(pathInfo)) {
|
||||
return false;
|
||||
}
|
||||
if (isBatchApi(pathInfo)) {
|
||||
return isBatchApiMatching(request);
|
||||
} else {
|
||||
return isApiMatching(method, pathInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isBatchApiMatching(BodyCachingHttpServletRequestWrapper request) throws IOException {
|
||||
for (BatchRequest batchRequest : getBatchRequests(request)) {
|
||||
String method = batchRequest.getMethod();
|
||||
String pathInfo = batchRequest.getRelativeUrl();
|
||||
if (isApiMatching(method, pathInfo)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<BatchRequest> getBatchRequests(BodyCachingHttpServletRequestWrapper request) throws IOException {
|
||||
List<BatchRequest> batchRequests = objectMapper.readValue(request.getInputStream(), new TypeReference<>() {});
|
||||
// since we read body, we have to reset so the upcoming readings are successful
|
||||
request.resetStream();
|
||||
for (BatchRequest batchRequest : batchRequests) {
|
||||
String pathInfo = "/" + batchRequest.getRelativeUrl();
|
||||
if (!isRelativeUrlVersioned(batchRequest.getRelativeUrl())) {
|
||||
pathInfo = "/v1/" + batchRequest.getRelativeUrl();
|
||||
}
|
||||
batchRequest.setRelativeUrl(pathInfo);
|
||||
}
|
||||
return batchRequests;
|
||||
}
|
||||
|
||||
private boolean isApiMatching(String method, String pathInfo) {
|
||||
return HTTP_METHODS.contains(HttpMethod.valueOf(method)) && !IGNORE_LOAN_PATH_PATTERN.matcher(pathInfo).find()
|
||||
&& URL_FUNCTION.test(pathInfo);
|
||||
}
|
||||
|
||||
private boolean isBatchApi(String pathInfo) {
|
||||
return pathInfo.startsWith("/v1/batches");
|
||||
}
|
||||
|
||||
private boolean isGlim(String pathInfo) {
|
||||
return LOAN_GLIMACCOUNT_PATH_PATTERN.matcher(pathInfo).matches();
|
||||
}
|
||||
|
||||
private List<Long> getGlimChildLoanIds(Long loanIdFromRequest) {
|
||||
GroupLoanIndividualMonitoringAccount glimAccount = glimAccountInfoRepository.findOneByIsAcceptingChildAndApplicationId(true,
|
||||
BigDecimal.valueOf(loanIdFromRequest));
|
||||
if (glimAccount != null) {
|
||||
return glimAccount.getChildLoan().stream().map(Loan::getId).toList();
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Long> calculateRelevantLoanIds(BodyCachingHttpServletRequestWrapper request) throws IOException {
|
||||
String pathInfo = request.getPathInfo();
|
||||
if (isBatchApi(pathInfo)) {
|
||||
return getLoanIdsFromBatchApi(request);
|
||||
} else {
|
||||
return getLoanIdsFromApi(pathInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Long> getLoanIdsFromBatchApi(BodyCachingHttpServletRequestWrapper request) throws IOException {
|
||||
List<Long> loanIds = new ArrayList<>();
|
||||
for (BatchRequest batchRequest : getBatchRequests(request)) {
|
||||
// check the URL for Loan related ID
|
||||
String relativeUrl = batchRequest.getRelativeUrl();
|
||||
if (!relativeUrl.contains("$.resourceId")) {
|
||||
// if resourceId reference is used, we simply don't know the resourceId without executing the requests
|
||||
// first, so skipping it
|
||||
loanIds.addAll(getLoanIdsFromApi(relativeUrl));
|
||||
}
|
||||
|
||||
// check the body for Loan ID
|
||||
Long loanId = getTopLevelLoanIdFromBatchRequest(batchRequest);
|
||||
if (loanId != null) {
|
||||
loanIds.add(loanId);
|
||||
}
|
||||
}
|
||||
return loanIds;
|
||||
}
|
||||
|
||||
private Long getTopLevelLoanIdFromBatchRequest(BatchRequest batchRequest) throws JsonProcessingException {
|
||||
String body = batchRequest.getBody();
|
||||
if (StringUtils.isNotBlank(body)) {
|
||||
JsonNode jsonNode = objectMapper.readTree(body);
|
||||
if (jsonNode.has("loanId")) {
|
||||
return jsonNode.get("loanId").asLong();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<Long> getLoanIdsFromApi(String pathInfo) {
|
||||
return getLoanIdList(pathInfo);
|
||||
}
|
||||
|
||||
private List<Long> getLoanIdList(String pathInfo) {
|
||||
boolean isGlim = isGlim(pathInfo);
|
||||
Long loanIdFromRequest = getLoanId(isGlim, pathInfo);
|
||||
if (loanIdFromRequest == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (isGlim) {
|
||||
return getGlimChildLoanIds(loanIdFromRequest);
|
||||
} else {
|
||||
return Collections.singletonList(loanIdFromRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
objectMapper.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
|
||||
}
|
||||
|
||||
}
|
||||
+7
@@ -35,6 +35,7 @@ import org.apache.fineract.infrastructure.core.service.MDCWrapper;
|
||||
import org.apache.fineract.infrastructure.instancemode.filter.FineractInstanceModeApiFilter;
|
||||
import org.apache.fineract.infrastructure.jobs.filter.LoanCOBApiFilter;
|
||||
import org.apache.fineract.infrastructure.jobs.filter.LoanCOBFilterHelper;
|
||||
import org.apache.fineract.infrastructure.jobs.filter.ProgressiveLoanModelCheckerFilter;
|
||||
import org.apache.fineract.infrastructure.security.converter.FineractJwtAuthenticationTokenConverter;
|
||||
import org.apache.fineract.infrastructure.security.data.TenantAuthenticationDetails;
|
||||
import org.apache.fineract.infrastructure.security.filter.BusinessDateFilter;
|
||||
@@ -118,6 +119,9 @@ public class AuthorizationServerConfig {
|
||||
@Autowired
|
||||
private BusinessDateReadPlatformService businessDateReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
ProgressiveLoanModelCheckerFilter progressiveLoanModelCheckerFilter;
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
public SecurityFilterChain publicEndpoints(HttpSecurity http) throws Exception {
|
||||
@@ -173,9 +177,12 @@ public class AuthorizationServerConfig {
|
||||
if (!Objects.isNull(loanCOBFilterHelper)) {
|
||||
http.addFilterAfter(loanCOBApiFilter(), FineractInstanceModeApiFilter.class) //
|
||||
.addFilterAfter(idempotencyStoreFilter(), LoanCOBApiFilter.class); //
|
||||
http.addFilterBefore(progressiveLoanModelCheckerFilter, LoanCOBApiFilter.class);
|
||||
} else {
|
||||
http.addFilterAfter(idempotencyStoreFilter(), FineractInstanceModeApiFilter.class); //
|
||||
http.addFilterAfter(progressiveLoanModelCheckerFilter, FineractInstanceModeApiFilter.class);
|
||||
}
|
||||
|
||||
if (fineractProperties.getIpTracking().isEnabled()) {
|
||||
http.addFilterAfter(callerIpTrackingFilter(), RequestResponseFilter.class);
|
||||
}
|
||||
|
||||
+3
-1
@@ -33,6 +33,7 @@ import java.util.Collections;
|
||||
import java.util.TreeMap;
|
||||
import org.apache.fineract.cob.COBBusinessStepService;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ProgressiveLoanModelProcessingService;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
@@ -41,8 +42,9 @@ import org.springframework.batch.item.ExecutionContext;
|
||||
public class LoanItemProcessorStepDefinitions implements En {
|
||||
|
||||
private COBBusinessStepService cobBusinessStepService = mock(COBBusinessStepService.class);
|
||||
private ProgressiveLoanModelProcessingService progressiveLoanModelProcessingService = mock(ProgressiveLoanModelProcessingService.class);
|
||||
|
||||
private LoanItemProcessor loanItemProcessor = new LoanItemProcessor(cobBusinessStepService);
|
||||
private LoanItemProcessor loanItemProcessor = new LoanItemProcessor(cobBusinessStepService, progressiveLoanModelProcessingService);
|
||||
|
||||
private Loan loan = mock(Loan.class);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user