FINERACT-2246: New command processing - document management
This commit is contained in:
committed by
Aleksandar Vidakovic
parent
8a61e30a45
commit
2ff0c62f40
+32
-15
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.bulkimport.api;
|
||||
|
||||
import static org.apache.fineract.util.StreamResponseUtil.DISPOSITION_TYPE_ATTACHMENT;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.GET;
|
||||
@@ -30,6 +32,7 @@ import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.UriInfo;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.bulkimport.data.GlobalEntityType;
|
||||
import org.apache.fineract.infrastructure.bulkimport.data.ImportData;
|
||||
@@ -39,7 +42,9 @@ import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.DocumentData;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.exception.DocumentNotFoundException;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.service.DocumentReadPlatformService;
|
||||
import org.apache.fineract.util.StreamResponseUtil;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/v1/imports")
|
||||
@@ -48,10 +53,8 @@ import org.springframework.stereotype.Component;
|
||||
@RequiredArgsConstructor
|
||||
public class BulkImportApiResource {
|
||||
|
||||
private static final String RESOURCE_NAME_FOR_PERMISSION = "IMPORT";
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final BulkImportWorkbookService bulkImportWorkbookService;
|
||||
private final DocumentReadPlatformService documentReadPlatformService;
|
||||
private final DefaultToApiJsonSerializer<ImportData> toApiJsonSerializer;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
|
||||
@@ -59,23 +62,26 @@ public class BulkImportApiResource {
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveImportDocuments(@Context final UriInfo uriInfo, @QueryParam("entityType") final String entityType) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSION);
|
||||
Collection<ImportData> importData = new ArrayList<>();
|
||||
|
||||
if (entityType.equals(GlobalEntityType.CLIENT.getCode())) {
|
||||
final Collection<ImportData> importForClientEntity = this.bulkImportWorkbookService.getImports(GlobalEntityType.CLIENTS_ENTITY);
|
||||
final Collection<ImportData> importForClientPerson = this.bulkImportWorkbookService.getImports(GlobalEntityType.CLIENTS_PERSON);
|
||||
final var importForClientEntity = this.bulkImportWorkbookService.getImports(GlobalEntityType.CLIENTS_ENTITY);
|
||||
final var importForClientPerson = this.bulkImportWorkbookService.getImports(GlobalEntityType.CLIENTS_PERSON);
|
||||
|
||||
if (importForClientEntity != null) {
|
||||
importData.addAll(importForClientEntity);
|
||||
}
|
||||
|
||||
if (importForClientPerson != null) {
|
||||
importData.addAll(importForClientPerson);
|
||||
}
|
||||
} else {
|
||||
final GlobalEntityType type = GlobalEntityType.fromCode(entityType);
|
||||
|
||||
if (type == null) {
|
||||
throw new ImportTypeNotFoundException(entityType);
|
||||
}
|
||||
|
||||
importData = this.bulkImportWorkbookService.getImports(type);
|
||||
}
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
@@ -84,17 +90,28 @@ public class BulkImportApiResource {
|
||||
|
||||
@GET
|
||||
@Path("getOutputTemplateLocation")
|
||||
public String retriveOutputTemplateLocation(@QueryParam("importDocumentId") final String importDocumentId) {
|
||||
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSION);
|
||||
final DocumentData documentData = this.bulkImportWorkbookService.getOutputTemplateLocation(importDocumentId);
|
||||
return this.toApiJsonSerializer.serialize(documentData.getLocation());
|
||||
public String retriveOutputTemplateLocation(@QueryParam("importDocumentId") final Long importDocumentId) {
|
||||
final var imporData = bulkImportWorkbookService.getImport(importDocumentId);
|
||||
|
||||
return Optional.ofNullable(imporData)
|
||||
.flatMap(importData -> Optional.ofNullable(documentReadPlatformService.retrieveDocument(imporData.getDocumentId())))
|
||||
.map(DocumentData::getLocation).orElse(null);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("downloadOutputTemplate")
|
||||
@Produces("application/vnd.ms-excel")
|
||||
public Response getOutputTemplate(@QueryParam("importDocumentId") final String importDocumentId) {
|
||||
return bulkImportWorkbookService.getOutputTemplate(importDocumentId);
|
||||
}
|
||||
public Response getOutputTemplate(@QueryParam("importDocumentId") final Long importDocumentId) {
|
||||
// TODO: can we avoid 2 calls by introducing a new function? clean code more important now
|
||||
final var docs = documentReadPlatformService.retrieveAllDocuments("IMPORT", importDocumentId);
|
||||
|
||||
final var docData = docs.stream().findFirst();
|
||||
|
||||
final var d = docData.orElseThrow(() -> new DocumentNotFoundException("IMPORT", importDocumentId, -1L));
|
||||
final var content = documentReadPlatformService.retrieveDocumentContent(d.getParentEntityType(), d.getParentEntityId(), d.getId());
|
||||
final var streamResponseData = StreamResponseUtil.StreamResponseData.builder().type(content.getContentType())
|
||||
.fileName(content.getFileName()).stream(content.getStream()).dispositionType(DISPOSITION_TYPE_ATTACHMENT).build();
|
||||
|
||||
return StreamResponseUtil.ok(streamResponseData);
|
||||
}
|
||||
}
|
||||
|
||||
+16
-26
@@ -18,48 +18,38 @@
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.bulkimport.data;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.apache.fineract.infrastructure.bulkimport.domain.ImportDocument;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractContext;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractEvent;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
||||
@Getter
|
||||
public final class BulkImportEvent extends FineractEvent {
|
||||
|
||||
private final Workbook workbook;
|
||||
|
||||
private final Long importId;
|
||||
private final ImportDocument importDocument;
|
||||
|
||||
private final String fileName;
|
||||
|
||||
private final String fileType;
|
||||
|
||||
private final String locale;
|
||||
|
||||
private final String dateFormat;
|
||||
|
||||
private BulkImportEvent(final Object source, final Workbook workbook, final Long importId, final String locale, final String dateFormat,
|
||||
FineractContext context) {
|
||||
private final Long entityId;
|
||||
|
||||
public BulkImportEvent(final Object source, final Workbook workbook, final String fileName, String fileType,
|
||||
final ImportDocument importDocument, final String locale, final String dateFormat, FineractContext context, Long entityId) {
|
||||
super(source, context);
|
||||
this.workbook = workbook;
|
||||
this.importId = importId;
|
||||
this.fileName = fileName;
|
||||
this.fileType = fileType;
|
||||
this.importDocument = importDocument;
|
||||
this.locale = locale;
|
||||
this.dateFormat = dateFormat;
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public static BulkImportEvent instance(final Object source, final Workbook workbook, final Long importId, final String locale,
|
||||
final String dateFormat, FineractContext context) {
|
||||
return new BulkImportEvent(source, workbook, importId, locale, dateFormat, context);
|
||||
}
|
||||
|
||||
public Workbook getWorkbook() {
|
||||
return workbook;
|
||||
}
|
||||
|
||||
public Long getImportId() {
|
||||
return importId;
|
||||
}
|
||||
|
||||
public String getDateFormat() {
|
||||
return dateFormat;
|
||||
}
|
||||
|
||||
public String getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-23
@@ -22,21 +22,26 @@ import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.domain.Document;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_import_document")
|
||||
public class ImportDocument extends AbstractPersistableCustom<Long> {
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = true)
|
||||
public final class ImportDocument extends AbstractPersistableCustom<Long> {
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "document_id")
|
||||
private Document document;
|
||||
@Column(name = "document_id")
|
||||
private Long documentId;
|
||||
|
||||
@Column(name = "import_time")
|
||||
private LocalDateTime importTime;
|
||||
@@ -63,11 +68,7 @@ public class ImportDocument extends AbstractPersistableCustom<Long> {
|
||||
@Column(name = "failure_count", nullable = true)
|
||||
private Integer failureCount;
|
||||
|
||||
protected ImportDocument() {
|
||||
|
||||
}
|
||||
|
||||
public static ImportDocument instance(final Document document, final LocalDateTime importTime, final Integer entityType,
|
||||
public static ImportDocument instance(final Long documentId, final LocalDateTime importTime, final Integer entityType,
|
||||
final AppUser createdBy, final Integer totalRecords) {
|
||||
|
||||
final Boolean completed = Boolean.FALSE;
|
||||
@@ -75,14 +76,14 @@ public class ImportDocument extends AbstractPersistableCustom<Long> {
|
||||
final Integer failureCount = 0;
|
||||
final LocalDateTime endTime = DateUtils.getLocalDateTimeOfTenant();
|
||||
|
||||
return new ImportDocument(document, importTime, endTime, completed, entityType, createdBy, totalRecords, successCount,
|
||||
return new ImportDocument(documentId, importTime, endTime, completed, entityType, createdBy, totalRecords, successCount,
|
||||
failureCount);
|
||||
}
|
||||
|
||||
private ImportDocument(final Document document, final LocalDateTime importTime, final LocalDateTime endTime, Boolean completed,
|
||||
private ImportDocument(final Long documentId, final LocalDateTime importTime, final LocalDateTime endTime, Boolean completed,
|
||||
final Integer entityType, final AppUser createdBy, final Integer totalRecords, final Integer successCount,
|
||||
final Integer failureCount) {
|
||||
this.document = document;
|
||||
this.documentId = documentId;
|
||||
this.importTime = importTime;
|
||||
this.endTime = endTime;
|
||||
this.completed = completed;
|
||||
@@ -100,13 +101,4 @@ public class ImportDocument extends AbstractPersistableCustom<Long> {
|
||||
this.successCount = successCount;
|
||||
this.failureCount = errorCount;
|
||||
}
|
||||
|
||||
public Document getDocument() {
|
||||
return this.document;
|
||||
}
|
||||
|
||||
public Integer getEntityType() {
|
||||
return this.entityType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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.bulkimport.mapping;
|
||||
|
||||
import static org.mapstruct.InjectionStrategy.CONSTRUCTOR;
|
||||
import static org.mapstruct.MappingConstants.ComponentModel.SPRING;
|
||||
|
||||
import org.apache.fineract.infrastructure.bulkimport.data.ImportData;
|
||||
import org.apache.fineract.infrastructure.bulkimport.domain.ImportDocument;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
@Mapper(componentModel = SPRING, injectionStrategy = CONSTRUCTOR)
|
||||
public interface ImportDocumentMapper {
|
||||
|
||||
@Mapping(source = "id", target = "importId")
|
||||
@Mapping(source = "documentId", target = "documentId")
|
||||
@Mapping(ignore = true, target = "name")
|
||||
@Mapping(source = "entityType", target = "entityType")
|
||||
@Mapping(source = "importTime", target = "importTime")
|
||||
@Mapping(source = "completed", target = "completed")
|
||||
@Mapping(source = "endTime", target = "endTime")
|
||||
@Mapping(source = "createdBy.id", target = "createdBy")
|
||||
@Mapping(source = "failureCount", target = "failureCount")
|
||||
@Mapping(source = "successCount", target = "successCount")
|
||||
@Mapping(source = "totalRecords", target = "totalRecords")
|
||||
ImportData map(ImportDocument source);
|
||||
}
|
||||
+27
-42
@@ -18,27 +18,21 @@
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.bulkimport.service;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URLConnection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.command.core.CommandPipeline;
|
||||
import org.apache.fineract.infrastructure.bulkimport.data.BulkImportEvent;
|
||||
import org.apache.fineract.infrastructure.bulkimport.data.Count;
|
||||
import org.apache.fineract.infrastructure.bulkimport.data.GlobalEntityType;
|
||||
import org.apache.fineract.infrastructure.bulkimport.domain.ImportDocument;
|
||||
import org.apache.fineract.infrastructure.bulkimport.domain.ImportDocumentRepository;
|
||||
import org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandler;
|
||||
import org.apache.fineract.infrastructure.contentstore.util.ContentPipe;
|
||||
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.command.DocumentCommand;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.domain.Document;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.service.DocumentWritePlatformService;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.command.DocumentUpdateCommand;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.DocumentCreateResponse;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.DocumentUpdateRequest;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -50,14 +44,15 @@ public class BulkImportEventListener implements ApplicationListener<BulkImportEv
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
private final ImportDocumentRepository importRepository;
|
||||
private final DocumentWritePlatformService documentService;
|
||||
private final ContentPipe pipe;
|
||||
private final CommandPipeline commandPipeline;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(final BulkImportEvent event) {
|
||||
try {
|
||||
ThreadLocalContextUtil.init(event.getContext());
|
||||
final ImportDocument importDocument = this.importRepository.findById(event.getImportId()).orElse(null);
|
||||
final GlobalEntityType entityType = GlobalEntityType.fromInt(importDocument.getEntityType());
|
||||
|
||||
final GlobalEntityType entityType = GlobalEntityType.fromInt(event.getImportDocument().getEntityType());
|
||||
|
||||
final ImportHandler importHandler = switch (entityType) {
|
||||
case OFFICES -> this.applicationContext.getBean("officeImportHandler", ImportHandler.class);
|
||||
@@ -85,38 +80,28 @@ public class BulkImportEventListener implements ApplicationListener<BulkImportEv
|
||||
throw new GeneralPlatformDomainRuleException("error.msg.unable.to.find.resource", "Unable to find requested resource");
|
||||
};
|
||||
|
||||
final Workbook workbook = event.getWorkbook();
|
||||
final Count count = importHandler.process(workbook, event.getLocale(), event.getDateFormat());
|
||||
importDocument.update(DateUtils.getLocalDateTimeOfTenant(), count.getSuccessCount(), count.getErrorCount());
|
||||
this.importRepository.saveAndFlush(importDocument);
|
||||
final var count = importHandler.process(event.getWorkbook(), event.getLocale(), event.getDateFormat());
|
||||
|
||||
final Set<String> modifiedParams = new HashSet<>();
|
||||
modifiedParams.add("fileName");
|
||||
modifiedParams.add("size");
|
||||
modifiedParams.add("type");
|
||||
modifiedParams.add("location");
|
||||
Document document = importDocument.getDocument();
|
||||
event.getImportDocument().update(DateUtils.getLocalDateTimeOfTenant(), count.getSuccessCount(), count.getErrorCount());
|
||||
|
||||
DocumentCommand documentCommand = new DocumentCommand(modifiedParams, document.getId(), entityType.name(), null,
|
||||
document.getName(), document.getFileName(), document.getSize(),
|
||||
URLConnection.guessContentTypeFromName(document.getFileName()), null, null);
|
||||
final var pipedInputStream = pipe.pipe(output -> {
|
||||
event.getWorkbook().write(output);
|
||||
});
|
||||
|
||||
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
try {
|
||||
try {
|
||||
workbook.write(bos);
|
||||
} finally {
|
||||
bos.close();
|
||||
}
|
||||
} catch (IOException io) {
|
||||
log.error("Problem occurred in onApplicationEvent function", io);
|
||||
}
|
||||
byte[] bytes = bos.toByteArray();
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
|
||||
this.documentService.updateDocument(documentCommand, bis);
|
||||
final var command = new DocumentUpdateCommand();
|
||||
|
||||
command.setPayload(DocumentUpdateRequest.builder().id(event.getImportDocument().getDocumentId()).entityId(event.getEntityId())
|
||||
.entityType("IMPORT").stream(pipedInputStream).build());
|
||||
|
||||
final Supplier<DocumentCreateResponse> response = commandPipeline.send(command);
|
||||
|
||||
response.get();
|
||||
|
||||
importRepository.saveAndFlush(event.getImportDocument());
|
||||
} catch (Exception e) {
|
||||
log.error("Bulk import error:", e);
|
||||
} finally {
|
||||
ThreadLocalContextUtil.reset();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+57
-89
@@ -18,70 +18,58 @@
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.bulkimport.service;
|
||||
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URLConnection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Supplier;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.fineract.command.core.CommandPipeline;
|
||||
import org.apache.fineract.infrastructure.bulkimport.data.BulkImportEvent;
|
||||
import org.apache.fineract.infrastructure.bulkimport.data.GlobalEntityType;
|
||||
import org.apache.fineract.infrastructure.bulkimport.data.ImportData;
|
||||
import org.apache.fineract.infrastructure.bulkimport.domain.ImportDocument;
|
||||
import org.apache.fineract.infrastructure.bulkimport.domain.ImportDocumentRepository;
|
||||
import org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandlerUtils;
|
||||
import org.apache.fineract.infrastructure.bulkimport.mapping.ImportDocumentMapper;
|
||||
import org.apache.fineract.infrastructure.contentstore.util.ContentPipe;
|
||||
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
|
||||
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.DocumentData;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.domain.Document;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.domain.DocumentRepository;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.service.DocumentWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.service.DocumentWritePlatformServiceJpaRepositoryImpl;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.command.DocumentCreateCommand;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.DocumentCreateRequest;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.DocumentCreateResponse;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.tika.Tika;
|
||||
import org.apache.tika.io.TikaInputStream;
|
||||
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class BulkImportWorkbookServiceImpl implements BulkImportWorkbookService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(BulkImportWorkbookServiceImpl.class);
|
||||
private final ApplicationContext applicationContext;
|
||||
private final PlatformSecurityContext securityContext;
|
||||
private final DocumentWritePlatformService documentWritePlatformService;
|
||||
private final DocumentRepository documentRepository;
|
||||
private final ImportDocumentRepository importDocumentRepository;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public BulkImportWorkbookServiceImpl(final ApplicationContext applicationContext, final PlatformSecurityContext securityContext,
|
||||
final DocumentWritePlatformService documentWritePlatformService, final DocumentRepository documentRepository,
|
||||
final ImportDocumentRepository importDocumentRepository, final JdbcTemplate jdbcTemplate) {
|
||||
this.applicationContext = applicationContext;
|
||||
this.securityContext = securityContext;
|
||||
this.documentWritePlatformService = documentWritePlatformService;
|
||||
this.documentRepository = documentRepository;
|
||||
this.importDocumentRepository = importDocumentRepository;
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
private final ContentPipe pipe;
|
||||
private final CommandPipeline commandPipeline;
|
||||
private final ImportDocumentMapper mapper;
|
||||
|
||||
@Override
|
||||
public Long importWorkbook(String entity, InputStream inputStream, FormDataContentDisposition fileDetail, final String locale,
|
||||
@@ -169,35 +157,56 @@ public class BulkImportWorkbookServiceImpl implements BulkImportWorkbookService
|
||||
throw new GeneralPlatformDomainRuleException("error.msg.unable.to.find.resource", "Unable to find requested resource");
|
||||
|
||||
}
|
||||
return publishEvent(primaryColumn, fileDetail, bis, entityType, workbook, locale, dateFormat);
|
||||
return publishEvent(primaryColumn, fileDetail, fileType, entityType, workbook, locale, dateFormat);
|
||||
}
|
||||
throw new GeneralPlatformDomainRuleException("error.msg.null", "One or more of the given parameters not found");
|
||||
} catch (IOException e) {
|
||||
LOG.error("Problem occurred in importWorkbook function", e);
|
||||
log.error("Problem occurred in importWorkbook function", e);
|
||||
throw new GeneralPlatformDomainRuleException("error.msg.io.exception",
|
||||
"IO exception occured with " + fileDetail.getFileName() + " " + e.getMessage(), e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Long publishEvent(final Integer primaryColumn, final FormDataContentDisposition fileDetail,
|
||||
final InputStream clonedInputStreamWorkbook, final GlobalEntityType entityType, final Workbook workbook, final String locale,
|
||||
final String dateFormat) {
|
||||
private DocumentCreateResponse createDocument(final Workbook workbook, final FormDataContentDisposition fileDetail,
|
||||
final String fileType) {
|
||||
final var pipedInputStream = pipe.pipe(output -> {
|
||||
workbook.write(output);
|
||||
});
|
||||
|
||||
final String fileName = fileDetail.getFileName();
|
||||
final var command = new DocumentCreateCommand();
|
||||
|
||||
final Long documentId = this.documentWritePlatformService.createInternalDocument(
|
||||
DocumentWritePlatformServiceJpaRepositoryImpl.DocumentManagementEntity.IMPORT.name(),
|
||||
this.securityContext.authenticatedUser().getId(), null, clonedInputStreamWorkbook,
|
||||
URLConnection.guessContentTypeFromName(fileName), fileName, null, fileName);
|
||||
final Document document = this.documentRepository.findById(documentId).orElse(null);
|
||||
// TODO: does it really make sense to use the current user's ID?
|
||||
// TODO: wouldn't it be better to use "entityType.name()" as entity name?
|
||||
command.setPayload(DocumentCreateRequest.builder().entityId(this.securityContext.authenticatedUser().getId()).entityType("IMPORT")
|
||||
.name(fileDetail.getFileName()).description(fileDetail.getFileName()).fileName(fileDetail.getFileName())
|
||||
.size(fileDetail.getSize()).type(fileType).stream(pipedInputStream).build());
|
||||
|
||||
final Supplier<DocumentCreateResponse> response = commandPipeline.send(command);
|
||||
return response.get();
|
||||
}
|
||||
|
||||
private Long publishEvent(final Integer primaryColumn, final FormDataContentDisposition fileDetail, final String fileType,
|
||||
final GlobalEntityType entityType, final Workbook workbook, final String locale, final String dateFormat) {
|
||||
|
||||
final var importDocument = ImportDocument.instance(null, DateUtils.getLocalDateTimeOfTenant(), entityType.getValue(),
|
||||
securityContext.authenticatedUser(), ImportHandlerUtils.getNumberOfRows(workbook.getSheetAt(0), primaryColumn));
|
||||
|
||||
final var response = createDocument(workbook, fileDetail, fileType);
|
||||
|
||||
importDocument.setDocumentId(response.getResourceId());
|
||||
|
||||
// TODO: should we mark as "not yet processed by import handler"?
|
||||
importDocumentRepository.saveAndFlush(importDocument);
|
||||
|
||||
final var event = new BulkImportEvent(this, workbook, fileDetail.getFileName(), fileType, importDocument, locale, dateFormat,
|
||||
ThreadLocalContextUtil.getContext(), this.securityContext.authenticatedUser().getId());
|
||||
|
||||
final ImportDocument importDocument = ImportDocument.instance(document, DateUtils.getLocalDateTimeOfTenant(), entityType.getValue(),
|
||||
this.securityContext.authenticatedUser(), ImportHandlerUtils.getNumberOfRows(workbook.getSheetAt(0), primaryColumn));
|
||||
this.importDocumentRepository.saveAndFlush(importDocument);
|
||||
BulkImportEvent event = BulkImportEvent.instance(this, workbook, importDocument.getId(), locale, dateFormat,
|
||||
ThreadLocalContextUtil.getContext());
|
||||
applicationContext.publishEvent(event);
|
||||
|
||||
// TODO: remove when done
|
||||
log.warn("Import document ID: {} ({})", importDocument.getId(), importDocument.getDocumentId());
|
||||
|
||||
return importDocument.getId();
|
||||
}
|
||||
|
||||
@@ -208,7 +217,12 @@ public class BulkImportWorkbookServiceImpl implements BulkImportWorkbookService
|
||||
final ImportMapper rm = new ImportMapper();
|
||||
final String sql = "select " + rm.schema() + " order by i.id desc";
|
||||
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] { type.getValue() }); // NOSONAR
|
||||
return this.jdbcTemplate.query(sql, rm, type.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImportData getImport(Long id) {
|
||||
return importDocumentRepository.findById(id).map(mapper::map).orElse(null);
|
||||
}
|
||||
|
||||
private static final class ImportMapper implements RowMapper<ImportData> {
|
||||
@@ -240,50 +254,4 @@ public class BulkImportWorkbookServiceImpl implements BulkImportWorkbookService
|
||||
failureCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocumentData getOutputTemplateLocation(String importDocumentId) {
|
||||
this.securityContext.authenticatedUser();
|
||||
final ImportTemplateLocationMapper importTemplateLocationMapper = new ImportTemplateLocationMapper();
|
||||
final String sql = "select " + importTemplateLocationMapper.schema();
|
||||
|
||||
return this.jdbcTemplate.queryForObject(sql, importTemplateLocationMapper, new Object[] { Long.parseLong(importDocumentId) }); // NOSONAR
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getOutputTemplate(String importDocumentId) {
|
||||
this.securityContext.authenticatedUser();
|
||||
final ImportTemplateLocationMapper importTemplateLocationMapper = new ImportTemplateLocationMapper();
|
||||
final String sql = "select " + importTemplateLocationMapper.schema();
|
||||
DocumentData documentData = this.jdbcTemplate.queryForObject(sql, importTemplateLocationMapper,
|
||||
new Object[] { Long.parseLong(importDocumentId) }); // NOSONAR
|
||||
return buildResponse(documentData);
|
||||
}
|
||||
|
||||
private Response buildResponse(DocumentData documentData) {
|
||||
String fileName = "Output" + documentData.getFileName();
|
||||
String fileLocation = documentData.getLocation();
|
||||
File file = new File(fileLocation);
|
||||
final Response.ResponseBuilder response = Response.ok(file);
|
||||
response.header("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
|
||||
response.header("Content-Type", "application/vnd.ms-excel");
|
||||
return response.build();
|
||||
}
|
||||
|
||||
private static final class ImportTemplateLocationMapper implements RowMapper<DocumentData> {
|
||||
|
||||
public String schema() {
|
||||
final StringBuilder sql = new StringBuilder();
|
||||
sql.append("d.location,d.file_name ").append("from m_import_document i inner join m_document d on i.document_id=d.id ")
|
||||
.append("where i.id= ? ");
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DocumentData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
|
||||
final String location = rs.getString("location");
|
||||
final String fileName = rs.getString("file_name");
|
||||
return new DocumentData(null, null, null, null, fileName, null, null, location, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+86
@@ -204,6 +204,92 @@ public class SecurityConfig {
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_SAVINGNOTE")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/groups/*/notes"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_GROUPNOTE")
|
||||
// document: clients
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/clients/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/clients/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.PUT, "/api/*/clients/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/clients/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_DOCUMENT")
|
||||
// document: client_identifiers
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/client_identifiers/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/client_identifiers/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.PUT, "/api/*/client_identifiers/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/client_identifiers/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_DOCUMENT")
|
||||
// document: staff
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/staff/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/staff/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.PUT, "/api/*/staff/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/staff/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_DOCUMENT")
|
||||
// document: loans
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/loans/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/loans/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.PUT, "/api/*/loans/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/loans/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_DOCUMENT")
|
||||
// document: savings
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/savings/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/savings/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.PUT, "/api/*/savings/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/savings/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_DOCUMENT")
|
||||
// document: groups
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/groups/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/groups/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.PUT, "/api/*/groups/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/groups/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_DOCUMENT")
|
||||
// document: import
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/import/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/import/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.PUT, "/api/*/import/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/import/*/documents"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_DOCUMENT")
|
||||
// image: clients
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/clients/*/images"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/clients/*/images"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_CLIENTIMAGE")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.PUT, "/api/*/clients/*/images"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_CLIENTIMAGE")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/clients/*/images"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_CLIENTIMAGE")
|
||||
// image: staff
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/staff/*/images"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_DOCUMENT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/staff/*/images"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_STAFFIMAGE")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.PUT, "/api/*/staff/*/images"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_STAFFIMAGE")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/staff/*/images"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_STAFFIMAGE")
|
||||
// bulk import
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/import"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_IMPORT")
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/import/*"))
|
||||
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_IMPORT")
|
||||
|
||||
.requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/twofactor/validate")).fullyAuthenticated()
|
||||
.requestMatchers(API_MATCHER.matcher("/api/*/twofactor")).fullyAuthenticated()
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ public class JerseyConfig extends ResourceConfig {
|
||||
|
||||
@PostConstruct
|
||||
public void setup() {
|
||||
appCtx.getBeansWithAnnotation(Path.class).values().forEach(component -> register(component.getClass()));
|
||||
appCtx.getBeansWithAnnotation(Path.class).values().forEach(this::register);
|
||||
|
||||
appCtx.getBeansWithAnnotation(Provider.class).values().forEach(this::register);
|
||||
}
|
||||
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.documentmanagement.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.api.ImagesApiResource.EntityTypeForImages;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.contentrepository.ContentRepository;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.contentrepository.ContentRepositoryFactory;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.FileData;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.ImageData;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.domain.StorageType;
|
||||
import org.apache.fineract.organisation.staff.domain.Staff;
|
||||
import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.client.exception.ImageNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class ImageReadPlatformServiceImpl implements ImageReadPlatformService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final ContentRepositoryFactory contentRepositoryFactory;
|
||||
private final ClientRepositoryWrapper clientRepositoryWrapper;
|
||||
private final StaffRepositoryWrapper staffRepositoryWrapper;
|
||||
|
||||
@Autowired
|
||||
public ImageReadPlatformServiceImpl(final JdbcTemplate jdbcTemplate, final ContentRepositoryFactory documentStoreFactory,
|
||||
final ClientRepositoryWrapper clientRepositoryWrapper, StaffRepositoryWrapper staffRepositoryWrapper) {
|
||||
this.staffRepositoryWrapper = staffRepositoryWrapper;
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
this.contentRepositoryFactory = documentStoreFactory;
|
||||
this.clientRepositoryWrapper = clientRepositoryWrapper;
|
||||
}
|
||||
|
||||
private static final class ImageMapper implements RowMapper<ImageData> {
|
||||
|
||||
private final String entityDisplayName;
|
||||
|
||||
ImageMapper(final String entityDisplayName) {
|
||||
this.entityDisplayName = entityDisplayName;
|
||||
}
|
||||
|
||||
public String schema(String entityType) {
|
||||
StringBuilder builder = new StringBuilder(
|
||||
"image.id as id, image.location as location, image.storage_type_enum as storageType ");
|
||||
if (EntityTypeForImages.CLIENTS.toString().equalsIgnoreCase(entityType)) {
|
||||
builder.append(" from m_image image , m_client client " + " where client.image_id = image.id and client.id=?");
|
||||
} else if (EntityTypeForImages.STAFF.toString().equalsIgnoreCase(entityType)) {
|
||||
builder.append("from m_image image , m_staff staff " + " where staff.image_id = image.id and staff.id=?");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
final String location = rs.getString("location");
|
||||
final Integer storageTypeInt = JdbcSupport.getInteger(rs, "storageType");
|
||||
StorageType storageType = storageTypeInt != null ? StorageType.fromInt(storageTypeInt) : null;
|
||||
return new ImageData(location, storageType, this.entityDisplayName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileData retrieveImage(String entityType, final Long entityId) {
|
||||
try {
|
||||
String displayName;
|
||||
if (EntityTypeForImages.CLIENTS.toString().equalsIgnoreCase(entityType)) {
|
||||
Client owner = this.clientRepositoryWrapper.findOneWithNotFoundDetection(entityId);
|
||||
displayName = owner.getDisplayName();
|
||||
} else if (EntityTypeForImages.STAFF.toString().equalsIgnoreCase(entityType)) {
|
||||
Staff owner = this.staffRepositoryWrapper.findOneWithNotFoundDetection(entityId);
|
||||
displayName = owner.displayName();
|
||||
} else {
|
||||
displayName = "UnknownEntityType:" + entityType;
|
||||
}
|
||||
final ImageMapper imageMapper = new ImageMapper(displayName);
|
||||
|
||||
final String sql = "select " + imageMapper.schema(entityType);
|
||||
|
||||
final ImageData imageData = this.jdbcTemplate.queryForObject(sql, imageMapper, entityId); // NOSONAR
|
||||
final ContentRepository contentRepository = this.contentRepositoryFactory.getRepository(imageData.storageType());
|
||||
return contentRepository.fetchImage(imageData);
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new ImageNotFoundException("clients", entityId, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
-167
@@ -1,167 +0,0 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.infrastructure.documentmanagement.service;
|
||||
|
||||
import java.io.InputStream;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.domain.Base64EncodedImage;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.api.ImagesApiResource.EntityTypeForImages;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.contentrepository.ContentRepository;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.contentrepository.ContentRepositoryFactory;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.domain.Image;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.domain.ImageRepository;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.domain.StorageType;
|
||||
import org.apache.fineract.organisation.staff.domain.Staff;
|
||||
import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class ImageWritePlatformServiceJpaRepositoryImpl implements ImageWritePlatformService {
|
||||
|
||||
private final ContentRepositoryFactory contentRepositoryFactory;
|
||||
private final ClientRepositoryWrapper clientRepositoryWrapper;
|
||||
private final ImageRepository imageRepository;
|
||||
private final StaffRepositoryWrapper staffRepositoryWrapper;
|
||||
|
||||
@Autowired
|
||||
public ImageWritePlatformServiceJpaRepositoryImpl(final ContentRepositoryFactory documentStoreFactory,
|
||||
final ClientRepositoryWrapper clientRepositoryWrapper, final ImageRepository imageRepository,
|
||||
StaffRepositoryWrapper staffRepositoryWrapper) {
|
||||
this.contentRepositoryFactory = documentStoreFactory;
|
||||
this.clientRepositoryWrapper = clientRepositoryWrapper;
|
||||
this.imageRepository = imageRepository;
|
||||
this.staffRepositoryWrapper = staffRepositoryWrapper;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult saveOrUpdateImage(String entityName, final Long clientId, final String imageName,
|
||||
final InputStream inputStream, final Long fileSize) {
|
||||
Object owner = deletePreviousImage(entityName, clientId);
|
||||
|
||||
final ContentRepository contentRepository = this.contentRepositoryFactory.getRepository();
|
||||
final String imageLocation = contentRepository.saveImage(inputStream, clientId, imageName, fileSize);
|
||||
return updateImage(owner, imageLocation, contentRepository.getStorageType());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult saveOrUpdateImage(String entityName, final Long clientId, final Base64EncodedImage encodedImage) {
|
||||
Object owner = deletePreviousImage(entityName, clientId);
|
||||
|
||||
final ContentRepository contenRepository = this.contentRepositoryFactory.getRepository();
|
||||
final String imageLocation = contenRepository.saveImage(encodedImage, clientId, "image");
|
||||
|
||||
return updateImage(owner, imageLocation, contenRepository.getStorageType());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult deleteImage(String entityName, final Long clientId) {
|
||||
Object owner = null;
|
||||
Image image = null;
|
||||
if (EntityTypeForImages.CLIENTS.toString().equals(entityName)) {
|
||||
owner = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId);
|
||||
Client client = (Client) owner;
|
||||
image = client.getImage();
|
||||
client.setImage(null);
|
||||
this.clientRepositoryWrapper.save(client);
|
||||
|
||||
} else if (EntityTypeForImages.STAFF.toString().equals(entityName)) {
|
||||
owner = this.staffRepositoryWrapper.findOneWithNotFoundDetection(clientId);
|
||||
Staff staff = (Staff) owner;
|
||||
image = staff.getImage();
|
||||
staff.setImage(null);
|
||||
this.staffRepositoryWrapper.save(staff);
|
||||
|
||||
}
|
||||
// delete image from the file system
|
||||
if (image != null) {
|
||||
final ContentRepository contentRepository = this.contentRepositoryFactory
|
||||
.getRepository(StorageType.fromInt(image.getStorageType()));
|
||||
contentRepository.deleteImage(image.getLocation());
|
||||
this.imageRepository.delete(image);
|
||||
}
|
||||
|
||||
return CommandProcessingResult.resourceResult(clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entityName
|
||||
* @param entityId
|
||||
* @return
|
||||
*/
|
||||
private Object deletePreviousImage(String entityName, final Long entityId) {
|
||||
Object owner = null;
|
||||
Image image = null;
|
||||
if (EntityTypeForImages.CLIENTS.toString().equals(entityName)) {
|
||||
Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(entityId);
|
||||
image = client.getImage();
|
||||
owner = client;
|
||||
} else if (EntityTypeForImages.STAFF.toString().equals(entityName)) {
|
||||
Staff staff = this.staffRepositoryWrapper.findOneWithNotFoundDetection(entityId);
|
||||
image = staff.getImage();
|
||||
owner = staff;
|
||||
}
|
||||
if (image != null) {
|
||||
final ContentRepository contentRepository = this.contentRepositoryFactory
|
||||
.getRepository(StorageType.fromInt(image.getStorageType()));
|
||||
contentRepository.deleteImage(image.getLocation());
|
||||
}
|
||||
return owner;
|
||||
}
|
||||
|
||||
private CommandProcessingResult updateImage(final Object owner, final String imageLocation, final StorageType storageType) {
|
||||
Image image = null;
|
||||
Long clientId = null;
|
||||
if (owner instanceof Client client) {
|
||||
image = client.getImage();
|
||||
clientId = client.getId();
|
||||
image = createImage(image, imageLocation, storageType);
|
||||
client.setImage(image);
|
||||
this.clientRepositoryWrapper.save(client);
|
||||
} else if (owner instanceof Staff staff) {
|
||||
image = staff.getImage();
|
||||
clientId = staff.getId();
|
||||
image = createImage(image, imageLocation, storageType);
|
||||
staff.setImage(image);
|
||||
this.staffRepositoryWrapper.save(staff);
|
||||
}
|
||||
|
||||
if (image != null) {
|
||||
this.imageRepository.save(image);
|
||||
}
|
||||
return CommandProcessingResult.resourceResult(clientId);
|
||||
}
|
||||
|
||||
private Image createImage(Image image, final String imageLocation, final StorageType storageType) {
|
||||
if (image == null) {
|
||||
image = new Image(imageLocation, storageType);
|
||||
} else {
|
||||
image.setLocation(imageLocation);
|
||||
image.setStorageType(storageType.getValue());
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
}
|
||||
+4
-35
@@ -19,28 +19,23 @@
|
||||
package org.apache.fineract.infrastructure.event.external.service.serialization.serializer.document;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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;
|
||||
|
||||
@Slf4j
|
||||
@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
|
||||
@@ -51,35 +46,9 @@ public class DocumentBusinessEventSerializer implements BusinessEventSerializer
|
||||
@Override
|
||||
public <T> ByteBufferSerializable toAvroDTO(BusinessEvent<T> rawEvent) {
|
||||
|
||||
DocumentBusinessEvent event = (DocumentBusinessEvent) rawEvent;
|
||||
Document entity = event.get(); // domain entity
|
||||
var event = (DocumentBusinessEvent) rawEvent;
|
||||
|
||||
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;
|
||||
return mapper.map(event.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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.organisation.staff.adapter;
|
||||
|
||||
import static java.util.Objects.nonNull;
|
||||
|
||||
import java.util.Optional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.adapter.EntityImageIdAdapter;
|
||||
import org.apache.fineract.organisation.staff.domain.StaffRepository;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Component
|
||||
@Deprecated
|
||||
class StaffImageIdAdapter implements EntityImageIdAdapter {
|
||||
|
||||
private static final String ENTITY_TYPE = "staff";
|
||||
|
||||
private final StaffRepository repository;
|
||||
|
||||
@Override
|
||||
public boolean accept(String entityType) {
|
||||
return ENTITY_TYPE.equalsIgnoreCase(entityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Optional<ImageIdResult> get(Long entityId) {
|
||||
return repository.findById(entityId).filter(staff -> nonNull(staff.getImageId()))
|
||||
.map(staff -> ImageIdResult.builder().id(staff.getImageId()).displayName(staff.getDisplayName()).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Optional<ImageIdResult> set(Long entityId, Long imageId) {
|
||||
final var result = get(entityId);
|
||||
|
||||
if (imageId == null) {
|
||||
repository.removeImageId(entityId);
|
||||
} else {
|
||||
repository.updateByIdAndImageId(entityId, imageId);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+8
-3
@@ -20,6 +20,7 @@ package org.apache.fineract.organisation.staff.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
@@ -27,10 +28,14 @@ public interface StaffRepository extends JpaRepository<Staff, Long>, JpaSpecific
|
||||
|
||||
String FIND_BY_OFFICE_QUERY = "select s from Staff s where s.id = :id AND s.office.id = :officeId";
|
||||
|
||||
/**
|
||||
* Find staff by officeid.
|
||||
*/
|
||||
@Query(FIND_BY_OFFICE_QUERY)
|
||||
Staff findByOffice(@Param("id") Long id, @Param("officeId") Long officeId);
|
||||
|
||||
@Modifying
|
||||
@Query("UPDATE Staff staff SET staff.imageId = :imageId WHERE staff.id = :staffId")
|
||||
void updateByIdAndImageId(@Param("staffId") Long staffId, @Param("imageId") Long imageId);
|
||||
|
||||
@Modifying
|
||||
@Query("UPDATE Staff staff SET staff.imageId = null WHERE staff.id = :staffId")
|
||||
void removeImageId(@Param("staffId") Long staffId);
|
||||
}
|
||||
|
||||
+12
-12
@@ -34,22 +34,22 @@ import org.mapstruct.Named;
|
||||
@Mapper(config = MapstructMapperConfig.class)
|
||||
public interface ClientMapper {
|
||||
|
||||
@Mapping(target = "accountNo", source = "source.accountNumber")
|
||||
@Mapping(target = "accountNo", source = "accountNumber")
|
||||
@Mapping(target = "status", source = "source", qualifiedByName = "clientStatusEnum")
|
||||
@Mapping(target = "subStatus", source = "source", qualifiedByName = "clientSubStatusCode")
|
||||
@Mapping(target = "officeId", source = "source.office.id")
|
||||
@Mapping(target = "officeName", source = "source.office.name")
|
||||
@Mapping(target = "transferToOfficeId", source = "source.transferToOffice.id")
|
||||
@Mapping(target = "transferToOfficeName", source = "source.transferToOffice.name")
|
||||
@Mapping(target = "externalId", source = "source.externalId")
|
||||
@Mapping(target = "officeId", source = "office.id")
|
||||
@Mapping(target = "officeName", source = "office.name")
|
||||
@Mapping(target = "transferToOfficeId", source = "transferToOffice.id")
|
||||
@Mapping(target = "transferToOfficeName", source = "transferToOffice.name")
|
||||
@Mapping(target = "externalId", source = "externalId")
|
||||
@Mapping(target = "gender", source = "source", qualifiedByName = "clientGenderCode")
|
||||
@Mapping(target = "imageId", source = "source.image.id")
|
||||
@Mapping(target = "staffId", source = "source.staff.id")
|
||||
@Mapping(target = "staffName", source = "source.staff.displayName")
|
||||
@Mapping(target = "imageId", source = "imageId")
|
||||
@Mapping(target = "staffId", source = "staff.id")
|
||||
@Mapping(target = "staffName", source = "staff.displayName")
|
||||
@Mapping(target = "timeline", source = "source", qualifiedByName = "clientTimelineData")
|
||||
@Mapping(target = "savingsProductId", source = "source.savingsProductId")
|
||||
@Mapping(target = "savingsProductName", source = "source.id")
|
||||
@Mapping(target = "savingsAccountId", source = "source.savingsAccountId")
|
||||
@Mapping(target = "savingsProductId", source = "savingsProductId")
|
||||
@Mapping(target = "savingsProductName", source = "id")
|
||||
@Mapping(target = "savingsAccountId", source = "savingsAccountId")
|
||||
@Mapping(target = "clientType", source = "source", qualifiedByName = "clientTypeCode")
|
||||
@Mapping(target = "clientClassification", source = "source", qualifiedByName = "clientClassificationCode")
|
||||
@Mapping(target = "legalForm", source = "source", qualifiedByName = "clientLegalFormEnum")
|
||||
|
||||
+92
-15
@@ -18,6 +18,16 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.self.client.api;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static org.apache.fineract.infrastructure.contentstore.processor.DataUrlDecoderContentProcessor.DATA_URL_DECODE_RESULT_CONTENT_TYPE;
|
||||
import static org.apache.fineract.infrastructure.contentstore.processor.DataUrlEncoderContentProcessor.DATA_URL_ENCODE_PARAM_CONTENT_TYPE;
|
||||
import static org.apache.fineract.infrastructure.contentstore.processor.DataUrlEncoderContentProcessor.DATA_URL_ENCODE_PARAM_ENCODING;
|
||||
import static org.apache.fineract.infrastructure.contentstore.processor.ImageResizeContentProcessor.IMAGE_RESIZE_PARAM_FORMAT;
|
||||
import static org.apache.fineract.infrastructure.contentstore.processor.ImageResizeContentProcessor.IMAGE_RESIZE_PARAM_MAX_HEIGHT;
|
||||
import static org.apache.fineract.infrastructure.contentstore.processor.ImageResizeContentProcessor.IMAGE_RESIZE_PARAM_MAX_WIDTH;
|
||||
import static org.apache.fineract.infrastructure.contentstore.processor.SizeContentProcessor.SIZE_RESULT_VALUE;
|
||||
import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
@@ -40,10 +50,28 @@ import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.UriInfo;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.command.core.CommandPipeline;
|
||||
import org.apache.fineract.infrastructure.contentstore.detector.ContentDetectorContext;
|
||||
import org.apache.fineract.infrastructure.contentstore.detector.ContentDetectorManager;
|
||||
import org.apache.fineract.infrastructure.contentstore.processor.Base64DecoderContentProcessor;
|
||||
import org.apache.fineract.infrastructure.contentstore.processor.Base64EncoderContentProcessor;
|
||||
import org.apache.fineract.infrastructure.contentstore.processor.ContentProcessorContext;
|
||||
import org.apache.fineract.infrastructure.contentstore.processor.DataUrlDecoderContentProcessor;
|
||||
import org.apache.fineract.infrastructure.contentstore.processor.DataUrlEncoderContentProcessor;
|
||||
import org.apache.fineract.infrastructure.contentstore.processor.ImageResizeContentProcessor;
|
||||
import org.apache.fineract.infrastructure.contentstore.processor.SizeContentProcessor;
|
||||
import org.apache.fineract.infrastructure.core.data.UploadRequest;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.api.ImagesApiResource;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.command.ImageCreateCommand;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.command.ImageDeleteCommand;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.ImageCreateRequest;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.ImageCreateResponse;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.ImageDeleteRequest;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.ImageDeleteResponse;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.service.ImageReadPlatformService;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.portfolio.client.api.ClientApiConstants;
|
||||
import org.apache.fineract.portfolio.client.api.ClientChargesApiResource;
|
||||
@@ -54,6 +82,7 @@ import org.apache.fineract.portfolio.self.client.data.SelfClientDataValidator;
|
||||
import org.apache.fineract.portfolio.self.client.service.AppuserClientMapperReadService;
|
||||
import org.apache.fineract.portfolio.self.config.SelfServiceModuleIsEnabledCondition;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.apache.fineract.util.StreamResponseUtil;
|
||||
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
|
||||
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
||||
import org.glassfish.jersey.media.multipart.FormDataParam;
|
||||
@@ -69,11 +98,19 @@ public class SelfClientsApiResource {
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final ClientsApiResource clientApiResource;
|
||||
private final ImagesApiResource imagesApiResource;
|
||||
private final ClientChargesApiResource clientChargesApiResource;
|
||||
private final ClientTransactionsApiResource clientTransactionsApiResource;
|
||||
private final AppuserClientMapperReadService appUserClientMapperReadService;
|
||||
private final SelfClientDataValidator dataValidator;
|
||||
private final ImageReadPlatformService imageReadPlatformService;
|
||||
private final CommandPipeline commandPipeline;
|
||||
private final ImageResizeContentProcessor imageResizeContentProcessor;
|
||||
private final Base64EncoderContentProcessor base64EncoderContentProcessor;
|
||||
private final Base64DecoderContentProcessor base64DecoderContentProcessor;
|
||||
private final DataUrlEncoderContentProcessor dataUrlEncoderContentProcessor;
|
||||
private final DataUrlDecoderContentProcessor dataUrlDecoderContentProcessor;
|
||||
private final SizeContentProcessor sizeContentProcessor;
|
||||
private final ContentDetectorManager contentDetectorManager;
|
||||
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@@ -149,7 +186,20 @@ public class SelfClientsApiResource {
|
||||
|
||||
validateAppuserClientsMapping(clientId);
|
||||
|
||||
return this.imagesApiResource.retrieveImage("clients", clientId, maxWidth, maxHeight, output, MediaType.TEXT_PLAIN);
|
||||
final var content = imageReadPlatformService.retrieveImage(ClientApiConstants.clientEntityName, clientId);
|
||||
|
||||
// stream base64 encoded original format
|
||||
final var detectorCtx = contentDetectorManager.detect(ContentDetectorContext.builder().fileName(content.getFileName()).build());
|
||||
final var ctx = imageResizeContentProcessor.then(base64EncoderContentProcessor).then(dataUrlEncoderContentProcessor)
|
||||
.process(new ContentProcessorContext(content.getStream(),
|
||||
Map.of(IMAGE_RESIZE_PARAM_MAX_WIDTH, maxWidth, IMAGE_RESIZE_PARAM_MAX_HEIGHT, maxHeight, IMAGE_RESIZE_PARAM_FORMAT,
|
||||
detectorCtx.getFormat(), DATA_URL_ENCODE_PARAM_CONTENT_TYPE, detectorCtx.getMimeType(),
|
||||
DATA_URL_ENCODE_PARAM_ENCODING, "base64")));
|
||||
|
||||
final var streamResponseData = StreamResponseUtil.StreamResponseData.builder().fileName(content.getFileName())
|
||||
.type(TEXT_PLAIN_VALUE).stream(ctx.getInputStream()).build();
|
||||
|
||||
return StreamResponseUtil.ok(streamResponseData);
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -233,36 +283,63 @@ public class SelfClientsApiResource {
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@RequestBody(description = "Add new client image", content = {
|
||||
@Content(mediaType = MediaType.MULTIPART_FORM_DATA, schema = @Schema(implementation = UploadRequest.class)) })
|
||||
public CommandProcessingResult addNewClientImage(@PathParam("clientId") final Long clientId,
|
||||
@HeaderParam("Content-Length") final Long fileSize, @FormDataParam("file") final InputStream inputStream,
|
||||
@FormDataParam("file") final FormDataContentDisposition fileDetails, @FormDataParam("file") final FormDataBodyPart bodyPart) {
|
||||
public ImageCreateResponse addNewClientImage(@PathParam("clientId") final Long clientId,
|
||||
@HeaderParam("Content-Length") final Long fileSize, @FormDataParam("file") final InputStream is,
|
||||
@FormDataParam("file") final FormDataContentDisposition fileDetails, @FormDataParam("file") final FormDataBodyPart filePart) {
|
||||
|
||||
validateAppuserClientsMapping(clientId);
|
||||
return this.imagesApiResource.addNewClientImage(ClientApiConstants.clientEntityName, clientId, fileSize, inputStream, fileDetails,
|
||||
bodyPart);
|
||||
|
||||
// TODO: add proper error messages
|
||||
requireNonNull(fileDetails, "");
|
||||
requireNonNull(filePart, "");
|
||||
requireNonNull(is, "");
|
||||
|
||||
final var command = new ImageCreateCommand();
|
||||
|
||||
command.setPayload(ImageCreateRequest.builder().entityId(clientId).entityType(ClientApiConstants.clientEntityName)
|
||||
.fileName(fileDetails.getFileName()).size(fileSize).type(filePart.getMediaType().toString()).stream(is).build());
|
||||
|
||||
final Supplier<ImageCreateResponse> response = commandPipeline.send(command);
|
||||
|
||||
return response.get();
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("{clientId}/images")
|
||||
@Consumes({ MediaType.TEXT_PLAIN, MediaType.TEXT_HTML, MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public CommandProcessingResult addNewClientImage(@PathParam("entity") final String entityName,
|
||||
@PathParam("clientId") final Long clientId, final String jsonRequestBody) {
|
||||
public ImageCreateResponse addNewClientImage(@PathParam("clientId") final Long clientId, final InputStream body) {
|
||||
validateAppuserClientsMapping(clientId);
|
||||
return this.imagesApiResource.addNewClientImage(ClientApiConstants.clientEntityName, clientId, jsonRequestBody);
|
||||
|
||||
final var ctx = dataUrlDecoderContentProcessor.then(base64DecoderContentProcessor).then(sizeContentProcessor).process(body);
|
||||
|
||||
final String contentType = ctx.getResult(DATA_URL_DECODE_RESULT_CONTENT_TYPE);
|
||||
Long size = ctx.getResult(SIZE_RESULT_VALUE);
|
||||
|
||||
final var command = new ImageCreateCommand();
|
||||
|
||||
command.setPayload(ImageCreateRequest.builder().entityId(clientId).entityType(ClientApiConstants.clientEntityName)
|
||||
.fileName(UUID.randomUUID().toString()).size(size).type(contentType).stream(ctx.getInputStream()).build());
|
||||
|
||||
final Supplier<ImageCreateResponse> response = commandPipeline.send(command);
|
||||
|
||||
return response.get();
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{clientId}/images")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public CommandProcessingResult deleteClientImage(@PathParam("clientId") final Long clientId) {
|
||||
|
||||
public ImageDeleteResponse deleteClientImage(@PathParam("clientId") final Long clientId) {
|
||||
validateAppuserClientsMapping(clientId);
|
||||
return this.imagesApiResource.deleteClientImage(ClientApiConstants.clientEntityName, clientId);
|
||||
|
||||
final var command = new ImageDeleteCommand();
|
||||
|
||||
command.setPayload(ImageDeleteRequest.builder().entityId(clientId).entityType(ClientApiConstants.clientEntityName).build());
|
||||
|
||||
final Supplier<ImageDeleteResponse> response = commandPipeline.send(command);
|
||||
|
||||
return response.get();
|
||||
}
|
||||
|
||||
@GET
|
||||
|
||||
@@ -182,6 +182,7 @@ fineract.content.regex-whitelist-enabled=${FINERACT_CONTENT_REGEX_WHITELIST_ENAB
|
||||
fineract.content.regex-whitelist=${FINERACT_CONTENT_REGEX_WHITELIST:.*\\.pdf$,.*\\.doc,.*\\.docx,.*\\.xls,.*\\.xlsx,.*\\.jpg,.*\\.jpeg,.*\\.png}
|
||||
fineract.content.mime-whitelist-enabled=${FINERACT_CONTENT_MIME_WHITELIST_ENABLED:true}
|
||||
fineract.content.mime-whitelist=${FINERACT_CONTENT_MIME_WHITELIST:application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,image/jpeg,image/png}
|
||||
fineract.content.default-buffer-size=${FINERACT_CONTENT_DEFAULT_BUFFER_SIZE:8192}
|
||||
fineract.content.filesystem.enabled=${FINERACT_CONTENT_FILESYSTEM_ENABLED:true}
|
||||
fineract.content.filesystem.rootFolder=${FINERACT_CONTENT_FILESYSTEM_ROOT_FOLDER:${user.home}/.fineract}
|
||||
fineract.content.s3.enabled=${FINERACT_CONTENT_S3_ENABLED:false}
|
||||
@@ -192,6 +193,9 @@ fineract.content.s3.region=${FINERACT_CONTENT_S3_REGION:}
|
||||
fineract.content.s3.endpoint=${FINERACT_CONTENT_S3_ENDPOINT:}
|
||||
fineract.content.s3.path-style-addressing-enabled=${FINERACT_CONTENT_S3_PATH_STYLE_ADDRESSING_ENABLED:false}
|
||||
|
||||
spring.servlet.multipart.max-file-size=${FINERACT_MULTIPART_FILE_SIZE:5MB}
|
||||
spring.servlet.multipart.max-request-size=${FINERACT_MULTIPART_REQUEST_SIZE:10MB}
|
||||
|
||||
fineract.template.regex-whitelist-enabled=${FINERACT_TEMPLATE_REGEX_WHITELIST_ENABLED:true}
|
||||
fineract.template.regex-whitelist=${FINERACT_TEMPLATE_REGEX_WHITELIST:}
|
||||
|
||||
@@ -489,55 +493,89 @@ resilience4j.retry.instances.postInterest.retryExceptions=${FINERACT_PROCESS_POS
|
||||
|
||||
# business date
|
||||
|
||||
resilience4j.retry.instances.commandBusinessDateUpdate.max-attempts=${FINERACT_PROCESS_COMMAND_BUSINESS_DATE_UPDATE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandBusinessDateUpdate.wait-duration=${FINERACT_PROCESS_COMMAND_BUSINESS_DATE_UPDATE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandBusinessDateUpdate.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_BUSINESS_DATE_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandBusinessDateUpdate.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_BUSINESS_DATE_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandBusinessDateUpdate.retryExceptions=${FINERACT_PROCESS_COMMAND_BUSINESS_DATE_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
resilience4j.retry.instances.commandBusinessDateUpdate.max-attempts=${FINERACT_COMMAND_BUSINESS_DATE_UPDATE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandBusinessDateUpdate.wait-duration=${FINERACT_COMMAND_BUSINESS_DATE_UPDATE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandBusinessDateUpdate.enable-exponential-backoff=${FINERACT_COMMAND_BUSINESS_DATE_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandBusinessDateUpdate.exponential-backoff-multiplier=${FINERACT_COMMAND_BUSINESS_DATE_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandBusinessDateUpdate.retryExceptions=${FINERACT_COMMAND_BUSINESS_DATE_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
# cache
|
||||
|
||||
resilience4j.retry.instances.commandCacheSwitch.max-attempts=${FINERACT_PROCESS_COMMAND_CACHE_SWITCH_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandCacheSwitch.wait-duration=${FINERACT_PROCESS_COMMAND_CACHE_SWITCH_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandCacheSwitch.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_CACHE_SWITCH_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandCacheSwitch.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_CACHE_SWITCH_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandCacheSwitch.retryExceptions=${FINERACT_PROCESS_COMMAND_CACHE_SWITCH_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
resilience4j.retry.instances.commandCacheSwitch.max-attempts=${FINERACT_COMMAND_CACHE_SWITCH_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandCacheSwitch.wait-duration=${FINERACT_COMMAND_CACHE_SWITCH_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandCacheSwitch.enable-exponential-backoff=${FINERACT_COMMAND_CACHE_SWITCH_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandCacheSwitch.exponential-backoff-multiplier=${FINERACT_COMMAND_CACHE_SWITCH_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandCacheSwitch.retryExceptions=${FINERACT_COMMAND_CACHE_SWITCH_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
# currency
|
||||
|
||||
resilience4j.retry.instances.commandCurrencyUpdate.max-attempts=${FINERACT_PROCESS_COMMAND_CURRENCY_UPDATE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandCurrencyUpdate.wait-duration=${FINERACT_PROCESS_COMMAND_CURRENCY_UPDATE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandCurrencyUpdate.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_CURRENCY_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandCurrencyUpdate.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_CURRENCY_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandCurrencyUpdate.retryExceptions=${FINERACT_PROCESS_COMMAND_CURRENCY_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
resilience4j.retry.instances.commandCurrencyUpdate.max-attempts=${FINERACT_COMMAND_CURRENCY_UPDATE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandCurrencyUpdate.wait-duration=${FINERACT_COMMAND_CURRENCY_UPDATE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandCurrencyUpdate.enable-exponential-backoff=${FINERACT_COMMAND_CURRENCY_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandCurrencyUpdate.exponential-backoff-multiplier=${FINERACT_COMMAND_CURRENCY_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandCurrencyUpdate.retryExceptions=${FINERACT_COMMAND_CURRENCY_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
# external event configuration
|
||||
|
||||
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.max-attempts=${FINERACT_PROCESS_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.wait-duration=${FINERACT_PROCESS_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.retryExceptions=${FINERACT_PROCESS_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.max-attempts=${FINERACT_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.wait-duration=${FINERACT_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.enable-exponential-backoff=${FINERACT_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.exponential-backoff-multiplier=${FINERACT_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.retryExceptions=${FINERACT_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
# note
|
||||
|
||||
resilience4j.retry.instances.commandNoteCreate.max-attempts=${FINERACT_PROCESS_COMMAND_NOTE_CREATE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandNoteCreate.wait-duration=${FINERACT_PROCESS_COMMAND_NOTE_CREATE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandNoteCreate.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_NOTE_CREATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandNoteCreate.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_NOTE_CREATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandNoteCreate.retryExceptions=${FINERACT_PROCESS_COMMAND_NOTE_CREATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
resilience4j.retry.instances.commandNoteCreate.max-attempts=${FINERACT_COMMAND_NOTE_CREATE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandNoteCreate.wait-duration=${FINERACT_COMMAND_NOTE_CREATE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandNoteCreate.enable-exponential-backoff=${FINERACT_COMMAND_NOTE_CREATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandNoteCreate.exponential-backoff-multiplier=${FINERACT_COMMAND_NOTE_CREATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandNoteCreate.retryExceptions=${FINERACT_COMMAND_NOTE_CREATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
resilience4j.retry.instances.commandNoteUpdate.max-attempts=${FINERACT_PROCESS_COMMAND_NOTE_UPDATE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandNoteUpdate.wait-duration=${FINERACT_PROCESS_COMMAND_NOTE_UPDATE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandNoteUpdate.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_NOTE_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandNoteUpdate.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_NOTE_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandNoteUpdate.retryExceptions=${FINERACT_PROCESS_COMMAND_NOTE_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
resilience4j.retry.instances.commandNoteUpdate.max-attempts=${FINERACT_COMMAND_NOTE_UPDATE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandNoteUpdate.wait-duration=${FINERACT_COMMAND_NOTE_UPDATE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandNoteUpdate.enable-exponential-backoff=${FINERACT_COMMAND_NOTE_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandNoteUpdate.exponential-backoff-multiplier=${FINERACT_COMMAND_NOTE_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandNoteUpdate.retryExceptions=${FINERACT_COMMAND_NOTE_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
resilience4j.retry.instances.commandNoteDelete.max-attempts=${FINERACT_PROCESS_COMMAND_NOTE_DELETE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandNoteDelete.wait-duration=${FINERACT_PROCESS_COMMAND_NOTE_DELETE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandNoteDelete.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_NOTE_DELETE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandNoteDelete.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_NOTE_DELETE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandNoteDelete.retryExceptions=${FINERACT_PROCESS_COMMAND_NOTE_DELETE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
resilience4j.retry.instances.commandNoteDelete.max-attempts=${FINERACT_COMMAND_NOTE_DELETE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandNoteDelete.wait-duration=${FINERACT_COMMAND_NOTE_DELETE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandNoteDelete.enable-exponential-backoff=${FINERACT_COMMAND_NOTE_DELETE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandNoteDelete.exponential-backoff-multiplier=${FINERACT_COMMAND_NOTE_DELETE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandNoteDelete.retryExceptions=${FINERACT_COMMAND_NOTE_DELETE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
# document
|
||||
|
||||
resilience4j.retry.instances.commandDocumentCreate.max-attempts=${FINERACT_COMMAND_DOCUMENT_CREATE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandDocumentCreate.wait-duration=${FINERACT_COMMAND_DOCUMENT_CREATE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandDocumentCreate.enable-exponential-backoff=${FINERACT_COMMAND_DOCUMENT_CREATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandDocumentCreate.exponential-backoff-multiplier=${FINERACT_COMMAND_DOCUMENT_CREATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandDocumentCreate.retryExceptions=${FINERACT_COMMAND_DOCUMENT_CREATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
resilience4j.retry.instances.commandDocumentUpdate.max-attempts=${FINERACT_COMMAND_DOCUMENT_UPDATE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandDocumentUpdate.wait-duration=${FINERACT_COMMAND_DOCUMENT_UPDATE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandDocumentUpdate.enable-exponential-backoff=${FINERACT_COMMAND_DOCUMENT_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandDocumentUpdate.exponential-backoff-multiplier=${FINERACT_COMMAND_DOCUMENT_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandDocumentUpdate.retryExceptions=${FINERACT_COMMAND_DOCUMENT_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
resilience4j.retry.instances.commandDocumentDelete.max-attempts=${FINERACT_COMMAND_DOCUMENT_DELETE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandDocumentDelete.wait-duration=${FINERACT_COMMAND_DOCUMENT_DELETE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandDocumentDelete.enable-exponential-backoff=${FINERACT_COMMAND_DOCUMENT_DELETE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandDocumentDelete.exponential-backoff-multiplier=${FINERACT_COMMAND_DOCUMENT_DELETE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandDocumentDelete.retryExceptions=${FINERACT_COMMAND_DOCUMENT_DELETE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
# image
|
||||
|
||||
resilience4j.retry.instances.commandImageCreate.max-attempts=${FINERACT_COMMAND_IMAGE_CREATE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandImageCreate.wait-duration=${FINERACT_COMMAND_IMAGE_CREATE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandImageCreate.enable-exponential-backoff=${FINERACT_COMMAND_IMAGE_CREATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandImageCreate.exponential-backoff-multiplier=${FINERACT_COMMAND_IMAGE_CREATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandImageCreate.retryExceptions=${FINERACT_COMMAND_IMAGE_CREATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
resilience4j.retry.instances.commandImageDelete.max-attempts=${FINERACT_COMMAND_IMAGE_DELETE_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandImageDelete.wait-duration=${FINERACT_COMMAND_IMAGE_DELETE_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandImageDelete.enable-exponential-backoff=${FINERACT_COMMAND_IMAGE_DELETE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandImageDelete.exponential-backoff-multiplier=${FINERACT_COMMAND_IMAGE_DELETE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandImageDelete.retryExceptions=${FINERACT_COMMAND_IMAGE_DELETE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
fineract.command.enabled=true
|
||||
fineract.command.executor=${FINERACT_COMMAND_EXECUTOR:sync}
|
||||
@@ -551,26 +589,26 @@ fineract.command.file-dead-letter-queue-path=${FINERACT_FILE_DEAD_LETTER_QUEUE_P
|
||||
|
||||
# command
|
||||
|
||||
resilience4j.retry.instances.commandAuditProcessing.max-attempts=${FINERACT_PROCESS_COMMAND_AUDIT_PROCESSING_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandAuditProcessing.wait-duration=${FINERACT_PROCESS_COMMAND_AUDIT_PROCESSING_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandAuditProcessing.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_AUDIT_PROCESSING_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandAuditProcessing.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_AUDIT_PROCESSING_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandAuditProcessing.retryExceptions=${FINERACT_PROCESS_COMMAND_AUDIT_PROCESSING_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
resilience4j.retry.instances.commandAuditProcessing.max-attempts=${FINERACT_COMMAND_AUDIT_PROCESSING_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandAuditProcessing.wait-duration=${FINERACT_COMMAND_AUDIT_PROCESSING_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandAuditProcessing.enable-exponential-backoff=${FINERACT_COMMAND_AUDIT_PROCESSING_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandAuditProcessing.exponential-backoff-multiplier=${FINERACT_COMMAND_AUDIT_PROCESSING_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandAuditProcessing.retryExceptions=${FINERACT_COMMAND_AUDIT_PROCESSING_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
resilience4j.retry.instances.commandAuditProcessed.max-attempts=${FINERACT_PROCESS_COMMAND_AUDIT_PROCESSED_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandAuditProcessed.wait-duration=${FINERACT_PROCESS_COMMAND_AUDIT_PROCESSED_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandAuditProcessed.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_AUDIT_PROCESSED_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandAuditProcessed.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_AUDIT_PROCESSED_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandAuditProcessed.retryExceptions=${FINERACT_PROCESS_COMMAND_AUDIT_PROCESSED_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
resilience4j.retry.instances.commandAuditProcessed.max-attempts=${FINERACT_COMMAND_AUDIT_PROCESSED_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandAuditProcessed.wait-duration=${FINERACT_COMMAND_AUDIT_PROCESSED_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandAuditProcessed.enable-exponential-backoff=${FINERACT_COMMAND_AUDIT_PROCESSED_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandAuditProcessed.exponential-backoff-multiplier=${FINERACT_COMMAND_AUDIT_PROCESSED_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandAuditProcessed.retryExceptions=${FINERACT_COMMAND_AUDIT_PROCESSED_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
resilience4j.retry.instances.commandAuditError.max-attempts=${FINERACT_PROCESS_COMMAND_AUDIT_ERROR_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandAuditError.wait-duration=${FINERACT_PROCESS_COMMAND_AUDIT_ERROR_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandAuditError.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_AUDIT_ERROR_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandAuditError.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_AUDIT_ERROR_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandAuditError.retryExceptions=${FINERACT_PROCESS_COMMAND_AUDIT_ERROR_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
resilience4j.retry.instances.commandAuditError.max-attempts=${FINERACT_COMMAND_AUDIT_ERROR_RETRY_MAX_ATTEMPTS:3}
|
||||
resilience4j.retry.instances.commandAuditError.wait-duration=${FINERACT_COMMAND_AUDIT_ERROR_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandAuditError.enable-exponential-backoff=${FINERACT_COMMAND_AUDIT_ERROR_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandAuditError.exponential-backoff-multiplier=${FINERACT_COMMAND_AUDIT_ERROR_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandAuditError.retryExceptions=${FINERACT_COMMAND_AUDIT_ERROR_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
resilience4j.retry.instances.commandAuditFallback.max-attempts=${FINERACT_PROCESS_COMMAND_AUDIT_FALLBACK_RETRY_MAX_ATTEMPTS:1}
|
||||
resilience4j.retry.instances.commandAuditFallback.wait-duration=${FINERACT_PROCESS_COMMAND_AUDIT_FALLBACK_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandAuditFallback.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_AUDIT_FALLBACK_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandAuditFallback.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_AUDIT_FALLBACK_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandAuditFallback.retryExceptions=${FINERACT_PROCESS_COMMAND_AUDIT_FALLBACK_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
resilience4j.retry.instances.commandAuditFallback.max-attempts=${FINERACT_COMMAND_AUDIT_FALLBACK_RETRY_MAX_ATTEMPTS:1}
|
||||
resilience4j.retry.instances.commandAuditFallback.wait-duration=${FINERACT_COMMAND_AUDIT_FALLBACK_RETRY_WAIT_DURATION:1s}
|
||||
resilience4j.retry.instances.commandAuditFallback.enable-exponential-backoff=${FINERACT_COMMAND_AUDIT_FALLBACK_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
|
||||
resilience4j.retry.instances.commandAuditFallback.exponential-backoff-multiplier=${FINERACT_COMMAND_AUDIT_FALLBACK_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
|
||||
resilience4j.retry.instances.commandAuditFallback.retryExceptions=${FINERACT_COMMAND_AUDIT_FALLBACK_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
|
||||
|
||||
-4
@@ -34,7 +34,6 @@
|
||||
<!-- Core Module Entities -->
|
||||
<class>org.apache.fineract.useradministration.domain.Role</class>
|
||||
<class>org.apache.fineract.portfolio.fund.domain.Fund</class>
|
||||
<class>org.apache.fineract.infrastructure.documentmanagement.domain.Image</class>
|
||||
<class>org.apache.fineract.organisation.workingdays.domain.WorkingDays</class>
|
||||
<class>org.apache.fineract.useradministration.domain.Permission</class>
|
||||
<class>org.apache.fineract.useradministration.domain.AppUserClientMapping</class>
|
||||
@@ -228,9 +227,6 @@
|
||||
<class>org.apache.fineract.portfolio.loanproduct.domain.SupportedInterestRefundTypesListConverter</class>
|
||||
<class>org.apache.fineract.portfolio.loanaccount.domain.LoanStatusConverter</class>
|
||||
|
||||
<!-- Document Module Entities -->
|
||||
<class>org.apache.fineract.infrastructure.documentmanagement.domain.Document</class>
|
||||
|
||||
<!-- Tax Module Entities -->
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxComponent</class>
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxComponentHistory</class>
|
||||
|
||||
Reference in New Issue
Block a user