You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by GitBox <gi...@apache.org> on 2022/11/29 14:39:38 UTC

[GitHub] [fineract] taskain7 opened a new pull request, #2777: [FINERACT-1678] Loan COB Catch Up

taskain7 opened a new pull request, #2777:
URL: https://github.com/apache/fineract/pull/2777

   ## Description
   
    - API that retrieves the oldest processed Loan, date and the current business date
    - API that for Loan COB catch up, COB will run on every old processed loan until the current business date
     - Automatic catch up mechanism for Inline COB
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1037949603


##########
fineract-provider/src/test/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImplTest.java:
##########
@@ -45,17 +52,24 @@ class InlineLoanCOBExecutorServiceImplTest {
     private InlineLoanCOBExecutorServiceImpl testObj;
     @Mock
     private TransactionTemplate transactionTemplate;
-
     @Mock
     private InlineLoanCOBExecutionDataParser dataParser;
+    @Mock
+    private LoanRepository loanRepository;
 
     @Test
     void shouldExceptionThrownIfLoanIsAlreadyLocked() {
         JsonCommand command = mock(JsonCommand.class);
         ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
+        HashMap<BusinessDateType, LocalDate> businessDates = new HashMap<>();
+        LocalDate businessDate = LocalDate.now(ZoneId.systemDefault());
+        businessDates.put(BusinessDateType.BUSINESS_DATE, businessDate);
+        businessDates.put(BusinessDateType.COB_DATE, businessDate.plusDays(1));

Review Comment:
   This is wrong. COB date shall be behind by a day of the (default) business date!!



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] taskain7 commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
taskain7 commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1068752548


##########
fineract-provider/src/main/java/org/apache/fineract/cob/api/LoanCOBCatchUpApiResource.java:
##########
@@ -0,0 +1,73 @@
+/**
+ * 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.cob.api;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+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 javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.service.LoanCOBCatchUpService;
+import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.springframework.stereotype.Component;
+
+@Path("/loans")
+@Component
+@Tag(name = "Loan COB Catch Up", description = "")
+@RequiredArgsConstructor
+public class LoanCOBCatchUpApiResource {
+
+    private final DefaultToApiJsonSerializer<OldestCOBProcessedLoanDTO> oldestCOBProcessedLoanSerializeService;
+    private final LoanCOBCatchUpService loanCOBCatchUpService;
+
+    @GET
+    @Path("oldest_cob_processed_loan")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Retrieves the oldest COB processed loan", description = "Retrieves the COB business date and the oldest COB processed loan")
+    @ApiResponses({
+            @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanCOBCatchUpApiResourceSwagger.GetOldestCOBProcessedLoanResponse.class))) })
+    public String getOldestCOBProcessedLoan() {
+        OldestCOBProcessedLoanDTO response = loanCOBCatchUpService.getOldestCOBProcessedLoan();
+
+        return oldestCOBProcessedLoanSerializeService.serialize(response);
+    }
+
+    @POST
+    @Path("loan_cob_catch_up")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Executes Loan COB Catch Up", description = "Executes the Loan COB job on every day from the oldest Loan to the current COB business date")
+    @ApiResponses({ @ApiResponse(responseCode = "200", description = "OK") })
+    public Response executeLoanCOBCatchUp() {
+        loanCOBCatchUpService.executeLoanCOBCatchUp();
+
+        return Response.status(202).build();

Review Comment:
   We decided to not returning any ID, since we will have multiple Spring Batch Execution IDs, instead of it we will introduce a new API that can tell whether the catch up is running or not



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1037483923


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java:
##########
@@ -94,6 +99,20 @@ public CommandProcessingResult executeInlineJob(JsonCommand command, String jobN
 
     @Override
     public void execute(List<Long> loanIds, String jobName) {
+        LocalDate oldestCOBBusinessDate = getOldestCOBBusinessDate(loanIds);
+        LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);

Review Comment:
   tend to agree. what is the use case here? when will this service to be called?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1066679786


##########
fineract-provider/src/main/java/org/apache/fineract/cob/api/LoanCOBCatchUpApiResource.java:
##########
@@ -0,0 +1,73 @@
+/**
+ * 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.cob.api;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+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 javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.service.LoanCOBCatchUpService;
+import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.springframework.stereotype.Component;
+
+@Path("/loans")
+@Component
+@Tag(name = "Loan COB Catch Up", description = "")
+@RequiredArgsConstructor
+public class LoanCOBCatchUpApiResource {
+
+    private final DefaultToApiJsonSerializer<OldestCOBProcessedLoanDTO> oldestCOBProcessedLoanSerializeService;
+    private final LoanCOBCatchUpService loanCOBCatchUpService;
+
+    @GET
+    @Path("oldest_cob_processed_loan")

Review Comment:
   @galovics `/loans/oldest-closed` is misleading. This has nothing to do with closed loans, instead COB closed / processed loans. Personally i like `oldest cob closed` or ` oldest cob processed`. Thoughts?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] taskain7 commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
taskain7 commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1062364639


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanCOBCatchUpServiceImpl.java:
##########
@@ -0,0 +1,105 @@
+/**
+ * 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.cob.service;
+
+import com.google.gson.Gson;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.loan.LoanCOBConstant;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetailRepository;
+import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
+import org.apache.fineract.infrastructure.jobs.service.JobStarter;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.configuration.JobLocator;
+import org.springframework.batch.core.launch.NoSuchJobException;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class LoanCOBCatchUpServiceImpl implements LoanCOBCatchUpService, InitializingBean {
+
+    private final LoanRepository loanRepository;
+    private final JobStarter jobStarter;
+    private final JobLocator jobLocator;
+    private final ScheduledJobDetailRepository scheduledJobDetailRepository;
+    private Gson gson;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        this.gson = GoogleGsonSerializerHelper.createSimpleGson();
+    }
+
+    @Override
+    public OldestCOBProcessedLoanDTO getOldestCOBProcessedLoan() {
+        List<Loan> oldestCOBProcessedLoan = loanRepository.findOldestCOBProcessedLoan();
+        OldestCOBProcessedLoanDTO oldestCOBProcessedLoanDTO = new OldestCOBProcessedLoanDTO();
+        oldestCOBProcessedLoanDTO.setLoanIds(oldestCOBProcessedLoan.stream().map(Loan::getId).toList());
+        oldestCOBProcessedLoanDTO
+                .setCobProcessedDate(oldestCOBProcessedLoan.stream().map(Loan::getLastClosedBusinessDate).findFirst().get());
+        oldestCOBProcessedLoanDTO.setCobBusinessDate(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE));
+        return oldestCOBProcessedLoanDTO;
+    }
+
+    @Override
+    public void executeLoanCOBCatchUp() {
+        FineractContext context = ThreadLocalContextUtil.getContext();
+        CompletableFuture<Void> executeCatchUpFuture = CompletableFuture.runAsync(() -> executeLoanCOBCatchUpAsync(context));

Review Comment:
   I've configured a Spring asny executor, you can review the PR again @galovics @adamsaghy 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] taskain7 commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
taskain7 commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1066752039


##########
fineract-provider/src/main/java/org/apache/fineract/cob/api/LoanCOBCatchUpApiResource.java:
##########
@@ -0,0 +1,73 @@
+/**
+ * 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.cob.api;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+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 javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.service.LoanCOBCatchUpService;
+import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.springframework.stereotype.Component;
+
+@Path("/loans")
+@Component
+@Tag(name = "Loan COB Catch Up", description = "")
+@RequiredArgsConstructor
+public class LoanCOBCatchUpApiResource {
+
+    private final DefaultToApiJsonSerializer<OldestCOBProcessedLoanDTO> oldestCOBProcessedLoanSerializeService;
+    private final LoanCOBCatchUpService loanCOBCatchUpService;
+
+    @GET
+    @Path("oldest_cob_processed_loan")

Review Comment:
   I agree @adamsaghy , I would go with `oldest-cob-closed`



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] galovics commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
galovics commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1037387206


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java:
##########
@@ -116,6 +135,12 @@ public void execute(List<Long> loanIds, String jobName) {
         }
     }
 
+    private LocalDate getOldestCOBBusinessDate(List<Long> loanIds) {
+        List<Loan> oldestCOBProcessedLoanByLoanIds = loanRepository.findOldestCOBProcessedLoanByLoanIds(loanIds);

Review Comment:
   I think this'll be a performance issue potentially cause we're retrieving Loan objects. Can't we do the "oldest" calculation in the query?



##########
fineract-provider/src/main/java/org/apache/fineract/cob/api/LoanCOBCatchUpApiResource.java:
##########
@@ -0,0 +1,73 @@
+/**
+ * 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.cob.api;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+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 javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.service.LoanCOBCatchUpService;
+import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.springframework.stereotype.Component;
+
+@Path("/loans")
+@Component
+@Tag(name = "Loan COB Catch Up", description = "")
+@RequiredArgsConstructor
+public class LoanCOBCatchUpApiResource {
+
+    private final DefaultToApiJsonSerializer<OldestCOBProcessedLoanDTO> oldestCOBProcessedLoanSerializeService;
+    private final LoanCOBCatchUpService loanCOBCatchUpService;
+
+    @GET
+    @Path("oldestCOBProcessedLoan")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Retrieves the oldest COB processed loan", description = "Retrieves the COB business date and the oldest COB processed loan")
+    @ApiResponses({
+            @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanCOBCatchUpApiResourceSwagger.GetOldestCOBProcessedLoanResponse.class))) })
+    public String getOldestCOBProcessedLoan() {
+        OldestCOBProcessedLoanDTO response = loanCOBCatchUpService.getOldestCOBProcessedLoan();
+
+        return oldestCOBProcessedLoanSerializeService.serialize(response);
+    }
+
+    @POST
+    @Path("loanCOBCatchUp")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Executes Loan COB Catch Up", description = "Executes the Loan COB job on every day from the oldest Loan to the current COB business date")
+    @ApiResponses({ @ApiResponse(responseCode = "200", description = "OK") })
+    public Response executeLoanCOBCatchUp() {
+        loanCOBCatchUpService.executeLoanCOBCatchUp();
+
+        return Response.status(200).build();

Review Comment:
   Make it HTTP 202.



##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanCOBCatchUpServiceImpl.java:
##########
@@ -0,0 +1,105 @@
+/**
+ * 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.cob.service;
+
+import com.google.gson.Gson;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.loan.LoanCOBConstant;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetailRepository;
+import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
+import org.apache.fineract.infrastructure.jobs.service.JobStarter;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.configuration.JobLocator;
+import org.springframework.batch.core.launch.NoSuchJobException;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class LoanCOBCatchUpServiceImpl implements LoanCOBCatchUpService, InitializingBean {
+
+    private final LoanRepository loanRepository;
+    private final JobStarter jobStarter;
+    private final JobLocator jobLocator;
+    private final ScheduledJobDetailRepository scheduledJobDetailRepository;
+    private Gson gson;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        this.gson = GoogleGsonSerializerHelper.createSimpleGson();
+    }
+
+    @Override
+    public OldestCOBProcessedLoanDTO getOldestCOBProcessedLoan() {
+        List<Loan> oldestCOBProcessedLoan = loanRepository.findOldestCOBProcessedLoan();
+        OldestCOBProcessedLoanDTO oldestCOBProcessedLoanDTO = new OldestCOBProcessedLoanDTO();
+        oldestCOBProcessedLoanDTO.setLoanIds(oldestCOBProcessedLoan.stream().map(Loan::getId).toList());
+        oldestCOBProcessedLoanDTO
+                .setCobProcessedDate(oldestCOBProcessedLoan.stream().map(Loan::getLastClosedBusinessDate).findFirst().get());
+        oldestCOBProcessedLoanDTO.setCobBusinessDate(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE));
+        return oldestCOBProcessedLoanDTO;
+    }
+
+    @Override
+    public void executeLoanCOBCatchUp() {
+        FineractContext context = ThreadLocalContextUtil.getContext();
+        CompletableFuture<Void> executeCatchUpFuture = CompletableFuture.runAsync(() -> executeLoanCOBCatchUpAsync(context));
+    }
+
+    private void executeLoanCOBCatchUpAsync(FineractContext context) {
+        ThreadLocalContextUtil.init(context);
+        LocalDate oldestCOBProcessedDate = loanRepository.findOldestCOBProcessedLoan().get(0).getLastClosedBusinessDate().plusDays(1);
+        LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
+        try {

Review Comment:
   Shouldn't we at least check wheteher the oldest date is the same as the business date and if they're the same, just skip the execution (or throw an exception)?



##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanCOBCatchUpServiceImpl.java:
##########
@@ -0,0 +1,105 @@
+/**
+ * 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.cob.service;
+
+import com.google.gson.Gson;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.loan.LoanCOBConstant;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetailRepository;
+import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
+import org.apache.fineract.infrastructure.jobs.service.JobStarter;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.configuration.JobLocator;
+import org.springframework.batch.core.launch.NoSuchJobException;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class LoanCOBCatchUpServiceImpl implements LoanCOBCatchUpService, InitializingBean {
+
+    private final LoanRepository loanRepository;
+    private final JobStarter jobStarter;
+    private final JobLocator jobLocator;
+    private final ScheduledJobDetailRepository scheduledJobDetailRepository;
+    private Gson gson;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        this.gson = GoogleGsonSerializerHelper.createSimpleGson();
+    }
+
+    @Override
+    public OldestCOBProcessedLoanDTO getOldestCOBProcessedLoan() {
+        List<Loan> oldestCOBProcessedLoan = loanRepository.findOldestCOBProcessedLoan();
+        OldestCOBProcessedLoanDTO oldestCOBProcessedLoanDTO = new OldestCOBProcessedLoanDTO();
+        oldestCOBProcessedLoanDTO.setLoanIds(oldestCOBProcessedLoan.stream().map(Loan::getId).toList());
+        oldestCOBProcessedLoanDTO
+                .setCobProcessedDate(oldestCOBProcessedLoan.stream().map(Loan::getLastClosedBusinessDate).findFirst().get());
+        oldestCOBProcessedLoanDTO.setCobBusinessDate(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE));
+        return oldestCOBProcessedLoanDTO;
+    }
+
+    @Override
+    public void executeLoanCOBCatchUp() {
+        FineractContext context = ThreadLocalContextUtil.getContext();
+        CompletableFuture<Void> executeCatchUpFuture = CompletableFuture.runAsync(() -> executeLoanCOBCatchUpAsync(context));

Review Comment:
   We should be very careful with this since this is using the default ForkJoinPool or a Thread per task based executor.
   Let's configure a proper AsyncTaskExecutor to submit this task (might be already configured in the app, haven't checked)



##########
fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/domain/ScheduledJobDetailRepository.java:
##########
@@ -45,4 +45,7 @@
     @Query("select jobDetail from ScheduledJobDetail jobDetail where jobDetail.nodeId = :nodeId or jobDetail.nodeId = 0")
     List<ScheduledJobDetail> findAllJobs(@Param("nodeId") Integer nodeId);
 
+    @Query("select jobDetail from ScheduledJobDetail jobDetail where jobDetail.jobName = :jobName")

Review Comment:
   No need for the custom Query. The generated Spring Data JPA one will be the same.



##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java:
##########
@@ -94,6 +99,20 @@ public CommandProcessingResult executeInlineJob(JsonCommand command, String jobN
 
     @Override
     public void execute(List<Long> loanIds, String jobName) {
+        LocalDate oldestCOBBusinessDate = getOldestCOBBusinessDate(loanIds);
+        LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);

Review Comment:
   Aren't we missing a condition here to check whether the oldest date is the same as the current COB business date and if that's the case, just skip the execution? And probably we should do the same thing to remove loans which is in this state.
   Might be wrong though, what do you think?
   cc @adamsaghy 



##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanCOBCatchUpServiceImpl.java:
##########
@@ -0,0 +1,105 @@
+/**
+ * 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.cob.service;
+
+import com.google.gson.Gson;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.loan.LoanCOBConstant;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetailRepository;
+import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
+import org.apache.fineract.infrastructure.jobs.service.JobStarter;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.configuration.JobLocator;
+import org.springframework.batch.core.launch.NoSuchJobException;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class LoanCOBCatchUpServiceImpl implements LoanCOBCatchUpService, InitializingBean {
+
+    private final LoanRepository loanRepository;
+    private final JobStarter jobStarter;
+    private final JobLocator jobLocator;
+    private final ScheduledJobDetailRepository scheduledJobDetailRepository;
+    private Gson gson;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        this.gson = GoogleGsonSerializerHelper.createSimpleGson();
+    }
+
+    @Override
+    public OldestCOBProcessedLoanDTO getOldestCOBProcessedLoan() {
+        List<Loan> oldestCOBProcessedLoan = loanRepository.findOldestCOBProcessedLoan();
+        OldestCOBProcessedLoanDTO oldestCOBProcessedLoanDTO = new OldestCOBProcessedLoanDTO();
+        oldestCOBProcessedLoanDTO.setLoanIds(oldestCOBProcessedLoan.stream().map(Loan::getId).toList());
+        oldestCOBProcessedLoanDTO
+                .setCobProcessedDate(oldestCOBProcessedLoan.stream().map(Loan::getLastClosedBusinessDate).findFirst().get());
+        oldestCOBProcessedLoanDTO.setCobBusinessDate(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE));
+        return oldestCOBProcessedLoanDTO;
+    }
+
+    @Override
+    public void executeLoanCOBCatchUp() {
+        FineractContext context = ThreadLocalContextUtil.getContext();
+        CompletableFuture<Void> executeCatchUpFuture = CompletableFuture.runAsync(() -> executeLoanCOBCatchUpAsync(context));
+    }
+
+    private void executeLoanCOBCatchUpAsync(FineractContext context) {
+        ThreadLocalContextUtil.init(context);

Review Comment:
   Since this is being executed on a separate thread, let's put it into a try-finally block to make sure we clean up the ThreadLocalContextUtil (with a reset call).



##########
integration-tests/src/test/java/org/apache/fineract/integrationtests/inlinecob/InlineLoanCOBTest.java:
##########
@@ -0,0 +1,158 @@
+/**
+ * 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.inlinecob;
+
+import io.restassured.builder.RequestSpecBuilder;
+import io.restassured.builder.ResponseSpecBuilder;
+import io.restassured.http.ContentType;
+import io.restassured.path.json.JsonPath;
+import io.restassured.specification.RequestSpecification;
+import io.restassured.specification.ResponseSpecification;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import org.apache.fineract.client.models.GetLoansLoanIdResponse;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.integrationtests.common.BusinessDateHelper;
+import org.apache.fineract.integrationtests.common.ClientHelper;
+import org.apache.fineract.integrationtests.common.CollateralManagementHelper;
+import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
+import org.apache.fineract.integrationtests.common.Utils;
+import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
+import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
+import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
+import org.apache.fineract.integrationtests.common.loans.LoanStatusChecker;
+import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+
+@Order(1)
+@TestMethodOrder(MethodOrderer.MethodName.class)
+public class InlineLoanCOBTest {
+
+    private ResponseSpecification responseSpec;
+    private RequestSpecification requestSpec;
+    private InlineLoanCOBHelper inlineLoanCOBHelper;
+    private LoanTransactionHelper loanTransactionHelper;
+
+    @BeforeEach
+    public void setup() {
+        Utils.initializeRESTAssured();
+        requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
+        requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
+        requestSpec.header("Fineract-Platform-TenantId", "default");
+        responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
+        inlineLoanCOBHelper = new InlineLoanCOBHelper(requestSpec, responseSpec);
+    }
+
+    @Test
+    public void testInlineCOBCatchUpLoans() {

Review Comment:
   I don't think this is testing the catch-up behavior, does it?



##########
integration-tests/src/test/java/org/apache/fineract/integrationtests/inlinecob/InlineLoanCOBTest.java:
##########
@@ -0,0 +1,158 @@
+/**
+ * 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.inlinecob;
+
+import io.restassured.builder.RequestSpecBuilder;
+import io.restassured.builder.ResponseSpecBuilder;
+import io.restassured.http.ContentType;
+import io.restassured.path.json.JsonPath;
+import io.restassured.specification.RequestSpecification;
+import io.restassured.specification.ResponseSpecification;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import org.apache.fineract.client.models.GetLoansLoanIdResponse;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.integrationtests.common.BusinessDateHelper;
+import org.apache.fineract.integrationtests.common.ClientHelper;
+import org.apache.fineract.integrationtests.common.CollateralManagementHelper;
+import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
+import org.apache.fineract.integrationtests.common.Utils;
+import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
+import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
+import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
+import org.apache.fineract.integrationtests.common.loans.LoanStatusChecker;
+import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+
+@Order(1)
+@TestMethodOrder(MethodOrderer.MethodName.class)

Review Comment:
   Why do we need these 2 annotations?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1034872675


##########
fineract-provider/src/main/java/org/apache/fineract/cob/common/InitialisationTasklet.java:
##########
@@ -41,11 +47,17 @@ public class InitialisationTasklet implements Tasklet {
 
     @Override
     public RepeatStatus execute(@NotNull StepContribution contribution, @NotNull ChunkContext chunkContext) throws Exception {
+        HashMap<BusinessDateType, LocalDate> businessDates = ThreadLocalContextUtil.getBusinessDates();

Review Comment:
   Not a great problem, but it would be nice to not use directly the ThreadLocalContextUtil, rather fetch it from DateUtils, which can fetch it from the ThreadLocalContextUtil. Its just nicer to fetch it through the same object (DateUtils)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1037944537


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java:
##########
@@ -96,6 +97,19 @@ public CommandProcessingResult executeInlineJob(JsonCommand command, String jobN
 
     @Override
     public void execute(List<Long> loanIds, String jobName) {
+        LocalDate oldestCOBBusinessDate = getOldestCOBBusinessDate(loanIds);
+        LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
+        List<Long> loanIdsToBeProcessed = getLoanIdsTOBeProcessed(loanIds, oldestCOBBusinessDate, cobBusinessDate);
+        if (!loanIdsToBeProcessed.isEmpty()) {
+            LocalDate executingBusinessDate = oldestCOBBusinessDate.plusDays(1);
+            while (!executingBusinessDate.isAfter(cobBusinessDate)) {
+                execute(loanIdsToBeProcessed, jobName, executingBusinessDate);

Review Comment:
   The loanIdsToBeProcessed is not ordered. if the loan last cob date is not the same (1-5 days before the actual COB date), how it would now to not run the job for loans which are already processed for that particular day?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] galovics merged pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
galovics merged PR #2777:
URL: https://github.com/apache/fineract/pull/2777


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1061508505


##########
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java:
##########
@@ -72,14 +73,20 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
 
     String FIND_ALL_NON_CLOSED = "select loan.id from Loan loan where loan.loanStatus in (100,200,300,303,304)";
 
-    String FIND_ALL_NON_CLOSED_ONE_DAY_BEHIND = "select loan.id from Loan loan where loan.loanStatus in (100,200,300,303,304) and (:last_closed_business_date = loan.lastClosedBusinessDate or loan.lastClosedBusinessDate is NULL)";
+    String FIND_ALL_NON_CLOSED_ONE_DAY_BEHIND = "select loan.id from Loan loan where loan.loanStatus in (100,200,300,303,304) and (:businessDate = loan.lastClosedBusinessDate or loan.lastClosedBusinessDate is NULL)";
 
     String FIND_NON_CLOSED_LOAN_THAT_BELONGS_TO_CLIENT = "select loan from Loan loan where loan.id = :loanId and loan.loanStatus = 300 and loan.client.id = :clientId";
 
     String FIND_BY_ACCOUNT_NUMBER = "select loan from Loan loan where loan.accountNumber = :accountNumber";
 
     String FIND_ID_BY_EXTERNAL_ID = "SELECT loan.id FROM Loan loan WHERE loan.externalId = :externalId";
 
+    String FIND_OLDEST_COB_PROCESSED_LOAN = "select loan from Loan loan where loan.lastClosedBusinessDate = (select min(l.lastClosedBusinessDate) from Loan l)";
+
+    String FIND_OLDEST_COB_PROCESSED_LOAN_DATE_BY_LOAN_IDS = "select min(loan.lastClosedBusinessDate) from Loan loan where loan.id in :loanIds";
+
+    String FIND_ALL_NON_CLOSED_LOAN_IDS_BEHIND_BY_LOAN_IDS = "select loan.id from Loan loan where loan.id IN :loanIds and (loan.lastClosedBusinessDate <> :cobBusinessDate or loan.lastClosedBusinessDate is null)";

Review Comment:
   Should we consider to merge 2-3 queries into one and in 1 run get all the informations in a sorted way?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1037939515


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java:
##########
@@ -120,6 +132,19 @@ public void execute(List<Long> loanIds, String jobName) {
         }
     }
 
+    private LocalDate getOldestCOBBusinessDate(List<Long> loanIds) {
+        return loanRepository.findOldestCOBProcessedLoanByLoanIds(loanIds)
+                .orElse(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE).minusDays(1));
+    }
+
+    private List<Long> getLoanIdsTOBeProcessed(List<Long> loanIds, LocalDate oldestCOBBusinessDate, LocalDate cobBusinessDate) {
+        if (!oldestCOBBusinessDate.isBefore(cobBusinessDate)) {

Review Comment:
   for better readability would you switch this condition?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1037908085


##########
fineract-provider/src/main/java/org/apache/fineract/cob/api/LoanCOBCatchUpApiResource.java:
##########
@@ -0,0 +1,73 @@
+/**
+ * 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.cob.api;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+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 javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.service.LoanCOBCatchUpService;
+import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.springframework.stereotype.Component;
+
+@Path("/loans")
+@Component
+@Tag(name = "Loan COB Catch Up", description = "")
+@RequiredArgsConstructor
+public class LoanCOBCatchUpApiResource {
+
+    private final DefaultToApiJsonSerializer<OldestCOBProcessedLoanDTO> oldestCOBProcessedLoanSerializeService;
+    private final LoanCOBCatchUpService loanCOBCatchUpService;
+
+    @GET
+    @Path("oldestCOBProcessedLoan")

Review Comment:
   I think "lowercase with dash separator" would be better naming strategy for API.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] taskain7 commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
taskain7 commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1034856658


##########
fineract-provider/src/main/java/org/apache/fineract/cob/data/OldestCOBProcessedLoanDTO.java:
##########
@@ -0,0 +1,31 @@
+/**
+ * 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.cob.data;
+
+import java.time.LocalDate;
+import java.util.List;
+import lombok.Data;
+
+@Data
+public class OldestCOBProcessedLoanDTO {
+
+    private List<Long> loanIds;
+    private LocalDate COBProcessedDate;
+    private LocalDate COBBusinessDate;

Review Comment:
   Business Date is the current Business date, processed date is when the loan was successfully processed last time



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1066694008


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java:
##########
@@ -120,6 +141,16 @@ public void execute(List<Long> loanIds, String jobName) {
         }
     }
 
+    private LocalDate getOldestCOBBusinessDate(List<Loan> loans) {

Review Comment:
   Do we have test for this? It looks not straightforward logic... :/



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1061522871


##########
integration-tests/src/test/java/org/apache/fineract/integrationtests/DelinquencyBucketsIntegrationTest.java:
##########
@@ -781,7 +781,7 @@ public void testLoanClassificationStepAsPartOfCOB() {
 
         // Move the Business date to get older the loan and to have an overdue loan
         LocalDate lastLoanCOBBusinessDate = businessDate;
-        businessDate = businessDate.plusDays(3);
+        businessDate = businessDate.plusDays(4);

Review Comment:
   I dont like this.
   
   If it was not failing prior, why it started to fail when the catch up was introduced.
   
   If it was wrong, why it was not failing and why started now?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1037944537


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java:
##########
@@ -96,6 +97,19 @@ public CommandProcessingResult executeInlineJob(JsonCommand command, String jobN
 
     @Override
     public void execute(List<Long> loanIds, String jobName) {
+        LocalDate oldestCOBBusinessDate = getOldestCOBBusinessDate(loanIds);
+        LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
+        List<Long> loanIdsToBeProcessed = getLoanIdsTOBeProcessed(loanIds, oldestCOBBusinessDate, cobBusinessDate);
+        if (!loanIdsToBeProcessed.isEmpty()) {
+            LocalDate executingBusinessDate = oldestCOBBusinessDate.plusDays(1);
+            while (!executingBusinessDate.isAfter(cobBusinessDate)) {
+                execute(loanIdsToBeProcessed, jobName, executingBusinessDate);

Review Comment:
   The loanIdsToBeProcessed is not ordered. if the loan last cob date is not the same (1-5 days before the actual COB date), how it would know to not run the job for loans which are already processed for that particular day?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1034877184


##########
fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java:
##########
@@ -37,30 +41,41 @@
 import org.springframework.batch.core.scope.context.ChunkContext;
 import org.springframework.batch.core.step.tasklet.Tasklet;
 import org.springframework.batch.repeat.RepeatStatus;
-import org.springframework.stereotype.Component;
 
 @Slf4j
 @RequiredArgsConstructor
-@Component
 public class InlineLoanCOBBuildExecutionContextTasklet implements Tasklet {
 
-    private final GoogleGsonSerializerHelper gsonFactory;
     private final COBBusinessStepService cobBusinessStepService;
     private final CustomJobParameterRepository customJobParameterRepository;
 
     private final Gson gson = GoogleGsonSerializerHelper.createSimpleGson();
 
     @Override
     public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
+        HashMap<BusinessDateType, LocalDate> businessDates = ThreadLocalContextUtil.getBusinessDates();
         ThreadLocalContextUtil.setActionContext(ActionContext.COB);
         TreeMap<Long, String> cobBusinessStepMap = cobBusinessStepService.getCOBBusinessStepMap(LoanCOBBusinessStep.class,
                 LoanCOBConstant.LOAN_COB_JOB_NAME);
         contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.LOAN_IDS, getLoanIdsFromJobParameters(chunkContext));
+        String businessDate = getBusinessDateFromJobParameters(chunkContext);
+        contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME, businessDate);
         contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.BUSINESS_STEP_MAP, cobBusinessStepMap);
-
+        businessDates.put(BusinessDateType.COB_DATE, LocalDate.parse(businessDate, DateTimeFormatter.ISO_DATE));
+        businessDates.put(BusinessDateType.BUSINESS_DATE, LocalDate.parse(businessDate, DateTimeFormatter.ISO_DATE).plusDays(1));

Review Comment:
   You can save some perf on not doing the parse twice...



##########
fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java:
##########
@@ -37,30 +41,41 @@
 import org.springframework.batch.core.scope.context.ChunkContext;
 import org.springframework.batch.core.step.tasklet.Tasklet;
 import org.springframework.batch.repeat.RepeatStatus;
-import org.springframework.stereotype.Component;
 
 @Slf4j
 @RequiredArgsConstructor
-@Component
 public class InlineLoanCOBBuildExecutionContextTasklet implements Tasklet {
 
-    private final GoogleGsonSerializerHelper gsonFactory;
     private final COBBusinessStepService cobBusinessStepService;
     private final CustomJobParameterRepository customJobParameterRepository;
 
     private final Gson gson = GoogleGsonSerializerHelper.createSimpleGson();
 
     @Override
     public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
+        HashMap<BusinessDateType, LocalDate> businessDates = ThreadLocalContextUtil.getBusinessDates();
         ThreadLocalContextUtil.setActionContext(ActionContext.COB);
         TreeMap<Long, String> cobBusinessStepMap = cobBusinessStepService.getCOBBusinessStepMap(LoanCOBBusinessStep.class,
                 LoanCOBConstant.LOAN_COB_JOB_NAME);
         contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.LOAN_IDS, getLoanIdsFromJobParameters(chunkContext));
+        String businessDate = getBusinessDateFromJobParameters(chunkContext);
+        contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME, businessDate);
         contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.BUSINESS_STEP_MAP, cobBusinessStepMap);
-
+        businessDates.put(BusinessDateType.COB_DATE, LocalDate.parse(businessDate, DateTimeFormatter.ISO_DATE));
+        businessDates.put(BusinessDateType.BUSINESS_DATE, LocalDate.parse(businessDate, DateTimeFormatter.ISO_DATE).plusDays(1));

Review Comment:
   You can save some perf on not doing the parsing twice...



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1037918426


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java:
##########
@@ -120,6 +132,19 @@ public void execute(List<Long> loanIds, String jobName) {
         }
     }
 
+    private LocalDate getOldestCOBBusinessDate(List<Long> loanIds) {
+        return loanRepository.findOldestCOBProcessedLoanByLoanIds(loanIds)
+                .orElse(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE).minusDays(1));
+    }
+
+    private List<Long> getLoanIdsTOBeProcessed(List<Long> loanIds, LocalDate oldestCOBBusinessDate, LocalDate cobBusinessDate) {

Review Comment:
   typo in the method name



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1037947036


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanCOBCatchUpServiceImpl.java:
##########
@@ -0,0 +1,116 @@
+/**
+ * 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.cob.service;
+
+import com.google.gson.Gson;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.loan.LoanCOBConstant;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetailRepository;
+import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
+import org.apache.fineract.infrastructure.jobs.service.JobStarter;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.configuration.JobLocator;
+import org.springframework.batch.core.launch.NoSuchJobException;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class LoanCOBCatchUpServiceImpl implements LoanCOBCatchUpService, InitializingBean {
+
+    private final LoanRepository loanRepository;
+    private final JobStarter jobStarter;
+    private final JobLocator jobLocator;
+    private final ScheduledJobDetailRepository scheduledJobDetailRepository;
+    private Gson gson;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        this.gson = GoogleGsonSerializerHelper.createSimpleGson();
+    }
+
+    @Override
+    public OldestCOBProcessedLoanDTO getOldestCOBProcessedLoan() {
+        List<Loan> oldestCOBProcessedLoan = loanRepository.findOldestCOBProcessedLoan();
+        OldestCOBProcessedLoanDTO oldestCOBProcessedLoanDTO = new OldestCOBProcessedLoanDTO();
+        oldestCOBProcessedLoanDTO.setLoanIds(oldestCOBProcessedLoan.stream().map(Loan::getId).toList());
+        oldestCOBProcessedLoanDTO
+                .setCobProcessedDate(oldestCOBProcessedLoan.stream().map(Loan::getLastClosedBusinessDate).findFirst().get());
+        oldestCOBProcessedLoanDTO.setCobBusinessDate(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE));
+        return oldestCOBProcessedLoanDTO;
+    }
+
+    @Override
+    public void executeLoanCOBCatchUp() {
+        FineractContext context = ThreadLocalContextUtil.getContext();
+        CompletableFuture<Void> executeCatchUpFuture = CompletableFuture.runAsync(() -> executeLoanCOBCatchUpAsync(context));
+    }
+
+    private void executeLoanCOBCatchUpAsync(FineractContext context) {
+        try {
+            ThreadLocalContextUtil.init(context);
+            LocalDate oldestCOBProcessedDate = loanRepository.findOldestCOBProcessedLoan().get(0).getLastClosedBusinessDate();

Review Comment:
   What if `loanRepository.findOldestCOBProcessedLoan()` is empty?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1037946516


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanCOBCatchUpServiceImpl.java:
##########
@@ -0,0 +1,105 @@
+/**
+ * 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.cob.service;
+
+import com.google.gson.Gson;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.loan.LoanCOBConstant;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetailRepository;
+import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
+import org.apache.fineract.infrastructure.jobs.service.JobStarter;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.configuration.JobLocator;
+import org.springframework.batch.core.launch.NoSuchJobException;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class LoanCOBCatchUpServiceImpl implements LoanCOBCatchUpService, InitializingBean {
+
+    private final LoanRepository loanRepository;
+    private final JobStarter jobStarter;
+    private final JobLocator jobLocator;
+    private final ScheduledJobDetailRepository scheduledJobDetailRepository;
+    private Gson gson;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        this.gson = GoogleGsonSerializerHelper.createSimpleGson();
+    }
+
+    @Override
+    public OldestCOBProcessedLoanDTO getOldestCOBProcessedLoan() {
+        List<Loan> oldestCOBProcessedLoan = loanRepository.findOldestCOBProcessedLoan();
+        OldestCOBProcessedLoanDTO oldestCOBProcessedLoanDTO = new OldestCOBProcessedLoanDTO();
+        oldestCOBProcessedLoanDTO.setLoanIds(oldestCOBProcessedLoan.stream().map(Loan::getId).toList());
+        oldestCOBProcessedLoanDTO
+                .setCobProcessedDate(oldestCOBProcessedLoan.stream().map(Loan::getLastClosedBusinessDate).findFirst().get());
+        oldestCOBProcessedLoanDTO.setCobBusinessDate(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE));
+        return oldestCOBProcessedLoanDTO;
+    }
+
+    @Override
+    public void executeLoanCOBCatchUp() {
+        FineractContext context = ThreadLocalContextUtil.getContext();
+        CompletableFuture<Void> executeCatchUpFuture = CompletableFuture.runAsync(() -> executeLoanCOBCatchUpAsync(context));

Review Comment:
   Do we really need async behaviour here?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1066683156


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/AsyncLoanCOBExecutorServiceImpl.java:
##########
@@ -0,0 +1,93 @@
+/**
+ * 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.cob.service;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.loan.LoanCOBConstant;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetailRepository;
+import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
+import org.apache.fineract.infrastructure.jobs.service.JobStarter;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.configuration.JobLocator;
+import org.springframework.batch.core.launch.NoSuchJobException;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class AsyncLoanCOBExecutorServiceImpl implements AsyncLoanCOBExecutorService {
+
+    private final LoanRepository loanRepository;
+    private final JobLocator jobLocator;
+    private final ScheduledJobDetailRepository scheduledJobDetailRepository;
+    private final JobStarter jobStarter;
+
+    @Override
+    @Async("threadPoolTaskExecutor")
+    public void executeLoanCOBCatchUpAsync(FineractContext context) {
+        try {
+            ThreadLocalContextUtil.init(context);
+            LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
+            List<Loan> oldestCOBProcessedLoan = loanRepository.findOldestCOBProcessedLoan();

Review Comment:
   This could be problematic. We really dont need to fetch the full Loan entity to use the `last closed business date` of one of them.
   
   Edge case: if none of them are behind, it will fetch all the loans.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] github-actions[bot] commented on pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
github-actions[bot] commented on PR #2777:
URL: https://github.com/apache/fineract/pull/2777#issuecomment-1368573542

   This pull request seems to be stale.  Are you still planning to work on it?  We will automatically close it in 30 days.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1034853850


##########
fineract-provider/src/main/java/org/apache/fineract/cob/common/InitialisationTasklet.java:
##########
@@ -41,11 +47,16 @@ public class InitialisationTasklet implements Tasklet {
 
     @Override
     public RepeatStatus execute(@NotNull StepContribution contribution, @NotNull ChunkContext chunkContext) throws Exception {
+        HashMap<BusinessDateType, LocalDate> businessDates = ThreadLocalContextUtil.getBusinessDates();
         AppUser user = userRepository.fetchSystemUser();
         UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, user.getPassword(),
                 new NullAuthoritiesMapper().mapAuthorities(user.getAuthorities()));
         SecurityContextHolder.getContext().setAuthentication(auth);
         ThreadLocalContextUtil.setActionContext(ActionContext.COB);
+        String businessDate = Objects.requireNonNull((String) chunkContext.getStepContext().getStepExecution().getJobExecution()
+                .getExecutionContext().get(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME));
+        businessDates.put(BusinessDateType.COB_DATE, LocalDate.parse(businessDate, DateTimeFormatter.ISO_DATE));

Review Comment:
   If we are about to support anyhow the SOB (Start of Business), we should update the other date (DEFAULT) as well, to the next day of the provided COB date. 
   This way if one of the Business steps would like to use the "following day" instead of the COB date, they can easily do that by setting the ActionContext to DEFAULT.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1066687503


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java:
##########
@@ -96,6 +99,26 @@ public CommandProcessingResult executeInlineJob(JsonCommand command, String jobN
 
     @Override
     public void execute(List<Long> loanIds, String jobName) {
+        LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
+        List<Loan> loansToBeProcessed = getLoansToBeProcessed(loanIds, cobBusinessDate);
+        LocalDate executingBusinessDate = getOldestCOBBusinessDate(loansToBeProcessed).plusDays(1);
+        if (!loansToBeProcessed.isEmpty()) {
+            while (executingBusinessDate.isBefore(cobBusinessDate)) {
+                execute(getLoanIdsToBeProcessed(loansToBeProcessed, executingBusinessDate), jobName, executingBusinessDate);
+                executingBusinessDate = executingBusinessDate.plusDays(1);
+            }
+            List<Long> loanIdsToBeProcessed = loansToBeProcessed.stream().map(Loan::getId).toList();

Review Comment:
   Why do we execute it one more time?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] galovics commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
galovics commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1072602144


##########
fineract-provider/src/main/java/org/apache/fineract/cob/data/ProjectIdAndLastClosedBusinessDate.java:
##########
@@ -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.cob.data;
+
+import java.time.LocalDate;
+
+public interface ProjectIdAndLastClosedBusinessDate {

Review Comment:
   Why don't we call this simply LoanIdAndLastClosedBusinessDate?



##########
fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/async/SpringAsyncConfig.java:
##########
@@ -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.infrastructure.configuration.async;
+
+import java.util.concurrent.Executor;
+import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.AsyncConfigurer;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+@Configuration
+@EnableAsync
+public class SpringAsyncConfig implements AsyncConfigurer {
+
+    @Bean(name = "loanCOBCatchUpThreadPoolTaskExecutor")
+    public Executor loanCOBCatchUpThreadPoolTaskExecutor() {
+        return new ThreadPoolTaskExecutor();

Review Comment:
   Let's set the thread prefix on the executor + you can set the max pool size to 1 since this executor is only intended to run on a single thread.



##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/AsyncLoanCOBExecutorServiceImpl.java:
##########
@@ -0,0 +1,107 @@
+/**
+ * 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.cob.service;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.ProjectIdAndLastClosedBusinessDate;
+import org.apache.fineract.cob.loan.LoanCOBConstant;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
+import org.apache.fineract.infrastructure.jobs.domain.JobParameter;
+import org.apache.fineract.infrastructure.jobs.domain.JobParameterRepository;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetailRepository;
+import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
+import org.apache.fineract.infrastructure.jobs.service.JobStarter;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.configuration.JobLocator;
+import org.springframework.batch.core.launch.NoSuchJobException;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class AsyncLoanCOBExecutorServiceImpl implements AsyncLoanCOBExecutorService {
+
+    private final LoanRepository loanRepository;
+    private final JobLocator jobLocator;
+    private final ScheduledJobDetailRepository scheduledJobDetailRepository;
+    private final JobStarter jobStarter;
+    private final JobParameterRepository jobParameterRepository;
+
+    @Override
+    @Async("loanCOBCatchUpThreadPoolTaskExecutor")
+    public void executeLoanCOBCatchUpAsync(FineractContext context) {
+        try {
+            ThreadLocalContextUtil.init(context);
+            LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
+            List<ProjectIdAndLastClosedBusinessDate> projectIdAndLastClosedBusinessDate = loanRepository
+                    .findOldestCOBProcessedLoan(cobBusinessDate);
+            LocalDate oldestCOBProcessedDate = !projectIdAndLastClosedBusinessDate.isEmpty()
+                    ? projectIdAndLastClosedBusinessDate.get(0).getLastClosedBusinessDate()
+                    : cobBusinessDate;
+            if (oldestCOBProcessedDate.isBefore(cobBusinessDate)) {
+                executeLoanCOBDayByDayUntilCOBBusinessDate(oldestCOBProcessedDate, cobBusinessDate);
+            }
+        } catch (NoSuchJobException e) {
+            throw new JobNotFoundException(LoanCOBConstant.JOB_NAME, e);
+        } catch (JobInstanceAlreadyCompleteException | JobRestartException | JobParametersInvalidException
+                | JobExecutionAlreadyRunningException e) {
+            throw new RuntimeException(e);
+        } finally {
+            ThreadLocalContextUtil.reset();
+        }
+    }
+
+    private void executeLoanCOBDayByDayUntilCOBBusinessDate(LocalDate oldestCOBProcessedDate, LocalDate cobBusinessDate)
+            throws NoSuchJobException, JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException,
+            JobParametersInvalidException, JobRestartException {
+        Job job = jobLocator.getJob(LoanCOBConstant.JOB_NAME);
+        ScheduledJobDetail scheduledJobDetail = scheduledJobDetailRepository.findByJobName(LoanCOBConstant.JOB_HUMAN_READABLE_NAME);
+        LocalDate executingBusinessDate = oldestCOBProcessedDate.plusDays(1);
+        while (!executingBusinessDate.isAfter(cobBusinessDate)) {
+            JobParameterDTO jobParameterDTO = new JobParameterDTO(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME,
+                    executingBusinessDate.format(DateTimeFormatter.ISO_DATE));
+            Set<JobParameterDTO> jobParameters = Collections.singleton(jobParameterDTO);
+            saveCatchUpJobParameter(scheduledJobDetail);
+            jobStarter.run(job, scheduledJobDetail, ThreadLocalContextUtil.getContext(), jobParameters);
+            executingBusinessDate = executingBusinessDate.plusDays(1);
+        }
+    }
+
+    private void saveCatchUpJobParameter(ScheduledJobDetail scheduledJobDetail) {
+        JobParameter jobParameter = new JobParameter();
+        jobParameter.setJobId(scheduledJobDetail.getId());
+        jobParameter.setParameterName(LoanCOBConstant.IS_CATCH_UP_PARAMETER_NAME);
+        jobParameter.setParameterValue("1");

Review Comment:
   Can't we use booleans here instead of numbers?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1061515116


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanCOBCatchUpServiceImpl.java:
##########
@@ -0,0 +1,116 @@
+/**
+ * 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.cob.service;
+
+import com.google.gson.Gson;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.loan.LoanCOBConstant;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetailRepository;
+import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
+import org.apache.fineract.infrastructure.jobs.service.JobStarter;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.configuration.JobLocator;
+import org.springframework.batch.core.launch.NoSuchJobException;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class LoanCOBCatchUpServiceImpl implements LoanCOBCatchUpService, InitializingBean {
+
+    private final LoanRepository loanRepository;
+    private final JobStarter jobStarter;
+    private final JobLocator jobLocator;
+    private final ScheduledJobDetailRepository scheduledJobDetailRepository;
+    private Gson gson;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        this.gson = GoogleGsonSerializerHelper.createSimpleGson();
+    }
+
+    @Override
+    public OldestCOBProcessedLoanDTO getOldestCOBProcessedLoan() {
+        List<Loan> oldestCOBProcessedLoan = loanRepository.findOldestCOBProcessedLoan();
+        OldestCOBProcessedLoanDTO oldestCOBProcessedLoanDTO = new OldestCOBProcessedLoanDTO();
+        oldestCOBProcessedLoanDTO.setLoanIds(oldestCOBProcessedLoan.stream().map(Loan::getId).toList());
+        oldestCOBProcessedLoanDTO
+                .setCobProcessedDate(oldestCOBProcessedLoan.stream().map(Loan::getLastClosedBusinessDate).findFirst().get());
+        oldestCOBProcessedLoanDTO.setCobBusinessDate(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE));
+        return oldestCOBProcessedLoanDTO;
+    }
+
+    @Override
+    public void executeLoanCOBCatchUp() {
+        FineractContext context = ThreadLocalContextUtil.getContext();
+        CompletableFuture<Void> executeCatchUpFuture = CompletableFuture.runAsync(() -> executeLoanCOBCatchUpAsync(context));
+    }
+
+    private void executeLoanCOBCatchUpAsync(FineractContext context) {
+        try {
+            ThreadLocalContextUtil.init(context);
+            LocalDate oldestCOBProcessedDate = loanRepository.findOldestCOBProcessedLoan().get(0).getLastClosedBusinessDate();

Review Comment:
   NPE risk... but edge case



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1034856058


##########
fineract-provider/src/main/java/org/apache/fineract/cob/loan/InlineLoanCOBBuildExecutionContextTasklet.java:
##########
@@ -37,30 +41,40 @@
 import org.springframework.batch.core.scope.context.ChunkContext;
 import org.springframework.batch.core.step.tasklet.Tasklet;
 import org.springframework.batch.repeat.RepeatStatus;
-import org.springframework.stereotype.Component;
 
 @Slf4j
 @RequiredArgsConstructor
-@Component
 public class InlineLoanCOBBuildExecutionContextTasklet implements Tasklet {
 
-    private final GoogleGsonSerializerHelper gsonFactory;
     private final COBBusinessStepService cobBusinessStepService;
     private final CustomJobParameterRepository customJobParameterRepository;
 
     private final Gson gson = GoogleGsonSerializerHelper.createSimpleGson();
 
     @Override
     public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
+        HashMap<BusinessDateType, LocalDate> businessDates = ThreadLocalContextUtil.getBusinessDates();
         ThreadLocalContextUtil.setActionContext(ActionContext.COB);
         TreeMap<Long, String> cobBusinessStepMap = cobBusinessStepService.getCOBBusinessStepMap(LoanCOBBusinessStep.class,
                 LoanCOBConstant.LOAN_COB_JOB_NAME);
         contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.LOAN_IDS, getLoanIdsFromJobParameters(chunkContext));
+        String businessDate = getBusinessDateFromJobParameters(chunkContext);
+        contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME, businessDate);
         contribution.getStepExecution().getExecutionContext().put(LoanCOBConstant.BUSINESS_STEP_MAP, cobBusinessStepMap);
-
+        businessDates.put(BusinessDateType.COB_DATE, LocalDate.parse(businessDate, DateTimeFormatter.ISO_DATE));

Review Comment:
   Same as above...



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1037909217


##########
fineract-provider/src/main/java/org/apache/fineract/cob/api/LoanCOBCatchUpApiResourceSwagger.java:
##########
@@ -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.cob.api;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import java.time.LocalDate;
+import java.util.List;
+
+final class LoanCOBCatchUpApiResourceSwagger {
+
+    private LoanCOBCatchUpApiResourceSwagger() {
+
+    }
+
+    @Schema(description = "GetOldestCOBProcessedLoanResponse")
+    public static final class GetOldestCOBProcessedLoanResponse {
+
+        private GetOldestCOBProcessedLoanResponse() {}
+
+        public List<Long> loanIds;
+        public LocalDate cobProcessedDate;

Review Comment:
   Example would be nice:
   `@Schema(example = "[2012, 5, 18]")`



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1061512542


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java:
##########
@@ -96,6 +97,19 @@ public CommandProcessingResult executeInlineJob(JsonCommand command, String jobN
 
     @Override
     public void execute(List<Long> loanIds, String jobName) {
+        LocalDate oldestCOBBusinessDate = getOldestCOBBusinessDate(loanIds);
+        LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
+        List<Long> loanIdsToBeProcessed = getLoanIdsTOBeProcessed(loanIds, oldestCOBBusinessDate, cobBusinessDate);
+        if (!loanIdsToBeProcessed.isEmpty()) {
+            LocalDate executingBusinessDate = oldestCOBBusinessDate.plusDays(1);
+            while (!executingBusinessDate.isAfter(cobBusinessDate)) {
+                execute(loanIdsToBeProcessed, jobName, executingBusinessDate);

Review Comment:
   If we have these loanids:
   1,2,3
   Oldest COB date: 20-11-2022
   Loan 1 : last cob date is 20-11-2022
   Loan 2 : last cob date is 21-11-2022
   Loan 3 : last cob date is 22-11-2022
   
   It will execute the inline COB for loan 1 which is good
   It will execute the inline COB for loan 2 which is bad
   It will execute the inline COB for loan 3 which is bad
   
   Shall we run it only where it matches with the particular date? so give only sublist...



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1061496763


##########
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java:
##########
@@ -177,6 +184,16 @@ List<Loan> findByGroupOfficeIdsAndLoanStatus(@Param("officeIds") Collection<Long
     Long findIdByExternalId(@Param("externalId") ExternalId externalId);
 
     @Query(FIND_ALL_NON_CLOSED_ONE_DAY_BEHIND)
-    List<Long> findAllNonClosedLoanIdsOneDayBehind(@Param("last_closed_business_date") LocalDate businessDate);
+    List<Long> findAllNonClosedLoanIdsOneDayBehind(@Param("businessDate") LocalDate businessDate);
+
+    @Query(FIND_ALL_NON_CLOSED_LOAN_IDS_BEHIND_BY_LOAN_IDS)

Review Comment:
   Please find a more generic name for this ;)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1037943155


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/InlineLoanCOBExecutorServiceImpl.java:
##########
@@ -120,6 +132,19 @@ public void execute(List<Long> loanIds, String jobName) {
         }
     }
 
+    private LocalDate getOldestCOBBusinessDate(List<Long> loanIds) {
+        return loanRepository.findOldestCOBProcessedLoanByLoanIds(loanIds)
+                .orElse(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE).minusDays(1));
+    }
+
+    private List<Long> getLoanIdsTOBeProcessed(List<Long> loanIds, LocalDate oldestCOBBusinessDate, LocalDate cobBusinessDate) {
+        if (!oldestCOBBusinessDate.isBefore(cobBusinessDate)) {
+            return Collections.emptyList();
+        } else {
+            return loanRepository.findAllNonClosedLoanIdsOneDayBehindByLoanIds(cobBusinessDate, loanIds);

Review Comment:
   Is this correct? Why do we fetch only the loans that one day behind? We should fetch all of them, no?
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1037948686


##########
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java:
##########
@@ -178,4 +185,14 @@ List<Loan> findByGroupOfficeIdsAndLoanStatus(@Param("officeIds") Collection<Long
     @Query(FIND_ALL_NON_CLOSED_ONE_DAY_BEHIND)
     List<Long> findAllNonClosedLoanIdsOneDayBehind(@Param("last_closed_business_date") LocalDate businessDate);
 
+    @Query(FIND_ALL_OLD_COB_PROCESSED_BY_LOAN_IDS)
+    List<Long> findAllNonClosedLoanIdsOneDayBehindByLoanIds(@Param("cob_business_date") LocalDate cobBusinessDate,

Review Comment:
   Wrong method name?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] taskain7 commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
taskain7 commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1073290311


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/AsyncLoanCOBExecutorServiceImpl.java:
##########
@@ -0,0 +1,107 @@
+/**
+ * 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.cob.service;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.ProjectIdAndLastClosedBusinessDate;
+import org.apache.fineract.cob.loan.LoanCOBConstant;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
+import org.apache.fineract.infrastructure.jobs.domain.JobParameter;
+import org.apache.fineract.infrastructure.jobs.domain.JobParameterRepository;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetailRepository;
+import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
+import org.apache.fineract.infrastructure.jobs.service.JobStarter;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.configuration.JobLocator;
+import org.springframework.batch.core.launch.NoSuchJobException;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class AsyncLoanCOBExecutorServiceImpl implements AsyncLoanCOBExecutorService {
+
+    private final LoanRepository loanRepository;
+    private final JobLocator jobLocator;
+    private final ScheduledJobDetailRepository scheduledJobDetailRepository;
+    private final JobStarter jobStarter;
+    private final JobParameterRepository jobParameterRepository;
+
+    @Override
+    @Async("loanCOBCatchUpThreadPoolTaskExecutor")
+    public void executeLoanCOBCatchUpAsync(FineractContext context) {
+        try {
+            ThreadLocalContextUtil.init(context);
+            LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE);
+            List<ProjectIdAndLastClosedBusinessDate> projectIdAndLastClosedBusinessDate = loanRepository
+                    .findOldestCOBProcessedLoan(cobBusinessDate);
+            LocalDate oldestCOBProcessedDate = !projectIdAndLastClosedBusinessDate.isEmpty()
+                    ? projectIdAndLastClosedBusinessDate.get(0).getLastClosedBusinessDate()
+                    : cobBusinessDate;
+            if (oldestCOBProcessedDate.isBefore(cobBusinessDate)) {
+                executeLoanCOBDayByDayUntilCOBBusinessDate(oldestCOBProcessedDate, cobBusinessDate);
+            }
+        } catch (NoSuchJobException e) {
+            throw new JobNotFoundException(LoanCOBConstant.JOB_NAME, e);
+        } catch (JobInstanceAlreadyCompleteException | JobRestartException | JobParametersInvalidException
+                | JobExecutionAlreadyRunningException e) {
+            throw new RuntimeException(e);
+        } finally {
+            ThreadLocalContextUtil.reset();
+        }
+    }
+
+    private void executeLoanCOBDayByDayUntilCOBBusinessDate(LocalDate oldestCOBProcessedDate, LocalDate cobBusinessDate)
+            throws NoSuchJobException, JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException,
+            JobParametersInvalidException, JobRestartException {
+        Job job = jobLocator.getJob(LoanCOBConstant.JOB_NAME);
+        ScheduledJobDetail scheduledJobDetail = scheduledJobDetailRepository.findByJobName(LoanCOBConstant.JOB_HUMAN_READABLE_NAME);
+        LocalDate executingBusinessDate = oldestCOBProcessedDate.plusDays(1);
+        while (!executingBusinessDate.isAfter(cobBusinessDate)) {
+            JobParameterDTO jobParameterDTO = new JobParameterDTO(LoanCOBConstant.BUSINESS_DATE_PARAMETER_NAME,
+                    executingBusinessDate.format(DateTimeFormatter.ISO_DATE));
+            Set<JobParameterDTO> jobParameters = Collections.singleton(jobParameterDTO);
+            saveCatchUpJobParameter(scheduledJobDetail);
+            jobStarter.run(job, scheduledJobDetail, ThreadLocalContextUtil.getContext(), jobParameters);
+            executingBusinessDate = executingBusinessDate.plusDays(1);
+        }
+    }
+
+    private void saveCatchUpJobParameter(ScheduledJobDetail scheduledJobDetail) {
+        JobParameter jobParameter = new JobParameter();
+        jobParameter.setJobId(scheduledJobDetail.getId());
+        jobParameter.setParameterName(LoanCOBConstant.IS_CATCH_UP_PARAMETER_NAME);
+        jobParameter.setParameterValue("1");

Review Comment:
   Unfortunately we only can use number values for this type of parameters, and I had to use this type of parameters since we use it only for the catch up.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] galovics commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
galovics commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1065847510


##########
fineract-provider/src/main/java/org/apache/fineract/cob/api/LoanCOBCatchUpApiResource.java:
##########
@@ -0,0 +1,73 @@
+/**
+ * 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.cob.api;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+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 javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.service.LoanCOBCatchUpService;
+import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.springframework.stereotype.Component;
+
+@Path("/loans")
+@Component
+@Tag(name = "Loan COB Catch Up", description = "")
+@RequiredArgsConstructor
+public class LoanCOBCatchUpApiResource {
+
+    private final DefaultToApiJsonSerializer<OldestCOBProcessedLoanDTO> oldestCOBProcessedLoanSerializeService;
+    private final LoanCOBCatchUpService loanCOBCatchUpService;
+
+    @GET
+    @Path("oldest_cob_processed_loan")

Review Comment:
   1. Let's use dashes instead of underscores.
   2. Naming could be a bit better. `/loans` is already in the API path so let's drop the loan postfix.  `processed` is not the best way to name it cause the terminology is `closed`. So it could be named like `/loans/oldest-closed`



##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/AsyncLoanCOBExecutorServiceImpl.java:
##########
@@ -0,0 +1,93 @@
+/**
+ * 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.cob.service;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.loan.LoanCOBConstant;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetailRepository;
+import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
+import org.apache.fineract.infrastructure.jobs.service.JobStarter;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.configuration.JobLocator;
+import org.springframework.batch.core.launch.NoSuchJobException;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class AsyncLoanCOBExecutorServiceImpl implements AsyncLoanCOBExecutorService {
+
+    private final LoanRepository loanRepository;
+    private final JobLocator jobLocator;
+    private final ScheduledJobDetailRepository scheduledJobDetailRepository;
+    private final JobStarter jobStarter;
+
+    @Override
+    @Async("threadPoolTaskExecutor")

Review Comment:
   This is way too generic. Let's use a specific threadpool for this.



##########
fineract-provider/src/main/java/org/apache/fineract/cob/api/LoanCOBCatchUpApiResource.java:
##########
@@ -0,0 +1,73 @@
+/**
+ * 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.cob.api;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+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 javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.service.LoanCOBCatchUpService;
+import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.springframework.stereotype.Component;
+
+@Path("/loans")
+@Component
+@Tag(name = "Loan COB Catch Up", description = "")
+@RequiredArgsConstructor
+public class LoanCOBCatchUpApiResource {
+
+    private final DefaultToApiJsonSerializer<OldestCOBProcessedLoanDTO> oldestCOBProcessedLoanSerializeService;
+    private final LoanCOBCatchUpService loanCOBCatchUpService;
+
+    @GET
+    @Path("oldest_cob_processed_loan")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Retrieves the oldest COB processed loan", description = "Retrieves the COB business date and the oldest COB processed loan")
+    @ApiResponses({
+            @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanCOBCatchUpApiResourceSwagger.GetOldestCOBProcessedLoanResponse.class))) })
+    public String getOldestCOBProcessedLoan() {
+        OldestCOBProcessedLoanDTO response = loanCOBCatchUpService.getOldestCOBProcessedLoan();
+
+        return oldestCOBProcessedLoanSerializeService.serialize(response);
+    }
+
+    @POST
+    @Path("loan_cob_catch_up")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Executes Loan COB Catch Up", description = "Executes the Loan COB job on every day from the oldest Loan to the current COB business date")
+    @ApiResponses({ @ApiResponse(responseCode = "200", description = "OK") })
+    public Response executeLoanCOBCatchUp() {
+        loanCOBCatchUpService.executeLoanCOBCatchUp();
+
+        return Response.status(202).build();

Review Comment:
   Didn't we discuss returning an ID that identifies the catch-up so that it can be easily polled from the UI?



##########
fineract-provider/src/main/java/org/apache/fineract/cob/api/LoanCOBCatchUpApiResource.java:
##########
@@ -0,0 +1,73 @@
+/**
+ * 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.cob.api;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+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 javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.service.LoanCOBCatchUpService;
+import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.springframework.stereotype.Component;
+
+@Path("/loans")
+@Component
+@Tag(name = "Loan COB Catch Up", description = "")
+@RequiredArgsConstructor
+public class LoanCOBCatchUpApiResource {
+
+    private final DefaultToApiJsonSerializer<OldestCOBProcessedLoanDTO> oldestCOBProcessedLoanSerializeService;
+    private final LoanCOBCatchUpService loanCOBCatchUpService;
+
+    @GET
+    @Path("oldest_cob_processed_loan")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Retrieves the oldest COB processed loan", description = "Retrieves the COB business date and the oldest COB processed loan")
+    @ApiResponses({
+            @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanCOBCatchUpApiResourceSwagger.GetOldestCOBProcessedLoanResponse.class))) })
+    public String getOldestCOBProcessedLoan() {
+        OldestCOBProcessedLoanDTO response = loanCOBCatchUpService.getOldestCOBProcessedLoan();
+
+        return oldestCOBProcessedLoanSerializeService.serialize(response);
+    }
+
+    @POST
+    @Path("loan_cob_catch_up")

Review Comment:
   Naming (based on the above suggestion) could be POST `/loans/catch-up`



##########
fineract-provider/src/main/java/org/apache/fineract/cob/api/LoanCOBCatchUpApiResource.java:
##########
@@ -0,0 +1,73 @@
+/**
+ * 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.cob.api;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+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 javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.service.LoanCOBCatchUpService;
+import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.springframework.stereotype.Component;
+
+@Path("/loans")
+@Component
+@Tag(name = "Loan COB Catch Up", description = "")
+@RequiredArgsConstructor
+public class LoanCOBCatchUpApiResource {
+
+    private final DefaultToApiJsonSerializer<OldestCOBProcessedLoanDTO> oldestCOBProcessedLoanSerializeService;
+    private final LoanCOBCatchUpService loanCOBCatchUpService;
+
+    @GET
+    @Path("oldest_cob_processed_loan")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Retrieves the oldest COB processed loan", description = "Retrieves the COB business date and the oldest COB processed loan")
+    @ApiResponses({
+            @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanCOBCatchUpApiResourceSwagger.GetOldestCOBProcessedLoanResponse.class))) })
+    public String getOldestCOBProcessedLoan() {
+        OldestCOBProcessedLoanDTO response = loanCOBCatchUpService.getOldestCOBProcessedLoan();
+
+        return oldestCOBProcessedLoanSerializeService.serialize(response);
+    }
+
+    @POST
+    @Path("loan_cob_catch_up")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Executes Loan COB Catch Up", description = "Executes the Loan COB job on every day from the oldest Loan to the current COB business date")
+    @ApiResponses({ @ApiResponse(responseCode = "200", description = "OK") })
+    public Response executeLoanCOBCatchUp() {
+        loanCOBCatchUpService.executeLoanCOBCatchUp();

Review Comment:
   Bonus: This way the system can be easily overloaded by just spamming this API. We should do some checks to prevent multiple executions of the catch-up at the same time.



##########
fineract-provider/src/main/java/org/apache/fineract/cob/api/LoanCOBCatchUpApiResource.java:
##########
@@ -0,0 +1,73 @@
+/**
+ * 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.cob.api;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+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 javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.service.LoanCOBCatchUpService;
+import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.springframework.stereotype.Component;
+
+@Path("/loans")
+@Component
+@Tag(name = "Loan COB Catch Up", description = "")
+@RequiredArgsConstructor
+public class LoanCOBCatchUpApiResource {
+
+    private final DefaultToApiJsonSerializer<OldestCOBProcessedLoanDTO> oldestCOBProcessedLoanSerializeService;
+    private final LoanCOBCatchUpService loanCOBCatchUpService;
+
+    @GET
+    @Path("oldest_cob_processed_loan")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Retrieves the oldest COB processed loan", description = "Retrieves the COB business date and the oldest COB processed loan")
+    @ApiResponses({
+            @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanCOBCatchUpApiResourceSwagger.GetOldestCOBProcessedLoanResponse.class))) })
+    public String getOldestCOBProcessedLoan() {
+        OldestCOBProcessedLoanDTO response = loanCOBCatchUpService.getOldestCOBProcessedLoan();
+
+        return oldestCOBProcessedLoanSerializeService.serialize(response);
+    }
+
+    @POST
+    @Path("loan_cob_catch_up")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Executes Loan COB Catch Up", description = "Executes the Loan COB job on every day from the oldest Loan to the current COB business date")
+    @ApiResponses({ @ApiResponse(responseCode = "200", description = "OK") })

Review Comment:
   We're lying here because we're returning HTTP 202 in practice.



##########
fineract-provider/src/main/java/org/apache/fineract/cob/api/LoanCOBCatchUpApiResource.java:
##########
@@ -0,0 +1,73 @@
+/**
+ * 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.cob.api;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+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 javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.service.LoanCOBCatchUpService;
+import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.springframework.stereotype.Component;
+
+@Path("/loans")
+@Component
+@Tag(name = "Loan COB Catch Up", description = "")
+@RequiredArgsConstructor
+public class LoanCOBCatchUpApiResource {
+
+    private final DefaultToApiJsonSerializer<OldestCOBProcessedLoanDTO> oldestCOBProcessedLoanSerializeService;
+    private final LoanCOBCatchUpService loanCOBCatchUpService;
+
+    @GET
+    @Path("oldest_cob_processed_loan")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Retrieves the oldest COB processed loan", description = "Retrieves the COB business date and the oldest COB processed loan")
+    @ApiResponses({
+            @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = LoanCOBCatchUpApiResourceSwagger.GetOldestCOBProcessedLoanResponse.class))) })
+    public String getOldestCOBProcessedLoan() {
+        OldestCOBProcessedLoanDTO response = loanCOBCatchUpService.getOldestCOBProcessedLoan();
+
+        return oldestCOBProcessedLoanSerializeService.serialize(response);
+    }
+
+    @POST
+    @Path("loan_cob_catch_up")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Operation(summary = "Executes Loan COB Catch Up", description = "Executes the Loan COB job on every day from the oldest Loan to the current COB business date")
+    @ApiResponses({ @ApiResponse(responseCode = "200", description = "OK") })
+    public Response executeLoanCOBCatchUp() {
+        loanCOBCatchUpService.executeLoanCOBCatchUp();

Review Comment:
   I think we could be a bit smarter here. The API could return 2 responses:
   1. If the catch-up is being executed, HTTP 202
   2. If the catch-up doesn't need to be executed since all loans are up-to-date, just return HTTP 200 a.k.a nothing to do



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1034855249


##########
fineract-provider/src/main/java/org/apache/fineract/cob/data/OldestCOBProcessedLoanDTO.java:
##########
@@ -0,0 +1,31 @@
+/**
+ * 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.cob.data;
+
+import java.time.LocalDate;
+import java.util.List;
+import lombok.Data;
+
+@Data
+public class OldestCOBProcessedLoanDTO {
+
+    private List<Long> loanIds;
+    private LocalDate COBProcessedDate;
+    private LocalDate COBBusinessDate;

Review Comment:
   What is the difference of business date and processed date?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] taskain7 commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
taskain7 commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1062364639


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanCOBCatchUpServiceImpl.java:
##########
@@ -0,0 +1,105 @@
+/**
+ * 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.cob.service;
+
+import com.google.gson.Gson;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.loan.LoanCOBConstant;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetailRepository;
+import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
+import org.apache.fineract.infrastructure.jobs.service.JobStarter;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.configuration.JobLocator;
+import org.springframework.batch.core.launch.NoSuchJobException;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class LoanCOBCatchUpServiceImpl implements LoanCOBCatchUpService, InitializingBean {
+
+    private final LoanRepository loanRepository;
+    private final JobStarter jobStarter;
+    private final JobLocator jobLocator;
+    private final ScheduledJobDetailRepository scheduledJobDetailRepository;
+    private Gson gson;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        this.gson = GoogleGsonSerializerHelper.createSimpleGson();
+    }
+
+    @Override
+    public OldestCOBProcessedLoanDTO getOldestCOBProcessedLoan() {
+        List<Loan> oldestCOBProcessedLoan = loanRepository.findOldestCOBProcessedLoan();
+        OldestCOBProcessedLoanDTO oldestCOBProcessedLoanDTO = new OldestCOBProcessedLoanDTO();
+        oldestCOBProcessedLoanDTO.setLoanIds(oldestCOBProcessedLoan.stream().map(Loan::getId).toList());
+        oldestCOBProcessedLoanDTO
+                .setCobProcessedDate(oldestCOBProcessedLoan.stream().map(Loan::getLastClosedBusinessDate).findFirst().get());
+        oldestCOBProcessedLoanDTO.setCobBusinessDate(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE));
+        return oldestCOBProcessedLoanDTO;
+    }
+
+    @Override
+    public void executeLoanCOBCatchUp() {
+        FineractContext context = ThreadLocalContextUtil.getContext();
+        CompletableFuture<Void> executeCatchUpFuture = CompletableFuture.runAsync(() -> executeLoanCOBCatchUpAsync(context));

Review Comment:
   I've configured a Spring async executor, you can review the PR again @galovics @adamsaghy 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] galovics commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
galovics commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1067253956


##########
fineract-provider/src/main/java/org/apache/fineract/cob/api/LoanCOBCatchUpApiResource.java:
##########
@@ -0,0 +1,73 @@
+/**
+ * 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.cob.api;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+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 javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.service.LoanCOBCatchUpService;
+import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.springframework.stereotype.Component;
+
+@Path("/loans")
+@Component
+@Tag(name = "Loan COB Catch Up", description = "")
+@RequiredArgsConstructor
+public class LoanCOBCatchUpApiResource {
+
+    private final DefaultToApiJsonSerializer<OldestCOBProcessedLoanDTO> oldestCOBProcessedLoanSerializeService;
+    private final LoanCOBCatchUpService loanCOBCatchUpService;
+
+    @GET
+    @Path("oldest_cob_processed_loan")

Review Comment:
   sure thing.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1061507954


##########
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java:
##########
@@ -72,14 +73,20 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
 
     String FIND_ALL_NON_CLOSED = "select loan.id from Loan loan where loan.loanStatus in (100,200,300,303,304)";
 
-    String FIND_ALL_NON_CLOSED_ONE_DAY_BEHIND = "select loan.id from Loan loan where loan.loanStatus in (100,200,300,303,304) and (:last_closed_business_date = loan.lastClosedBusinessDate or loan.lastClosedBusinessDate is NULL)";
+    String FIND_ALL_NON_CLOSED_ONE_DAY_BEHIND = "select loan.id from Loan loan where loan.loanStatus in (100,200,300,303,304) and (:businessDate = loan.lastClosedBusinessDate or loan.lastClosedBusinessDate is NULL)";
 
     String FIND_NON_CLOSED_LOAN_THAT_BELONGS_TO_CLIENT = "select loan from Loan loan where loan.id = :loanId and loan.loanStatus = 300 and loan.client.id = :clientId";
 
     String FIND_BY_ACCOUNT_NUMBER = "select loan from Loan loan where loan.accountNumber = :accountNumber";
 
     String FIND_ID_BY_EXTERNAL_ID = "SELECT loan.id FROM Loan loan WHERE loan.externalId = :externalId";
 
+    String FIND_OLDEST_COB_PROCESSED_LOAN = "select loan from Loan loan where loan.lastClosedBusinessDate = (select min(l.lastClosedBusinessDate) from Loan l)";

Review Comment:
   Should it consider loan status? (only pick up active ones?)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1061497105


##########
fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepository.java:
##########
@@ -72,14 +73,20 @@ public interface LoanRepository extends JpaRepository<Loan, Long>, JpaSpecificat
 
     String FIND_ALL_NON_CLOSED = "select loan.id from Loan loan where loan.loanStatus in (100,200,300,303,304)";
 
-    String FIND_ALL_NON_CLOSED_ONE_DAY_BEHIND = "select loan.id from Loan loan where loan.loanStatus in (100,200,300,303,304) and (:last_closed_business_date = loan.lastClosedBusinessDate or loan.lastClosedBusinessDate is NULL)";
+    String FIND_ALL_NON_CLOSED_ONE_DAY_BEHIND = "select loan.id from Loan loan where loan.loanStatus in (100,200,300,303,304) and (:businessDate = loan.lastClosedBusinessDate or loan.lastClosedBusinessDate is NULL)";

Review Comment:
   Please find a more generic name for this ;)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [fineract] adamsaghy commented on a diff in pull request #2777: [FINERACT-1678] Loan COB Catch Up

Posted by GitBox <gi...@apache.org>.
adamsaghy commented on code in PR #2777:
URL: https://github.com/apache/fineract/pull/2777#discussion_r1061515116


##########
fineract-provider/src/main/java/org/apache/fineract/cob/service/LoanCOBCatchUpServiceImpl.java:
##########
@@ -0,0 +1,116 @@
+/**
+ * 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.cob.service;
+
+import com.google.gson.Gson;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.cob.data.OldestCOBProcessedLoanDTO;
+import org.apache.fineract.cob.loan.LoanCOBConstant;
+import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
+import org.apache.fineract.infrastructure.core.domain.FineractContext;
+import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
+import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
+import org.apache.fineract.infrastructure.jobs.data.JobParameterDTO;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail;
+import org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetailRepository;
+import org.apache.fineract.infrastructure.jobs.exception.JobNotFoundException;
+import org.apache.fineract.infrastructure.jobs.service.JobStarter;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.configuration.JobLocator;
+import org.springframework.batch.core.launch.NoSuchJobException;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class LoanCOBCatchUpServiceImpl implements LoanCOBCatchUpService, InitializingBean {
+
+    private final LoanRepository loanRepository;
+    private final JobStarter jobStarter;
+    private final JobLocator jobLocator;
+    private final ScheduledJobDetailRepository scheduledJobDetailRepository;
+    private Gson gson;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        this.gson = GoogleGsonSerializerHelper.createSimpleGson();
+    }
+
+    @Override
+    public OldestCOBProcessedLoanDTO getOldestCOBProcessedLoan() {
+        List<Loan> oldestCOBProcessedLoan = loanRepository.findOldestCOBProcessedLoan();
+        OldestCOBProcessedLoanDTO oldestCOBProcessedLoanDTO = new OldestCOBProcessedLoanDTO();
+        oldestCOBProcessedLoanDTO.setLoanIds(oldestCOBProcessedLoan.stream().map(Loan::getId).toList());
+        oldestCOBProcessedLoanDTO
+                .setCobProcessedDate(oldestCOBProcessedLoan.stream().map(Loan::getLastClosedBusinessDate).findFirst().get());
+        oldestCOBProcessedLoanDTO.setCobBusinessDate(ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE));
+        return oldestCOBProcessedLoanDTO;
+    }
+
+    @Override
+    public void executeLoanCOBCatchUp() {
+        FineractContext context = ThreadLocalContextUtil.getContext();
+        CompletableFuture<Void> executeCatchUpFuture = CompletableFuture.runAsync(() -> executeLoanCOBCatchUpAsync(context));
+    }
+
+    private void executeLoanCOBCatchUpAsync(FineractContext context) {
+        try {
+            ThreadLocalContextUtil.init(context);
+            LocalDate oldestCOBProcessedDate = loanRepository.findOldestCOBProcessedLoan().get(0).getLastClosedBusinessDate();

Review Comment:
   NPE risk...



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@fineract.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org