diff --git a/fineract-avro-schemas/src/main/avro/loan/v1/LoanRepaymentDueDataV1.avsc b/fineract-avro-schemas/src/main/avro/loan/v1/LoanRepaymentDueDataV1.avsc new file mode 100644 index 000000000..50c05f577 --- /dev/null +++ b/fineract-avro-schemas/src/main/avro/loan/v1/LoanRepaymentDueDataV1.avsc @@ -0,0 +1,63 @@ +{ + "name": "LoanRepaymentDueDataV1", + "namespace": "org.apache.fineract.avro.loan.v1", + "type": "record", + "fields": [ + { + "default": null, + "name": "id", + "type": [ + "null", + "long" + ] + }, + { + "default": null, + "name": "accountNo", + "type": [ + "null", + "string" + ] + }, + { + "default": null, + "name": "externalId", + "type": [ + "null", + "string" + ] + }, + { + "default": null, + "name": "dueDate", + "type": [ + "null", + "string" + ] + }, + { + "default": null, + "name": "currency", + "type": [ + "null", + "org.apache.fineract.avro.generic.v1.CurrencyDataV1" + ] + }, + { + "default": null, + "name": "totalLoanAmountDue", + "type": [ + "null", + "bigdecimal" + ] + }, + { + "default": null, + "name": "repaymentDue", + "type": [ + "null", + "org.apache.fineract.avro.loan.v1.RepaymentDueDataV1" + ] + } + ] +} diff --git a/fineract-avro-schemas/src/main/avro/loan/v1/RepaymentDueDataV1.avsc b/fineract-avro-schemas/src/main/avro/loan/v1/RepaymentDueDataV1.avsc new file mode 100644 index 000000000..d33076511 --- /dev/null +++ b/fineract-avro-schemas/src/main/avro/loan/v1/RepaymentDueDataV1.avsc @@ -0,0 +1,55 @@ +{ + "name": "RepaymentDueDataV1", + "namespace": "org.apache.fineract.avro.loan.v1", + "type": "record", + "fields": [ + { + "default": null, + "name": "installmentNumber", + "type": [ + "null", + "int" + ] + }, + { + "default": null, + "name": "principalAmountDue", + "type": [ + "null", + "bigdecimal" + ] + }, + { + "default": null, + "name": "interestAmountDue", + "type": [ + "null", + "bigdecimal" + ] + }, + { + "default": null, + "name": "feeChargeAmountDue", + "type": [ + "null", + "bigdecimal" + ] + }, + { + "default": null, + "name": "penaltyChargeAmountDue", + "type": [ + "null", + "bigdecimal" + ] + }, + { + "default": null, + "name": "totalAmountDue", + "type": [ + "null", + "bigdecimal" + ] + } + ] +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStep.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStep.java index a85bf6b38..7ab04af41 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStep.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStep.java @@ -23,7 +23,7 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.service.DateUtils; -import org.apache.fineract.infrastructure.event.business.domain.loan.LoanRepaymentDueBusinessEvent; +import org.apache.fineract.infrastructure.event.business.domain.loan.repayment.LoanRepaymentDueBusinessEvent; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; @@ -44,7 +44,7 @@ public class CheckLoanRepaymentDueBusinessStep implements LoanCOBBusinessStep { for (LoanRepaymentScheduleInstallment repaymentSchedule : loanRepaymentScheduleInstallments) { LocalDate repaymentDate = repaymentSchedule.getDueDate(); if (repaymentDate.minusDays(numberOfDaysBeforeDueDateToRaiseEvent).equals(currentDate)) { - businessEventNotifierService.notifyPostBusinessEvent(new LoanRepaymentDueBusinessEvent(loan)); + businessEventNotifierService.notifyPostBusinessEvent(new LoanRepaymentDueBusinessEvent(repaymentSchedule)); break; } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStep.java b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStep.java index d30d507d4..531720bfb 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStep.java +++ b/fineract-provider/src/main/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStep.java @@ -23,7 +23,7 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.service.DateUtils; -import org.apache.fineract.infrastructure.event.business.domain.loan.LoanRepaymentOverdueBusinessEvent; +import org.apache.fineract.infrastructure.event.business.domain.loan.repayment.LoanRepaymentOverdueBusinessEvent; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; @@ -45,7 +45,7 @@ public class CheckLoanRepaymentOverdueBusinessStep implements LoanCOBBusinessSte if (!repaymentSchedule.isObligationsMet()) { LocalDate installmentDueDate = repaymentSchedule.getDueDate(); if (installmentDueDate.plusDays(numberOfDaysAfterDueDateToRaiseEvent).equals(currentDate)) { - businessEventNotifierService.notifyPostBusinessEvent(new LoanRepaymentOverdueBusinessEvent(loan)); + businessEventNotifierService.notifyPostBusinessEvent(new LoanRepaymentOverdueBusinessEvent(repaymentSchedule)); break; } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/repayment/LoanRepaymentBusinessEvent.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/repayment/LoanRepaymentBusinessEvent.java new file mode 100644 index 000000000..4ae53fad8 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/repayment/LoanRepaymentBusinessEvent.java @@ -0,0 +1,36 @@ +/** + * 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.business.domain.loan.repayment; + +import org.apache.fineract.infrastructure.event.business.domain.AbstractBusinessEvent; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; + +public abstract class LoanRepaymentBusinessEvent extends AbstractBusinessEvent { + + private static final String CATEGORY = "Loan"; + + public LoanRepaymentBusinessEvent(LoanRepaymentScheduleInstallment value) { + super(value); + } + + @Override + public String getCategory() { + return CATEGORY; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/LoanRepaymentDueBusinessEvent.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/repayment/LoanRepaymentDueBusinessEvent.java similarity index 79% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/LoanRepaymentDueBusinessEvent.java rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/repayment/LoanRepaymentDueBusinessEvent.java index 3cb3fb491..f371e60fc 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/LoanRepaymentDueBusinessEvent.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/repayment/LoanRepaymentDueBusinessEvent.java @@ -16,15 +16,15 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.fineract.infrastructure.event.business.domain.loan; +package org.apache.fineract.infrastructure.event.business.domain.loan.repayment; -import org.apache.fineract.portfolio.loanaccount.domain.Loan; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; -public class LoanRepaymentDueBusinessEvent extends LoanBusinessEvent { +public class LoanRepaymentDueBusinessEvent extends LoanRepaymentBusinessEvent { private static final String TYPE = "LoanRepaymentDueBusinessEvent"; - public LoanRepaymentDueBusinessEvent(Loan value) { + public LoanRepaymentDueBusinessEvent(LoanRepaymentScheduleInstallment value) { super(value); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/LoanRepaymentOverdueBusinessEvent.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/repayment/LoanRepaymentOverdueBusinessEvent.java similarity index 79% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/LoanRepaymentOverdueBusinessEvent.java rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/repayment/LoanRepaymentOverdueBusinessEvent.java index f6f4053be..f21425b93 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/LoanRepaymentOverdueBusinessEvent.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/loan/repayment/LoanRepaymentOverdueBusinessEvent.java @@ -16,15 +16,15 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.fineract.infrastructure.event.business.domain.loan; +package org.apache.fineract.infrastructure.event.business.domain.loan.repayment; -import org.apache.fineract.portfolio.loanaccount.domain.Loan; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; -public class LoanRepaymentOverdueBusinessEvent extends LoanBusinessEvent { +public class LoanRepaymentOverdueBusinessEvent extends LoanRepaymentBusinessEvent { private static final String TYPE = "LoanRepaymentOverdueBusinessEvent"; - public LoanRepaymentOverdueBusinessEvent(Loan value) { + public LoanRepaymentOverdueBusinessEvent(LoanRepaymentScheduleInstallment value) { super(value); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializer.java new file mode 100644 index 000000000..f283ba604 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializer.java @@ -0,0 +1,79 @@ +/** + * 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 java.math.BigDecimal; +import lombok.RequiredArgsConstructor; +import org.apache.avro.generic.GenericContainer; +import org.apache.fineract.avro.generator.ByteBufferSerializable; +import org.apache.fineract.avro.generic.v1.CurrencyDataV1; +import org.apache.fineract.avro.loan.v1.LoanRepaymentDueDataV1; +import org.apache.fineract.avro.loan.v1.RepaymentDueDataV1; +import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent; +import org.apache.fineract.infrastructure.event.business.domain.loan.repayment.LoanRepaymentBusinessEvent; +import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.support.AvroDateTimeMapper; +import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.AbstractBusinessEventSerializer; +import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; +import org.apache.fineract.portfolio.loanaccount.domain.Loan; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class LoanRepaymentBusinessEventSerializer extends AbstractBusinessEventSerializer { + + private final AvroDateTimeMapper dataTimeMapper; + + @Override + protected ByteBufferSerializable toAvroDTO(BusinessEvent rawEvent) { + + LoanRepaymentBusinessEvent event = (LoanRepaymentBusinessEvent) rawEvent; + LoanRepaymentScheduleInstallment repaymentInstallment = event.get(); + Loan loan = repaymentInstallment.getLoan(); + Long id = loan.getId(); + String accountNo = loan.getAccountNumber(); + String externalId = loan.getExternalId(); + String dueDate = dataTimeMapper.mapLocalDate(repaymentInstallment.getDueDate()); + MonetaryCurrency loanCurrency = loan.getCurrency(); + CurrencyDataV1 currency = CurrencyDataV1.newBuilder().setCode(loanCurrency.getCode()) + .setDecimalPlaces(loanCurrency.getDigitsAfterDecimal()).setInMultiplesOf(loanCurrency.getCurrencyInMultiplesOf()).build(); + BigDecimal totalLoanAmountDue = loan.getLoanSummary().getTotalOutstanding(); + + Integer installmentNumber = repaymentInstallment.getInstallmentNumber(); + BigDecimal principalAmountDue = repaymentInstallment.getPrincipalOutstanding(loanCurrency).getAmount(); + BigDecimal interestAmountDue = repaymentInstallment.getInterestOutstanding(loanCurrency).getAmount(); + BigDecimal feeChargeAmountDue = repaymentInstallment.getFeeChargesOutstanding(loanCurrency).getAmount(); + BigDecimal penaltyChargeAmountDue = repaymentInstallment.getPenaltyChargesOutstanding(loanCurrency).getAmount(); + BigDecimal totalAmountDue = repaymentInstallment.getTotalOutstanding(loanCurrency).getAmount(); + + RepaymentDueDataV1 repaymentDue = new RepaymentDueDataV1(installmentNumber, principalAmountDue, interestAmountDue, + feeChargeAmountDue, penaltyChargeAmountDue, totalAmountDue); + return new LoanRepaymentDueDataV1(id, accountNo, externalId, dueDate, currency, totalLoanAmountDue, repaymentDue); + } + + @Override + public boolean canSerialize(BusinessEvent event) { + return event instanceof LoanRepaymentBusinessEvent; + } + + @Override + public Class getSupportedSchema() { + return LoanRepaymentDueDataV1.class; + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStepTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStepTest.java index 2d412a275..828a461be 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStepTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentDueBusinessStepTest.java @@ -37,7 +37,7 @@ import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDoma import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; -import org.apache.fineract.infrastructure.event.business.domain.loan.LoanRepaymentDueBusinessEvent; +import org.apache.fineract.infrastructure.event.business.domain.loan.repayment.LoanRepaymentDueBusinessEvent; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; @@ -73,19 +73,19 @@ public class CheckLoanRepaymentDueBusinessStepTest { when(configurationDomainService.retrieveRepaymentDueDays()).thenReturn(1L); LocalDate loanInstallmentRepaymentDueDate = DateUtils.getBusinessLocalDate().plusDays(1); Loan loanForProcessing = Mockito.mock(Loan.class); - List loanRepaymentScheduleInstallments = Arrays - .asList(new LoanRepaymentScheduleInstallment(loanForProcessing, 1, LocalDate.now(ZoneId.systemDefault()), - loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), - BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0))); + LoanRepaymentScheduleInstallment repaymentInstallment = new LoanRepaymentScheduleInstallment(loanForProcessing, 1, + LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), + BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0)); + List loanRepaymentScheduleInstallments = Arrays.asList(repaymentInstallment); when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments); // when Loan processedLoan = underTest.execute(loanForProcessing); // then verify(businessEventNotifierService, times(1)).notifyPostBusinessEvent(loanRepaymentDueEvent.capture()); - Loan loanPayloadForEvent = loanRepaymentDueEvent.getValue().get(); - assertEquals(loanForProcessing, loanPayloadForEvent); - assertEquals(processedLoan, loanPayloadForEvent); + LoanRepaymentScheduleInstallment loanPayloadForEvent = loanRepaymentDueEvent.getValue().get(); + assertEquals(repaymentInstallment, loanPayloadForEvent); + assertEquals(processedLoan, loanForProcessing); } diff --git a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java index 252e01d96..7e9c38dab 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java +++ b/fineract-provider/src/test/java/org/apache/fineract/cob/loan/CheckLoanRepaymentOverdueBusinessStepTest.java @@ -37,7 +37,7 @@ import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDoma import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; -import org.apache.fineract.infrastructure.event.business.domain.loan.LoanRepaymentOverdueBusinessEvent; +import org.apache.fineract.infrastructure.event.business.domain.loan.repayment.LoanRepaymentOverdueBusinessEvent; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; @@ -74,19 +74,19 @@ public class CheckLoanRepaymentOverdueBusinessStepTest { when(configurationDomainService.retrieveRepaymentOverdueDays()).thenReturn(1L); LocalDate loanInstallmentRepaymentDueDate = DateUtils.getBusinessLocalDate().minusDays(1); Loan loanForProcessing = Mockito.mock(Loan.class); - List loanRepaymentScheduleInstallments = Arrays - .asList(new LoanRepaymentScheduleInstallment(loanForProcessing, 1, LocalDate.now(ZoneId.systemDefault()), - loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), - BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0))); + LoanRepaymentScheduleInstallment repaymentInstallment = new LoanRepaymentScheduleInstallment(loanForProcessing, 1, + LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), + BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0)); + List loanRepaymentScheduleInstallments = Arrays.asList(repaymentInstallment); when(loanForProcessing.getRepaymentScheduleInstallments()).thenReturn(loanRepaymentScheduleInstallments); // when Loan processedLoan = underTest.execute(loanForProcessing); // then verify(businessEventNotifierService, times(1)).notifyPostBusinessEvent(loanRepaymentOverdueBusinessEventArgumentCaptor.capture()); - Loan loanPayloadForEvent = loanRepaymentOverdueBusinessEventArgumentCaptor.getValue().get(); - assertEquals(loanForProcessing, loanPayloadForEvent); - assertEquals(processedLoan, loanPayloadForEvent); + LoanRepaymentScheduleInstallment loanPayloadForEvent = loanRepaymentOverdueBusinessEventArgumentCaptor.getValue().get(); + assertEquals(repaymentInstallment, loanPayloadForEvent); + assertEquals(processedLoan, loanForProcessing); } @Test diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java new file mode 100644 index 000000000..c1ea9114e --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanRepaymentBusinessEventSerializerTest.java @@ -0,0 +1,113 @@ +/** + * 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 org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import org.apache.fineract.avro.generic.v1.CurrencyDataV1; +import org.apache.fineract.avro.loan.v1.LoanRepaymentDueDataV1; +import org.apache.fineract.avro.loan.v1.RepaymentDueDataV1; +import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; +import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; +import org.apache.fineract.infrastructure.core.service.DateUtils; +import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; +import org.apache.fineract.infrastructure.event.business.domain.loan.repayment.LoanRepaymentDueBusinessEvent; +import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.support.AvroDateTimeMapper; +import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; +import org.apache.fineract.organisation.monetary.domain.MoneyHelper; +import org.apache.fineract.portfolio.loanaccount.domain.Loan; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; +import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary; +import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; +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.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class LoanRepaymentBusinessEventSerializerTest { + + @Mock + private AvroDateTimeMapper mapper; + + @BeforeEach + public void setUp() { + ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null)); + ThreadLocalContextUtil + .setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.now(ZoneId.systemDefault())))); + } + + @Test + public void testLoanRepaymentEventPayloadSerialization() throws IOException { + // given + LoanRepaymentBusinessEventSerializer serializer = new LoanRepaymentBusinessEventSerializer(mapper); + + LocalDate loanInstallmentRepaymentDueDate = DateUtils.getBusinessLocalDate().plusDays(1); + + Loan loanForProcessing = Mockito.mock(Loan.class); + LoanProduct loanProduct = Mockito.mock(LoanProduct.class); + LoanSummary loanSummary = Mockito.mock(LoanSummary.class); + MonetaryCurrency loanCurrency = Mockito.mock(MonetaryCurrency.class); + MockedStatic moneyHelper = Mockito.mockStatic(MoneyHelper.class); + + LoanRepaymentScheduleInstallment repaymentInstallment = new LoanRepaymentScheduleInstallment(loanForProcessing, 1, + LocalDate.now(ZoneId.systemDefault()), loanInstallmentRepaymentDueDate, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), + BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), false, new HashSet<>(), BigDecimal.valueOf(0.0)); + LoanRepaymentDueBusinessEvent event = new LoanRepaymentDueBusinessEvent(repaymentInstallment); + + when(loanForProcessing.getId()).thenReturn(1L); + when(loanForProcessing.getAccountNumber()).thenReturn("0001"); + when(loanForProcessing.getExternalId()).thenReturn("externalId"); + when(loanForProcessing.getLoanSummary()).thenReturn(loanSummary); + when(loanSummary.getTotalOutstanding()).thenReturn(BigDecimal.valueOf(0.0)); + when(loanForProcessing.getCurrency()).thenReturn(loanCurrency); + when(loanCurrency.getCode()).thenReturn("CODE"); + when(loanCurrency.getCurrencyInMultiplesOf()).thenReturn(1); + when(loanCurrency.getDigitsAfterDecimal()).thenReturn(1); + when(mapper.mapLocalDate(any())).thenReturn(loanInstallmentRepaymentDueDate.format(DateTimeFormatter.ISO_DATE)); + moneyHelper.when(() -> MoneyHelper.getRoundingMode()).thenReturn(RoundingMode.UP); + + // when + LoanRepaymentDueDataV1 data = (LoanRepaymentDueDataV1) serializer.toAvroDTO(event); + + // then + CurrencyDataV1 currency = CurrencyDataV1.newBuilder().setCode("CODE").setDecimalPlaces(1).setInMultiplesOf(1).build(); + RepaymentDueDataV1 repaymentDue = new RepaymentDueDataV1(1, BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), + BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0), BigDecimal.valueOf(0.0)); + LoanRepaymentDueDataV1 expectedSerializedData = new LoanRepaymentDueDataV1(1L, "0001", "externalId", + loanInstallmentRepaymentDueDate.format(DateTimeFormatter.ISO_DATE), currency, BigDecimal.valueOf(0.0), repaymentDue); + + assertEquals(data, expectedSerializedData); + moneyHelper.close(); + } +}