FINERACT-2104: Accrual Activity Posting Job
This commit is contained in:
+1
@@ -57,6 +57,7 @@ public enum JobName {
|
||||
SEND_ASYNCHRONOUS_EVENTS("Send Asynchronous Events"), //
|
||||
PURGE_EXTERNAL_EVENTS("Purge External Events"), //
|
||||
PURGE_PROCESSED_COMMANDS("Purge Processed Commands"), //
|
||||
ACCRUAL_ACTIVITY_POSTING("Accrual Activity Posting"), //
|
||||
;
|
||||
|
||||
private final String name;
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.domain;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Set;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface LoanAccrualActivityRepository extends Repository<Loan, Long> {
|
||||
|
||||
@Query("select loan.id from Loan loan left join LoanTransaction lt on lt.loan = loan and lt.typeOf = 32 and lt.reversed = false and lt.dateOf = :currentDate inner join LoanRepaymentScheduleInstallment rs on rs.loan = loan and rs.isDownPayment = false and rs.additional = false and rs.dueDate = :currentDate where loan.loanRepaymentScheduleDetail.enableAccrualActivityPosting = true and loan.loanStatus = 300 and lt.id is null ")
|
||||
Set<Long> fetchLoanIdsForAccrualActivityPosting(@Param("currentDate") LocalDate currentDate);
|
||||
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
public interface LoanAccrualActivityProcessingService {
|
||||
|
||||
@Transactional
|
||||
void makeAccrualActivityTransaction(Long loanId, LocalDate currentDate);
|
||||
|
||||
Loan makeAccrualActivityTransaction(Loan loan, LocalDate currentDate);
|
||||
|
||||
}
|
||||
+1
-1
@@ -54,7 +54,7 @@ public interface LoanWritePlatformService {
|
||||
JsonCommand command, boolean isRecoveryRepayment, String chargeRefundChargeType);
|
||||
|
||||
@Transactional
|
||||
Loan makeAccrualActivityTransaction(Loan loan, LoanRepaymentScheduleInstallment installment, LocalDate currentDate);
|
||||
Loan makeAccrualActivityTransaction(Loan loan, LoanRepaymentScheduleInstallment installment, LocalDate transactionDate);
|
||||
|
||||
@Transactional
|
||||
CommandProcessingResult makeInterestPaymentWaiver(JsonCommand command);
|
||||
|
||||
+4
-28
@@ -19,18 +19,11 @@
|
||||
package org.apache.fineract.cob.loan;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountDomainService;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualActivityProcessingService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@@ -38,32 +31,15 @@ import org.springframework.stereotype.Component;
|
||||
@RequiredArgsConstructor
|
||||
public class AccrualActivityPostingBusinessStep implements LoanCOBBusinessStep {
|
||||
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
private final LoanAccountDomainService loanAccountDomainService;
|
||||
private final ExternalIdFactory externalIdFactory;
|
||||
private final LoanWritePlatformService loanWritePlatformService;
|
||||
private final LoanAccrualActivityProcessingService loanAccrualActivityProcessingService;
|
||||
|
||||
@Override
|
||||
public Loan execute(Loan loan) {
|
||||
log.debug("start processing loan accrual activity posting on installment due date with id [{}]", loan.getId());
|
||||
final LocalDate currentDate = DateUtils.getBusinessLocalDate();
|
||||
|
||||
// check if loan capable for posting
|
||||
if (loan.getLoanProductRelatedDetail().isEnableAccrualActivityPosting()) {
|
||||
final LocalDate currentDate = DateUtils.getBusinessLocalDate();
|
||||
// check if loan has installment due on business day
|
||||
Optional<LoanRepaymentScheduleInstallment> first = loan.getRepaymentScheduleInstallments().stream()
|
||||
.filter(loanRepaymentScheduleInstallment -> loanRepaymentScheduleInstallment.getDueDate().isEqual(currentDate))
|
||||
.findFirst();
|
||||
if (first.isPresent()) {
|
||||
final LoanRepaymentScheduleInstallment installment = first.get();
|
||||
// check if there is no not-replayed-accrual-activity related to business date
|
||||
List<LoanTransaction> loanTransactions = loan.getLoanTransactions(loanTransaction -> loanTransaction.isNotReversed()
|
||||
&& loanTransaction.isAccrualActivity() && loanTransaction.getTransactionDate().isEqual(currentDate));
|
||||
if (loanTransactions.isEmpty()) {
|
||||
loan = loanWritePlatformService.makeAccrualActivityTransaction(loan, installment, currentDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
loanAccrualActivityProcessingService.makeAccrualActivityTransaction(loan, currentDate);
|
||||
|
||||
log.debug("end processing loan accrual activity posting on installment due date with id [{}]", loan.getId());
|
||||
return loan;
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.jobs.accrualactivityposting;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.jobs.service.JobName;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.job.builder.JobBuilder;
|
||||
import org.springframework.batch.core.launch.support.RunIdIncrementer;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.step.builder.StepBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
public class AccrualActivityPostingConfig {
|
||||
|
||||
private final JobRepository jobRepository;
|
||||
private final PlatformTransactionManager transactionManager;
|
||||
|
||||
@Bean
|
||||
protected Step accrualActivityPostingStep(AccrualActivityPostingTasklet accrualActivityPostingTasklet) {
|
||||
return new StepBuilder(JobName.ACCRUAL_ACTIVITY_POSTING.name(), jobRepository)
|
||||
.tasklet(accrualActivityPostingTasklet, transactionManager).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Job accrualActivityPostingJob(AccrualActivityPostingTasklet accrualActivityPosting) {
|
||||
return new JobBuilder(JobName.ACCRUAL_ACTIVITY_POSTING.name(), jobRepository)
|
||||
.start(accrualActivityPostingStep(accrualActivityPosting)).incrementer(new RunIdIncrementer()).build();
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.jobs.accrualactivityposting;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccrualActivityRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualActivityProcessingService;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
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 AccrualActivityPostingTasklet implements Tasklet {
|
||||
|
||||
private final LoanAccrualActivityProcessingService loanAccrualActivityProcessingService;
|
||||
private final LoanAccrualActivityRepository loanAccrualActivityRepository;
|
||||
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
||||
final LocalDate yesterday = DateUtils.getBusinessLocalDate().minusDays(1);
|
||||
List<Throwable> errors = new ArrayList<>();
|
||||
Set<Long> loanAccounts = loanAccrualActivityRepository.fetchLoanIdsForAccrualActivityPosting(yesterday);
|
||||
for (Long accountId : loanAccounts) {
|
||||
try {
|
||||
loanAccrualActivityProcessingService.makeAccrualActivityTransaction(accountId, yesterday);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to add accrual activity transaction for loan {}", accountId, e);
|
||||
errors.add(e);
|
||||
}
|
||||
}
|
||||
if (!errors.isEmpty()) {
|
||||
throw new JobExecutionException(errors);
|
||||
}
|
||||
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class LoanAccrualActivityProcessingServiceImpl implements LoanAccrualActivityProcessingService {
|
||||
|
||||
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
||||
private final LoanWritePlatformService loanWritePlatformService;
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public void makeAccrualActivityTransaction(Long loanId, final LocalDate currentDate) {
|
||||
Loan loan = loanRepositoryWrapper.findOneWithNotFoundDetection(loanId, true);
|
||||
makeAccrualActivityTransaction(loan, currentDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loan makeAccrualActivityTransaction(Loan loan, final LocalDate currentDate) {
|
||||
if (loan.getLoanProductRelatedDetail().isEnableAccrualActivityPosting()) {
|
||||
// check if loan has installment due on business day
|
||||
Optional<LoanRepaymentScheduleInstallment> first = loan.getRepaymentScheduleInstallments().stream()
|
||||
.filter(loanRepaymentScheduleInstallment -> loanRepaymentScheduleInstallment.getDueDate().isEqual(currentDate))
|
||||
.findFirst();
|
||||
if (first.isPresent()) {
|
||||
final LoanRepaymentScheduleInstallment installment = first.get();
|
||||
// check if there is no not-replayed-accrual-activity related to business date
|
||||
List<LoanTransaction> loanTransactions = loan.getLoanTransactions(loanTransaction -> loanTransaction.isNotReversed()
|
||||
&& loanTransaction.isAccrualActivity() && loanTransaction.getTransactionDate().isEqual(currentDate));
|
||||
if (loanTransactions.isEmpty()) {
|
||||
loan = loanWritePlatformService.makeAccrualActivityTransaction(loan, installment, currentDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
return loan;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -162,4 +162,5 @@
|
||||
<include file="parts/0140_trial_balance_with_asset_transfer_update.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/0141_add_interest_payment_waiver_transaction_type.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/0142_add_accrual_activity_transaction.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/0143_add_accrual_activity_posting_job.xml" relativeToChangelogFile="true" />
|
||||
</databaseChangeLog>
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||
<changeSet author="fineract" id="1">
|
||||
<insert tableName="job">
|
||||
<column name="name" value="Accrual Activity Posting"/>
|
||||
<column name="display_name" value="Accrual Activity Posting"/>
|
||||
<column name="cron_expression" value="0 0 1 * * ?"/>
|
||||
<column name="create_time" valueDate="${current_datetime}"/>
|
||||
<column name="task_priority" valueNumeric="5"/>
|
||||
<column name="group_name"/>
|
||||
<column name="previous_run_start_time"/>
|
||||
<column name="job_key" value="Accrual Activity Posting1 _ DEFAULT"/>
|
||||
<column name="initializing_errorlog"/>
|
||||
<column name="is_active" valueBoolean="false"/>
|
||||
<column name="currently_running" valueBoolean="false"/>
|
||||
<column name="updates_allowed" valueBoolean="true"/>
|
||||
<column name="scheduler_group" valueNumeric="0"/>
|
||||
<column name="is_misfired" valueBoolean="false"/>
|
||||
<column name="node_id" valueNumeric="1"/>
|
||||
<column name="is_mismatched_job" valueBoolean="true"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+130
@@ -46,6 +46,7 @@ import org.apache.fineract.client.models.PostLoansLoanIdRequest;
|
||||
import org.apache.fineract.client.models.PostLoansRequest;
|
||||
import org.apache.fineract.integrationtests.common.BusinessStepHelper;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.SchedulerJobHelper;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension;
|
||||
@@ -76,6 +77,7 @@ public class LoanTransactionAccrualActivityPostingTest extends BaseLoanIntegrati
|
||||
private static ChargesHelper chargesHelper;
|
||||
private static InlineLoanCOBHelper inlineLoanCOBHelper;
|
||||
private static BusinessStepHelper businessStepHelper;
|
||||
private static SchedulerJobHelper schedulerJobHelper;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
@@ -85,6 +87,7 @@ public class LoanTransactionAccrualActivityPostingTest extends BaseLoanIntegrati
|
||||
requestSpec.header("Fineract-Platform-TenantId", "default");
|
||||
responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
|
||||
loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec);
|
||||
schedulerJobHelper = new SchedulerJobHelper(requestSpec);
|
||||
ClientHelper clientHelper = new ClientHelper(requestSpec, responseSpec);
|
||||
chargesHelper = new ChargesHelper();
|
||||
client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
|
||||
@@ -167,6 +170,133 @@ public class LoanTransactionAccrualActivityPostingTest extends BaseLoanIntegrati
|
||||
});
|
||||
}
|
||||
|
||||
// Create Loan with Interest and enabled Accrual Activity Posting
|
||||
// Approve and disburse loan
|
||||
// charge penalty with due date as 1st installment
|
||||
// charge fee with due date as 1st installment
|
||||
// charge penalty with due date as 3rd installment
|
||||
// charge fee with due date as 2nd installment
|
||||
// set business day to the day before closing day of 1st installment, run "Accrual Activity Posting" Job, verify no
|
||||
// Accrual Activity
|
||||
// posted
|
||||
// set business day to the closing day of 1st installment, run "Accrual Activity Posting" Job, verify Accrual
|
||||
// Activity posted
|
||||
// set business day to the day after closing day of 1st installment, run "Accrual Activity Posting" Job, verify no
|
||||
// Accrual Activity
|
||||
// posted
|
||||
@Test
|
||||
public void testAccrualActivityPostingJob() {
|
||||
final String disbursementDay = "01 January 2023";
|
||||
final String repaymentPeriod1DueDate = "01 February 2023";
|
||||
final String repaymentPeriod1CloseDate = "02 February 2023";
|
||||
final String repaymentPeriod1OneDayBeforeCloseDate = "01 February 2023";
|
||||
final String repaymentPeriod1OneDayAfterCloseDate = "03 February 2023";
|
||||
final String repaymentPeriod2DueDate = "01 March 2023";
|
||||
final String repaymentPeriod3DueDate = "01 April 2023";
|
||||
final String creationBusinessDay = "15 May 2023";
|
||||
AtomicReference<Long> loanId = new AtomicReference<>();
|
||||
runAt(creationBusinessDay, () -> {
|
||||
|
||||
Long localLoanProductId = createLoanProductAccountingAccrualPeriodicWithInterest();
|
||||
loanId.set(applyForLoanApplicationWithInterest(client.getClientId(), localLoanProductId, BigDecimal.valueOf(40000),
|
||||
disbursementDay));
|
||||
|
||||
LOG.info("Test Loan Product Id {1} http://localhost:4200/#/products/loan-products/{}/general", localLoanProductId);
|
||||
LOG.info("Test Client Id {1} http://localhost:4200/#/clients/{}", client.getClientId());
|
||||
LOG.info("Test Loan Id {2} http://localhost:4200/#/clients/{}/loans-accounts/{}/transactions", client.getClientId(), loanId);
|
||||
|
||||
loanTransactionHelper.approveLoan(loanId.get(), new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000))
|
||||
.dateFormat(DATETIME_PATTERN).approvedOnDate(disbursementDay).locale("en"));
|
||||
|
||||
loanTransactionHelper.disburseLoan(loanId.get(), new PostLoansLoanIdRequest().actualDisbursementDate(disbursementDay)
|
||||
.dateFormat(DATETIME_PATTERN).transactionAmount(BigDecimal.valueOf(1000.0)).locale("en"));
|
||||
|
||||
chargePenalty(loanId.get(), 30.0, repaymentPeriod1DueDate);
|
||||
chargePenalty(loanId.get(), 50.0, repaymentPeriod2DueDate);
|
||||
chargeFee(loanId.get(), 40.0, repaymentPeriod1DueDate);
|
||||
chargeFee(loanId.get(), 60.0, repaymentPeriod3DueDate);
|
||||
|
||||
});
|
||||
runAt(repaymentPeriod1OneDayBeforeCloseDate, () -> {
|
||||
schedulerJobHelper.executeAndAwaitJob("Accrual Activity Posting");
|
||||
verifyTransactions(loanId.get(), //
|
||||
transaction(1000.0, "Disbursement", disbursementDay, 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
|
||||
});
|
||||
runAt(repaymentPeriod1CloseDate, () -> {
|
||||
schedulerJobHelper.executeAndAwaitJob("Accrual Activity Posting");
|
||||
|
||||
verifyTransactions(loanId.get(), //
|
||||
transaction(1000.0, "Disbursement", disbursementDay, 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(90.0, "Accrual Activity", "01 February 2023", 0, 0, 20.0, 40.0, 30.0, 0.0, 0.0));
|
||||
});
|
||||
runAt(repaymentPeriod1OneDayAfterCloseDate, () -> {
|
||||
schedulerJobHelper.executeAndAwaitJob("Accrual Activity Posting");
|
||||
verifyTransactions(loanId.get(), //
|
||||
transaction(1000.0, "Disbursement", disbursementDay, 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(90.0, "Accrual Activity", "01 February 2023", 0, 0, 20.0, 40.0, 30.0, 0.0, 0.0));
|
||||
});
|
||||
}
|
||||
|
||||
// Create Loan with Interest and enabled Accrual Activity Posting
|
||||
// Approve and disburse loan
|
||||
// charge penalty with due date as 1st installment
|
||||
// charge fee with due date as 1st installment
|
||||
// charge penalty with due date as 3rd installment
|
||||
// charge fee with due date as 2nd installment
|
||||
// set business day to the day before closing day of 1st installment, run "Accrual Activity Posting" Job, verify no
|
||||
// Accrual Activity
|
||||
// posted
|
||||
// set business day to the closing day of 1st installment, run "Accrual Activity Posting" Job, verify Accrual
|
||||
// Activity posted
|
||||
// set business day to the day after closing day of 1st installment, run "Accrual Activity Posting" Job, verify no
|
||||
// Accrual Activity
|
||||
// posted
|
||||
@Test
|
||||
public void testAccrualActivityPostingJobForMultipleLoans() {
|
||||
final String disbursementDay = "01 January 2023";
|
||||
final String repaymentPeriod1DueDate = "01 February 2023";
|
||||
final String repaymentPeriod1CloseDate = "02 February 2023";
|
||||
final String creationBusinessDay = "15 May 2023";
|
||||
AtomicReference<Long> loanId1 = new AtomicReference<>();
|
||||
AtomicReference<Long> loanId2 = new AtomicReference<>();
|
||||
runAt(creationBusinessDay, () -> {
|
||||
|
||||
Long localLoanProductId = createLoanProductAccountingAccrualPeriodicWithInterest();
|
||||
|
||||
loanId1.set(applyForLoanApplicationWithInterest(client.getClientId(), localLoanProductId, BigDecimal.valueOf(40000),
|
||||
disbursementDay));
|
||||
loanId2.set(applyForLoanApplicationWithInterest(client.getClientId(), localLoanProductId, BigDecimal.valueOf(40000),
|
||||
disbursementDay));
|
||||
|
||||
loanTransactionHelper.approveLoan(loanId1.get(), new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000))
|
||||
.dateFormat(DATETIME_PATTERN).approvedOnDate(disbursementDay).locale("en"));
|
||||
loanTransactionHelper.approveLoan(loanId2.get(), new PostLoansLoanIdRequest().approvedLoanAmount(BigDecimal.valueOf(1000))
|
||||
.dateFormat(DATETIME_PATTERN).approvedOnDate(disbursementDay).locale("en"));
|
||||
|
||||
loanTransactionHelper.disburseLoan(loanId1.get(), new PostLoansLoanIdRequest().actualDisbursementDate(disbursementDay)
|
||||
.dateFormat(DATETIME_PATTERN).transactionAmount(BigDecimal.valueOf(1000.0)).locale("en"));
|
||||
loanTransactionHelper.disburseLoan(loanId2.get(), new PostLoansLoanIdRequest().actualDisbursementDate(disbursementDay)
|
||||
.dateFormat(DATETIME_PATTERN).transactionAmount(BigDecimal.valueOf(1000.0)).locale("en"));
|
||||
|
||||
chargePenalty(loanId1.get(), 30.0, repaymentPeriod1DueDate);
|
||||
chargeFee(loanId1.get(), 40.0, repaymentPeriod1DueDate);
|
||||
|
||||
chargePenalty(loanId2.get(), 30.0, repaymentPeriod1DueDate);
|
||||
chargeFee(loanId2.get(), 40.0, repaymentPeriod1DueDate);
|
||||
|
||||
});
|
||||
runAt(repaymentPeriod1CloseDate, () -> {
|
||||
schedulerJobHelper.executeAndAwaitJob("Accrual Activity Posting");
|
||||
|
||||
verifyTransactions(loanId1.get(), //
|
||||
transaction(1000.0, "Disbursement", disbursementDay, 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(90.0, "Accrual Activity", "01 February 2023", 0, 0, 20.0, 40.0, 30.0, 0.0, 0.0));
|
||||
verifyTransactions(loanId2.get(), //
|
||||
transaction(1000.0, "Disbursement", disbursementDay, 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(90.0, "Accrual Activity", "01 February 2023", 0, 0, 20.0, 40.0, 30.0, 0.0, 0.0));
|
||||
});
|
||||
}
|
||||
|
||||
// Create Loan with Interest and enabled Accrual Activity Posting
|
||||
// Approve and disburse loan
|
||||
// make partial repayment before first installment day
|
||||
|
||||
Reference in New Issue
Block a user