FINERACT-1971: Added installment level delinquency data to LoanAccountDataV1/CollectionDataV1 avro schema
diff --git a/fineract-avro-schemas/src/main/avro/loan/v1/CollectionDataV1.avsc b/fineract-avro-schemas/src/main/avro/loan/v1/CollectionDataV1.avsc
index 36256d2..3fdc726 100644
--- a/fineract-avro-schemas/src/main/avro/loan/v1/CollectionDataV1.avsc
+++ b/fineract-avro-schemas/src/main/avro/loan/v1/CollectionDataV1.avsc
@@ -93,6 +93,17 @@
                     "items": "org.apache.fineract.avro.loan.v1.DelinquencyPausePeriodV1"
                 }
             ]
+        },
+        {
+            "default": null,
+            "name": "installmentDelinquencyBuckets",
+            "type": [
+                "null",
+                {
+                    "type": "array",
+                    "items": "org.apache.fineract.avro.loan.v1.LoanInstallmentDelinquencyBucketDataV1"
+                }
+            ]
         }
     ]
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountDataMapper.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountDataMapper.java
index 03b1446..d55a124 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountDataMapper.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/loan/LoanAccountDataMapper.java
@@ -36,6 +36,7 @@
     @Mapping(target = "externalOwnerId", ignore = true)
     @Mapping(target = "settlementDate", ignore = true)
     @Mapping(target = "purchasePriceRatio", ignore = true)
+    @Mapping(target = "delinquent.installmentDelinquencyBuckets", ignore = true)
     LoanAccountDataV1 map(LoanAccountData source);
 
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanBusinessEventSerializer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanBusinessEventSerializer.java
index 2ed1594..6844fe2 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanBusinessEventSerializer.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanBusinessEventSerializer.java
@@ -19,11 +19,13 @@
 package org.apache.fineract.infrastructure.event.external.service.serialization.serializer.loan;
 
 import java.util.Collection;
+import java.util.List;
 import lombok.RequiredArgsConstructor;
 import org.apache.avro.generic.GenericContainer;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.fineract.avro.generator.ByteBufferSerializable;
 import org.apache.fineract.avro.loan.v1.LoanAccountDataV1;
+import org.apache.fineract.avro.loan.v1.LoanInstallmentDelinquencyBucketDataV1;
 import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent;
 import org.apache.fineract.infrastructure.event.business.domain.loan.LoanBusinessEvent;
 import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.loan.LoanAccountDataMapper;
@@ -46,6 +48,7 @@
     private final LoanAccountDataMapper mapper;
     private final LoanChargeReadPlatformService loanChargeReadPlatformService;
     private final DelinquencyReadPlatformService delinquencyReadPlatformService;
+    private final LoanInstallmentLevelDelinquencyEventProducer installmentLevelDelinquencyEventProducer;
 
     @Override
     public <T> boolean canSerialize(BusinessEvent<T> event) {
@@ -74,7 +77,13 @@
         } else {
             data.setSummary(LoanSummaryData.withOnlyCurrencyData(data.getCurrency()));
         }
-        return mapper.map(data);
+
+        List<LoanInstallmentDelinquencyBucketDataV1> installmentsDelinquencyData = installmentLevelDelinquencyEventProducer
+                .calculateInstallmentLevelDelinquencyData(event.get(), data.getCurrency());
+
+        LoanAccountDataV1 result = mapper.map(data);
+        result.getDelinquent().setInstallmentDelinquencyBuckets(installmentsDelinquencyData);
+        return result;
     }
 
     @Override
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanDelinquencyRangeChangeBusinessEventSerializer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanDelinquencyRangeChangeBusinessEventSerializer.java
index 22a606c..01c7b01 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanDelinquencyRangeChangeBusinessEventSerializer.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanDelinquencyRangeChangeBusinessEventSerializer.java
@@ -19,12 +19,8 @@
 package org.apache.fineract.infrastructure.event.external.service.serialization.serializer.loan;
 
 import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 import java.util.function.BiFunction;
-import java.util.stream.Collectors;
 import lombok.RequiredArgsConstructor;
 import org.apache.avro.generic.GenericContainer;
 import org.apache.fineract.avro.generator.ByteBufferSerializable;
@@ -33,7 +29,6 @@
 import org.apache.fineract.avro.loan.v1.LoanAmountDataV1;
 import org.apache.fineract.avro.loan.v1.LoanChargeDataRangeViewV1;
 import org.apache.fineract.avro.loan.v1.LoanInstallmentDelinquencyBucketDataV1;
-import org.apache.fineract.infrastructure.core.service.DateUtils;
 import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent;
 import org.apache.fineract.infrastructure.event.business.domain.loan.LoanDelinquencyRangeChangeBusinessEvent;
 import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.generic.CurrencyDataMapper;
@@ -42,12 +37,10 @@
 import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.support.AvroDateTimeMapper;
 import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
-import org.apache.fineract.portfolio.delinquency.data.LoanInstallmentDelinquencyTagData;
 import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
 import org.apache.fineract.portfolio.loanaccount.data.CollectionData;
 import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
 import org.apache.fineract.portfolio.loanaccount.service.LoanChargeReadPlatformService;
 import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
@@ -72,6 +65,7 @@
 
     private final CurrencyDataMapper currencyMapper;
     private final AvroDateTimeMapper dataTimeMapper;
+    private final LoanInstallmentLevelDelinquencyEventProducer installmentLevelDelinquencyEventProducer;
 
     @Override
     public <T> ByteBufferSerializable toAvroDTO(BusinessEvent<T> rawEvent) {
@@ -103,8 +97,8 @@
 
         DelinquencyRangeDataV1 delinquencyRange = mapper.map(data.getDelinquencyRange());
 
-        List<LoanInstallmentDelinquencyBucketDataV1> installmentsDelinquencyData = calculateInstallmentLevelDelinquencyData(event.get(),
-                data);
+        List<LoanInstallmentDelinquencyBucketDataV1> installmentsDelinquencyData = installmentLevelDelinquencyEventProducer
+                .calculateInstallmentLevelDelinquencyData(event.get(), data.getCurrency());
 
         LoanAccountDelinquencyRangeDataV1.Builder builder = LoanAccountDelinquencyRangeDataV1.newBuilder();
         return builder//
@@ -119,79 +113,6 @@
                 .setInstallmentDelinquencyBuckets(installmentsDelinquencyData).build();
     }
 
-    private List<LoanInstallmentDelinquencyBucketDataV1> calculateInstallmentLevelDelinquencyData(Loan loan, LoanAccountData data) {
-        List<LoanInstallmentDelinquencyBucketDataV1> loanInstallmentDelinquencyData = new ArrayList<>();
-        if (loan.isEnableInstallmentLevelDelinquency()) {
-            Collection<LoanInstallmentDelinquencyTagData> installmentDelinquencyTags = delinquencyReadPlatformService
-                    .retrieveLoanInstallmentsCurrentDelinquencyTag(loan.getId());
-            if (installmentDelinquencyTags != null && installmentDelinquencyTags.size() > 0) {
-                // group installments that are in same range
-                Map<Long, List<LoanInstallmentDelinquencyTagData>> installmentsInSameRange = installmentDelinquencyTags.stream().collect(
-                        Collectors.groupingBy(installmentDelnquencyTags -> installmentDelnquencyTags.getDelinquencyRange().getId()));
-                // for installments in each range, get details from loan repayment schedule installment, add amounts,
-                // list charges
-                for (Map.Entry<Long, List<LoanInstallmentDelinquencyTagData>> installmentDelinquencyTagData : installmentsInSameRange
-                        .entrySet()) {
-                    // get installments details
-                    List<LoanRepaymentScheduleInstallment> delinquentInstallmentsInSameRange = loan.getRepaymentScheduleInstallments()
-                            .stream().filter(installment -> installmentDelinquencyTagData.getValue().stream()
-                                    .anyMatch(installmentTag -> installmentTag.getId().equals(installment.getId())))
-                            .toList();
-                    // add amounts
-                    LoanAmountDataV1 amount = LoanAmountDataV1.newBuilder()//
-                            .setPrincipalAmount(delinquentInstallmentsInSameRange.stream()
-                                    .map(instlment -> instlment.getPrincipalOutstanding(loan.getCurrency()).getAmount())
-                                    .reduce(BigDecimal.ZERO, BigDecimal::add))//
-                            .setFeeAmount(delinquentInstallmentsInSameRange.stream()
-                                    .map(instlment -> instlment.getFeeChargesOutstanding(loan.getCurrency()).getAmount())
-                                    .reduce(BigDecimal.ZERO, BigDecimal::add))//
-                            .setInterestAmount(delinquentInstallmentsInSameRange.stream()
-                                    .map(instlment -> instlment.getInterestOutstanding(loan.getCurrency()).getAmount())
-                                    .reduce(BigDecimal.ZERO, BigDecimal::add))//
-                            .setPenaltyAmount(delinquentInstallmentsInSameRange.stream()
-                                    .map(instlment -> instlment.getPenaltyChargesOutstanding(loan.getCurrency()).getAmount())
-                                    .reduce(BigDecimal.ZERO, BigDecimal::add))//
-                            .setTotalAmount(delinquentInstallmentsInSameRange.stream()
-                                    .map(instlment -> instlment.getTotalOutstanding(loan.getCurrency()).getAmount())
-                                    .reduce(BigDecimal.ZERO, BigDecimal::add))//
-                            .build();
-
-                    // get list of charges for installments in same range
-                    List<LoanCharge> chargesForInstallmentsInSameRange = loan.getLoanCharges().stream().filter(loanCharge -> !loanCharge
-                            .isPaid()
-                            && delinquentInstallmentsInSameRange.stream().anyMatch(installmentForCharge -> (DateUtils
-                                    .isAfter(loanCharge.getEffectiveDueDate(), installmentForCharge.getFromDate())
-                                    || DateUtils.isEqual(loanCharge.getEffectiveDueDate(), installmentForCharge.getFromDate()))
-                                    && (DateUtils.isBefore(loanCharge.getEffectiveDueDate(), installmentForCharge.getDueDate())
-                                            || DateUtils.isEqual(loanCharge.getEffectiveDueDate(), installmentForCharge.getDueDate()))))
-                            .toList();
-
-                    List<LoanChargeDataRangeViewV1> charges = new ArrayList<>();
-                    for (LoanCharge charge : chargesForInstallmentsInSameRange) {
-                        LoanChargeDataRangeViewV1 chargeData = LoanChargeDataRangeViewV1.newBuilder().setId(charge.getId())
-                                .setName(charge.name()).setAmount(charge.amountOutstanding())
-                                .setCurrency(currencyMapper.map(data.getCurrency())).build();
-                        charges.add(chargeData);
-                    }
-
-                    LoanInstallmentDelinquencyTagData.InstallmentDelinquencyRange delinquencyRange = installmentDelinquencyTagData
-                            .getValue().get(0).getDelinquencyRange();
-
-                    DelinquencyRangeDataV1 delinquencyRangeDataV1 = DelinquencyRangeDataV1.newBuilder().setId(delinquencyRange.getId())
-                            .setClassification(delinquencyRange.getClassification()).setMinimumAgeDays(delinquencyRange.getMinimumAgeDays())
-                            .setMaximumAgeDays(delinquencyRange.getMaximumAgeDays()).build();
-
-                    LoanInstallmentDelinquencyBucketDataV1 installmentDelinquencyBucketDataV1 = LoanInstallmentDelinquencyBucketDataV1
-                            .newBuilder().setDelinquencyRange(delinquencyRangeDataV1).setAmount(amount).setCharges(charges)
-                            .setCurrency(currencyMapper.map(data.getCurrency())).build();
-
-                    loanInstallmentDelinquencyData.add(installmentDelinquencyBucketDataV1);
-                }
-            }
-        }
-        return loanInstallmentDelinquencyData;
-    }
-
     private BigDecimal calculateDataSummary(Loan loan, BiFunction<Loan, LoanRepaymentScheduleInstallment, BigDecimal> mapper) {
         return loan.getRepaymentScheduleInstallments().stream().map(installment -> mapper.apply(loan, installment)).reduce(BigDecimal.ZERO,
                 BigDecimal::add);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanInstallmentLevelDelinquencyEventProducer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanInstallmentLevelDelinquencyEventProducer.java
new file mode 100644
index 0000000..59d4175
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanInstallmentLevelDelinquencyEventProducer.java
@@ -0,0 +1,121 @@
+/**
+ * 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 java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.avro.loan.v1.DelinquencyRangeDataV1;
+import org.apache.fineract.avro.loan.v1.LoanAmountDataV1;
+import org.apache.fineract.avro.loan.v1.LoanChargeDataRangeViewV1;
+import org.apache.fineract.avro.loan.v1.LoanInstallmentDelinquencyBucketDataV1;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.generic.CurrencyDataMapper;
+import org.apache.fineract.organisation.monetary.data.CurrencyData;
+import org.apache.fineract.portfolio.delinquency.data.LoanInstallmentDelinquencyTagData;
+import org.apache.fineract.portfolio.delinquency.service.DelinquencyReadPlatformService;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class LoanInstallmentLevelDelinquencyEventProducer {
+
+    private final DelinquencyReadPlatformService delinquencyReadPlatformService;
+    private final CurrencyDataMapper currencyMapper;
+
+    public List<LoanInstallmentDelinquencyBucketDataV1> calculateInstallmentLevelDelinquencyData(Loan loan, CurrencyData currency) {
+        List<LoanInstallmentDelinquencyBucketDataV1> loanInstallmentDelinquencyData = new ArrayList<>();
+        if (loan.isEnableInstallmentLevelDelinquency()) {
+            Collection<LoanInstallmentDelinquencyTagData> installmentDelinquencyTags = delinquencyReadPlatformService
+                    .retrieveLoanInstallmentsCurrentDelinquencyTag(loan.getId());
+            if (installmentDelinquencyTags != null && installmentDelinquencyTags.size() > 0) {
+                // group installments that are in same range
+                Map<Long, List<LoanInstallmentDelinquencyTagData>> installmentsInSameRange = installmentDelinquencyTags.stream().collect(
+                        Collectors.groupingBy(installmentDelnquencyTags -> installmentDelnquencyTags.getDelinquencyRange().getId()));
+                // for installments in each range, get details from loan repayment schedule installment, add amounts,
+                // list charges
+                for (Map.Entry<Long, List<LoanInstallmentDelinquencyTagData>> installmentDelinquencyTagData : installmentsInSameRange
+                        .entrySet()) {
+                    // get installments details
+                    List<LoanRepaymentScheduleInstallment> delinquentInstallmentsInSameRange = loan.getRepaymentScheduleInstallments()
+                            .stream().filter(installment -> installmentDelinquencyTagData.getValue().stream()
+                                    .anyMatch(installmentTag -> installmentTag.getId().equals(installment.getId())))
+                            .toList();
+                    // add amounts
+                    LoanAmountDataV1 amount = LoanAmountDataV1.newBuilder()//
+                            .setPrincipalAmount(delinquentInstallmentsInSameRange.stream()
+                                    .map(installment -> installment.getPrincipalOutstanding(loan.getCurrency()).getAmount())
+                                    .reduce(BigDecimal.ZERO, BigDecimal::add))//
+                            .setFeeAmount(delinquentInstallmentsInSameRange.stream()
+                                    .map(installment -> installment.getFeeChargesOutstanding(loan.getCurrency()).getAmount())
+                                    .reduce(BigDecimal.ZERO, BigDecimal::add))//
+                            .setInterestAmount(delinquentInstallmentsInSameRange.stream()
+                                    .map(installment -> installment.getInterestOutstanding(loan.getCurrency()).getAmount())
+                                    .reduce(BigDecimal.ZERO, BigDecimal::add))//
+                            .setPenaltyAmount(delinquentInstallmentsInSameRange.stream()
+                                    .map(installment -> installment.getPenaltyChargesOutstanding(loan.getCurrency()).getAmount())
+                                    .reduce(BigDecimal.ZERO, BigDecimal::add))//
+                            .setTotalAmount(delinquentInstallmentsInSameRange.stream()
+                                    .map(installment -> installment.getTotalOutstanding(loan.getCurrency()).getAmount())
+                                    .reduce(BigDecimal.ZERO, BigDecimal::add))//
+                            .build();
+
+                    // get list of charges for installments in same range
+                    List<LoanCharge> chargesForInstallmentsInSameRange = loan.getLoanCharges().stream().filter(loanCharge -> !loanCharge
+                            .isPaid()
+                            && delinquentInstallmentsInSameRange.stream().anyMatch(installmentForCharge -> (DateUtils
+                                    .isAfter(loanCharge.getEffectiveDueDate(), installmentForCharge.getFromDate())
+                                    || DateUtils.isEqual(loanCharge.getEffectiveDueDate(), installmentForCharge.getFromDate()))
+                                    && (DateUtils.isBefore(loanCharge.getEffectiveDueDate(), installmentForCharge.getDueDate())
+                                            || DateUtils.isEqual(loanCharge.getEffectiveDueDate(), installmentForCharge.getDueDate()))))
+                            .toList();
+
+                    List<LoanChargeDataRangeViewV1> charges = new ArrayList<>();
+                    for (LoanCharge charge : chargesForInstallmentsInSameRange) {
+                        LoanChargeDataRangeViewV1 chargeData = LoanChargeDataRangeViewV1.newBuilder().setId(charge.getId())
+                                .setName(charge.name()).setAmount(charge.amountOutstanding()).setCurrency(currencyMapper.map(currency))
+                                .build();
+                        charges.add(chargeData);
+                    }
+
+                    LoanInstallmentDelinquencyTagData.InstallmentDelinquencyRange delinquencyRange = installmentDelinquencyTagData
+                            .getValue().get(0).getDelinquencyRange();
+
+                    DelinquencyRangeDataV1 delinquencyRangeDataV1 = DelinquencyRangeDataV1.newBuilder().setId(delinquencyRange.getId())
+                            .setClassification(delinquencyRange.getClassification()).setMinimumAgeDays(delinquencyRange.getMinimumAgeDays())
+                            .setMaximumAgeDays(delinquencyRange.getMaximumAgeDays()).build();
+
+                    LoanInstallmentDelinquencyBucketDataV1 installmentDelinquencyBucketDataV1 = LoanInstallmentDelinquencyBucketDataV1
+                            .newBuilder().setDelinquencyRange(delinquencyRangeDataV1).setAmount(amount).setCharges(charges)
+                            .setCurrency(currencyMapper.map(currency)).build();
+
+                    loanInstallmentDelinquencyData.add(installmentDelinquencyBucketDataV1);
+                }
+            }
+        }
+        return loanInstallmentDelinquencyData;
+    }
+}
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java
index 22a9aa3..62d8f49 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/loan/LoanAccountDelinquencyRangeEventSerializerTest.java
@@ -116,7 +116,8 @@
         // given
         LoanDelinquencyRangeChangeBusinessEventSerializer serializer = new LoanDelinquencyRangeChangeBusinessEventSerializer(
                 loanReadPlatformService, new LoanDelinquencyRangeDataMapperImpl(), loanChargeReadPlatformService,
-                delinquencyReadPlatformService, new LoanChargeDataMapperImpl(null, null, null), new CurrencyDataMapperImpl(), mapper);
+                delinquencyReadPlatformService, new LoanChargeDataMapperImpl(null, null, null), new CurrencyDataMapperImpl(), mapper,
+                new LoanInstallmentLevelDelinquencyEventProducer(delinquencyReadPlatformService, new CurrencyDataMapperImpl()));
 
         Loan loanForProcessing = Mockito.mock(Loan.class);
         LoanAccountData loanAccountData = mock(LoanAccountData.class);
@@ -180,7 +181,8 @@
         // given
         LoanDelinquencyRangeChangeBusinessEventSerializer serializer = new LoanDelinquencyRangeChangeBusinessEventSerializer(
                 loanReadPlatformService, new LoanDelinquencyRangeDataMapperImpl(), loanChargeReadPlatformService,
-                delinquencyReadPlatformService, new LoanChargeDataMapperImpl(null, null, null), new CurrencyDataMapperImpl(), mapper);
+                delinquencyReadPlatformService, new LoanChargeDataMapperImpl(null, null, null), new CurrencyDataMapperImpl(), mapper,
+                new LoanInstallmentLevelDelinquencyEventProducer(delinquencyReadPlatformService, new CurrencyDataMapperImpl()));
 
         Loan loanForProcessing = Mockito.mock(Loan.class);
         LoanAccountData loanAccountData = mock(LoanAccountData.class);