diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java index 78796b116..91e9a47b1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadWriteNonCoreDataServiceImpl.java @@ -106,8 +106,12 @@ import org.apache.fineract.infrastructure.dataqueries.data.ResultsetRowData; import org.apache.fineract.infrastructure.dataqueries.exception.DatatableEntryRequiredException; import org.apache.fineract.infrastructure.dataqueries.exception.DatatableNotFoundException; import org.apache.fineract.infrastructure.dataqueries.exception.DatatableSystemErrorException; +import org.apache.fineract.infrastructure.event.business.domain.datatable.DatatableEntryCreatedBusinessEvent; +import org.apache.fineract.infrastructure.event.business.domain.datatable.DatatableEntryDeletedBusinessEvent; +import org.apache.fineract.infrastructure.event.business.domain.datatable.DatatableEntryDetails; +import org.apache.fineract.infrastructure.event.business.domain.datatable.DatatableEntryUpdatedBusinessEvent; +import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; -import org.apache.fineract.infrastructure.security.service.SqlInjectionPreventerService; import org.apache.fineract.infrastructure.security.service.SqlValidator; import org.apache.fineract.infrastructure.security.utils.ColumnValidator; import org.apache.fineract.portfolio.search.data.AdvancedQueryData; @@ -156,10 +160,10 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ private final DataTableValidator dataTableValidator; private final ColumnValidator columnValidator; private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; - private final SqlInjectionPreventerService preventSqlInjectionService; private final DatatableKeywordGenerator datatableKeywordGenerator; private final SqlValidator sqlValidator; private final SearchUtil searchUtil; + private final BusinessEventNotifierService businessEventNotifierService; @Override public List retrieveDatatableNames(final String appTable) { @@ -1307,8 +1311,9 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ ArrayList insertColumns = new ArrayList<>( List.of(entityTable.getForeignKeyColumnNameOnDatatable(), CREATEDAT_FIELD_NAME, UPDATEDAT_FIELD_NAME)); - LocalDateTime auditDateTime = DateUtils.getAuditLocalDateTime(); + final LocalDateTime auditDateTime = DateUtils.getAuditLocalDateTime(); ArrayList params = new ArrayList<>(List.of(appTableId, auditDateTime, auditDateTime)); + Map dataObjectParams = new HashMap(); for (Map.Entry entry : dataParams.entrySet()) { if (isTechnicalParam(entry.getKey())) { continue; @@ -1318,8 +1323,11 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ continue; } insertColumns.add(columnHeader.getColumnName()); - params.add(searchUtil.parseJdbcColumnValue(columnHeader, entry.getValue(), dateFormat, dateTimeFormat, locale, false, - sqlGenerator)); + Object valueParam = searchUtil.parseJdbcColumnValue(columnHeader, entry.getValue(), dateFormat, dateTimeFormat, locale, false, + sqlGenerator); + params.add(valueParam); + dataObjectParams.put(entry.getKey(), valueParam); + } if (addScore) { List scoreIds = params.stream().filter(e -> e != null && !String.valueOf(e).isBlank()).toList(); @@ -1353,6 +1361,11 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ if (isMultirowDatatable(columnHeaders)) { resourceId = sqlGenerator.fetchPK(keyHolder); } + + final DatatableEntryDetails datatableEntryDetails = new DatatableEntryDetails(dataTableName, entityTable, resourceId, + appTableId, dataObjectParams); + businessEventNotifierService.notifyPostBusinessEvent(new DatatableEntryCreatedBusinessEvent(datatableEntryDetails)); + return CommandProcessingResult.fromCommandProcessingResult(commandProcessingResult, resourceId); } catch (final DataAccessException dve) { handleDataIntegrityIssues(dataTableName, appTableId, dve.getMostSpecificCause(), dve); @@ -1422,6 +1435,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ final Type typeOfMap = new TypeToken>() {}.getType(); final Map dataParams = fromJsonHelper.extractDataMap(typeOfMap, command.json()); + final Map dataObjectParams = new HashMap(); final String dateFormat = dataParams.get(API_PARAM_DATE_FORMAT); // fall back to dateFormat to keep backward compatibility @@ -1445,6 +1459,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ Object existingValue = valuesByHeader.get(columnHeader); Object columnValue = searchUtil.parseColumnValue(columnHeader, entry.getValue(), dateFormat, dateTimeFormat, locale, false, sqlGenerator); + dataObjectParams.put(entry.getKey(), columnValue); if ((columnHeader.getColumnType().isDecimalType() && MathUtil.isEqualTo((BigDecimal) existingValue, (BigDecimal) columnValue)) || (existingValue == null ? columnValue == null : existingValue.equals(columnValue))) { log.debug("Ignore change on update {}:{}", dataTableName, columnName); @@ -1457,16 +1472,23 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ Long primaryKey = datatableId == null ? appTableId : datatableId; if (!updateColumns.isEmpty()) { ResultsetColumnHeaderData pkColumn = searchUtil.getFiltered(columnHeaders, ResultsetColumnHeaderData::getIsColumnPrimaryKey); - params.add(primaryKey); - final String sql = sqlGenerator.buildUpdate(dataTableName, updateColumns, headersByName) + " WHERE " + pkColumn.getColumnName() - + " = ?"; - int updated = jdbcTemplate.update(sql, params.toArray(Object[]::new)); // NOSONAR - if (updated != 1) { - throw new PlatformDataIntegrityException("error.msg.invalid.update", "Expected one updated row."); + if (pkColumn != null) { + params.add(primaryKey); + final String sql = sqlGenerator.buildUpdate(dataTableName, updateColumns, headersByName) + " WHERE " + + pkColumn.getColumnName() + " = ?"; + int updated = jdbcTemplate.update(sql, params.toArray(Object[]::new)); // NOSONAR + if (updated != 1) { + throw new PlatformDataIntegrityException("error.msg.invalid.update", "Expected one updated row."); + } } } else { log.debug("No change on update {}", dataTableName); } + + final DatatableEntryDetails datatableEntryDetails = new DatatableEntryDetails(dataTableName, entityTable, datatableId, appTableId, + dataObjectParams); + businessEventNotifierService.notifyPostBusinessEvent(new DatatableEntryUpdatedBusinessEvent(datatableEntryDetails)); + return new CommandProcessingResultBuilder().withCommandId(command.commandId()) // .withEntityId(primaryKey) // .withOfficeId(commandProcessingResult.getOfficeId()) // @@ -1517,6 +1539,11 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ + whereValue; this.jdbcTemplate.update(sql); // NOSONAR + final Map dataParams = null; + final DatatableEntryDetails datatableEntryDetails = new DatatableEntryDetails(dataTableName, entityTable, datatableId, appTableId, + dataParams); + businessEventNotifierService.notifyPostBusinessEvent(new DatatableEntryDeletedBusinessEvent(datatableEntryDetails)); + return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // .withEntityId(whereValue) // diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/starter/DataQueriesAutoConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/starter/DataQueriesAutoConfiguration.java index 8425fa997..4de72b69a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/starter/DataQueriesAutoConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/starter/DataQueriesAutoConfiguration.java @@ -29,8 +29,8 @@ import org.apache.fineract.infrastructure.dataqueries.service.DatatableKeywordGe import org.apache.fineract.infrastructure.dataqueries.service.GenericDataService; import org.apache.fineract.infrastructure.dataqueries.service.ReadWriteNonCoreDataService; import org.apache.fineract.infrastructure.dataqueries.service.ReadWriteNonCoreDataServiceImpl; +import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; -import org.apache.fineract.infrastructure.security.service.SqlInjectionPreventerService; import org.apache.fineract.infrastructure.security.service.SqlValidator; import org.apache.fineract.infrastructure.security.utils.ColumnValidator; import org.apache.fineract.portfolio.search.service.SearchUtil; @@ -51,11 +51,11 @@ public class DataQueriesAutoConfiguration { final DatatableCommandFromApiJsonDeserializer fromApiJsonDeserializer, final ConfigurationDomainService configurationDomainService, final CodeReadPlatformService codeReadPlatformService, final DataTableValidator dataTableValidator, final ColumnValidator columnValidator, - final NamedParameterJdbcTemplate namedParameterJdbcTemplate, final SqlInjectionPreventerService preventSqlInjectionService, - DatatableKeywordGenerator datatableKeywordGenerator, SqlValidator sqlValidator, SearchUtil searchUtil) { + final NamedParameterJdbcTemplate namedParameterJdbcTemplate, DatatableKeywordGenerator datatableKeywordGenerator, + SqlValidator sqlValidator, SearchUtil searchUtil, final BusinessEventNotifierService businessEventNotifierService) { return new ReadWriteNonCoreDataServiceImpl(jdbcTemplate, databaseTypeResolver, sqlGenerator, context, fromJsonHelper, genericDataService, fromApiJsonDeserializer, configurationDomainService, codeReadPlatformService, dataTableValidator, - columnValidator, namedParameterJdbcTemplate, preventSqlInjectionService, datatableKeywordGenerator, sqlValidator, - searchUtil); + columnValidator, namedParameterJdbcTemplate, datatableKeywordGenerator, sqlValidator, searchUtil, + businessEventNotifierService); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryBusinessEvent.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryBusinessEvent.java new file mode 100644 index 000000000..3a51b060b --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryBusinessEvent.java @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.event.business.domain.datatable; + +import lombok.Getter; +import org.apache.fineract.infrastructure.event.business.domain.AbstractBusinessEvent; + +@Getter +public abstract class DatatableEntryBusinessEvent extends AbstractBusinessEvent { + + protected static final String CATEGORY = "Datatable"; + public static final String TYPE = "DatatableEntryBusinessEvent"; + + protected DatatableEntryDetails datatableEntryDetails; + + public DatatableEntryBusinessEvent(final DatatableEntryDetails datatableEntryDetails) { + super(datatableEntryDetails); + this.datatableEntryDetails = datatableEntryDetails; + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public String getCategory() { + return CATEGORY; + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryCreatedBusinessEvent.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryCreatedBusinessEvent.java new file mode 100644 index 000000000..a61688b42 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryCreatedBusinessEvent.java @@ -0,0 +1,41 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.event.business.domain.datatable; + +import org.apache.fineract.infrastructure.event.business.domain.NoExternalEvent; + +public class DatatableEntryCreatedBusinessEvent extends DatatableEntryBusinessEvent implements NoExternalEvent { + + public static final String TYPE = "DatatableEntryCreatedBusinessEvent"; + + public DatatableEntryCreatedBusinessEvent(final DatatableEntryDetails datatableEntryDetails) { + super(datatableEntryDetails); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public Long getAggregateRootId() { + return datatableEntryDetails.getEntityId(); + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryDeletedBusinessEvent.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryDeletedBusinessEvent.java new file mode 100644 index 000000000..e1fa56247 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryDeletedBusinessEvent.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.event.business.domain.datatable; + +import org.apache.fineract.infrastructure.event.business.domain.NoExternalEvent; + +public class DatatableEntryDeletedBusinessEvent extends DatatableEntryBusinessEvent implements NoExternalEvent { + + public static final String TYPE = "DatatableEntryDeletedBusinessEvent"; + + public DatatableEntryDeletedBusinessEvent(final DatatableEntryDetails datatableEntryDetails) { + super(datatableEntryDetails); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public Long getAggregateRootId() { + return datatableEntryDetails.getEntityId(); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryDetails.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryDetails.java new file mode 100644 index 000000000..0aada8cc6 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryDetails.java @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.event.business.domain.datatable; + +import java.util.Map; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; + +@Data +@RequiredArgsConstructor +public class DatatableEntryDetails { + + private final String datatableName; + private final EntityTables entityType; + private final Long entityId; + private final Long appTableId; + private final Map data; + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryUpdatedBusinessEvent.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryUpdatedBusinessEvent.java new file mode 100644 index 000000000..ed361fdd2 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/event/business/domain/datatable/DatatableEntryUpdatedBusinessEvent.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.event.business.domain.datatable; + +import org.apache.fineract.infrastructure.event.business.domain.NoExternalEvent; + +public class DatatableEntryUpdatedBusinessEvent extends DatatableEntryBusinessEvent implements NoExternalEvent { + + public static final String TYPE = "DatatableEntryUpdatedBusinessEvent"; + + public DatatableEntryUpdatedBusinessEvent(final DatatableEntryDetails datatableEntryDetails) { + super(datatableEntryDetails); + } + + @Override + public String getType() { + return TYPE; + } + + @Override + public Long getAggregateRootId() { + return datatableEntryDetails.getEntityId(); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResource.java index dab2cffbc..7a1140235 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResource.java @@ -68,6 +68,7 @@ import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPl import org.apache.fineract.portfolio.client.data.ClientData; import org.apache.fineract.portfolio.client.exception.ClientNotFoundException; import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; +import org.apache.fineract.portfolio.client.service.ClientTemplateReadPlatformService; import org.apache.fineract.portfolio.loanaccount.guarantor.data.ObligeeData; import org.apache.fineract.portfolio.loanaccount.guarantor.service.GuarantorReadPlatformService; import org.apache.fineract.portfolio.savings.data.SavingsAccountData; @@ -85,6 +86,7 @@ public class ClientsApiResource { private final PlatformSecurityContext context; private final ClientReadPlatformService clientReadPlatformService; + private final ClientTemplateReadPlatformService clientTemplateReadPlatformService; private final ToApiJsonSerializer toApiJsonSerializer; private final ToApiJsonSerializer clientAccountSummaryToApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; @@ -122,7 +124,7 @@ public class ClientsApiResource { } else if (CommandParameterUtil.is(commandParam, "withdraw")) { clientData = clientReadPlatformService.retrieveAllNarrations(ClientApiConstants.CLIENT_WITHDRAW_REASON); } else { - clientData = clientReadPlatformService.retrieveTemplate(officeId, staffInSelectedOfficeOnly); + clientData = clientTemplateReadPlatformService.retrieveTemplate(officeId, staffInSelectedOfficeOnly); } final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); @@ -458,7 +460,8 @@ public class ClientsApiResource { private ClientData retrieveClientData(final Long clientId, final boolean staffInSelectedOfficeOnly, final boolean isTemplate) { ClientData clientData = clientReadPlatformService.retrieveOne(clientId); if (isTemplate) { - final ClientData templateData = clientReadPlatformService.retrieveTemplate(clientData.getOfficeId(), staffInSelectedOfficeOnly); + final ClientData templateData = clientTemplateReadPlatformService.retrieveTemplate(clientData.getOfficeId(), + staffInSelectedOfficeOnly); clientData = ClientData.templateOnTop(clientData, templateData); Collection savingAccountOptions = savingsAccountReadPlatformService.retrieveForLookup(clientId, null); if (savingAccountOptions != null && savingAccountOptions.size() > 0) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformService.java index 60514e729..5fa017e72 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformService.java @@ -27,8 +27,6 @@ import org.apache.fineract.portfolio.client.data.ClientData; public interface ClientReadPlatformService { - ClientData retrieveTemplate(Long officeId, boolean staffInSelectedOfficeOnly); - Page retrieveAll(SearchParameters searchParameters); ClientData retrieveOne(Long clientId); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java index 7f747b78e..74d45fcb4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientReadPlatformServiceImpl.java @@ -32,54 +32,36 @@ import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService; -import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.domain.JdbcSupport; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; -import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.core.service.PaginationHelper; import org.apache.fineract.infrastructure.core.service.SearchParameters; import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator; -import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; -import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; -import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; -import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.utils.ColumnValidator; -import org.apache.fineract.organisation.office.data.OfficeData; -import org.apache.fineract.organisation.office.service.OfficeReadPlatformService; -import org.apache.fineract.organisation.staff.data.StaffData; -import org.apache.fineract.organisation.staff.service.StaffReadPlatformService; -import org.apache.fineract.portfolio.address.data.AddressData; -import org.apache.fineract.portfolio.address.service.AddressReadPlatformService; -import org.apache.fineract.portfolio.client.api.ClientApiConstants; import org.apache.fineract.portfolio.client.data.ClientCollateralManagementData; import org.apache.fineract.portfolio.client.data.ClientData; -import org.apache.fineract.portfolio.client.data.ClientFamilyMembersData; import org.apache.fineract.portfolio.client.data.ClientNonPersonData; import org.apache.fineract.portfolio.client.data.ClientTimelineData; import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.domain.ClientEnumerations; import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; import org.apache.fineract.portfolio.client.domain.ClientStatus; -import org.apache.fineract.portfolio.client.domain.LegalForm; import org.apache.fineract.portfolio.client.exception.ClientNotFoundException; import org.apache.fineract.portfolio.client.mapper.ClientMapper; import org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollateralManagement; import org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollateralManagementRepositoryWrapper; import org.apache.fineract.portfolio.group.data.GroupGeneralData; -import org.apache.fineract.portfolio.savings.data.SavingsProductData; -import org.apache.fineract.portfolio.savings.service.SavingsProductReadPlatformService; import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; @Service @RequiredArgsConstructor @@ -87,10 +69,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService private final JdbcTemplate jdbcTemplate; private final PlatformSecurityContext context; - private final OfficeReadPlatformService officeReadPlatformService; - private final StaffReadPlatformService staffReadPlatformService; private final CodeValueReadPlatformService codeValueReadPlatformService; - private final SavingsProductReadPlatformService savingsProductReadPlatformService; // data mappers private final PaginationHelper paginationHelper; private final DatabaseSpecificSQLGenerator sqlGenerator; @@ -99,71 +78,11 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService private final ClientMembersOfGroupMapper membersOfGroupMapper = new ClientMembersOfGroupMapper(); private final ParentGroupsMapper clientGroupsMapper = new ParentGroupsMapper(); - private final AddressReadPlatformService addressReadPlatformService; - private final ClientFamilyMembersReadPlatformService clientFamilyMembersReadPlatformService; - private final EntityDatatableChecksReadService entityDatatableChecksReadService; private final ColumnValidator columnValidator; private final ClientCollateralManagementRepositoryWrapper clientCollateralManagementRepositoryWrapper; - private final ConfigurationDomainService configurationDomainService; private final ClientRepositoryWrapper clientRepositoryWrapper; private final ClientMapper clientMapper; - @Override - public ClientData retrieveTemplate(final Long officeId, final boolean staffInSelectedOfficeOnly) { - this.context.authenticatedUser(); - - final Long defaultOfficeId = defaultToUsersOfficeIfNull(officeId); - AddressData address = null; - - final Collection offices = this.officeReadPlatformService.retrieveAllOfficesForDropdown(); - - final Collection savingsProductDatas = this.savingsProductReadPlatformService.retrieveAllForLookupByType(null); - - final Boolean isAddressEnabled = configurationDomainService.isAddressEnabled(); - if (isAddressEnabled) { - address = this.addressReadPlatformService.retrieveTemplate(); - } - - final ClientFamilyMembersData familyMemberOptions = this.clientFamilyMembersReadPlatformService.retrieveTemplate(); - - Collection staffOptions = null; - - final boolean loanOfficersOnly = false; - if (staffInSelectedOfficeOnly) { - staffOptions = this.staffReadPlatformService.retrieveAllStaffForDropdown(defaultOfficeId); - } else { - staffOptions = this.staffReadPlatformService.retrieveAllStaffInOfficeAndItsParentOfficeHierarchy(defaultOfficeId, - loanOfficersOnly); - } - if (CollectionUtils.isEmpty(staffOptions)) { - staffOptions = null; - } - final List genderOptions = new ArrayList<>( - this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.GENDER)); - - final List clientTypeOptions = new ArrayList<>( - this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.CLIENT_TYPE)); - - final List clientClassificationOptions = new ArrayList<>( - this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.CLIENT_CLASSIFICATION)); - - final List clientNonPersonConstitutionOptions = new ArrayList<>( - this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.CLIENT_NON_PERSON_CONSTITUTION)); - - final List clientNonPersonMainBusinessLineOptions = new ArrayList<>( - this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.CLIENT_NON_PERSON_MAIN_BUSINESS_LINE)); - - final List clientLegalFormOptions = ClientEnumerations.legalForm(LegalForm.values()); - - final List datatableTemplates = this.entityDatatableChecksReadService.retrieveTemplates(StatusEnum.CREATE.getValue(), - EntityTables.CLIENT.getName(), null); - - return ClientData.template(defaultOfficeId, LocalDate.now(DateUtils.getDateTimeZoneOfTenant()), offices, staffOptions, null, - genderOptions, savingsProductDatas, clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, - clientNonPersonMainBusinessLineOptions, clientLegalFormOptions, familyMemberOptions, - new ArrayList(Arrays.asList(address)), isAddressEnabled, datatableTemplates); - } - @Override public Page retrieveAll(final SearchParameters searchParameters) { @@ -643,14 +562,6 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService } } - private Long defaultToUsersOfficeIfNull(final Long officeId) { - Long defaultOfficeId = officeId; - if (defaultOfficeId == null) { - defaultOfficeId = this.context.authenticatedUser().getOffice().getId(); - } - return defaultOfficeId; - } - @Override public ClientData retrieveAllNarrations(final String clientNarrations) { final List narrations = new ArrayList<>( diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTemplateReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTemplateReadPlatformService.java new file mode 100644 index 000000000..b4ac660da --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTemplateReadPlatformService.java @@ -0,0 +1,27 @@ +/** + * 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.portfolio.client.service; + +import org.apache.fineract.portfolio.client.data.ClientData; + +public interface ClientTemplateReadPlatformService { + + ClientData retrieveTemplate(Long officeId, boolean staffInSelectedOfficeOnly); + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTemplateReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTemplateReadPlatformServiceImpl.java new file mode 100644 index 000000000..7bb563cee --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTemplateReadPlatformServiceImpl.java @@ -0,0 +1,133 @@ +/** + * 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.portfolio.client.service; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.infrastructure.codes.data.CodeValueData; +import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; +import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.core.service.DateUtils; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.organisation.office.data.OfficeData; +import org.apache.fineract.organisation.office.service.OfficeReadPlatformService; +import org.apache.fineract.organisation.staff.data.StaffData; +import org.apache.fineract.organisation.staff.service.StaffReadPlatformService; +import org.apache.fineract.portfolio.address.data.AddressData; +import org.apache.fineract.portfolio.address.service.AddressReadPlatformService; +import org.apache.fineract.portfolio.client.api.ClientApiConstants; +import org.apache.fineract.portfolio.client.data.ClientData; +import org.apache.fineract.portfolio.client.data.ClientFamilyMembersData; +import org.apache.fineract.portfolio.client.domain.ClientEnumerations; +import org.apache.fineract.portfolio.client.domain.LegalForm; +import org.apache.fineract.portfolio.savings.data.SavingsProductData; +import org.apache.fineract.portfolio.savings.service.SavingsProductReadPlatformService; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +@Service +@RequiredArgsConstructor +public class ClientTemplateReadPlatformServiceImpl implements ClientTemplateReadPlatformService { + + private final PlatformSecurityContext context; + private final OfficeReadPlatformService officeReadPlatformService; + private final StaffReadPlatformService staffReadPlatformService; + private final CodeValueReadPlatformService codeValueReadPlatformService; + private final SavingsProductReadPlatformService savingsProductReadPlatformService; + // data mappers + private final EntityDatatableChecksReadService entityDatatableChecksReadService; + + private final AddressReadPlatformService addressReadPlatformService; + private final ClientFamilyMembersReadPlatformService clientFamilyMembersReadPlatformService; + private final ConfigurationDomainService configurationDomainService; + + @Override + public ClientData retrieveTemplate(final Long officeId, final boolean staffInSelectedOfficeOnly) { + this.context.authenticatedUser(); + + final Long defaultOfficeId = defaultToUsersOfficeIfNull(officeId); + AddressData address = null; + + final Collection offices = this.officeReadPlatformService.retrieveAllOfficesForDropdown(); + + final Collection savingsProductDatas = this.savingsProductReadPlatformService.retrieveAllForLookupByType(null); + + final Boolean isAddressEnabled = configurationDomainService.isAddressEnabled(); + if (isAddressEnabled) { + address = this.addressReadPlatformService.retrieveTemplate(); + } + + final ClientFamilyMembersData familyMemberOptions = this.clientFamilyMembersReadPlatformService.retrieveTemplate(); + + Collection staffOptions = null; + + final boolean loanOfficersOnly = false; + if (staffInSelectedOfficeOnly) { + staffOptions = this.staffReadPlatformService.retrieveAllStaffForDropdown(defaultOfficeId); + } else { + staffOptions = this.staffReadPlatformService.retrieveAllStaffInOfficeAndItsParentOfficeHierarchy(defaultOfficeId, + loanOfficersOnly); + } + if (CollectionUtils.isEmpty(staffOptions)) { + staffOptions = null; + } + final List genderOptions = new ArrayList<>( + this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.GENDER)); + + final List clientTypeOptions = new ArrayList<>( + this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.CLIENT_TYPE)); + + final List clientClassificationOptions = new ArrayList<>( + this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.CLIENT_CLASSIFICATION)); + + final List clientNonPersonConstitutionOptions = new ArrayList<>( + this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.CLIENT_NON_PERSON_CONSTITUTION)); + + final List clientNonPersonMainBusinessLineOptions = new ArrayList<>( + this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.CLIENT_NON_PERSON_MAIN_BUSINESS_LINE)); + + final List clientLegalFormOptions = ClientEnumerations.legalForm(LegalForm.values()); + + final List datatableTemplates = this.entityDatatableChecksReadService.retrieveTemplates(StatusEnum.CREATE.getValue(), + EntityTables.CLIENT.getName(), null); + + return ClientData.template(defaultOfficeId, LocalDate.now(DateUtils.getDateTimeZoneOfTenant()), offices, staffOptions, null, + genderOptions, savingsProductDatas, clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, + clientNonPersonMainBusinessLineOptions, clientLegalFormOptions, familyMemberOptions, + new ArrayList(Arrays.asList(address)), isAddressEnabled, datatableTemplates); + } + + private Long defaultToUsersOfficeIfNull(final Long officeId) { + Long defaultOfficeId = officeId; + if (defaultOfficeId == null) { + defaultOfficeId = this.context.authenticatedUser().getOffice().getId(); + } + return defaultOfficeId; + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountsApiResource.java index 32d6a50ae..1aa63d0fa 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsAccountsApiResource.java @@ -74,6 +74,7 @@ import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData; import org.apache.fineract.portfolio.savings.exception.SavingsAccountNotFoundException; import org.apache.fineract.portfolio.savings.service.SavingsAccountChargeReadPlatformService; import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformService; +import org.apache.fineract.portfolio.savings.service.SavingsAccountTemplateReadPlatformService; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import org.glassfish.jersey.media.multipart.FormDataParam; import org.springframework.stereotype.Component; @@ -86,6 +87,7 @@ import org.springframework.util.CollectionUtils; public class SavingsAccountsApiResource { private final SavingsAccountReadPlatformService savingsAccountReadPlatformService; + private final SavingsAccountTemplateReadPlatformService savingsAccountTemplateReadPlatformService; private final PlatformSecurityContext context; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; @@ -112,7 +114,7 @@ public class SavingsAccountsApiResource { context.authenticatedUser().validateHasReadPermission(SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME); - final SavingsAccountData savingsAccount = savingsAccountReadPlatformService.retrieveTemplate(clientId, groupId, productId, + final SavingsAccountData savingsAccount = savingsAccountTemplateReadPlatformService.retrieveTemplate(clientId, groupId, productId, staffInSelectedOfficeOnly); final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); @@ -662,8 +664,8 @@ public class SavingsAccountsApiResource { SavingsAccountData templateData = null; final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); if (settings.isTemplate()) { - templateData = savingsAccountReadPlatformService.retrieveTemplate(savingsAccount.getClientId(), savingsAccount.getGroupId(), - savingsAccount.getSavingsProductId(), staffInSelectedOfficeOnly); + templateData = savingsAccountTemplateReadPlatformService.retrieveTemplate(savingsAccount.getClientId(), + savingsAccount.getGroupId(), savingsAccount.getSavingsProductId(), staffInSelectedOfficeOnly); } return SavingsAccountData.withTemplateOptions(savingsAccount, templateData, transactions, charges); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java index 46579b8a7..22a9298d1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java @@ -42,23 +42,12 @@ import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.core.service.PaginationHelper; import org.apache.fineract.infrastructure.core.service.SearchParameters; import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator; -import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; -import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; -import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; -import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.utils.ColumnValidator; import org.apache.fineract.organisation.monetary.data.CurrencyData; -import org.apache.fineract.organisation.staff.data.StaffData; -import org.apache.fineract.organisation.staff.service.StaffReadPlatformService; import org.apache.fineract.portfolio.account.data.AccountTransferData; -import org.apache.fineract.portfolio.charge.data.ChargeData; -import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; -import org.apache.fineract.portfolio.charge.util.ConvertChargeDataToSpecificChargeData; import org.apache.fineract.portfolio.client.data.ClientData; -import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; import org.apache.fineract.portfolio.group.data.GroupGeneralData; -import org.apache.fineract.portfolio.group.service.GroupReadPlatformService; import org.apache.fineract.portfolio.paymentdetail.data.PaymentDetailData; import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData; import org.apache.fineract.portfolio.savings.DepositAccountType; @@ -91,19 +80,12 @@ import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.RowMapper; -import org.springframework.util.CollectionUtils; public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountReadPlatformService { private final PlatformSecurityContext context; private final JdbcTemplate jdbcTemplate; - private final ClientReadPlatformService clientReadPlatformService; - private final GroupReadPlatformService groupReadPlatformService; - private final SavingsProductReadPlatformService savingsProductReadPlatformService; - private final StaffReadPlatformService staffReadPlatformService; - private final SavingsDropdownReadPlatformService dropdownReadPlatformService; private final DatabaseSpecificSQLGenerator sqlGenerator; - private final ChargeReadPlatformService chargeReadPlatformService; // mappers private final SavingsAccountTransactionTemplateMapper transactionTemplateMapper; @@ -116,35 +98,22 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead // pagination private final PaginationHelper paginationHelper; - private final EntityDatatableChecksReadService entityDatatableChecksReadService; private final ColumnValidator columnValidator; private final SavingsAccountAssembler savingAccountAssembler; private final SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper; public SavingsAccountReadPlatformServiceImpl(final PlatformSecurityContext context, final JdbcTemplate jdbcTemplate, - final ClientReadPlatformService clientReadPlatformService, final GroupReadPlatformService groupReadPlatformService, - final SavingsProductReadPlatformService savingProductReadPlatformService, - final StaffReadPlatformService staffReadPlatformService, final SavingsDropdownReadPlatformService dropdownReadPlatformService, - final ChargeReadPlatformService chargeReadPlatformService, - final EntityDatatableChecksReadService entityDatatableChecksReadService, final ColumnValidator columnValidator, - final SavingsAccountAssembler savingAccountAssembler, PaginationHelper paginationHelper, + final SavingsAccountAssembler savingAccountAssembler, PaginationHelper paginationHelper, ColumnValidator columnValidator, DatabaseSpecificSQLGenerator sqlGenerator, SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper) { this.context = context; this.jdbcTemplate = jdbcTemplate; - this.clientReadPlatformService = clientReadPlatformService; - this.groupReadPlatformService = groupReadPlatformService; - this.savingsProductReadPlatformService = savingProductReadPlatformService; - this.staffReadPlatformService = staffReadPlatformService; - this.dropdownReadPlatformService = dropdownReadPlatformService; this.sqlGenerator = sqlGenerator; this.savingsAccountRepositoryWrapper = savingsAccountRepositoryWrapper; this.transactionTemplateMapper = new SavingsAccountTransactionTemplateMapper(); this.transactionsMapper = new SavingsAccountTransactionsMapper(); this.savingsAccountTransactionsForBatchMapper = new SavingsAccountTransactionsForBatchMapper(); this.savingAccountMapper = new SavingAccountMapper(); - this.chargeReadPlatformService = chargeReadPlatformService; - this.entityDatatableChecksReadService = entityDatatableChecksReadService; this.columnValidator = columnValidator; this.paginationHelper = paginationHelper; this.savingAccountMapperForInterestPosting = new SavingAccountMapperForInterestPosting(); @@ -1033,141 +1002,6 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead } } - @Override - public SavingsAccountData retrieveTemplate(final Long clientId, final Long groupId, final Long productId, - final boolean staffInSelectedOfficeOnly) { - - final AppUser loggedInUser = this.context.authenticatedUser(); - Long officeId = loggedInUser.getOffice().getId(); - - ClientData client = null; - if (clientId != null) { - client = this.clientReadPlatformService.retrieveOne(clientId); - officeId = client.getOfficeId(); - } - - GroupGeneralData group = null; - if (groupId != null) { - group = this.groupReadPlatformService.retrieveOne(groupId); - officeId = group.getOfficeId(); - } - - final Collection productOptions = this.savingsProductReadPlatformService.retrieveAllForLookup(); - SavingsAccountData template = null; - if (productId != null) { - - final SavingAccountTemplateMapper mapper = new SavingAccountTemplateMapper(client, group); - - final String sql = "select " + mapper.schema() + " where sp.id = ?"; - template = this.jdbcTemplate.queryForObject(sql, mapper, new Object[] { productId }); // NOSONAR - - final Collection interestCompoundingPeriodTypeOptions = this.dropdownReadPlatformService - .retrieveCompoundingInterestPeriodTypeOptions(); - - final Collection interestPostingPeriodTypeOptions = this.dropdownReadPlatformService - .retrieveInterestPostingPeriodTypeOptions(); - - final Collection interestCalculationTypeOptions = this.dropdownReadPlatformService - .retrieveInterestCalculationTypeOptions(); - - final Collection interestCalculationDaysInYearTypeOptions = this.dropdownReadPlatformService - .retrieveInterestCalculationDaysInYearTypeOptions(); - - final Collection lockinPeriodFrequencyTypeOptions = this.dropdownReadPlatformService - .retrieveLockinPeriodFrequencyTypeOptions(); - - final Collection withdrawalFeeTypeOptions = this.dropdownReadPlatformService.retrievewithdrawalFeeTypeOptions(); - - final Collection transactions = null; - final Collection productCharges = this.chargeReadPlatformService.retrieveSavingsProductCharges(productId); - // update charges from Product charges - final Collection charges = fromChargesToSavingsCharges(productCharges); - - final boolean feeChargesOnly = false; - final Collection chargeOptions = this.chargeReadPlatformService - .retrieveSavingsProductApplicableCharges(feeChargesOnly); - - Collection fieldOfficerOptions = null; - - if (officeId != null) { - - if (staffInSelectedOfficeOnly) { - // only bring back loan officers in selected branch/office - final Collection fieldOfficersInBranch = this.staffReadPlatformService - .retrieveAllLoanOfficersInOfficeById(officeId); - - if (!CollectionUtils.isEmpty(fieldOfficersInBranch)) { - fieldOfficerOptions = new ArrayList<>(fieldOfficersInBranch); - } - } else { - // by default bring back all officers in selected - // branch/office as well as officers in office above - // this office - final boolean restrictToLoanOfficersOnly = true; - final Collection loanOfficersInHierarchy = this.staffReadPlatformService - .retrieveAllStaffInOfficeAndItsParentOfficeHierarchy(officeId, restrictToLoanOfficersOnly); - - if (!CollectionUtils.isEmpty(loanOfficersInHierarchy)) { - fieldOfficerOptions = new ArrayList<>(loanOfficersInHierarchy); - } - } - } - - template = SavingsAccountData.withTemplateOptions(template, productOptions, fieldOfficerOptions, - interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions, - interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions, - charges, chargeOptions); - } else { - - String clientName = null; - if (client != null) { - clientName = client.getDisplayName(); - } - - String groupName = null; - if (group != null) { - groupName = group.getName(); - } - - template = SavingsAccountData.withClientTemplate(clientId, clientName, groupId, groupName); - - final Collection fieldOfficerOptions = null; - final Collection interestCompoundingPeriodTypeOptions = null; - final Collection interestPostingPeriodTypeOptions = null; - final Collection interestCalculationTypeOptions = null; - final Collection interestCalculationDaysInYearTypeOptions = null; - final Collection lockinPeriodFrequencyTypeOptions = null; - final Collection withdrawalFeeTypeOptions = null; - - final Collection transactions = null; - final Collection charges = null; - - final boolean feeChargesOnly = false; - final Collection chargeOptions = this.chargeReadPlatformService - .retrieveSavingsProductApplicableCharges(feeChargesOnly); - - template = SavingsAccountData.withTemplateOptions(template, productOptions, fieldOfficerOptions, - interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions, - interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions, - charges, chargeOptions); - } - - final List datatableTemplates = this.entityDatatableChecksReadService.retrieveTemplates(StatusEnum.CREATE.getValue(), - EntityTables.SAVINGS.getName(), productId); - template.setDatatables(datatableTemplates); - - return template; - } - - private Collection fromChargesToSavingsCharges(final Collection productCharges) { - final Collection savingsCharges = new ArrayList<>(); - for (final ChargeData chargeData : productCharges) { - final SavingsAccountChargeData savingsCharge = ConvertChargeDataToSpecificChargeData.toSavingsAccountChargeData(chargeData); - savingsCharges.add(savingsCharge); - } - return savingsCharges; - } - @Override public SavingsAccountTransactionData retrieveDepositTransactionTemplate(final Long savingsId, final DepositAccountType depositAccountType) { @@ -1402,188 +1236,6 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead } } - private static final class SavingAccountTemplateMapper implements RowMapper { - - private final ClientData client; - private final GroupGeneralData group; - - private final String schemaSql; - - SavingAccountTemplateMapper(final ClientData client, final GroupGeneralData group) { - this.client = client; - this.group = group; - - final StringBuilder sqlBuilder = new StringBuilder(400); - sqlBuilder.append("sp.id as productId, sp.name as productName, "); - sqlBuilder.append( - "sp.currency_code as currencyCode, sp.currency_digits as currencyDigits, sp.currency_multiplesof as inMultiplesOf, "); - sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, "); - sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, "); - sqlBuilder.append("sp.nominal_annual_interest_rate as nominalAnnualIterestRate, "); - sqlBuilder.append("sp.interest_compounding_period_enum as interestCompoundingPeriodType, "); - sqlBuilder.append("sp.interest_posting_period_enum as interestPostingPeriodType, "); - sqlBuilder.append("sp.interest_calculation_type_enum as interestCalculationType, "); - sqlBuilder.append("sp.interest_calculation_days_in_year_type_enum as interestCalculationDaysInYearType, "); - sqlBuilder.append("sp.min_required_opening_balance as minRequiredOpeningBalance, "); - sqlBuilder.append("sp.lockin_period_frequency as lockinPeriodFrequency,"); - sqlBuilder.append("sp.lockin_period_frequency_enum as lockinPeriodFrequencyType, "); - // sqlBuilder.append("sp.withdrawal_fee_amount as - // withdrawalFeeAmount,"); - // sqlBuilder.append("sp.withdrawal_fee_type_enum as - // withdrawalFeeTypeEnum, "); - sqlBuilder.append("sp.withdrawal_fee_for_transfer as withdrawalFeeForTransfers, "); - sqlBuilder.append("sp.min_balance_for_interest_calculation as minBalanceForInterestCalculation, "); - sqlBuilder.append("sp.allow_overdraft as allowOverdraft, "); - sqlBuilder.append("sp.overdraft_limit as overdraftLimit, "); - sqlBuilder.append("sp.nominal_annual_interest_rate_overdraft as nominalAnnualInterestRateOverdraft, "); - sqlBuilder.append("sp.min_overdraft_for_interest_calculation as minOverdraftForInterestCalculation, "); - sqlBuilder.append("sp.withhold_tax as withHoldTax,"); - sqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName, "); - - // sqlBuilder.append("sp.annual_fee_amount as annualFeeAmount,"); - // sqlBuilder.append("sp.annual_fee_on_month as annualFeeOnMonth, - // "); - // sqlBuilder.append("sp.annual_fee_on_day as annualFeeOnDay "); - sqlBuilder.append("sp.min_required_balance as minRequiredBalance, "); - sqlBuilder.append("sp.enforce_min_required_balance as enforceMinRequiredBalance, "); - sqlBuilder.append("sp.max_allowed_lien_limit as maxAllowedLienLimit, "); - sqlBuilder.append("sp.is_lien_allowed as lienAllowed "); - sqlBuilder.append("from m_savings_product sp "); - sqlBuilder.append("join m_currency curr on curr.code = sp.currency_code "); - sqlBuilder.append("left join m_tax_group tg on tg.id = sp.tax_group_id "); - - this.schemaSql = sqlBuilder.toString(); - } - - public String schema() { - return this.schemaSql; - } - - @Override - public SavingsAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { - - final Long productId = rs.getLong("productId"); - final String productName = rs.getString("productName"); - - final String currencyCode = rs.getString("currencyCode"); - final String currencyName = rs.getString("currencyName"); - final String currencyNameCode = rs.getString("currencyNameCode"); - final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol"); - final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits"); - final Integer inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf"); - final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf, currencyDisplaySymbol, - currencyNameCode); - - final BigDecimal nominalAnnualIterestRate = rs.getBigDecimal("nominalAnnualIterestRate"); - - final EnumOptionData interestCompoundingPeriodType = SavingsEnumerations.compoundingInterestPeriodType( - SavingsCompoundingInterestPeriodType.fromInt(JdbcSupport.getInteger(rs, "interestCompoundingPeriodType"))); - - final EnumOptionData interestPostingPeriodType = SavingsEnumerations.interestPostingPeriodType( - SavingsPostingInterestPeriodType.fromInt(JdbcSupport.getInteger(rs, "interestPostingPeriodType"))); - - final EnumOptionData interestCalculationType = SavingsEnumerations - .interestCalculationType(SavingsInterestCalculationType.fromInt(JdbcSupport.getInteger(rs, "interestCalculationType"))); - - final EnumOptionData interestCalculationDaysInYearType = SavingsEnumerations.interestCalculationDaysInYearType( - SavingsInterestCalculationDaysInYearType.fromInt(JdbcSupport.getInteger(rs, "interestCalculationDaysInYearType"))); - - final BigDecimal minRequiredOpeningBalance = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minRequiredOpeningBalance"); - - final Integer lockinPeriodFrequency = JdbcSupport.getInteger(rs, "lockinPeriodFrequency"); - EnumOptionData lockinPeriodFrequencyType = null; - final Integer lockinPeriodFrequencyTypeValue = JdbcSupport.getInteger(rs, "lockinPeriodFrequencyType"); - if (lockinPeriodFrequencyTypeValue != null) { - final SavingsPeriodFrequencyType lockinPeriodType = SavingsPeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue); - lockinPeriodFrequencyType = SavingsEnumerations.lockinPeriodFrequencyType(lockinPeriodType); - } - - // final BigDecimal withdrawalFeeAmount = - // rs.getBigDecimal("withdrawalFeeAmount"); - - /* - * EnumOptionData withdrawalFeeType = null; final Integer withdrawalFeeTypeValue = - * JdbcSupport.getInteger(rs, "withdrawalFeeTypeEnum"); if (withdrawalFeeTypeValue != null) { - * withdrawalFeeType = SavingsEnumerations.withdrawalFeeType(withdrawalFeeTypeValue); } - */ - final boolean withdrawalFeeForTransfers = rs.getBoolean("withdrawalFeeForTransfers"); - - final boolean allowOverdraft = rs.getBoolean("allowOverdraft"); - final BigDecimal overdraftLimit = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "overdraftLimit"); - final BigDecimal nominalAnnualInterestRateOverdraft = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, - "nominalAnnualInterestRateOverdraft"); - final BigDecimal minOverdraftForInterestCalculation = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, - "minOverdraftForInterestCalculation"); - - final BigDecimal minRequiredBalance = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minRequiredBalance"); - final boolean enforceMinRequiredBalance = rs.getBoolean("enforceMinRequiredBalance"); - final BigDecimal maxAllowedLienLimit = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "maxAllowedLienLimit"); - final boolean lienAllowed = rs.getBoolean("lienAllowed"); - final BigDecimal minBalanceForInterestCalculation = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, - "minBalanceForInterestCalculation"); - - // final BigDecimal annualFeeAmount = - // JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, - // "annualFeeAmount"); - - /* - * MonthDay annualFeeOnMonthDay = null; final Integer annualFeeOnMonth = JdbcSupport.getInteger(rs, - * "annualFeeOnMonth"); final Integer annualFeeOnDay = JdbcSupport.getInteger(rs, "annualFeeOnDay"); if - * (annualFeeAmount != null && annualFeeOnDay != null) { annualFeeOnMonthDay = new - * MonthDay(annualFeeOnMonth, annualFeeOnDay); } - */ - - final boolean withHoldTax = rs.getBoolean("withHoldTax"); - final Long taxGroupId = JdbcSupport.getLong(rs, "taxGroupId"); - final String taxGroupName = rs.getString("taxGroupName"); - TaxGroupData taxGroupData = null; - if (taxGroupId != null) { - taxGroupData = TaxGroupData.lookup(taxGroupId, taxGroupName); - } - - Long clientId = null; - String clientName = null; - if (this.client != null) { - clientId = this.client.getId(); - clientName = this.client.getDisplayName(); - } - - Long groupId = null; - String groupName = null; - if (this.group != null) { - groupId = this.group.getId(); - groupName = this.group.getName(); - } - - final Long fieldOfficerId = null; - final String fieldOfficerName = null; - final SavingsAccountStatusEnumData status = null; - // final LocalDate annualFeeNextDueDate = null; - final SavingsAccountSummaryData summary = null; - final BigDecimal onHoldFunds = null; - final BigDecimal savingsAmountOnHold = null; - - final SavingsAccountSubStatusEnumData subStatus = null; - final String reasonForBlock = null; - final LocalDate lastActiveTransactionDate = null; - final boolean isDormancyTrackingActive = false; - final Integer daysToInactive = null; - final Integer daysToDormancy = null; - final Integer daysToEscheat = null; - - final SavingsAccountApplicationTimelineData timeline = SavingsAccountApplicationTimelineData.templateDefault(); - final EnumOptionData depositType = null; - return SavingsAccountData.instance(null, null, depositType, null, groupId, groupName, clientId, clientName, productId, - productName, fieldOfficerId, fieldOfficerName, status, subStatus, reasonForBlock, timeline, currency, - nominalAnnualIterestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, - interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, - withdrawalFeeForTransfers, summary, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, - maxAllowedLienLimit, lienAllowed, minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft, - minOverdraftForInterestCalculation, withHoldTax, taxGroupData, lastActiveTransactionDate, isDormancyTrackingActive, - daysToInactive, daysToDormancy, daysToEscheat, savingsAmountOnHold); - } - } - @Override public Collection retrieveForLookup(Long clientId, Boolean overdraft) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountTemplateReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountTemplateReadPlatformServiceImpl.java new file mode 100644 index 000000000..3817eb063 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountTemplateReadPlatformServiceImpl.java @@ -0,0 +1,412 @@ +/** + * 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.portfolio.savings.service; + +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.core.domain.JdbcSupport; +import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; +import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; +import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.infrastructure.security.utils.ColumnValidator; +import org.apache.fineract.organisation.monetary.data.CurrencyData; +import org.apache.fineract.organisation.staff.data.StaffData; +import org.apache.fineract.organisation.staff.service.StaffReadPlatformService; +import org.apache.fineract.portfolio.charge.data.ChargeData; +import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService; +import org.apache.fineract.portfolio.charge.util.ConvertChargeDataToSpecificChargeData; +import org.apache.fineract.portfolio.client.data.ClientData; +import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; +import org.apache.fineract.portfolio.group.data.GroupGeneralData; +import org.apache.fineract.portfolio.group.service.GroupReadPlatformService; +import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType; +import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType; +import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType; +import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType; +import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType; +import org.apache.fineract.portfolio.savings.data.SavingsAccountApplicationTimelineData; +import org.apache.fineract.portfolio.savings.data.SavingsAccountChargeData; +import org.apache.fineract.portfolio.savings.data.SavingsAccountData; +import org.apache.fineract.portfolio.savings.data.SavingsAccountStatusEnumData; +import org.apache.fineract.portfolio.savings.data.SavingsAccountSubStatusEnumData; +import org.apache.fineract.portfolio.savings.data.SavingsAccountSummaryData; +import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData; +import org.apache.fineract.portfolio.savings.data.SavingsProductData; +import org.apache.fineract.portfolio.tax.data.TaxGroupData; +import org.apache.fineract.useradministration.domain.AppUser; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.util.CollectionUtils; + +public class SavingsAccountTemplateReadPlatformServiceImpl implements SavingsAccountTemplateReadPlatformService { + + private final PlatformSecurityContext context; + private final JdbcTemplate jdbcTemplate; + private final ClientReadPlatformService clientReadPlatformService; + private final GroupReadPlatformService groupReadPlatformService; + private final SavingsProductReadPlatformService savingsProductReadPlatformService; + private final StaffReadPlatformService staffReadPlatformService; + private final SavingsDropdownReadPlatformService dropdownReadPlatformService; + private final ChargeReadPlatformService chargeReadPlatformService; + + private final EntityDatatableChecksReadService entityDatatableChecksReadService; + + public SavingsAccountTemplateReadPlatformServiceImpl(final PlatformSecurityContext context, final JdbcTemplate jdbcTemplate, + final ClientReadPlatformService clientReadPlatformService, final GroupReadPlatformService groupReadPlatformService, + final SavingsProductReadPlatformService savingProductReadPlatformService, + final StaffReadPlatformService staffReadPlatformService, final SavingsDropdownReadPlatformService dropdownReadPlatformService, + final ChargeReadPlatformService chargeReadPlatformService, + final EntityDatatableChecksReadService entityDatatableChecksReadService, final ColumnValidator columnValidator) { + this.context = context; + this.jdbcTemplate = jdbcTemplate; + this.clientReadPlatformService = clientReadPlatformService; + this.groupReadPlatformService = groupReadPlatformService; + this.savingsProductReadPlatformService = savingProductReadPlatformService; + this.staffReadPlatformService = staffReadPlatformService; + this.dropdownReadPlatformService = dropdownReadPlatformService; + this.chargeReadPlatformService = chargeReadPlatformService; + this.entityDatatableChecksReadService = entityDatatableChecksReadService; + } + + @Override + public SavingsAccountData retrieveTemplate(final Long clientId, final Long groupId, final Long productId, + final boolean staffInSelectedOfficeOnly) { + + final AppUser loggedInUser = this.context.authenticatedUser(); + Long officeId = loggedInUser.getOffice().getId(); + + ClientData client = null; + if (clientId != null) { + client = this.clientReadPlatformService.retrieveOne(clientId); + officeId = client.getOfficeId(); + } + + GroupGeneralData group = null; + if (groupId != null) { + group = this.groupReadPlatformService.retrieveOne(groupId); + officeId = group.getOfficeId(); + } + + final Collection productOptions = this.savingsProductReadPlatformService.retrieveAllForLookup(); + SavingsAccountData template = null; + if (productId != null) { + + final SavingAccountTemplateMapper mapper = new SavingAccountTemplateMapper(client, group); + + final String sql = "select " + mapper.schema() + " where sp.id = ?"; + template = this.jdbcTemplate.queryForObject(sql, mapper, new Object[] { productId }); // NOSONAR + + final Collection interestCompoundingPeriodTypeOptions = this.dropdownReadPlatformService + .retrieveCompoundingInterestPeriodTypeOptions(); + + final Collection interestPostingPeriodTypeOptions = this.dropdownReadPlatformService + .retrieveInterestPostingPeriodTypeOptions(); + + final Collection interestCalculationTypeOptions = this.dropdownReadPlatformService + .retrieveInterestCalculationTypeOptions(); + + final Collection interestCalculationDaysInYearTypeOptions = this.dropdownReadPlatformService + .retrieveInterestCalculationDaysInYearTypeOptions(); + + final Collection lockinPeriodFrequencyTypeOptions = this.dropdownReadPlatformService + .retrieveLockinPeriodFrequencyTypeOptions(); + + final Collection withdrawalFeeTypeOptions = this.dropdownReadPlatformService.retrievewithdrawalFeeTypeOptions(); + + final Collection transactions = null; + final Collection productCharges = this.chargeReadPlatformService.retrieveSavingsProductCharges(productId); + // update charges from Product charges + final Collection charges = fromChargesToSavingsCharges(productCharges); + + final boolean feeChargesOnly = false; + final Collection chargeOptions = this.chargeReadPlatformService + .retrieveSavingsProductApplicableCharges(feeChargesOnly); + + Collection fieldOfficerOptions = null; + + if (officeId != null) { + + if (staffInSelectedOfficeOnly) { + // only bring back loan officers in selected branch/office + final Collection fieldOfficersInBranch = this.staffReadPlatformService + .retrieveAllLoanOfficersInOfficeById(officeId); + + if (!CollectionUtils.isEmpty(fieldOfficersInBranch)) { + fieldOfficerOptions = new ArrayList<>(fieldOfficersInBranch); + } + } else { + // by default bring back all officers in selected + // branch/office as well as officers in office above + // this office + final boolean restrictToLoanOfficersOnly = true; + final Collection loanOfficersInHierarchy = this.staffReadPlatformService + .retrieveAllStaffInOfficeAndItsParentOfficeHierarchy(officeId, restrictToLoanOfficersOnly); + + if (!CollectionUtils.isEmpty(loanOfficersInHierarchy)) { + fieldOfficerOptions = new ArrayList<>(loanOfficersInHierarchy); + } + } + } + + template = SavingsAccountData.withTemplateOptions(template, productOptions, fieldOfficerOptions, + interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions, + interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions, + charges, chargeOptions); + } else { + + String clientName = null; + if (client != null) { + clientName = client.getDisplayName(); + } + + String groupName = null; + if (group != null) { + groupName = group.getName(); + } + + template = SavingsAccountData.withClientTemplate(clientId, clientName, groupId, groupName); + + final Collection fieldOfficerOptions = null; + final Collection interestCompoundingPeriodTypeOptions = null; + final Collection interestPostingPeriodTypeOptions = null; + final Collection interestCalculationTypeOptions = null; + final Collection interestCalculationDaysInYearTypeOptions = null; + final Collection lockinPeriodFrequencyTypeOptions = null; + final Collection withdrawalFeeTypeOptions = null; + + final Collection transactions = null; + final Collection charges = null; + + final boolean feeChargesOnly = false; + final Collection chargeOptions = this.chargeReadPlatformService + .retrieveSavingsProductApplicableCharges(feeChargesOnly); + + template = SavingsAccountData.withTemplateOptions(template, productOptions, fieldOfficerOptions, + interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions, + interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions, + charges, chargeOptions); + } + + final List datatableTemplates = this.entityDatatableChecksReadService.retrieveTemplates(StatusEnum.CREATE.getValue(), + EntityTables.SAVINGS.getName(), productId); + template.setDatatables(datatableTemplates); + + return template; + } + + private static final class SavingAccountTemplateMapper implements RowMapper { + + private final ClientData client; + private final GroupGeneralData group; + + private final String schemaSql; + + SavingAccountTemplateMapper(final ClientData client, final GroupGeneralData group) { + this.client = client; + this.group = group; + + final StringBuilder sqlBuilder = new StringBuilder(400); + sqlBuilder.append("sp.id as productId, sp.name as productName, "); + sqlBuilder.append( + "sp.currency_code as currencyCode, sp.currency_digits as currencyDigits, sp.currency_multiplesof as inMultiplesOf, "); + sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, "); + sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, "); + sqlBuilder.append("sp.nominal_annual_interest_rate as nominalAnnualIterestRate, "); + sqlBuilder.append("sp.interest_compounding_period_enum as interestCompoundingPeriodType, "); + sqlBuilder.append("sp.interest_posting_period_enum as interestPostingPeriodType, "); + sqlBuilder.append("sp.interest_calculation_type_enum as interestCalculationType, "); + sqlBuilder.append("sp.interest_calculation_days_in_year_type_enum as interestCalculationDaysInYearType, "); + sqlBuilder.append("sp.min_required_opening_balance as minRequiredOpeningBalance, "); + sqlBuilder.append("sp.lockin_period_frequency as lockinPeriodFrequency,"); + sqlBuilder.append("sp.lockin_period_frequency_enum as lockinPeriodFrequencyType, "); + // sqlBuilder.append("sp.withdrawal_fee_amount as + // withdrawalFeeAmount,"); + // sqlBuilder.append("sp.withdrawal_fee_type_enum as + // withdrawalFeeTypeEnum, "); + sqlBuilder.append("sp.withdrawal_fee_for_transfer as withdrawalFeeForTransfers, "); + sqlBuilder.append("sp.min_balance_for_interest_calculation as minBalanceForInterestCalculation, "); + sqlBuilder.append("sp.allow_overdraft as allowOverdraft, "); + sqlBuilder.append("sp.overdraft_limit as overdraftLimit, "); + sqlBuilder.append("sp.nominal_annual_interest_rate_overdraft as nominalAnnualInterestRateOverdraft, "); + sqlBuilder.append("sp.min_overdraft_for_interest_calculation as minOverdraftForInterestCalculation, "); + sqlBuilder.append("sp.withhold_tax as withHoldTax,"); + sqlBuilder.append("tg.id as taxGroupId, tg.name as taxGroupName, "); + + // sqlBuilder.append("sp.annual_fee_amount as annualFeeAmount,"); + // sqlBuilder.append("sp.annual_fee_on_month as annualFeeOnMonth, + // "); + // sqlBuilder.append("sp.annual_fee_on_day as annualFeeOnDay "); + sqlBuilder.append("sp.min_required_balance as minRequiredBalance, "); + sqlBuilder.append("sp.enforce_min_required_balance as enforceMinRequiredBalance, "); + sqlBuilder.append("sp.max_allowed_lien_limit as maxAllowedLienLimit, "); + sqlBuilder.append("sp.is_lien_allowed as lienAllowed "); + sqlBuilder.append("from m_savings_product sp "); + sqlBuilder.append("join m_currency curr on curr.code = sp.currency_code "); + sqlBuilder.append("left join m_tax_group tg on tg.id = sp.tax_group_id "); + + this.schemaSql = sqlBuilder.toString(); + } + + public String schema() { + return this.schemaSql; + } + + @Override + public SavingsAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final Long productId = rs.getLong("productId"); + final String productName = rs.getString("productName"); + + final String currencyCode = rs.getString("currencyCode"); + final String currencyName = rs.getString("currencyName"); + final String currencyNameCode = rs.getString("currencyNameCode"); + final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol"); + final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits"); + final Integer inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf"); + final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf, currencyDisplaySymbol, + currencyNameCode); + + final BigDecimal nominalAnnualIterestRate = rs.getBigDecimal("nominalAnnualIterestRate"); + + final EnumOptionData interestCompoundingPeriodType = SavingsEnumerations.compoundingInterestPeriodType( + SavingsCompoundingInterestPeriodType.fromInt(JdbcSupport.getInteger(rs, "interestCompoundingPeriodType"))); + + final EnumOptionData interestPostingPeriodType = SavingsEnumerations.interestPostingPeriodType( + SavingsPostingInterestPeriodType.fromInt(JdbcSupport.getInteger(rs, "interestPostingPeriodType"))); + + final EnumOptionData interestCalculationType = SavingsEnumerations + .interestCalculationType(SavingsInterestCalculationType.fromInt(JdbcSupport.getInteger(rs, "interestCalculationType"))); + + final EnumOptionData interestCalculationDaysInYearType = SavingsEnumerations.interestCalculationDaysInYearType( + SavingsInterestCalculationDaysInYearType.fromInt(JdbcSupport.getInteger(rs, "interestCalculationDaysInYearType"))); + + final BigDecimal minRequiredOpeningBalance = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minRequiredOpeningBalance"); + + final Integer lockinPeriodFrequency = JdbcSupport.getInteger(rs, "lockinPeriodFrequency"); + EnumOptionData lockinPeriodFrequencyType = null; + final Integer lockinPeriodFrequencyTypeValue = JdbcSupport.getInteger(rs, "lockinPeriodFrequencyType"); + if (lockinPeriodFrequencyTypeValue != null) { + final SavingsPeriodFrequencyType lockinPeriodType = SavingsPeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue); + lockinPeriodFrequencyType = SavingsEnumerations.lockinPeriodFrequencyType(lockinPeriodType); + } + + // final BigDecimal withdrawalFeeAmount = + // rs.getBigDecimal("withdrawalFeeAmount"); + + /* + * EnumOptionData withdrawalFeeType = null; final Integer withdrawalFeeTypeValue = + * JdbcSupport.getInteger(rs, "withdrawalFeeTypeEnum"); if (withdrawalFeeTypeValue != null) { + * withdrawalFeeType = SavingsEnumerations.withdrawalFeeType(withdrawalFeeTypeValue); } + */ + final boolean withdrawalFeeForTransfers = rs.getBoolean("withdrawalFeeForTransfers"); + + final boolean allowOverdraft = rs.getBoolean("allowOverdraft"); + final BigDecimal overdraftLimit = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "overdraftLimit"); + final BigDecimal nominalAnnualInterestRateOverdraft = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, + "nominalAnnualInterestRateOverdraft"); + final BigDecimal minOverdraftForInterestCalculation = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, + "minOverdraftForInterestCalculation"); + + final BigDecimal minRequiredBalance = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minRequiredBalance"); + final boolean enforceMinRequiredBalance = rs.getBoolean("enforceMinRequiredBalance"); + final BigDecimal maxAllowedLienLimit = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "maxAllowedLienLimit"); + final boolean lienAllowed = rs.getBoolean("lienAllowed"); + final BigDecimal minBalanceForInterestCalculation = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, + "minBalanceForInterestCalculation"); + + // final BigDecimal annualFeeAmount = + // JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, + // "annualFeeAmount"); + + /* + * MonthDay annualFeeOnMonthDay = null; final Integer annualFeeOnMonth = JdbcSupport.getInteger(rs, + * "annualFeeOnMonth"); final Integer annualFeeOnDay = JdbcSupport.getInteger(rs, "annualFeeOnDay"); if + * (annualFeeAmount != null && annualFeeOnDay != null) { annualFeeOnMonthDay = new + * MonthDay(annualFeeOnMonth, annualFeeOnDay); } + */ + + final boolean withHoldTax = rs.getBoolean("withHoldTax"); + final Long taxGroupId = JdbcSupport.getLong(rs, "taxGroupId"); + final String taxGroupName = rs.getString("taxGroupName"); + TaxGroupData taxGroupData = null; + if (taxGroupId != null) { + taxGroupData = TaxGroupData.lookup(taxGroupId, taxGroupName); + } + + Long clientId = null; + String clientName = null; + if (this.client != null) { + clientId = this.client.getId(); + clientName = this.client.getDisplayName(); + } + + Long groupId = null; + String groupName = null; + if (this.group != null) { + groupId = this.group.getId(); + groupName = this.group.getName(); + } + + final Long fieldOfficerId = null; + final String fieldOfficerName = null; + final SavingsAccountStatusEnumData status = null; + // final LocalDate annualFeeNextDueDate = null; + final SavingsAccountSummaryData summary = null; + final BigDecimal onHoldFunds = null; + final BigDecimal savingsAmountOnHold = null; + + final SavingsAccountSubStatusEnumData subStatus = null; + final String reasonForBlock = null; + final LocalDate lastActiveTransactionDate = null; + final boolean isDormancyTrackingActive = false; + final Integer daysToInactive = null; + final Integer daysToDormancy = null; + final Integer daysToEscheat = null; + + final SavingsAccountApplicationTimelineData timeline = SavingsAccountApplicationTimelineData.templateDefault(); + final EnumOptionData depositType = null; + return SavingsAccountData.instance(null, null, depositType, null, groupId, groupName, clientId, clientName, productId, + productName, fieldOfficerId, fieldOfficerName, status, subStatus, reasonForBlock, timeline, currency, + nominalAnnualIterestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, + interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, + withdrawalFeeForTransfers, summary, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, + maxAllowedLienLimit, lienAllowed, minBalanceForInterestCalculation, onHoldFunds, nominalAnnualInterestRateOverdraft, + minOverdraftForInterestCalculation, withHoldTax, taxGroupData, lastActiveTransactionDate, isDormancyTrackingActive, + daysToInactive, daysToDormancy, daysToEscheat, savingsAmountOnHold); + } + } + + private Collection fromChargesToSavingsCharges(final Collection productCharges) { + final Collection savingsCharges = new ArrayList<>(); + for (final ChargeData chargeData : productCharges) { + final SavingsAccountChargeData savingsCharge = ConvertChargeDataToSpecificChargeData.toSavingsAccountChargeData(chargeData); + savingsCharges.add(savingsCharge); + } + return savingsCharges; + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java index c81ab4eef..19578d472 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/starter/SavingsConfiguration.java @@ -124,6 +124,8 @@ import org.apache.fineract.portfolio.savings.service.SavingsAccountInterestPosti import org.apache.fineract.portfolio.savings.service.SavingsAccountInterestPostingServiceImpl; import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformService; import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformServiceImpl; +import org.apache.fineract.portfolio.savings.service.SavingsAccountTemplateReadPlatformService; +import org.apache.fineract.portfolio.savings.service.SavingsAccountTemplateReadPlatformServiceImpl; import org.apache.fineract.portfolio.savings.service.SavingsAccountWritePlatformService; import org.apache.fineract.portfolio.savings.service.SavingsAccountWritePlatformServiceJpaRepositoryImpl; import org.apache.fineract.portfolio.savings.service.SavingsApplicationProcessWritePlatformService; @@ -335,16 +337,23 @@ public class SavingsConfiguration { @Bean @ConditionalOnMissingBean(SavingsAccountReadPlatformService.class) public SavingsAccountReadPlatformService savingsAccountReadPlatformService(PlatformSecurityContext context, JdbcTemplate jdbcTemplate, - ClientReadPlatformService clientReadPlatformService, GroupReadPlatformService groupReadPlatformService, - SavingsProductReadPlatformService savingProductReadPlatformService, StaffReadPlatformService staffReadPlatformService, - SavingsDropdownReadPlatformService dropdownReadPlatformService, ChargeReadPlatformService chargeReadPlatformService, - EntityDatatableChecksReadService entityDatatableChecksReadService, ColumnValidator columnValidator, SavingsAccountAssembler savingAccountAssembler, PaginationHelper paginationHelper, DatabaseSpecificSQLGenerator sqlGenerator, - SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper) { - return new SavingsAccountReadPlatformServiceImpl(context, jdbcTemplate, clientReadPlatformService, groupReadPlatformService, + SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper, ColumnValidator columnValidator) { + return new SavingsAccountReadPlatformServiceImpl(context, jdbcTemplate, savingAccountAssembler, paginationHelper, columnValidator, + sqlGenerator, savingsAccountRepositoryWrapper); + } + + @Bean + @ConditionalOnMissingBean(SavingsAccountTemplateReadPlatformService.class) + public SavingsAccountTemplateReadPlatformService savingsAccountTemplateReadPlatformService(PlatformSecurityContext context, + JdbcTemplate jdbcTemplate, ClientReadPlatformService clientReadPlatformService, + GroupReadPlatformService groupReadPlatformService, SavingsProductReadPlatformService savingProductReadPlatformService, + StaffReadPlatformService staffReadPlatformService, SavingsDropdownReadPlatformService dropdownReadPlatformService, + ChargeReadPlatformService chargeReadPlatformService, EntityDatatableChecksReadService entityDatatableChecksReadService, + ColumnValidator columnValidator) { + return new SavingsAccountTemplateReadPlatformServiceImpl(context, jdbcTemplate, clientReadPlatformService, groupReadPlatformService, savingProductReadPlatformService, staffReadPlatformService, dropdownReadPlatformService, chargeReadPlatformService, - entityDatatableChecksReadService, columnValidator, savingAccountAssembler, paginationHelper, sqlGenerator, - savingsAccountRepositoryWrapper); + entityDatatableChecksReadService, columnValidator); } @Bean diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableBusinessEventTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableBusinessEventTest.java new file mode 100644 index 000000000..13171e7d7 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableBusinessEventTest.java @@ -0,0 +1,207 @@ +/** + * 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.dataqueries.service; + +import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; +import org.apache.fineract.infrastructure.codes.service.CodeReadPlatformService; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; +import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.domain.ActionContext; +import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant; +import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection; +import org.apache.fineract.infrastructure.core.serialization.DatatableCommandFromApiJsonDeserializer; +import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; +import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; +import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator; +import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver; +import org.apache.fineract.infrastructure.dataqueries.data.DataTableValidator; +import org.apache.fineract.infrastructure.dataqueries.data.ResultsetRowData; +import org.apache.fineract.infrastructure.event.business.domain.BusinessEvent; +import org.apache.fineract.infrastructure.event.business.domain.datatable.DatatableEntryBusinessEvent; +import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.infrastructure.security.utils.ColumnValidator; +import org.apache.fineract.infrastructure.security.utils.DefaultSqlValidator; +import org.apache.fineract.organisation.office.domain.Office; +import org.apache.fineract.portfolio.search.service.SearchUtil; +import org.apache.fineract.useradministration.domain.AppUser; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.PreparedStatementCreator; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.jdbc.support.rowset.SqlRowSet; + +@ExtendWith(MockitoExtension.class) +public class DatatableBusinessEventTest { + + @Mock + private PlatformSecurityContext context; + @Mock + private BusinessEventNotifierService businessEventNotifierService; + @Mock + private JdbcTemplate jdbcTemplate; + @Mock + private GenericDataService genericDataService; + @Mock + private SearchUtil searchUtil; + @Mock + private DatabaseTypeResolver databaseTypeResolver; + @Mock + private DatabaseSpecificSQLGenerator sqlGenerator; + @Mock + private FineractPlatformTenantConnection tenantConnection; + @Mock + private DefaultSqlValidator sqlValidator; + @Mock + private FromJsonHelper fromJsonHelper; + @Mock + private DatatableCommandFromApiJsonDeserializer fromApiJsonDeserializer; + @Mock + private ConfigurationDomainService configurationDomainService; + @Mock + private CodeReadPlatformService codeReadPlatformService; + @Mock + private DataTableValidator dataTableValidator; + @Mock + private ColumnValidator columnValidator; + @Mock + private NamedParameterJdbcTemplate namedParameterJdbcTemplate; + @Mock + private DatatableKeywordGenerator datatableKeywordGenerator; + + @InjectMocks + private ReadWriteNonCoreDataServiceImpl underTest; + + @Captor + private ArgumentCaptor> businessEventArgumentCaptor; + + private static String DATATABLE_NAME = "test_loan_data"; + + @BeforeEach + public void setUp() { + ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null)); + ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT); + ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.parse("2024-01-16"), + BusinessDateType.COB_DATE, LocalDate.parse("2024-01-15")))); + + SqlRowSet sqlRS = Mockito.mock(SqlRowSet.class); + SqlRowSet sqlRSData = Mockito.mock(SqlRowSet.class); + doNothing().when(sqlValidator).validate(anyString()); + when(jdbcTemplate.queryForRowSet(anyString(), anyString())).thenReturn(sqlRS); + when(jdbcTemplate.queryForRowSet(anyString())).thenReturn(sqlRSData); + + when(sqlRS.next()).thenReturn(true).thenReturn(false); + when(sqlRS.getString("application_table_name")).thenReturn("m_loan"); + when(sqlRSData.next()).thenReturn(true).thenReturn(false); + when(sqlRSData.getObject(anyString())).thenReturn(1L); + + AppUser currentUser = Mockito.mock(AppUser.class); + Office office = Mockito.mock(Office.class); + when(context.authenticatedUser()).thenReturn(currentUser); + when(currentUser.getOffice()).thenReturn(office); + when(office.getHierarchy()).thenReturn("."); + } + + @AfterEach + public void tearDown() { + ThreadLocalContextUtil.reset(); + } + + @Test + public void businessEventCreateNewDatatableEntryTest() { + when(jdbcTemplate.update(any(PreparedStatementCreator.class), any(KeyHolder.class))).thenReturn(1); + + underTest.createNewDatatableEntry(DATATABLE_NAME, 1L, createJsonCommand("{}", 1L)); + + ArgumentCaptor> businessEventArgumentCaptor = verifyBusinessEvents(1); + verifyDatatableBusinessEvent(businessEventArgumentCaptor, 0, 1L); + } + + @Test + public void businessEventUpdateDatatableEntryTest() { + List values = new ArrayList<>(); + values.add(1L); + List result = new ArrayList<>(); + result.add(ResultsetRowData.create(values)); + when(genericDataService.fillResultsetRowData(anyString(), any())).thenReturn(result); + + // ResultsetColumnHeaderData resultSet = Mockito.mock(ResultsetColumnHeaderData.class); + // when(searchUtil.getFiltered(columnHeaders, + // ResultsetColumnHeaderData::getIsColumnPrimaryKey)).thenReturn(resultSet); + + underTest.updateDatatableEntryOneToMany(DATATABLE_NAME, 1L, 1L, createJsonCommand("{}", 1L)); + + ArgumentCaptor> businessEventArgumentCaptor = verifyBusinessEvents(1); + verifyDatatableBusinessEvent(businessEventArgumentCaptor, 0, 1L); + } + + @Test + public void businessEventDeleteDatatableEntryTest() { + + underTest.deleteDatatableEntry(DATATABLE_NAME, 1L, 1L, createJsonCommand("{}", 1L)); + + ArgumentCaptor> businessEventArgumentCaptor = verifyBusinessEvents(1); + verifyDatatableBusinessEvent(businessEventArgumentCaptor, 0, 1L); + } + + @NotNull + private ArgumentCaptor> verifyBusinessEvents(int expectedBusinessEvents) { + @SuppressWarnings("unchecked") + ArgumentCaptor> businessEventArgumentCaptor = ArgumentCaptor.forClass(BusinessEvent.class); + verify(businessEventNotifierService, times(expectedBusinessEvents)).notifyPostBusinessEvent(businessEventArgumentCaptor.capture()); + return businessEventArgumentCaptor; + } + + private void verifyDatatableBusinessEvent(ArgumentCaptor> businessEventArgumentCaptor, int index, Long entityId) { + assertTrue(businessEventArgumentCaptor.getAllValues().get(index) instanceof DatatableEntryBusinessEvent); + assertEquals(DATATABLE_NAME, ((DatatableEntryBusinessEvent) businessEventArgumentCaptor.getAllValues().get(index)) + .getDatatableEntryDetails().getDatatableName()); + assertEquals(entityId, ((DatatableEntryBusinessEvent) businessEventArgumentCaptor.getAllValues().get(index)).getAggregateRootId()); + } + + private JsonCommand createJsonCommand(final String jsonCommand, final Long resourceId) { + return new JsonCommand(null, jsonCommand, null, null, null, resourceId, null, null, null, null, null, null, null, null, null, null, + null, null); + } +} diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformService.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformService.java index 4a39f4454..dc36728b5 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformService.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountReadPlatformService.java @@ -40,8 +40,6 @@ public interface SavingsAccountReadPlatformService { SavingsAccountData retrieveOne(Long savingsId); - SavingsAccountData retrieveTemplate(Long clientId, Long groupId, Long productId, boolean staffInSelectedOfficeOnly); - SavingsAccountTransactionData retrieveDepositTransactionTemplate(Long savingsId, DepositAccountType depositAccountType); Collection retrieveAllTransactions(Long savingsId, DepositAccountType depositAccountType); diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountTemplateReadPlatformService.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountTemplateReadPlatformService.java new file mode 100644 index 000000000..d0f6233be --- /dev/null +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountTemplateReadPlatformService.java @@ -0,0 +1,27 @@ +/** + * 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.portfolio.savings.service; + +import org.apache.fineract.portfolio.savings.data.SavingsAccountData; + +public interface SavingsAccountTemplateReadPlatformService { + + SavingsAccountData retrieveTemplate(Long clientId, Long groupId, Long productId, boolean staffInSelectedOfficeOnly); + +}