diff --git a/fineract-avro-schemas/src/main/avro/loan/v1/LoanChargeDataV1.avsc b/fineract-avro-schemas/src/main/avro/loan/v1/LoanChargeDataV1.avsc index 0987d32a5..9eaa4adbc 100644 --- a/fineract-avro-schemas/src/main/avro/loan/v1/LoanChargeDataV1.avsc +++ b/fineract-avro-schemas/src/main/avro/loan/v1/LoanChargeDataV1.avsc @@ -256,6 +256,17 @@ "null", "string" ] + }, + { + "default": null, + "name": "customData", + "type": [ + "null", + { + "values": "bytes", + "type": "map" + } + ] } ] } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanChargeDataMapper.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanChargeDataMapper.java index 2e49121e7..049a48899 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanChargeDataMapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanChargeDataMapper.java @@ -29,6 +29,7 @@ import org.mapstruct.Mapping; public interface LoanChargeDataMapper { @Mapping(target = "externalOwnerId", ignore = true) + @Mapping(target = "customData", ignore = true) LoanChargeDataV1 map(LoanChargeData source); LoanChargeDataRangeViewV1 mapRangeView(LoanChargeData source); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanChargeBusinessEventSerializer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanChargeBusinessEventSerializer.java index 7a80e872b..433f0df78 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanChargeBusinessEventSerializer.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanChargeBusinessEventSerializer.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.infrastructure.event.external.service.serialization.serializer.loan; +import java.util.List; import lombok.RequiredArgsConstructor; import org.apache.avro.generic.GenericContainer; import org.apache.fineract.avro.generator.ByteBufferSerializable; @@ -25,17 +26,18 @@ import org.apache.fineract.avro.loan.v1.LoanChargeDataV1; import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.loan.charge.LoanChargeBusinessEvent; import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.loan.LoanChargeDataMapper; -import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer; +import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.ExternalEventCustomDataSerializer; import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData; import org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService; import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor -public class LoanChargeBusinessEventSerializer implements BusinessEventSerializer { +public class LoanChargeBusinessEventSerializer extends AbstractLoanBusinessEventSerializer { private final LoanChargeReadPlatformService service; private final LoanChargeDataMapper mapper; + private final List> externalEventCustomDataSerializers; @Override public boolean canSerialize(BusinessEvent event) { @@ -46,11 +48,18 @@ public class LoanChargeBusinessEventSerializer implements BusinessEventSerialize public ByteBufferSerializable toAvroDTO(BusinessEvent rawEvent) { LoanChargeBusinessEvent event = (LoanChargeBusinessEvent) rawEvent; LoanChargeData data = service.retrieveLoanChargeDetails(event.get().getId(), event.get().getLoan().getId()); - return mapper.map(data); + final LoanChargeDataV1 loanChargeDataV1 = mapper.map(data); + loanChargeDataV1.setCustomData(collectCustomData(event)); + return loanChargeDataV1; } @Override public Class getSupportedSchema() { return LoanChargeDataV1.class; } + + @Override + protected List> getExternalEventCustomDataSerializers() { + return externalEventCustomDataSerializers; + } } diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanChargeBusinessEventSerializerTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanChargeBusinessEventSerializerTest.java new file mode 100644 index 000000000..991176c39 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanChargeBusinessEventSerializerTest.java @@ -0,0 +1,130 @@ +/** + * 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.loan; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.fineract.avro.loan.v1.LoanChargeDataV1; +import org.apache.fineract.infrastructure.event.business.domain.loan.charge.LoanChargeBusinessEvent; +import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.loan.LoanChargeDataMapper; +import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.ExternalEventCustomDataSerializer; +import org.apache.fineract.portfolio.loanaccount.data.LoanChargeData; +import org.apache.fineract.portfolio.loanaccount.domain.Loan; +import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge; +import org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService; +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.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + +@MockitoSettings(strictness = Strictness.LENIENT) +@ExtendWith(MockitoExtension.class) +class LoanChargeBusinessEventSerializerTest { + + @Mock + private LoanChargeReadPlatformService loanChargeReadPlatformService; + @Mock + private LoanChargeDataMapper loanChargeDataMapper; + + private LoanChargeBusinessEventSerializer serializer; + + @BeforeEach + void setUp() { + final List> externalEventCustomDataSerializers = List + .of(new ExternalEventCustomDataSerializer<>() { + + @Override + public ByteBuffer serialize(final LoanChargeBusinessEvent event) { + return ByteBuffer.wrap("test_data_for_loan_charge".getBytes(UTF_8)); + } + + @Override + public String key() { + return "test_key_1"; + } + }, new ExternalEventCustomDataSerializer<>() { + + @Override + public ByteBuffer serialize(final LoanChargeBusinessEvent event) { + return ByteBuffer.wrap("test_data_for_loan_charge_1".getBytes(UTF_8)); + } + + @Override + public String key() { + return "test_key_1"; + } + }, new ExternalEventCustomDataSerializer<>() { + + @Override + public ByteBuffer serialize(final LoanChargeBusinessEvent event) { + return ByteBuffer.wrap("test_data_for_loan_charge_2".getBytes(UTF_8)); + } + + @Override + public String key() { + return "test_key_2"; + } + }); + serializer = new LoanChargeBusinessEventSerializer(loanChargeReadPlatformService, loanChargeDataMapper, + externalEventCustomDataSerializers); + } + + @Test + void testLoanChargeCustomDataSerialization() { + final long loanId = 1; + final long chargeId = 2; + + final Loan loan = mock(Loan.class); + final LoanChargeData loanChargeData = mock(LoanChargeData.class); + final LoanChargeBusinessEvent event = mock(LoanChargeBusinessEvent.class); + final LoanCharge loanCharge = mock(LoanCharge.class); + + when(loan.getId()).thenReturn(loanId); + when(loanCharge.getId()).thenReturn(chargeId); + when(loanCharge.getLoan()).thenReturn(loan); + when(event.get()).thenReturn(loanCharge); + + when(loanChargeReadPlatformService.retrieveLoanChargeDetails(chargeId, loanId)).thenReturn(loanChargeData); + + final LoanChargeDataV1 expectedAvroData = LoanChargeDataV1.newBuilder().setId(chargeId).setLoanId(loanId) + .setCustomData(new HashMap<>()).build(); + when(loanChargeDataMapper.map(any(LoanChargeData.class))).thenReturn(expectedAvroData); + + final LoanChargeDataV1 result = (LoanChargeDataV1) serializer.toAvroDTO(event); + + assertNotNull(result); + assertNotNull(result.getCustomData()); + final Map customData = result.getCustomData(); + assertEquals("test_data_for_loan_charge_1", new String(customData.get("test_key_1").array(), UTF_8)); + assertEquals("test_data_for_loan_charge_2", new String(customData.get("test_key_2").array(), UTF_8)); + } + +}