You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ad...@apache.org on 2025/06/18 10:20:40 UTC
(fineract) branch develop updated: FINERACT-2309: Emit external events on document upload and delete
This is an automated email from the ASF dual-hosted git repository.
adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 159eff0ad4 FINERACT-2309: Emit external events on document upload and delete
159eff0ad4 is described below
commit 159eff0ad4ff90d275a8d5c68a2d91bb7f94a2a3
Author: Abhinav Cillanki <ab...@gmail.com>
AuthorDate: Sat Jun 14 13:04:12 2025 +0530
FINERACT-2309: Emit external events on document upload and delete
---
.../src/main/avro/document/v1/DocumentDataV1.avsc | 80 +++++++++++++++++
...umentWritePlatformServiceJpaRepositoryImpl.java | 9 +-
.../domain/document/DocumentBusinessEvent.java | 41 +++++++++
.../document/DocumentCreatedBusinessEvent.java | 35 ++++++++
.../document/DocumentDeletedBusinessEvent.java | 35 ++++++++
.../mapper/document/DocumentDataMapper.java | 30 +++++++
.../document/DocumentBusinessEventSerializer.java | 89 ++++++++++++++++++
.../db/changelog/tenant/changelog-tenant.xml | 1 +
.../0184_add_document_event_configuration.xml | 35 ++++++++
...nalEventConfigurationValidationServiceTest.java | 40 ++++-----
.../DocumentBusinessEventSerializerTest.java | 100 +++++++++++++++++++++
.../common/ExternalEventConfigurationHelper.java | 10 +++
12 files changed, 484 insertions(+), 21 deletions(-)
diff --git a/fineract-avro-schemas/src/main/avro/document/v1/DocumentDataV1.avsc b/fineract-avro-schemas/src/main/avro/document/v1/DocumentDataV1.avsc
new file mode 100644
index 0000000000..6c09870653
--- /dev/null
+++ b/fineract-avro-schemas/src/main/avro/document/v1/DocumentDataV1.avsc
@@ -0,0 +1,80 @@
+{
+ "name": "DocumentDataV1",
+ "namespace": "org.apache.fineract.avro.document.v1",
+ "doc": "Metadata emitted by DocumentCreatedBusinessEvent when a file is stored in Fineract.",
+ "type": "record",
+ "fields": [
+ {
+ "default": null,
+ "name": "id",
+ "type": [
+ "null",
+ "long"
+ ]
+ },
+ {
+ "default": null,
+ "name": "parentEntityType",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ {
+ "default": null,
+ "name": "parentEntityId",
+ "type": [
+ "null",
+ "long"
+ ]
+ },
+ {
+ "default": null,
+ "name": "name",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ {
+ "default": null,
+ "name": "fileName",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ {
+ "default": null,
+ "name": "size",
+ "type": [
+ "null",
+ "long"
+ ]
+ },
+ {
+ "default": null,
+ "name": "type",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ {
+ "default": null,
+ "name": "description",
+ "type": [
+ "null",
+ "string"
+ ]
+ },
+ {
+ "default": null,
+ "name": "storageType",
+ "type": [
+ "null",
+ "int"
+ ]
+ }
+ ]
+}
diff --git a/fineract-document/src/main/java/org/apache/fineract/infrastructure/documentmanagement/service/DocumentWritePlatformServiceJpaRepositoryImpl.java b/fineract-document/src/main/java/org/apache/fineract/infrastructure/documentmanagement/service/DocumentWritePlatformServiceJpaRepositoryImpl.java
index 869de535e3..e87575d658 100644
--- a/fineract-document/src/main/java/org/apache/fineract/infrastructure/documentmanagement/service/DocumentWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-document/src/main/java/org/apache/fineract/infrastructure/documentmanagement/service/DocumentWritePlatformServiceJpaRepositoryImpl.java
@@ -31,6 +31,9 @@ import org.apache.fineract.infrastructure.documentmanagement.domain.StorageType;
import org.apache.fineract.infrastructure.documentmanagement.exception.ContentManagementException;
import org.apache.fineract.infrastructure.documentmanagement.exception.DocumentNotFoundException;
import org.apache.fineract.infrastructure.documentmanagement.exception.InvalidEntityTypeForDocumentManagementException;
+import org.apache.fineract.infrastructure.event.business.domain.document.DocumentCreatedBusinessEvent;
+import org.apache.fineract.infrastructure.event.business.domain.document.DocumentDeletedBusinessEvent;
+import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -48,13 +51,15 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements DocumentWr
private final PlatformSecurityContext context;
private final DocumentRepository documentRepository;
private final ContentRepositoryFactory contentRepositoryFactory;
+ private final BusinessEventNotifierService businessEventNotifierService;
@Autowired
public DocumentWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final DocumentRepository documentRepository,
- final ContentRepositoryFactory documentStoreFactory) {
+ final ContentRepositoryFactory documentStoreFactory, BusinessEventNotifierService businessEventNotifierService) {
this.context = context;
this.documentRepository = documentRepository;
this.contentRepositoryFactory = documentStoreFactory;
+ this.businessEventNotifierService = businessEventNotifierService;
}
@Transactional
@@ -78,6 +83,7 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements DocumentWr
documentCommand.getDescription(), fileLocation, contentRepository.getStorageType());
this.documentRepository.saveAndFlush(document);
+ businessEventNotifierService.notifyPostBusinessEvent(new DocumentCreatedBusinessEvent(document));
return document.getId();
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
@@ -158,6 +164,7 @@ public class DocumentWritePlatformServiceJpaRepositoryImpl implements DocumentWr
final ContentRepository contentRepository = this.contentRepositoryFactory.getRepository(document.storageType());
contentRepository.deleteFile(document.getLocation());
+ businessEventNotifierService.notifyPostBusinessEvent(new DocumentDeletedBusinessEvent(document));
return CommandProcessingResult.resourceResult(document.getId());
}
diff --git a/fineract-document/src/main/java/org/apache/fineract/infrastructure/event/business/domain/document/DocumentBusinessEvent.java b/fineract-document/src/main/java/org/apache/fineract/infrastructure/event/business/domain/document/DocumentBusinessEvent.java
new file mode 100644
index 0000000000..dc0aca7d43
--- /dev/null
+++ b/fineract-document/src/main/java/org/apache/fineract/infrastructure/event/business/domain/document/DocumentBusinessEvent.java
@@ -0,0 +1,41 @@
+/**
+ * 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.document;
+
+import org.apache.fineract.infrastructure.documentmanagement.domain.Document;
+import org.apache.fineract.infrastructure.event.business.domain.AbstractBusinessEvent;
+
+public abstract class DocumentBusinessEvent extends AbstractBusinessEvent<Document> {
+
+ private static final String CATEGORY = "Document";
+
+ protected DocumentBusinessEvent(Document value) {
+ super(value);
+ }
+
+ @Override
+ public String getCategory() {
+ return CATEGORY; // e.g. will appear as “Document”
+ }
+
+ @Override
+ public Long getAggregateRootId() {
+ return get().getId(); // primary-key of the uploaded doc
+ }
+}
diff --git a/fineract-document/src/main/java/org/apache/fineract/infrastructure/event/business/domain/document/DocumentCreatedBusinessEvent.java b/fineract-document/src/main/java/org/apache/fineract/infrastructure/event/business/domain/document/DocumentCreatedBusinessEvent.java
new file mode 100644
index 0000000000..b323857e7a
--- /dev/null
+++ b/fineract-document/src/main/java/org/apache/fineract/infrastructure/event/business/domain/document/DocumentCreatedBusinessEvent.java
@@ -0,0 +1,35 @@
+/**
+ * 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.document;
+
+import org.apache.fineract.infrastructure.documentmanagement.domain.Document;
+
+public class DocumentCreatedBusinessEvent extends DocumentBusinessEvent {
+
+ private static final String TYPE = "DocumentCreatedBusinessEvent";
+
+ public DocumentCreatedBusinessEvent(Document value) {
+ super(value);
+ }
+
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+}
diff --git a/fineract-document/src/main/java/org/apache/fineract/infrastructure/event/business/domain/document/DocumentDeletedBusinessEvent.java b/fineract-document/src/main/java/org/apache/fineract/infrastructure/event/business/domain/document/DocumentDeletedBusinessEvent.java
new file mode 100644
index 0000000000..14184b59e2
--- /dev/null
+++ b/fineract-document/src/main/java/org/apache/fineract/infrastructure/event/business/domain/document/DocumentDeletedBusinessEvent.java
@@ -0,0 +1,35 @@
+/**
+ * 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.document;
+
+import org.apache.fineract.infrastructure.documentmanagement.domain.Document;
+
+public class DocumentDeletedBusinessEvent extends DocumentBusinessEvent {
+
+ private static final String TYPE = "DocumentDeletedBusinessEvent";
+
+ public DocumentDeletedBusinessEvent(Document value) {
+ super(value);
+ }
+
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/document/DocumentDataMapper.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/document/DocumentDataMapper.java
new file mode 100644
index 0000000000..04a8093bdc
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/mapper/document/DocumentDataMapper.java
@@ -0,0 +1,30 @@
+/**
+ * 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.document;
+
+import org.apache.fineract.avro.document.v1.DocumentDataV1;
+import org.apache.fineract.infrastructure.documentmanagement.data.DocumentData;
+import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.support.AvroMapperConfig;
+import org.mapstruct.Mapper;
+
+@Mapper(config = AvroMapperConfig.class)
+public interface DocumentDataMapper {
+
+ DocumentDataV1 map(DocumentData source);
+}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/document/DocumentBusinessEventSerializer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/document/DocumentBusinessEventSerializer.java
new file mode 100644
index 0000000000..a2b68d1cfb
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/document/DocumentBusinessEventSerializer.java
@@ -0,0 +1,89 @@
+/**
+ * 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.document;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.avro.generic.GenericContainer;
+import org.apache.fineract.avro.document.v1.DocumentDataV1;
+import org.apache.fineract.avro.generator.ByteBufferSerializable;
+import org.apache.fineract.infrastructure.documentmanagement.data.DocumentData;
+import org.apache.fineract.infrastructure.documentmanagement.domain.Document;
+import org.apache.fineract.infrastructure.documentmanagement.service.DocumentReadPlatformService;
+import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent;
+import org.apache.fineract.infrastructure.event.business.domain.document.DocumentBusinessEvent;
+import org.apache.fineract.infrastructure.event.business.domain.document.DocumentCreatedBusinessEvent;
+import org.apache.fineract.infrastructure.event.business.domain.document.DocumentDeletedBusinessEvent;
+import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.document.DocumentDataMapper;
+import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class DocumentBusinessEventSerializer implements BusinessEventSerializer {
+
+ private static final Logger log = LoggerFactory.getLogger(DocumentBusinessEventSerializer.class);
+ private final DocumentReadPlatformService service;
+ private final DocumentDataMapper mapper;
+
+ @Override
+ public <T> boolean canSerialize(BusinessEvent<T> event) {
+ return event instanceof DocumentCreatedBusinessEvent || event instanceof DocumentDeletedBusinessEvent;
+ }
+
+ @Override
+ public <T> ByteBufferSerializable toAvroDTO(BusinessEvent<T> rawEvent) {
+
+ DocumentBusinessEvent event = (DocumentBusinessEvent) rawEvent;
+ Document entity = event.get(); // domain entity
+
+ DocumentData dto = null;
+ if (rawEvent instanceof DocumentCreatedBusinessEvent) {
+ try {
+ dto = service.retrieveDocument(entity.getParentEntityType(), entity.getParentEntityId(), entity.getId());
+ } catch (Exception ex) {
+ // log at DEBUG and fall back to entity mapping
+ log.debug("DocumentData not found, falling back to entity", ex);
+ }
+ }
+
+ // If we have the DTO, let MapStruct do the work. Otherwise, build from the entity
+
+ DocumentDataV1 avro;
+ if (dto != null) {
+ avro = mapper.map(dto);
+ } else {
+ avro = DocumentDataV1.newBuilder().setId(entity.getId()).setParentEntityType(entity.getParentEntityType())
+ .setParentEntityId(entity.getParentEntityId()).setName(entity.getName()).setFileName(entity.getFileName())
+ .setSize(entity.getSize()).setType(entity.getType()).setDescription(entity.getDescription()).build();
+ }
+
+ Integer storageTypeCode = (dto != null && dto.getStorageType() != null && dto.storageType() != null) ? dto.getStorageType()
+ : (entity.storageType() != null ? entity.storageType().getValue() : null);
+ avro.setStorageType(storageTypeCode);
+
+ return avro;
+ }
+
+ @Override
+ public Class<? extends GenericContainer> getSupportedSchema() {
+ return DocumentDataV1.class;
+ }
+}
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
index 50b68a01f9..a66325bad0 100644
--- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
@@ -202,4 +202,5 @@
<include file="parts/0181_add_capitalized_income_amortization_adjustment_transaction.xml" relativeToChangelogFile="true" />
<include file="parts/0182_transaction_summary_with_asset_owner_report_fix_charge_reason_and_add_buyback_intermediate.xml" relativeToChangelogFile="true" />
<include file="parts/0183_add_LoanCapitalizedIncomeTransactionCreatedBusinessEvent.xml" relativeToChangelogFile="true" />
+ <include file="parts/0184_add_document_event_configuration.xml" relativeToChangelogFile="true" />
</databaseChangeLog>
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0184_add_document_event_configuration.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0184_add_document_event_configuration.xml
new file mode 100644
index 0000000000..096b403282
--- /dev/null
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0184_add_document_event_configuration.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
+ <changeSet id="1" author="fineract">
+ <insert tableName="m_external_event_configuration">
+ <column name="type" value="DocumentCreatedBusinessEvent"/>
+ <column name="enabled" valueBoolean="false"/>
+ </insert>
+ <insert tableName="m_external_event_configuration">
+ <column name="type" value="DocumentDeletedBusinessEvent"/>
+ <column name="enabled" valueBoolean="false"/>
+ </insert>
+ </changeSet>
+</databaseChangeLog>
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java
index 5d5e47edde..6e56c097f1 100644
--- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java
+++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/ExternalEventConfigurationValidationServiceTest.java
@@ -67,20 +67,20 @@ public class ExternalEventConfigurationValidationServiceTest {
// given
List<String> configurations = Arrays.asList("CentersCreateBusinessEvent", "ClientActivateBusinessEvent",
- "ClientCreateBusinessEvent", "ClientRejectBusinessEvent", "FixedDepositAccountCreateBusinessEvent",
- "GroupsCreateBusinessEvent", "LoanAcceptTransferBusinessEvent", "LoanAddChargeBusinessEvent",
- "LoanAdjustTransactionBusinessEvent", "LoanApplyOverdueChargeBusinessEvent", "LoanApprovedBusinessEvent",
- "LoanBalanceChangedBusinessEvent", "LoanChargebackTransactionBusinessEvent", "LoanChargePaymentPostBusinessEvent",
- "LoanChargePaymentPreBusinessEvent", "LoanChargeRefundBusinessEvent", "LoanCloseAsRescheduleBusinessEvent",
- "LoanCloseBusinessEvent", "LoanCreatedBusinessEvent", "LoanCreditBalanceRefundPostBusinessEvent",
- "LoanCreditBalanceRefundPreBusinessEvent", "LoanDeleteChargeBusinessEvent", "LoanDisbursalBusinessEvent",
- "LoanDisbursalTransactionBusinessEvent", "LoanForeClosurePostBusinessEvent", "LoanForeClosurePreBusinessEvent",
- "LoanInitiateTransferBusinessEvent", "LoanInterestRecalculationBusinessEvent", "LoanProductCreateBusinessEvent",
- "LoanReassignOfficerBusinessEvent", "LoanRefundPostBusinessEvent", "LoanRefundPreBusinessEvent",
- "LoanRejectedBusinessEvent", "LoanRejectTransferBusinessEvent", "LoanRemoveOfficerBusinessEvent",
- "LoanRepaymentDueBusinessEvent", "LoanRepaymentOverdueBusinessEvent", "LoanRescheduledDueCalendarChangeBusinessEvent",
- "LoanRescheduledDueHolidayBusinessEvent", "LoanScheduleVariationsAddedBusinessEvent",
- "LoanScheduleVariationsDeletedBusinessEvent", "LoanStatusChangedBusinessEvent",
+ "ClientCreateBusinessEvent", "ClientRejectBusinessEvent", "DocumentCreatedBusinessEvent", "DocumentDeletedBusinessEvent",
+ "FixedDepositAccountCreateBusinessEvent", "GroupsCreateBusinessEvent", "LoanAcceptTransferBusinessEvent",
+ "LoanAddChargeBusinessEvent", "LoanAdjustTransactionBusinessEvent", "LoanApplyOverdueChargeBusinessEvent",
+ "LoanApprovedBusinessEvent", "LoanBalanceChangedBusinessEvent", "LoanChargebackTransactionBusinessEvent",
+ "LoanChargePaymentPostBusinessEvent", "LoanChargePaymentPreBusinessEvent", "LoanChargeRefundBusinessEvent",
+ "LoanCloseAsRescheduleBusinessEvent", "LoanCloseBusinessEvent", "LoanCreatedBusinessEvent",
+ "LoanCreditBalanceRefundPostBusinessEvent", "LoanCreditBalanceRefundPreBusinessEvent", "LoanDeleteChargeBusinessEvent",
+ "LoanDisbursalBusinessEvent", "LoanDisbursalTransactionBusinessEvent", "LoanForeClosurePostBusinessEvent",
+ "LoanForeClosurePreBusinessEvent", "LoanInitiateTransferBusinessEvent", "LoanInterestRecalculationBusinessEvent",
+ "LoanProductCreateBusinessEvent", "LoanReassignOfficerBusinessEvent", "LoanRefundPostBusinessEvent",
+ "LoanRefundPreBusinessEvent", "LoanRejectedBusinessEvent", "LoanRejectTransferBusinessEvent",
+ "LoanRemoveOfficerBusinessEvent", "LoanRepaymentDueBusinessEvent", "LoanRepaymentOverdueBusinessEvent",
+ "LoanRescheduledDueCalendarChangeBusinessEvent", "LoanRescheduledDueHolidayBusinessEvent",
+ "LoanScheduleVariationsAddedBusinessEvent", "LoanScheduleVariationsDeletedBusinessEvent", "LoanStatusChangedBusinessEvent",
"LoanTransactionGoodwillCreditPostBusinessEvent", "LoanTransactionGoodwillCreditPreBusinessEvent",
"LoanTransactionMakeRepaymentPostBusinessEvent", "LoanTransactionMakeRepaymentPreBusinessEvent",
"LoanTransactionMerchantIssuedRefundPostBusinessEvent", "LoanTransactionMerchantIssuedRefundPreBusinessEvent",
@@ -157,12 +157,12 @@ public class ExternalEventConfigurationValidationServiceTest {
// given
List<String> configurationWithMissingCentersCreateBusinessEvent = Arrays.asList("MockBusinessEvent", "MockBusinessEvent",
- "ClientActivateBusinessEvent", "ClientCreateBusinessEvent", "ClientRejectBusinessEvent",
- "FixedDepositAccountCreateBusinessEvent", "GroupsCreateBusinessEvent", "LoanAcceptTransferBusinessEvent",
- "LoanAddChargeBusinessEvent", "LoanAdjustTransactionBusinessEvent", "LoanApplyOverdueChargeBusinessEvent",
- "LoanApprovedBusinessEvent", "LoanBalanceChangedBusinessEvent", "LoanChargebackTransactionBusinessEvent",
- "LoanChargePaymentPostBusinessEvent", "LoanChargePaymentPreBusinessEvent", "LoanChargeRefundBusinessEvent",
- "LoanCloseAsRescheduleBusinessEvent", "LoanCloseBusinessEvent", "LoanCreatedBusinessEvent",
+ "ClientActivateBusinessEvent", "ClientCreateBusinessEvent", "ClientRejectBusinessEvent", "DocumentCreatedBusinessEvent",
+ "DocumentDeletedBusinessEvent", "FixedDepositAccountCreateBusinessEvent", "GroupsCreateBusinessEvent",
+ "LoanAcceptTransferBusinessEvent", "LoanAddChargeBusinessEvent", "LoanAdjustTransactionBusinessEvent",
+ "LoanApplyOverdueChargeBusinessEvent", "LoanApprovedBusinessEvent", "LoanBalanceChangedBusinessEvent",
+ "LoanChargebackTransactionBusinessEvent", "LoanChargePaymentPostBusinessEvent", "LoanChargePaymentPreBusinessEvent",
+ "LoanChargeRefundBusinessEvent", "LoanCloseAsRescheduleBusinessEvent", "LoanCloseBusinessEvent", "LoanCreatedBusinessEvent",
"LoanCreditBalanceRefundPostBusinessEvent", "LoanCreditBalanceRefundPreBusinessEvent", "LoanDeleteChargeBusinessEvent",
"LoanDisbursalBusinessEvent", "LoanDisbursalTransactionBusinessEvent", "LoanForeClosurePostBusinessEvent",
"LoanForeClosurePreBusinessEvent", "LoanInitiateTransferBusinessEvent", "LoanInterestRecalculationBusinessEvent",
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/document/DocumentBusinessEventSerializerTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/document/DocumentBusinessEventSerializerTest.java
new file mode 100644
index 0000000000..8bf5bf31d6
--- /dev/null
+++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/service/serialization/serializer/document/DocumentBusinessEventSerializerTest.java
@@ -0,0 +1,100 @@
+/**
+ * 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.document;
+
+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 org.apache.fineract.avro.document.v1.DocumentDataV1;
+import org.apache.fineract.avro.generator.ByteBufferSerializable;
+import org.apache.fineract.infrastructure.documentmanagement.data.DocumentData;
+import org.apache.fineract.infrastructure.documentmanagement.domain.Document;
+import org.apache.fineract.infrastructure.documentmanagement.domain.StorageType;
+import org.apache.fineract.infrastructure.documentmanagement.service.DocumentReadPlatformService;
+import org.apache.fineract.infrastructure.event.business.domain.document.DocumentCreatedBusinessEvent;
+import org.apache.fineract.infrastructure.event.external.service.serialization.mapper.document.DocumentDataMapper;
+import org.apache.fineract.infrastructure.event.external.service.serialization.serializer.BusinessEventSerializer;
+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 DocumentBusinessEventSerializerTest {
+
+ @Mock
+ private DocumentReadPlatformService readService;
+ @Mock
+ private DocumentDataMapper mapper;
+
+ private BusinessEventSerializer serializer;
+
+ @BeforeEach
+ void setUp() {
+ serializer = new DocumentBusinessEventSerializer(readService, mapper);
+ }
+
+ @Test
+ void documentStorageTypeIsPatchedIntoAvro() {
+
+ long docId = 42L;
+ String parentEntity = "loans";
+ long parentEntityId = 979L;
+ String name = "test_document";
+ String fileName = "test_document.pdf";
+ String fileType = "application/pdf";
+ String description = "Test document description";
+ Integer storageTypeInt = StorageType.FILE_SYSTEM.getValue();
+
+ Document document = mock(Document.class);
+ when(document.getId()).thenReturn(docId);
+ when(document.getParentEntityType()).thenReturn(parentEntity);
+ when(document.getParentEntityId()).thenReturn(parentEntityId);
+ when(document.getName()).thenReturn(name);
+ when(document.getFileName()).thenReturn(fileName);
+ when(document.getType()).thenReturn(fileType);
+ when(document.getDescription()).thenReturn(description);
+ when(document.storageType()).thenReturn(StorageType.fromInt(storageTypeInt));
+
+ DocumentCreatedBusinessEvent event = new DocumentCreatedBusinessEvent(document);
+
+ DocumentData dtoFromReadService = mock(DocumentData.class);
+ when(readService.retrieveDocument(parentEntity, parentEntityId, docId)).thenReturn(dtoFromReadService);
+
+ DocumentDataV1 avroFromMapper = DocumentDataV1.newBuilder().setId(docId).setParentEntityType(parentEntity)
+ .setParentEntityId(parentEntityId).setName(name).setFileName(fileName).setType(fileType).setDescription(description)
+ .build();
+ when(mapper.map(any(DocumentData.class))).thenReturn(avroFromMapper);
+
+ ByteBufferSerializable serialised = serializer.toAvroDTO(event);
+ assertNotNull(serialised);
+
+ DocumentDataV1 avro = (DocumentDataV1) serialised;
+
+ assertEquals(storageTypeInt, avro.getStorageType(), "Serializer must patch storageType taken from the domain entity");
+ }
+}
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalEventConfigurationHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalEventConfigurationHelper.java
index acbadd414d..5a993bbf7f 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalEventConfigurationHelper.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalEventConfigurationHelper.java
@@ -73,6 +73,16 @@ public class ExternalEventConfigurationHelper {
clientRejectBusinessEvent.put("enabled", false);
defaults.add(clientRejectBusinessEvent);
+ Map<String, Object> documentCreatedBusinessEvent = new HashMap<>();
+ documentCreatedBusinessEvent.put("type", "DocumentCreatedBusinessEvent");
+ documentCreatedBusinessEvent.put("enabled", false);
+ defaults.add(documentCreatedBusinessEvent);
+
+ Map<String, Object> documentDeletedBusinessEvent = new HashMap<>();
+ documentDeletedBusinessEvent.put("type", "DocumentDeletedBusinessEvent");
+ documentDeletedBusinessEvent.put("enabled", false);
+ defaults.add(documentDeletedBusinessEvent);
+
Map<String, Object> fixedDepositAccountCreateBusinessEvent = new HashMap<>();
fixedDepositAccountCreateBusinessEvent.put("type", "FixedDepositAccountCreateBusinessEvent");
fixedDepositAccountCreateBusinessEvent.put("enabled", false);