FINERACT-2386: Journal entry aggregation capabilities
This commit is contained in:
+92
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.jobs.service.aggregationjob;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||
import org.apache.fineract.infrastructure.core.service.migration.TenantDataSourceFactory;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.listener.JournalEntryAggregationJobListener;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.tasklet.JournalEntryAggregationTrackingTasklet;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.scope.context.JobSynchronizationManager;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
@EnableConfigurationProperties({ FineractProperties.class })
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class JournalEntryAggregationJobConfigurationTest {
|
||||
|
||||
@InjectMocks
|
||||
private JournalEntryAggregationJobConfiguration configuration;
|
||||
@Mock
|
||||
JournalEntryAggregationJobListener journalEntryAggregationJobListener;
|
||||
@Mock
|
||||
private JobRepository jobRepository;
|
||||
|
||||
@Mock
|
||||
private JournalEntryAggregationJobExecutionDecider journalEntryAggregationJobExecutionDecider;
|
||||
|
||||
@Mock
|
||||
private JournalEntryAggregationJobWriter aggregationItemWriter;
|
||||
|
||||
@Mock
|
||||
private PlatformTransactionManager transactionManager;
|
||||
|
||||
@Mock
|
||||
private JournalEntryAggregationTrackingTasklet journalEntryAggregationTrackingTasklet;
|
||||
|
||||
@Mock
|
||||
private TenantDataSourceFactory tenantDataSourceFactory;
|
||||
|
||||
@Mock
|
||||
private FineractProperties fineractProperties;
|
||||
|
||||
@Mock
|
||||
private FineractProperties.FineractJobProperties fineractJobProperties;
|
||||
|
||||
@Mock
|
||||
private FineractProperties.FineractJournalEntryAggregationProperties journalEntryAggregationProperties;
|
||||
|
||||
@Mock
|
||||
private JobExecution jobExecution;
|
||||
|
||||
@Mock
|
||||
private ExecutionContext executionContext;
|
||||
|
||||
/**
|
||||
* Test method for {@link JournalEntryAggregationJobConfiguration#journalEntryAggregation()}.
|
||||
*/
|
||||
@Test
|
||||
public void testJournalEntryDailyAggregationJob() {
|
||||
given(fineractProperties.getJob()).willReturn(fineractJobProperties);
|
||||
given(fineractJobProperties.getJournalEntryAggregation()).willReturn(journalEntryAggregationProperties);
|
||||
given(fineractJobProperties.getJournalEntryAggregation().getChunkSize()).willReturn(5);
|
||||
JobSynchronizationManager.register(jobExecution);
|
||||
assertNotNull(configuration.journalEntryAggregation(), "The journalEntryDailyAggregationJob bean should not be null");
|
||||
}
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.jobs.service.aggregationjob;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.stream.Stream;
|
||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class JournalEntryAggregationJobExecutionDeciderTest {
|
||||
|
||||
final LocalDate aggregatedOnDate = LocalDate.now(ZoneId.of("UTC"));
|
||||
@InjectMocks
|
||||
private JournalEntryAggregationJobExecutionDecider decider;
|
||||
@Mock
|
||||
private JobExecution jobExecution;
|
||||
@Mock
|
||||
private StepExecution stepExecution;
|
||||
@Mock
|
||||
private ExecutionContext executionContext;
|
||||
|
||||
@Mock
|
||||
private FineractProperties.FineractJobProperties fineractJobProperties;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
when(jobExecution.getExecutionContext()).thenReturn(executionContext);
|
||||
when(jobExecution.getExecutionContext().get(JournalEntryAggregationJobConstant.AGGREGATED_ON_DATE)).thenReturn(aggregatedOnDate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecideContinueExecution() {
|
||||
// Arrange
|
||||
LocalDate lastAggregatedOnDate = aggregatedOnDate.minusDays(1);
|
||||
when(jobExecution.getExecutionContext().get(JournalEntryAggregationJobConstant.LAST_AGGREGATED_ON_DATE))
|
||||
.thenReturn(lastAggregatedOnDate);
|
||||
|
||||
// Act
|
||||
FlowExecutionStatus status = decider.decide(jobExecution, stepExecution);
|
||||
|
||||
// Assert
|
||||
assertEquals(JournalEntryAggregationJobConstant.CONTINUE_JOB_EXECUTION, status.getName(),
|
||||
"Should continue execution when lastAggregatedOnDate is before aggregatedOnDate");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideNoOpExecutionScenarios")
|
||||
public void testDecideNoOpExecution(LocalDate lastAggregatedOnDate, String scenarioDescription) {
|
||||
// Arrange
|
||||
when(jobExecution.getExecutionContext().get(JournalEntryAggregationJobConstant.LAST_AGGREGATED_ON_DATE))
|
||||
.thenReturn(lastAggregatedOnDate);
|
||||
when(jobExecution.getExitStatus()).thenReturn(ExitStatus.NOOP);
|
||||
|
||||
// Act
|
||||
FlowExecutionStatus status = decider.decide(jobExecution, stepExecution);
|
||||
|
||||
// Assert
|
||||
assertEquals(JournalEntryAggregationJobConstant.NO_OP_EXECUTION, status.getName(),
|
||||
"Should perform no-op execution when " + scenarioDescription);
|
||||
assertEquals(ExitStatus.NOOP, jobExecution.getExitStatus(),
|
||||
"Exit status should remain NOOP for scenario: " + scenarioDescription);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> provideNoOpExecutionScenarios() {
|
||||
LocalDate aggregatedOnDate = LocalDate.now(Clock.systemUTC());
|
||||
return Stream.of(Arguments.of(aggregatedOnDate, "lastAggregatedOnDate equals aggregatedOnDate"),
|
||||
Arguments.of(aggregatedOnDate.plusDays(1), "lastAggregatedOnDate is after aggregatedOnDate"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecideFirstTimeExecution() {
|
||||
// Arrange
|
||||
when(jobExecution.getExecutionContext().get(JournalEntryAggregationJobConstant.LAST_AGGREGATED_ON_DATE))
|
||||
.thenReturn(null);
|
||||
|
||||
// Act
|
||||
FlowExecutionStatus status = decider.decide(jobExecution, stepExecution);
|
||||
|
||||
// Assert
|
||||
assertEquals(JournalEntryAggregationJobConstant.CONTINUE_JOB_EXECUTION, status.getName(),
|
||||
"Should continue execution when no previous execution date exists (first time execution)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecideContinueExecutionWithMultipleDaysDifference() {
|
||||
// Arrange
|
||||
LocalDate lastAggregatedOnDate = aggregatedOnDate.minusDays(5);
|
||||
when(jobExecution.getExecutionContext().get(JournalEntryAggregationJobConstant.LAST_AGGREGATED_ON_DATE))
|
||||
.thenReturn(lastAggregatedOnDate);
|
||||
|
||||
// Act
|
||||
FlowExecutionStatus status = decider.decide(jobExecution, stepExecution);
|
||||
|
||||
// Assert
|
||||
assertEquals(JournalEntryAggregationJobConstant.CONTINUE_JOB_EXECUTION, status.getName(),
|
||||
"Should continue execution when lastAggregatedOnDate is multiple days before aggregatedOnDate");
|
||||
}
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.jobs.service.aggregationjob;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Date;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.infrastructure.core.service.migration.TenantDataSourceFactory;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.data.JournalEntryAggregationSummaryData;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.scope.context.JobSynchronizationManager;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class JournalEntryAggregationJobReaderTest {
|
||||
|
||||
@Mock
|
||||
private FineractPlatformTenantConnection fineractPlatformTenantConnection;
|
||||
@Mock
|
||||
private TenantDataSourceFactory tenantDataSourceFactory;
|
||||
@Mock
|
||||
private JobExecution jobExecution;
|
||||
@Mock
|
||||
private ExecutionContext executionContext;
|
||||
@Mock
|
||||
private HikariDataSource dataSource;
|
||||
@Mock
|
||||
private ResultSet resultSet;
|
||||
|
||||
private JournalEntryAggregationJobReader reader;
|
||||
private FineractPlatformTenant tenant;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
tenant = new FineractPlatformTenant(1L, "default", "Default Tenant", "default", fineractPlatformTenantConnection);
|
||||
ThreadLocalContextUtil.setTenant(tenant);
|
||||
ThreadLocalContextUtil
|
||||
.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault()))));
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
ThreadLocalContextUtil.reset();
|
||||
if (JobSynchronizationManager.getContext() != null) {
|
||||
JobSynchronizationManager.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRowMapping() throws Exception {
|
||||
// Arrange
|
||||
setupResultSetMocks();
|
||||
|
||||
// Act
|
||||
reader = new JournalEntryAggregationJobReader(tenantDataSourceFactory);
|
||||
JournalEntryAggregationSummaryData result = invokeMapRowMethod(resultSet, 1);
|
||||
|
||||
// Assert
|
||||
assertNotNull(result, "Mapped result should not be null");
|
||||
assertEquals(Long.valueOf(1001L), result.getGlAccountId(), "GL Account ID should match");
|
||||
assertEquals(100L, result.getProductId(), "Product ID should match");
|
||||
assertEquals(Long.valueOf(1L), result.getOffice(), "Office should be 1L");
|
||||
assertEquals(1L, result.getEntityTypeEnum(), "Entity type should be 1");
|
||||
assertEquals("USD", result.getCurrencyCode(), "Currency code should match");
|
||||
assertEquals(LocalDate.of(2023, 6, 15), result.getAggregatedOnDate(), "Aggregated date should match");
|
||||
assertEquals(Long.valueOf(500L), result.getExternalOwnerId(), "Asset owner should match");
|
||||
assertEquals(new BigDecimal("1000.00"), result.getDebitAmount(), "Debit amount should match");
|
||||
assertEquals(Boolean.FALSE, result.getManualEntry(), "Manual entry should be false");
|
||||
assertEquals(ThreadLocalContextUtil.getBusinessDate(), result.getSubmittedOnDate(), "Submitted on date should match business date");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRowMappingWithNullAssetOwner() throws Exception {
|
||||
// Arrange
|
||||
setupResultSetMocksWithNullOwner();
|
||||
|
||||
// Act
|
||||
reader = new JournalEntryAggregationJobReader(tenantDataSourceFactory);
|
||||
JournalEntryAggregationSummaryData result = invokeMapRowMethod(resultSet, 1);
|
||||
|
||||
// Assert
|
||||
assertEquals(Long.valueOf(0L), result.getExternalOwnerId(), "Asset owner should be 0 when null in resultset");
|
||||
}
|
||||
|
||||
private void setupResultSetMocks() throws SQLException {
|
||||
when(resultSet.getLong("glAccountId")).thenReturn(1001L);
|
||||
when(resultSet.getLong("productId")).thenReturn(100L);
|
||||
when(resultSet.getString("currencyCode")).thenReturn("USD");
|
||||
when(resultSet.getDate("aggregatedOnDate")).thenReturn(Date.valueOf(LocalDate.of(2023,6,15)));
|
||||
when(resultSet.findColumn("externalOwner")).thenReturn(5);
|
||||
when(resultSet.getLong(5)).thenReturn(500L);
|
||||
when(resultSet.getLong("officeId")).thenReturn(1L);
|
||||
when(resultSet.getLong("entityTypeEnum")).thenReturn(1L);
|
||||
when(resultSet.getBigDecimal("debitAmount")).thenReturn(new BigDecimal("1000.00"));
|
||||
when(resultSet.getBigDecimal("creditAmount")).thenReturn(new BigDecimal("800.00"));
|
||||
}
|
||||
|
||||
private void setupResultSetMocksWithNullOwner() throws SQLException {
|
||||
when(resultSet.getLong("glAccountId")).thenReturn(1001L);
|
||||
when(resultSet.getLong("productId")).thenReturn(100L);
|
||||
when(resultSet.getString("currencyCode")).thenReturn("USD");
|
||||
when(resultSet.getDate("aggregatedOnDate")).thenReturn(Date.valueOf(LocalDate.of(2023,6,15)));
|
||||
when(resultSet.getLong("officeId")).thenReturn(1L);
|
||||
when(resultSet.getLong("entityTypeEnum")).thenReturn(1L);
|
||||
when(resultSet.getBigDecimal("debitAmount")).thenReturn(new BigDecimal("1000.00"));
|
||||
when(resultSet.getBigDecimal("creditAmount")).thenReturn(new BigDecimal("800.00"));
|
||||
}
|
||||
|
||||
private JournalEntryAggregationSummaryData invokeMapRowMethod(ResultSet rs, int rowNum) throws Exception {
|
||||
Method mapRowMethod = JournalEntryAggregationJobReader.class.getDeclaredMethod("mapRow", ResultSet.class, int.class);
|
||||
mapRowMethod.setAccessible(true);
|
||||
return (JournalEntryAggregationSummaryData) mapRowMethod.invoke(reader, rs, rowNum);
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.jobs.service.aggregationjob;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyList;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.data.JournalEntryAggregationSummaryData;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.services.JournalEntryAggregationWriterService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.item.Chunk;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class JournalEntryAggregationJobWriterTest {
|
||||
|
||||
@InjectMocks
|
||||
private JournalEntryAggregationJobWriter writer;
|
||||
|
||||
@Mock
|
||||
private JournalEntryAggregationWriterService writerService;
|
||||
|
||||
@Test
|
||||
public void testWrite() {
|
||||
// Arrange
|
||||
JournalEntryAggregationSummaryData summaryData1 = mock(JournalEntryAggregationSummaryData.class);
|
||||
JournalEntryAggregationSummaryData summaryData2 = mock(JournalEntryAggregationSummaryData.class);
|
||||
Chunk<JournalEntryAggregationSummaryData> chunk = new Chunk<>(List.of(summaryData1, summaryData2));
|
||||
|
||||
StepExecution stepExecution = mock(StepExecution.class);
|
||||
JobExecution jobExecution = mock(JobExecution.class);
|
||||
when(stepExecution.getJobExecution()).thenReturn(jobExecution);
|
||||
when(jobExecution.getId()).thenReturn(123L);
|
||||
|
||||
writer.beforeStep(stepExecution);
|
||||
|
||||
// Act
|
||||
writer.write(chunk);
|
||||
|
||||
// Assert
|
||||
verify(writerService, times(1)).insertJournalEntrySummaryBatch(anyList());
|
||||
verify(summaryData1, times(1)).setJobExecutionId(123L);
|
||||
verify(summaryData2, times(1)).setJobExecutionId(123L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteEmptyChunk() {
|
||||
// Arrange
|
||||
Chunk<JournalEntryAggregationSummaryData> emptyChunk = new Chunk<>();
|
||||
|
||||
StepExecution stepExecution = mock(StepExecution.class);
|
||||
JobExecution jobExecution = mock(JobExecution.class);
|
||||
when(stepExecution.getJobExecution()).thenReturn(jobExecution);
|
||||
when(jobExecution.getId()).thenReturn(123L);
|
||||
|
||||
writer.beforeStep(stepExecution);
|
||||
|
||||
// Act
|
||||
writer.write(emptyChunk);
|
||||
|
||||
// Assert
|
||||
verify(writerService, times(1)).insertJournalEntrySummaryBatch(anyList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteSingleItem() {
|
||||
// Arrange
|
||||
JournalEntryAggregationSummaryData summaryData = mock(JournalEntryAggregationSummaryData.class);
|
||||
Chunk<JournalEntryAggregationSummaryData> chunk = new Chunk<>(List.of(summaryData));
|
||||
|
||||
StepExecution stepExecution = mock(StepExecution.class);
|
||||
JobExecution jobExecution = mock(JobExecution.class);
|
||||
when(stepExecution.getJobExecution()).thenReturn(jobExecution);
|
||||
when(jobExecution.getId()).thenReturn(456L);
|
||||
|
||||
writer.beforeStep(stepExecution);
|
||||
|
||||
// Act
|
||||
writer.write(chunk);
|
||||
|
||||
// Assert
|
||||
verify(writerService, times(1)).insertJournalEntrySummaryBatch(anyList());
|
||||
verify(summaryData, times(1)).setJobExecutionId(456L);
|
||||
}
|
||||
}
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.jobs.service.aggregationjob.listener;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.JournalEntryAggregationJobConstant;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.domain.JournalEntryAggregationTrackingRepository;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.scope.context.JobContext;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class JournalEntryAggregationJobListenerTest {
|
||||
|
||||
private final LocalDate businessDate = LocalDate.now(ZoneId.of("UTC"));
|
||||
|
||||
@Mock
|
||||
FineractPlatformTenantConnection fineractPlatformTenantConnection;
|
||||
|
||||
@Mock
|
||||
private FineractProperties fineractProperties;
|
||||
@Mock
|
||||
private FineractProperties.FineractJobProperties fineractJobProperties;
|
||||
@Mock
|
||||
private FineractProperties.FineractJournalEntryAggregationProperties fineractJournalEntryAggregationProperties;
|
||||
@Mock
|
||||
private JournalEntryAggregationTrackingRepository trackingRepository;
|
||||
@Mock
|
||||
private JobExecution jobExecution;
|
||||
@Mock
|
||||
private JobContext jobContext;
|
||||
@Mock
|
||||
private ExecutionContext executionContext;
|
||||
|
||||
@InjectMocks
|
||||
private JournalEntryAggregationJobListener listener;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
ThreadLocalContextUtil
|
||||
.setTenant(new FineractPlatformTenant(1L, "default", "Default Tenant", "default", fineractPlatformTenantConnection));
|
||||
|
||||
ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.COB_DATE, businessDate.minusDays(1))));
|
||||
ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, businessDate)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeforeJobWhenLastAggregatedOnDateNull() {
|
||||
// Arrange
|
||||
int lookBackDays = 2;
|
||||
|
||||
when(fineractProperties.getJob()).thenReturn(fineractJobProperties);
|
||||
when(fineractJobProperties.getJournalEntryAggregation()).thenReturn(fineractJournalEntryAggregationProperties);
|
||||
when(fineractJobProperties.getJournalEntryAggregation().getExcludeRecentNDays()).thenReturn(lookBackDays);
|
||||
when(trackingRepository.findLatestAggregatedOnDate()).thenReturn(null);
|
||||
|
||||
ExecutionContext executionContext = new ExecutionContext();
|
||||
when(jobExecution.getExecutionContext()).thenReturn(executionContext);
|
||||
|
||||
// Act
|
||||
listener.beforeJob(jobExecution);
|
||||
|
||||
// Assert
|
||||
assertEquals(businessDate.minusDays(lookBackDays), executionContext.get(JournalEntryAggregationJobConstant.AGGREGATED_ON_DATE));
|
||||
assertEquals(LocalDate.of(1970, 1, 1), executionContext.get(JournalEntryAggregationJobConstant.AGGREGATED_ON_DATE_FROM));
|
||||
assertNull(executionContext.get(JournalEntryAggregationJobConstant.LAST_AGGREGATED_ON_DATE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeforeJobWithLastAggregatedOnDate() {
|
||||
// Arrange
|
||||
LocalDate businessDate = LocalDate.now(ZoneId.of("UTC"));
|
||||
LocalDate lastAggregatedOnDate = businessDate.minusDays(5);
|
||||
int lookBackDays = 2;
|
||||
|
||||
when(fineractProperties.getJob()).thenReturn(fineractJobProperties);
|
||||
when(fineractJobProperties.getJournalEntryAggregation()).thenReturn(fineractJournalEntryAggregationProperties);
|
||||
when(fineractJobProperties.getJournalEntryAggregation().getExcludeRecentNDays()).thenReturn(lookBackDays);
|
||||
when(trackingRepository.findLatestAggregatedOnDate()).thenReturn(lastAggregatedOnDate);
|
||||
|
||||
JobExecution jobExecution = new JobExecution(1L);
|
||||
|
||||
// Act
|
||||
listener.beforeJob(jobExecution);
|
||||
|
||||
// Assert
|
||||
assertEquals(businessDate.minusDays(lookBackDays),
|
||||
jobExecution.getExecutionContext().get(JournalEntryAggregationJobConstant.AGGREGATED_ON_DATE));
|
||||
assertEquals(businessDate.minusDays(lookBackDays),
|
||||
jobExecution.getExecutionContext().get(JournalEntryAggregationJobConstant.AGGREGATED_ON_DATE_TO));
|
||||
assertEquals(lastAggregatedOnDate,
|
||||
jobExecution.getExecutionContext().get(JournalEntryAggregationJobConstant.LAST_AGGREGATED_ON_DATE));
|
||||
assertEquals(lastAggregatedOnDate,
|
||||
jobExecution.getExecutionContext().get(JournalEntryAggregationJobConstant.AGGREGATED_ON_DATE_FROM));
|
||||
}
|
||||
}
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.jobs.service.aggregationjob.services;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyList;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Clock;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.data.JournalEntryAggregationSummaryData;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.data.JournalEntryAggregationTrackingData;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.domain.JournalEntryAggregationTrackingRepository;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.domain.JournalEntrySummary;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.domain.JournalEntrySummaryRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class JournalEntryAggregationWriterServiceImplTest {
|
||||
|
||||
@InjectMocks
|
||||
private JournalEntryAggregationWriterServiceImpl writerService;
|
||||
|
||||
@Mock
|
||||
private JournalEntrySummaryRepository journalSummaryRepository;
|
||||
|
||||
@Mock
|
||||
private JournalEntryAggregationTrackingRepository journalEntryAggregationTrackingRepository;
|
||||
|
||||
@Mock
|
||||
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
||||
|
||||
@Test
|
||||
public void testInsertJournalEntryTracking() throws Exception {
|
||||
// Arrange
|
||||
JournalEntryAggregationTrackingData trackingData = mock(JournalEntryAggregationTrackingData.class);
|
||||
|
||||
// Act
|
||||
writerService.insertJournalEntryTracking(trackingData);
|
||||
|
||||
// Assert
|
||||
verify(journalEntryAggregationTrackingRepository, times(1)).save(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRollbackJournalEntrySummary() {
|
||||
// Arrange
|
||||
Long jobExecutionId = 123L;
|
||||
// Act
|
||||
writerService.rollbackJournalEntrySummary(jobExecutionId);
|
||||
// Assert
|
||||
verify(journalSummaryRepository, times(1)).deleteByJobExecutionId(jobExecutionId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRollbackJournalEntryTracking() {
|
||||
// Arrange
|
||||
final Long jobExecutionId = 123L;
|
||||
// Act
|
||||
writerService.rollbackJournalEntryTracking(jobExecutionId);
|
||||
// Assert
|
||||
verify(journalEntryAggregationTrackingRepository, times(1)).deleteByJobExecutionId(jobExecutionId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertJournalEntrySummaryBatch() {
|
||||
// Arrange
|
||||
JournalEntryAggregationSummaryData summaryData1 = mock(JournalEntryAggregationSummaryData.class);
|
||||
JournalEntryAggregationSummaryData summaryData2 = mock(JournalEntryAggregationSummaryData.class);
|
||||
|
||||
when(summaryData1.getAggregatedOnDate()).thenReturn(LocalDate.now(Clock.systemUTC()));
|
||||
when(summaryData2.getAggregatedOnDate()).thenReturn(LocalDate.now(Clock.systemUTC()));
|
||||
when(summaryData1.getJobExecutionId()).thenReturn(123L);
|
||||
when(summaryData2.getJobExecutionId()).thenReturn(123L);
|
||||
|
||||
List<JournalEntryAggregationSummaryData> summariesList = Arrays.asList(summaryData1, summaryData2);
|
||||
|
||||
// Act
|
||||
writerService.insertJournalEntrySummaryBatch(summariesList);
|
||||
|
||||
// Assert
|
||||
verify(journalSummaryRepository, times(1)).saveAll(anyList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertJournalEntrySummaryBatchEmpty() {
|
||||
// Arrange
|
||||
List<JournalEntryAggregationSummaryData> emptySummariesList = List.of();
|
||||
|
||||
// Act
|
||||
writerService.insertJournalEntrySummaryBatch(emptySummariesList);
|
||||
|
||||
// Assert
|
||||
verify(journalSummaryRepository, times(1)).saveAll(anyList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertJournalEntrySummaryBatchWithAmounts() {
|
||||
// Arrange
|
||||
JournalEntryAggregationSummaryData summaryData = mock(JournalEntryAggregationSummaryData.class);
|
||||
BigDecimal debitAmount = BigDecimal.valueOf(100.50);
|
||||
BigDecimal creditAmount = BigDecimal.valueOf(200.75);
|
||||
|
||||
when(summaryData.getAggregatedOnDate()).thenReturn(LocalDate.now(Clock.systemUTC()));
|
||||
when(summaryData.getDebitAmount()).thenReturn(debitAmount);
|
||||
when(summaryData.getCreditAmount()).thenReturn(creditAmount);
|
||||
when(summaryData.getJobExecutionId()).thenReturn(123L);
|
||||
|
||||
List<JournalEntryAggregationSummaryData> summariesList = List.of(summaryData);
|
||||
|
||||
// Act
|
||||
writerService.insertJournalEntrySummaryBatch(summariesList);
|
||||
|
||||
// Assert
|
||||
verify(journalSummaryRepository, times(1)).saveAll(argThat(entities -> {
|
||||
if (!(entities instanceof List) || ((List<?>) entities).isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
JournalEntrySummary entity = (JournalEntrySummary) ((List<?>) entities).getFirst();
|
||||
return entity.getDebitAmount().compareTo(debitAmount) == 0 && entity.getCreditAmount().compareTo(creditAmount) == 0;
|
||||
}));
|
||||
verify(summaryData, times(1)).getDebitAmount();
|
||||
verify(summaryData, times(1)).getCreditAmount();
|
||||
}
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.jobs.service.aggregationjob.tasklet;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.stream.Stream;
|
||||
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||
import org.apache.fineract.infrastructure.core.domain.ActionContext;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.JournalEntryAggregationJobConstant;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.data.JournalEntryAggregationTrackingData;
|
||||
import org.apache.fineract.infrastructure.jobs.service.aggregationjob.services.JournalEntryAggregationWriterService;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.scope.context.StepContext;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
class JournalEntryAggregationTrackingTaskletTest {
|
||||
|
||||
@Mock
|
||||
private StepContribution stepContribution;
|
||||
|
||||
@Mock
|
||||
private ChunkContext chunkContext;
|
||||
|
||||
@Mock
|
||||
private StepContext stepContext;
|
||||
|
||||
@Mock
|
||||
private StepExecution stepExecution;
|
||||
|
||||
@Mock
|
||||
private JobExecution jobExecutionContext;
|
||||
|
||||
@Mock
|
||||
private ExecutionContext executionContext;
|
||||
|
||||
@Mock
|
||||
private JournalEntryAggregationWriterService journalEntryAggregationWriterService;
|
||||
|
||||
@InjectMocks
|
||||
private JournalEntryAggregationTrackingTasklet underTest;
|
||||
|
||||
/**
|
||||
* DataProvider for the testHappyPath method.
|
||||
*
|
||||
* @return the argument list
|
||||
*/
|
||||
private static Stream<Arguments> recordWriteCount() {
|
||||
// spotless:off
|
||||
return Stream.of(Arguments.of(1L), Arguments.of(0L));
|
||||
// spotless:on
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("recordWriteCount")
|
||||
public void testHappyPath(final Long recordWriteCount) throws Exception {
|
||||
given(stepContribution.getStepExecution()).willReturn(stepExecution);
|
||||
given(stepExecution.getWriteCount()).willReturn(recordWriteCount);
|
||||
doNothing().when(journalEntryAggregationWriterService).insertJournalEntryTracking(any(JournalEntryAggregationTrackingData.class));
|
||||
given(chunkContext.getStepContext()).willReturn(stepContext);
|
||||
given(stepContext.getStepExecution()).willReturn(stepExecution);
|
||||
given(stepExecution.getJobExecution()).willReturn(jobExecutionContext);
|
||||
given(jobExecutionContext.getExecutionContext()).willReturn(executionContext);
|
||||
given(jobExecutionContext.getStepExecutions()).willReturn(Collections.singletonList(stepExecution));
|
||||
given(stepExecution.getStepName()).willReturn(JournalEntryAggregationJobConstant.JOB_SUMMARY_STEP_NAME);
|
||||
given(executionContext.get(any())).willReturn(LocalDate.now(Clock.systemUTC()));
|
||||
|
||||
final HashMap<BusinessDateType, LocalDate> businessDates = new HashMap<>();
|
||||
final LocalDate cobDate = LocalDate.now(Clock.systemUTC());
|
||||
businessDates.put(BusinessDateType.COB_DATE, cobDate);
|
||||
businessDates.put(BusinessDateType.BUSINESS_DATE, cobDate.plusDays(1));
|
||||
ThreadLocalContextUtil.setActionContext(ActionContext.COB);
|
||||
ThreadLocalContextUtil.setBusinessDates(businessDates);
|
||||
|
||||
RepeatStatus repeatStatus = underTest.execute(stepContribution, chunkContext);
|
||||
|
||||
if (recordWriteCount > 0) {
|
||||
verify(chunkContext, times(1)).getStepContext();
|
||||
verify(stepContext, times(1)).getStepExecution();
|
||||
verify(stepExecution, times(3)).getJobExecution();
|
||||
verify(jobExecutionContext, times(2)).getExecutionContext();
|
||||
verify(executionContext, times(2)).get(any());
|
||||
verify(journalEntryAggregationWriterService, times(1))
|
||||
.insertJournalEntryTracking(any(JournalEntryAggregationTrackingData.class));
|
||||
} else {
|
||||
verify(chunkContext, times(0)).getStepContext();
|
||||
verify(stepContext, times(0)).getStepExecution();
|
||||
verify(stepExecution, times(1)).getJobExecution();
|
||||
verify(jobExecutionContext, times(0)).getExecutionContext();
|
||||
verify(executionContext, times(0)).get(any());
|
||||
}
|
||||
assertEquals(RepeatStatus.FINISHED, repeatStatus);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -104,6 +104,11 @@ fineract.jpa.statementLoggingEnabled=${FINERACT_STATEMENT_LOGGING_ENABLED:false}
|
||||
fineract.database.defaultMasterPassword=${FINERACT_DEFAULT_MASTER_PASSWORD:fineract}
|
||||
|
||||
fineract.job.loan-cob-enabled=${FINERACT_JOB_LOAN_COB_ENABLED:true}
|
||||
# Aggregation job configuration
|
||||
fineract.job.journal-entry-aggregation.exclude-recent-N-days=${FINERACT_JOB_JOURNAL_ENTRY_AGGREGATION_EXCLUDE_RECENT_N_DAYS:1}
|
||||
fineract.job.journal-entry-aggregation.enabled=${FINERACT_JOB_JOURNAL_ENTRY_AGGREGATION_ENABLED:true}
|
||||
#this property if enabled, will create aggregated entry for all data on first run, instead of one entry per submitted_on_date
|
||||
fineract.job.journal-entry-aggregation.chunk-size=${FINERACT_JOB_JOURNAL_ENTRY_AGGREGATION_CHUNK_SIZE:2000}
|
||||
|
||||
fineract.sampling.enabled=false
|
||||
fineract.sampling.sampledClasses=
|
||||
|
||||
Reference in New Issue
Block a user