FINERACT-1694: External event storage integration
This commit is contained in:
committed by
Arnold Gálovics
parent
5a9ddab671
commit
f46abaf9e2
+2
-1
@@ -279,6 +279,8 @@ configure(project.fineractJavaProjects) {
|
|||||||
sourceSets.main.output.resourcesDir = sourceSets.main.java.outputDir
|
sourceSets.main.output.resourcesDir = sourceSets.main.java.outputDir
|
||||||
sourceSets.test.output.resourcesDir = sourceSets.test.java.outputDir
|
sourceSets.test.output.resourcesDir = sourceSets.test.java.outputDir
|
||||||
|
|
||||||
|
check.dependsOn('cucumber')
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
implementation.setCanBeResolved(true)
|
implementation.setCanBeResolved(true)
|
||||||
api.setCanBeResolved(true)
|
api.setCanBeResolved(true)
|
||||||
@@ -536,7 +538,6 @@ configure(project.fineractJavaProjects) {
|
|||||||
|
|
||||||
test {
|
test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
dependsOn 'cucumber'
|
|
||||||
|
|
||||||
if (project.hasProperty('excludeTests')) {
|
if (project.hasProperty('excludeTests')) {
|
||||||
filter {
|
filter {
|
||||||
|
|||||||
@@ -84,6 +84,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "fieldOfficerName",
|
"name": "fieldOfficerName",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -219,6 +220,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "transactions",
|
"name": "transactions",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -229,6 +231,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "charges",
|
"name": "charges",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|||||||
@@ -172,6 +172,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "recurringDates",
|
"name": "recurringDates",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -182,6 +183,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "nextTenRecurringDates",
|
"name": "nextTenRecurringDates",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|||||||
@@ -124,6 +124,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "groupRoles",
|
"name": "groupRoles",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -134,6 +135,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "calendarsData",
|
"name": "calendarsData",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "ranges",
|
"name": "ranges",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|||||||
@@ -436,6 +436,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "transactions",
|
"name": "transactions",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -446,6 +447,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "charges",
|
"name": "charges",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -464,6 +466,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "disbursementDetails",
|
"name": "disbursementDetails",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -514,6 +517,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "accountLinkingOptions",
|
"name": "accountLinkingOptions",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -564,6 +568,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "emiAmountVariations",
|
"name": "emiAmountVariations",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -574,6 +579,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "clientActiveLoanOptions",
|
"name": "clientActiveLoanOptions",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -640,6 +646,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "overdueCharges",
|
"name": "overdueCharges",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|||||||
@@ -124,6 +124,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "chargeOptions",
|
"name": "chargeOptions",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|||||||
@@ -460,6 +460,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "charges",
|
"name": "charges",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -470,6 +471,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "principalVariationsForBorrowerCycle",
|
"name": "principalVariationsForBorrowerCycle",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -480,6 +482,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "interestRateVariationsForBorrowerCycle",
|
"name": "interestRateVariationsForBorrowerCycle",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -490,6 +493,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "numberOfRepaymentVariationsForBorrowerCycle",
|
"name": "numberOfRepaymentVariationsForBorrowerCycle",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -508,6 +512,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "rates",
|
"name": "rates",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|||||||
@@ -180,6 +180,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "loanChargePaidByList",
|
"name": "loanChargePaidByList",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|||||||
@@ -68,6 +68,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "allowedParents",
|
"name": "allowedParents",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|||||||
+2
@@ -220,6 +220,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "transactions",
|
"name": "transactions",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -230,6 +231,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "charges",
|
"name": "charges",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|||||||
@@ -92,6 +92,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "fieldOfficerName",
|
"name": "fieldOfficerName",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -339,6 +340,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "transactions",
|
"name": "transactions",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -349,6 +351,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "charges",
|
"name": "charges",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|||||||
@@ -180,6 +180,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "chargesPaidByData",
|
"name": "chargesPaidByData",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "purchasedShares",
|
"name": "purchasedShares",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -118,6 +119,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "savingsAccountId",
|
"name": "savingsAccountId",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "marketPrice",
|
"name": "marketPrice",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
@@ -118,6 +119,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": null,
|
||||||
"name": "charges",
|
"name": "charges",
|
||||||
"type": [
|
"type": [
|
||||||
"null",
|
"null",
|
||||||
|
|||||||
+1
-1
@@ -54,7 +54,7 @@ public class ExternalEvent extends AbstractPersistableCustom {
|
|||||||
@Setter
|
@Setter
|
||||||
private ExternalEventStatus status;
|
private ExternalEventStatus status;
|
||||||
|
|
||||||
@Column(name = "sent_at", nullable = false)
|
@Column(name = "sent_at", nullable = true)
|
||||||
@Setter
|
@Setter
|
||||||
private OffsetDateTime sentAt;
|
private OffsetDateTime sentAt;
|
||||||
|
|
||||||
|
|||||||
+8
@@ -45,6 +45,14 @@ public class DelayedExternalEventService {
|
|||||||
return !localEventStorage.get().isEmpty();
|
return !localEventStorage.get().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clearEnqueuedEvents() {
|
||||||
|
localEventStorage.get().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BusinessEvent<?>> getEnqueuedEvents() {
|
||||||
|
return List.copyOf(localEventStorage.get());
|
||||||
|
}
|
||||||
|
|
||||||
public void postEnqueuedEvents() {
|
public void postEnqueuedEvents() {
|
||||||
List<BusinessEvent<?>> enqueuedEvents = localEventStorage.get();
|
List<BusinessEvent<?>> enqueuedEvents = localEventStorage.get();
|
||||||
if (enqueuedEvents.isEmpty()) {
|
if (enqueuedEvents.isEmpty()) {
|
||||||
|
|||||||
-43
@@ -1,43 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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.event.external.service.serialization;
|
|
||||||
|
|
||||||
import java.util.Comparator;
|
|
||||||
import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer;
|
|
||||||
import org.springframework.core.Ordered;
|
|
||||||
import org.springframework.core.annotation.Order;
|
|
||||||
|
|
||||||
public class BusinessEventSerializerComparator implements Comparator<BusinessEventSerializer> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(BusinessEventSerializer o1, BusinessEventSerializer o2) {
|
|
||||||
int o1Order = getOrderOrDefault(o1);
|
|
||||||
int o2Order = getOrderOrDefault(o2);
|
|
||||||
return Integer.compare(o1Order, o2Order);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getOrderOrDefault(BusinessEventSerializer serializer) {
|
|
||||||
Order orderAnnotation = serializer.getClass().getAnnotation(Order.class);
|
|
||||||
if (orderAnnotation != null) {
|
|
||||||
return orderAnnotation.value();
|
|
||||||
} else {
|
|
||||||
return Ordered.LOWEST_PRECEDENCE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-4
@@ -19,19 +19,17 @@
|
|||||||
package org.apache.fineract.infrastructure.event.external.service.serialization;
|
package org.apache.fineract.infrastructure.event.external.service.serialization;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer;
|
import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer;
|
||||||
import org.apache.fineract.portfolio.businessevent.domain.BusinessEvent;
|
import org.apache.fineract.portfolio.businessevent.domain.BusinessEvent;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class BusinessEventSerializerFactory {
|
public class BusinessEventSerializerFactory {
|
||||||
|
|
||||||
private final List<BusinessEventSerializer> serializers;
|
private final List<BusinessEventSerializer> serializers;
|
||||||
|
|
||||||
public BusinessEventSerializerFactory(List<BusinessEventSerializer> serializers) {
|
|
||||||
this.serializers = serializers.stream().sorted(new BusinessEventSerializerComparator()).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> BusinessEventSerializer create(BusinessEvent<T> event) {
|
public <T> BusinessEventSerializer create(BusinessEvent<T> event) {
|
||||||
for (BusinessEventSerializer serializer : serializers) {
|
for (BusinessEventSerializer serializer : serializers) {
|
||||||
if (serializer.canSerialize(event)) {
|
if (serializer.canSerialize(event)) {
|
||||||
|
|||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* 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.event.external.service.serialization.mapper.savings;
|
||||||
|
|
||||||
|
import org.apache.fineract.avro.savings.v1.SavingsAccountTransactionDataV1;
|
||||||
|
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
|
||||||
|
@Mapper(componentModel = "spring")
|
||||||
|
public interface SavingsAccountTransactionDataMapper {
|
||||||
|
|
||||||
|
SavingsAccountTransactionDataV1 map(SavingsAccountTransactionData source);
|
||||||
|
}
|
||||||
+9
-4
@@ -50,13 +50,18 @@ public class LoanAdjustTransactionBusinessEventSerializer implements BusinessEve
|
|||||||
public <T> byte[] serialize(BusinessEvent<T> rawEvent) throws IOException {
|
public <T> byte[] serialize(BusinessEvent<T> rawEvent) throws IOException {
|
||||||
LoanAdjustTransactionBusinessEvent event = (LoanAdjustTransactionBusinessEvent) rawEvent;
|
LoanAdjustTransactionBusinessEvent event = (LoanAdjustTransactionBusinessEvent) rawEvent;
|
||||||
LoanTransaction transactionToAdjust = event.get().getTransactionToAdjust();
|
LoanTransaction transactionToAdjust = event.get().getTransactionToAdjust();
|
||||||
LoanTransaction newTransactionDetail = event.get().getNewTransactionDetail();
|
|
||||||
LoanTransactionData transactionToAdjustData = service.retrieveLoanTransaction(transactionToAdjust.getLoan().getId(),
|
LoanTransactionData transactionToAdjustData = service.retrieveLoanTransaction(transactionToAdjust.getLoan().getId(),
|
||||||
transactionToAdjust.getId());
|
transactionToAdjust.getId());
|
||||||
LoanTransactionData newTransactionDetailData = service.retrieveLoanTransaction(newTransactionDetail.getLoan().getId(),
|
|
||||||
newTransactionDetail.getId());
|
|
||||||
LoanTransactionDataV1 transactionToAdjustAvroDto = mapper.map(transactionToAdjustData);
|
LoanTransactionDataV1 transactionToAdjustAvroDto = mapper.map(transactionToAdjustData);
|
||||||
LoanTransactionDataV1 newTransactionDetailAvroDto = mapper.map(newTransactionDetailData);
|
|
||||||
|
LoanTransaction newTransactionDetail = event.get().getNewTransactionDetail();
|
||||||
|
LoanTransactionDataV1 newTransactionDetailAvroDto = null;
|
||||||
|
if (newTransactionDetail != null) {
|
||||||
|
LoanTransactionData newTransactionDetailData = service.retrieveLoanTransaction(newTransactionDetail.getLoan().getId(),
|
||||||
|
newTransactionDetail.getId());
|
||||||
|
newTransactionDetailAvroDto = mapper.map(newTransactionDetailData);
|
||||||
|
|
||||||
|
}
|
||||||
LoanTransactionAdjustmentDataV1 avroDto = new LoanTransactionAdjustmentDataV1(transactionToAdjustAvroDto,
|
LoanTransactionAdjustmentDataV1 avroDto = new LoanTransactionAdjustmentDataV1(transactionToAdjustAvroDto,
|
||||||
newTransactionDetailAvroDto);
|
newTransactionDetailAvroDto);
|
||||||
ByteBuffer buffer = avroDto.toByteBuffer();
|
ByteBuffer buffer = avroDto.toByteBuffer();
|
||||||
|
|||||||
+58
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* 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.event.external.service.serialization.serializer.savings;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.fineract.avro.savings.v1.SavingsAccountTransactionDataV1;
|
||||||
|
import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.savings.SavingsAccountTransactionDataMapper;
|
||||||
|
import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer;
|
||||||
|
import org.apache.fineract.infrastructure.event.external.service.support.ByteBufferConverter;
|
||||||
|
import org.apache.fineract.portfolio.businessevent.domain.BusinessEvent;
|
||||||
|
import org.apache.fineract.portfolio.businessevent.domain.savings.transaction.SavingsAccountTransactionBusinessEvent;
|
||||||
|
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
|
||||||
|
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
|
||||||
|
import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SavingsAccountTransactionBusinessEventSerializer implements BusinessEventSerializer {
|
||||||
|
|
||||||
|
private final SavingsAccountReadPlatformService service;
|
||||||
|
private final SavingsAccountTransactionDataMapper mapper;
|
||||||
|
private final ByteBufferConverter byteBufferConverter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> boolean canSerialize(BusinessEvent<T> event) {
|
||||||
|
return event instanceof SavingsAccountTransactionBusinessEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> byte[] serialize(BusinessEvent<T> rawEvent) throws IOException {
|
||||||
|
SavingsAccountTransactionBusinessEvent event = (SavingsAccountTransactionBusinessEvent) rawEvent;
|
||||||
|
SavingsAccountTransaction tx = event.get();
|
||||||
|
SavingsAccountTransactionData data = service.retrieveSavingsTransaction(tx.getSavingsAccount().getId(), tx.getId(),
|
||||||
|
tx.getSavingsAccount().depositAccountType());
|
||||||
|
SavingsAccountTransactionDataV1 avroDto = mapper.map(data);
|
||||||
|
ByteBuffer buffer = avroDto.toByteBuffer();
|
||||||
|
return byteBufferConverter.convert(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
-2
@@ -212,8 +212,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
public LoanAccountData retrieveOne(final Long loanId) {
|
public LoanAccountData retrieveOne(final Long loanId) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final AppUser currentUser = this.context.authenticatedUser();
|
final String hierarchy = getHierarchyString();
|
||||||
final String hierarchy = currentUser.getOffice().getHierarchy();
|
|
||||||
final String hierarchySearchString = hierarchy + "%";
|
final String hierarchySearchString = hierarchy + "%";
|
||||||
|
|
||||||
final LoanMapper rm = new LoanMapper(sqlGenerator, delinquencyReadPlatformService);
|
final LoanMapper rm = new LoanMapper(sqlGenerator, delinquencyReadPlatformService);
|
||||||
@@ -231,6 +230,14 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getHierarchyString() {
|
||||||
|
AppUser currentUser = null;
|
||||||
|
if (this.context != null) {
|
||||||
|
currentUser = this.context.getAuthenticatedUserIfPresent();
|
||||||
|
}
|
||||||
|
return Optional.ofNullable(currentUser).map(appUser -> appUser.getOffice().getHierarchy()).orElse(".");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoanAccountData retrieveLoanByLoanAccount(String loanAccountNumber) {
|
public LoanAccountData retrieveLoanByLoanAccount(String loanAccountNumber) {
|
||||||
|
|
||||||
|
|||||||
-1
@@ -406,7 +406,6 @@ public final class SavingsAccountData implements Serializable {
|
|||||||
return this.interestCompoundingPeriodType;
|
return this.interestCompoundingPeriodType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Integer getInterestCompoundingPeriodTypeId() {
|
public Integer getInterestCompoundingPeriodTypeId() {
|
||||||
return this.interestCompoundingPeriodType.getId().intValue();
|
return this.interestCompoundingPeriodType.getId().intValue();
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -24,17 +24,16 @@
|
|||||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
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">
|
<changeSet author="fineract" id="1">
|
||||||
<delete tableName="m_external_event"/>
|
<delete tableName="m_external_event"/>
|
||||||
|
<dropColumn tableName="m_external_event" columnName="data"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="fineract" id="2-mysql" context="mysql">
|
<changeSet author="fineract" id="2-mysql" context="mysql">
|
||||||
<dropColumn tableName="m_external_event" columnName="data"/>
|
|
||||||
<addColumn tableName="m_external_event">
|
<addColumn tableName="m_external_event">
|
||||||
<column name="data" type="VARBINARY">
|
<column name="data" type="BLOB">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
</addColumn>
|
</addColumn>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="fineract" id="2-postgresql" context="postgresql">
|
<changeSet author="fineract" id="2-postgresql" context="postgresql">
|
||||||
<dropColumn tableName="m_external_event" columnName="data"/>
|
|
||||||
<addColumn tableName="m_external_event">
|
<addColumn tableName="m_external_event">
|
||||||
<column name="data" type="BYTEA">
|
<column name="data" type="BYTEA">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
|
|||||||
+116
@@ -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.infrastructure.event.external.service;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.fineract.portfolio.businessevent.domain.BulkBusinessEvent;
|
||||||
|
import org.apache.fineract.portfolio.businessevent.domain.BusinessEvent;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
class DelayedExternalEventServiceTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ExternalEventService delegate;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private DelayedExternalEventService underTest;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp() {
|
||||||
|
underTest.clearEnqueuedEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnqueueEventFailsWhenNullEventIsGiven() {
|
||||||
|
// given
|
||||||
|
// when & then
|
||||||
|
assertThatThrownBy(() -> underTest.enqueueEvent(null)).isExactlyInstanceOf(IllegalArgumentException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnqueueEventWorks() {
|
||||||
|
// given
|
||||||
|
BusinessEvent event = mock(BusinessEvent.class);
|
||||||
|
// when
|
||||||
|
underTest.enqueueEvent(event);
|
||||||
|
// then
|
||||||
|
List<BusinessEvent<?>> enqueuedEvents = underTest.getEnqueuedEvents();
|
||||||
|
assertThat(enqueuedEvents).hasSize(1);
|
||||||
|
assertThat(enqueuedEvents.get(0)).isEqualTo(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHasEnqueuedEventsReturnsTrueWhenEventIsEnqueued() {
|
||||||
|
// given
|
||||||
|
BusinessEvent event = mock(BusinessEvent.class);
|
||||||
|
underTest.enqueueEvent(event);
|
||||||
|
// when
|
||||||
|
boolean result = underTest.hasEnqueuedEvents();
|
||||||
|
// then
|
||||||
|
assertThat(result).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHasEnqueuedEventsReturnsFalseWhenNoEventIsEnqueued() {
|
||||||
|
// given
|
||||||
|
// when
|
||||||
|
boolean result = underTest.hasEnqueuedEvents();
|
||||||
|
// then
|
||||||
|
assertThat(result).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPostEnqueuedEventsFailsWhenNoEventIsEnqueued() {
|
||||||
|
// given
|
||||||
|
// when & then
|
||||||
|
assertThatThrownBy(() -> underTest.postEnqueuedEvents()).isExactlyInstanceOf(IllegalStateException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPostEnqueuedEventsWorks() {
|
||||||
|
// given
|
||||||
|
ArgumentCaptor<BusinessEvent> delegateEventCaptor = ArgumentCaptor.forClass(BusinessEvent.class);
|
||||||
|
|
||||||
|
BusinessEvent event = mock(BusinessEvent.class);
|
||||||
|
underTest.enqueueEvent(event);
|
||||||
|
// when
|
||||||
|
underTest.postEnqueuedEvents();
|
||||||
|
// then
|
||||||
|
verify(delegate).postEvent(delegateEventCaptor.capture());
|
||||||
|
BusinessEvent delegateEvent = delegateEventCaptor.getValue();
|
||||||
|
assertThat(delegateEvent).isExactlyInstanceOf(BulkBusinessEvent.class);
|
||||||
|
BulkBusinessEvent bulkDelegateEvent = (BulkBusinessEvent) delegateEvent;
|
||||||
|
List<BusinessEvent<?>> enqueuedEvents = bulkDelegateEvent.get();
|
||||||
|
assertThat(enqueuedEvents).hasSize(1);
|
||||||
|
assertThat(enqueuedEvents.get(0)).isEqualTo(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
+115
@@ -0,0 +1,115 @@
|
|||||||
|
/**
|
||||||
|
* 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.event.external.service;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
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.service.ThreadLocalContextUtil;
|
||||||
|
import org.apache.fineract.infrastructure.event.external.repository.ExternalEventRepository;
|
||||||
|
import org.apache.fineract.infrastructure.event.external.repository.domain.ExternalEvent;
|
||||||
|
import org.apache.fineract.infrastructure.event.external.service.idempotency.ExternalEventIdempotencyKeyGenerator;
|
||||||
|
import org.apache.fineract.infrastructure.event.external.service.serialization.BusinessEventSerializerFactory;
|
||||||
|
import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer;
|
||||||
|
import org.apache.fineract.portfolio.businessevent.domain.BusinessEvent;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
class ExternalEventServiceTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ExternalEventRepository repository;
|
||||||
|
@Mock
|
||||||
|
private ExternalEventIdempotencyKeyGenerator idempotencyKeyGenerator;
|
||||||
|
@Mock
|
||||||
|
private BusinessEventSerializerFactory serializerFactory;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private ExternalEventService underTest;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp() {
|
||||||
|
FineractPlatformTenant tenant = new FineractPlatformTenant(1L, "default", "Default Tenant", "Europe/Budapest", null);
|
||||||
|
ThreadLocalContextUtil.setTenant(tenant);
|
||||||
|
ThreadLocalContextUtil
|
||||||
|
.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPostEventShouldFailWhenNullEventIsGiven() {
|
||||||
|
// given
|
||||||
|
// when & then
|
||||||
|
assertThatThrownBy(() -> underTest.postEvent(null)).isExactlyInstanceOf(IllegalArgumentException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPostEventShouldFailWhenEventSerializationFails() throws IOException {
|
||||||
|
// given
|
||||||
|
BusinessEvent event = mock(BusinessEvent.class);
|
||||||
|
BusinessEventSerializer eventSerializer = mock(BusinessEventSerializer.class);
|
||||||
|
|
||||||
|
given(idempotencyKeyGenerator.generate(event)).willReturn("");
|
||||||
|
given(serializerFactory.create(event)).willReturn(eventSerializer);
|
||||||
|
given(eventSerializer.serialize(event)).willThrow(IOException.class);
|
||||||
|
// when & then
|
||||||
|
assertThatThrownBy(() -> underTest.postEvent(event)).isExactlyInstanceOf(RuntimeException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPostEventShouldWork() throws IOException {
|
||||||
|
// given
|
||||||
|
ArgumentCaptor<ExternalEvent> externalEventArgumentCaptor = ArgumentCaptor.forClass(ExternalEvent.class);
|
||||||
|
|
||||||
|
String eventType = "TestType";
|
||||||
|
String idempotencyKey = "key";
|
||||||
|
BusinessEvent event = mock(BusinessEvent.class);
|
||||||
|
BusinessEventSerializer eventSerializer = mock(BusinessEventSerializer.class);
|
||||||
|
byte[] data = new byte[0];
|
||||||
|
|
||||||
|
given(event.getType()).willReturn(eventType);
|
||||||
|
given(idempotencyKeyGenerator.generate(event)).willReturn(idempotencyKey);
|
||||||
|
given(serializerFactory.create(event)).willReturn(eventSerializer);
|
||||||
|
given(eventSerializer.serialize(event)).willReturn(data);
|
||||||
|
// when
|
||||||
|
underTest.postEvent(event);
|
||||||
|
// then
|
||||||
|
verify(repository).save(externalEventArgumentCaptor.capture());
|
||||||
|
ExternalEvent externalEvent = externalEventArgumentCaptor.getValue();
|
||||||
|
assertThat(externalEvent.getIdempotencyKey()).isEqualTo(idempotencyKey);
|
||||||
|
assertThat(externalEvent.getData()).isEqualTo(data);
|
||||||
|
assertThat(externalEvent.getType()).isEqualTo(eventType);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,6 +45,7 @@ fineract.partitioned-job.partitioned-job-properties[0].thread-count=1
|
|||||||
fineract.remote-job-message-handler.spring-events.enabled=${FINERACT_REMOTE_JOB_MESSAGE_HANDLER_SPRING_EVENTS_ENABLED:true}
|
fineract.remote-job-message-handler.spring-events.enabled=${FINERACT_REMOTE_JOB_MESSAGE_HANDLER_SPRING_EVENTS_ENABLED:true}
|
||||||
fineract.remote-job-message-handler.jms.enabled=${FINERACT_REMOTE_JOB_MESSAGE_HANDLER_JMS_ENABLED:false}
|
fineract.remote-job-message-handler.jms.enabled=${FINERACT_REMOTE_JOB_MESSAGE_HANDLER_JMS_ENABLED:false}
|
||||||
fineract.remote-job-message-handler.jms.request-queue-name=${FINERACT_REMOTE_JOB_MESSAGE_HANDLER_JMS_QUEUE_NAME:JMS-request-queue}
|
fineract.remote-job-message-handler.jms.request-queue-name=${FINERACT_REMOTE_JOB_MESSAGE_HANDLER_JMS_QUEUE_NAME:JMS-request-queue}
|
||||||
|
fineract.events.external.enabled=${FINERACT_EXTERNAL_EVENTS_ENABLED:false}
|
||||||
|
|
||||||
management.health.jms.enabled=false
|
management.health.jms.enabled=false
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ cargo {
|
|||||||
} else {
|
} else {
|
||||||
jvmArgs += '-Dspring.datasource.hikari.driverClassName=org.mariadb.jdbc.Driver -Dspring.datasource.hikari.jdbcUrl=jdbc:mariadb://localhost:3306/fineract_tenants -Dspring.datasource.hikari.username=root -Dspring.datasource.hikari.password=mysql -Dfineract.tenant.host=localhost -Dfineract.tenant.port=3306 -Dfineract.tenant.username=root -Dfineract.tenant.password=mysql'
|
jvmArgs += '-Dspring.datasource.hikari.driverClassName=org.mariadb.jdbc.Driver -Dspring.datasource.hikari.jdbcUrl=jdbc:mariadb://localhost:3306/fineract_tenants -Dspring.datasource.hikari.username=root -Dspring.datasource.hikari.password=mysql -Dfineract.tenant.host=localhost -Dfineract.tenant.port=3306 -Dfineract.tenant.username=root -Dfineract.tenant.password=mysql'
|
||||||
}
|
}
|
||||||
jvmArgs += ' -Dspring.profiles.active=test'
|
jvmArgs += ' -Dspring.profiles.active=test -Dfineract.events.external.enabled=true'
|
||||||
property 'cargo.start.jvmargs', jvmArgs
|
property 'cargo.start.jvmargs', jvmArgs
|
||||||
property 'cargo.tomcat.connector.keystoreFile', file("$rootDir/fineract-provider/src/main/resources/keystore.jks")
|
property 'cargo.tomcat.connector.keystoreFile', file("$rootDir/fineract-provider/src/main/resources/keystore.jks")
|
||||||
property 'cargo.tomcat.connector.keystorePass', 'openmf'
|
property 'cargo.tomcat.connector.keystorePass', 'openmf'
|
||||||
|
|||||||
Reference in New Issue
Block a user