Skip to content

Commit 4de7905

Browse files
author
Jose Alberto Hernandez
committed
FINERACT-2332: SavingCOB infrastructure
1 parent 1dfba8e commit 4de7905

File tree

23 files changed

+796
-13
lines changed

23 files changed

+796
-13
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "SavingsAccountStayedLockedDataV1",
3+
"namespace": "org.apache.fineract.avro.savings.v1",
4+
"type": "record",
5+
"fields": [
6+
{
7+
"name": "id",
8+
"type": "long"
9+
},
10+
{
11+
"default": null,
12+
"name": "externalId",
13+
"type": [
14+
"null",
15+
"string"
16+
]
17+
},
18+
{
19+
"default": null,
20+
"name": "accountNo",
21+
"type": [
22+
"null",
23+
"string"
24+
]
25+
}
26+
]
27+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "SavingsAccountsStayedLockedDataV1",
3+
"namespace": "org.apache.fineract.avro.savings.v1",
4+
"type": "record",
5+
"fields": [{
6+
"name": "savingsAccounts",
7+
"type": {
8+
"type": "array",
9+
"items": "org.apache.fineract.avro.savings.v1.SavingsAccountStayedLockedDataV1"
10+
}
11+
}]
12+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.cob.savings;
20+
21+
import java.sql.ResultSet;
22+
import java.sql.SQLException;
23+
import java.time.LocalDate;
24+
import java.util.ArrayList;
25+
import java.util.Arrays;
26+
import java.util.Collection;
27+
import java.util.List;
28+
import lombok.RequiredArgsConstructor;
29+
import org.apache.fineract.cob.data.COBIdAndExternalIdAndAccountNo;
30+
import org.apache.fineract.cob.data.COBIdAndLastClosedBusinessDate;
31+
import org.apache.fineract.cob.data.COBParameter;
32+
import org.apache.fineract.cob.data.COBPartition;
33+
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
34+
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
35+
import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepository;
36+
import org.apache.fineract.portfolio.savings.domain.SavingsAccountStatusType;
37+
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
38+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
39+
import org.springframework.stereotype.Service;
40+
41+
@Service
42+
@RequiredArgsConstructor
43+
public class RetrieveSavingsIdServiceImpl implements RetrieveSavingsIdService {
44+
45+
private static final Collection<Integer> NON_CLOSED_SAVINGS_STATUSES = new ArrayList<>(
46+
Arrays.asList(SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getValue(), SavingsAccountStatusType.APPROVED.getValue(),
47+
SavingsAccountStatusType.ACTIVE.getValue(), SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue(),
48+
SavingsAccountStatusType.TRANSFER_ON_HOLD.getValue()));
49+
50+
private final SavingsAccountRepository savingsAccountRepository;
51+
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
52+
53+
@Override
54+
public List<COBPartition> retrieveSavingsCOBPartitions(Long numberOfDays, LocalDate businessDate, boolean isCatchUp,
55+
int partitionSize) {
56+
StringBuilder sql = new StringBuilder();
57+
sql.append("select min(id) as min, max(id) as max, page, count(id) as count from ");
58+
sql.append(" (select floor(((row_number() over(order by id))-1) / :pageSize) as page, t.* from ");
59+
sql.append(" (select id from m_savings_account where status_enum in (:statusIds) and ");
60+
if (isCatchUp) {
61+
sql.append("last_closed_business_date = :businessDate ");
62+
} else {
63+
sql.append("(last_closed_business_date = :businessDate or last_closed_business_date is null) ");
64+
}
65+
sql.append("order by id) t) t2 ");
66+
sql.append("group by page ");
67+
sql.append("order by page");
68+
69+
MapSqlParameterSource parameters = new MapSqlParameterSource();
70+
parameters.addValue("pageSize", partitionSize);
71+
parameters.addValue("statusIds", NON_CLOSED_SAVINGS_STATUSES);
72+
parameters.addValue("businessDate", businessDate.minusDays(numberOfDays));
73+
return namedParameterJdbcTemplate.query(sql.toString(), parameters, RetrieveSavingsIdServiceImpl::mapRow);
74+
}
75+
76+
private static COBPartition mapRow(ResultSet rs, int rowNum) throws SQLException {
77+
return new COBPartition(rs.getLong("min"), rs.getLong("max"), rs.getLong("page"), rs.getLong("count"));
78+
}
79+
80+
@Override
81+
public List<COBIdAndLastClosedBusinessDate> retrieveSavingsIdsBehindDate(LocalDate businessDate, List<Long> savingsIds) {
82+
return savingsAccountRepository.findAllSavingsIdsBehindDate(businessDate, savingsIds);
83+
}
84+
85+
@Override
86+
public List<COBIdAndLastClosedBusinessDate> retrieveSavingsIdsBehindDateOrNull(LocalDate businessDate, List<Long> savingsIds) {
87+
return savingsAccountRepository.findAllSavingsIdsBehindDateOrNull(businessDate, savingsIds);
88+
}
89+
90+
@Override
91+
public List<COBIdAndLastClosedBusinessDate> retrieveSavingsIdsOldestCobProcessed(LocalDate businessDate) {
92+
return savingsAccountRepository.findAllSavingsIdsOldestCobProcessed();
93+
}
94+
95+
@Override
96+
public List<Long> retrieveAllNonClosedSavingsByLastClosedBusinessDateAndMinAndMaxSavingsId(COBParameter savingsCOBParameter,
97+
boolean isCatchUp) {
98+
LocalDate cobBusinessDate = ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE)
99+
.minusDays(SavingsCOBConstant.NUMBER_OF_DAYS_BEHIND);
100+
101+
if (isCatchUp) {
102+
return savingsAccountRepository.findAllSavingsByLastClosedBusinessDateNotNullAndMinAndMaxSavingsIdAndStatuses(
103+
savingsCOBParameter.getMinAccountId(), savingsCOBParameter.getMaxAccountId(), cobBusinessDate,
104+
NON_CLOSED_SAVINGS_STATUSES);
105+
} else {
106+
return savingsAccountRepository.findAllSavingsByLastClosedBusinessDateAndMinAndMaxSavingsIdAndStatuses(
107+
savingsCOBParameter.getMinAccountId(), savingsCOBParameter.getMaxAccountId(), cobBusinessDate,
108+
NON_CLOSED_SAVINGS_STATUSES);
109+
}
110+
}
111+
112+
@Override
113+
public List<COBIdAndExternalIdAndAccountNo> findAllStayedLockedByCobBusinessDate(LocalDate cobBusinessDate) {
114+
// This will be implemented when we add the query to join with SavingsAccountLock
115+
// For now, return empty list as the lock table doesn't exist yet
116+
return List.of();
117+
}
118+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.infrastructure.event.external.service.serialization.mapper.savings;
20+
21+
import org.apache.fineract.avro.savings.v1.SavingsAccountStayedLockedDataV1;
22+
import org.apache.fineract.avro.savings.v1.SavingsAccountsStayedLockedDataV1;
23+
import org.apache.fineract.cob.data.COBIdAndExternalIdAndAccountNo;
24+
import org.apache.fineract.cob.savings.SavingsAccountsStayedLockedData;
25+
import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.support.AvroMapperConfig;
26+
import org.mapstruct.Mapper;
27+
28+
@Mapper(config = AvroMapperConfig.class)
29+
public interface SavingsAccountsStayedLockedDataMapper {
30+
31+
SavingsAccountsStayedLockedDataV1 map(SavingsAccountsStayedLockedData savingsAccountsStayedLockedData);
32+
33+
SavingsAccountStayedLockedDataV1 map(COBIdAndExternalIdAndAccountNo cobIdAndExternalIdAndAccountNo);
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.infrastructure.event.external.service.serialization.serializer.savings;
20+
21+
import lombok.RequiredArgsConstructor;
22+
import org.apache.avro.generic.GenericContainer;
23+
import org.apache.fineract.avro.generator.ByteBufferSerializable;
24+
import org.apache.fineract.avro.savings.v1.SavingsAccountsStayedLockedDataV1;
25+
import org.apache.fineract.cob.savings.SavingsAccountsStayedLockedBusinessEvent;
26+
import org.apache.fineract.cob.savings.SavingsAccountsStayedLockedData;
27+
import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent;
28+
import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.savings.SavingsAccountsStayedLockedDataMapper;
29+
import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer;
30+
import org.springframework.stereotype.Component;
31+
32+
@Component
33+
@RequiredArgsConstructor
34+
public class SavingsAccountsStayedLockedBusinessEventSerializer implements BusinessEventSerializer {
35+
36+
private final SavingsAccountsStayedLockedDataMapper mapper;
37+
38+
@Override
39+
public <T> boolean canSerialize(BusinessEvent<T> event) {
40+
return event instanceof SavingsAccountsStayedLockedBusinessEvent;
41+
}
42+
43+
@Override
44+
public <T> ByteBufferSerializable toAvroDTO(BusinessEvent<T> rawEvent) {
45+
SavingsAccountsStayedLockedBusinessEvent event = (SavingsAccountsStayedLockedBusinessEvent) rawEvent;
46+
SavingsAccountsStayedLockedData savingsAccounts = event.get();
47+
return mapper.map(savingsAccounts);
48+
}
49+
50+
@Override
51+
public Class<? extends GenericContainer> getSupportedSchema() {
52+
return SavingsAccountsStayedLockedDataV1.class;
53+
}
54+
}

fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ public void givenAllConfigurationWhenValidatedThenValidationSuccessful() throws
112112
"LoanCapitalizedIncomeTransactionCreatedBusinessEvent", "LoanUndoContractTerminationBusinessEvent",
113113
"LoanBuyDownFeeTransactionCreatedBusinessEvent", "LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent",
114114
"LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent",
115-
"LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent", "LoanApprovedAmountChangedBusinessEvent");
115+
"LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent", "LoanApprovedAmountChangedBusinessEvent",
116+
"SavingsAccountsStayedLockedBusinessEvent");
116117

117118
List<FineractPlatformTenant> tenants = Arrays
118119
.asList(new FineractPlatformTenant(1L, "default", "Default Tenant", "Europe/Budapest", null));
@@ -149,6 +150,7 @@ public void givenNoEventConfigurationWhenValidatedThenThrowException() throws Ex
149150

150151
// then
151152
String expectedMessage = "No external events configured";
153+
152154
String actualMessage = exceptionThrown.getMessage();
153155

154156
assertTrue(actualMessage.contains(expectedMessage));
@@ -206,7 +208,8 @@ public void givenMissingEventConfigurationWhenValidatedThenThrowException() thro
206208
"LoanCapitalizedIncomeTransactionCreatedBusinessEvent", "LoanUndoContractTerminationBusinessEvent",
207209
"LoanBuyDownFeeTransactionCreatedBusinessEvent", "LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent",
208210
"LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent",
209-
"LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent", "LoanApprovedAmountChangedBusinessEvent");
211+
"LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent", "LoanApprovedAmountChangedBusinessEvent",
212+
"SavingsAccountsStayedLockedBusinessEvent");
210213

211214
List<FineractPlatformTenant> tenants = Arrays
212215
.asList(new FineractPlatformTenant(1L, "default", "Default Tenant", "Europe/Budapest", null));
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.cob.savings;
20+
21+
import java.time.LocalDate;
22+
import java.util.List;
23+
import org.apache.fineract.cob.data.COBIdAndExternalIdAndAccountNo;
24+
import org.apache.fineract.cob.data.COBIdAndLastClosedBusinessDate;
25+
import org.apache.fineract.cob.data.COBParameter;
26+
import org.apache.fineract.cob.data.COBPartition;
27+
import org.springframework.data.repository.query.Param;
28+
29+
public interface RetrieveSavingsIdService {
30+
31+
List<COBPartition> retrieveSavingsCOBPartitions(Long numberOfDays, LocalDate businessDate, boolean isCatchUp, int partitionSize);
32+
33+
List<COBIdAndLastClosedBusinessDate> retrieveSavingsIdsBehindDate(LocalDate businessDate, List<Long> savingsIds);
34+
35+
List<COBIdAndLastClosedBusinessDate> retrieveSavingsIdsBehindDateOrNull(LocalDate businessDate, List<Long> savingsIds);
36+
37+
List<COBIdAndLastClosedBusinessDate> retrieveSavingsIdsOldestCobProcessed(LocalDate businessDate);
38+
39+
List<Long> retrieveAllNonClosedSavingsByLastClosedBusinessDateAndMinAndMaxSavingsId(COBParameter savingsCOBParameter,
40+
boolean isCatchUp);
41+
42+
List<COBIdAndExternalIdAndAccountNo> findAllStayedLockedByCobBusinessDate(@Param("cobBusinessDate") LocalDate cobBusinessDate);
43+
44+
}

0 commit comments

Comments
 (0)