From 833dddb55151a113c0b99e264e16079a6a026f86 Mon Sep 17 00:00:00 2001 From: Jose Alberto Hernandez Date: Thu, 1 Dec 2022 22:57:26 -0600 Subject: [PATCH] FINERACT-1760: Client by External Id --- .../client/ClientEntityImportHandler.java | 13 +- .../client/ClientPersonImportHandler.java | 13 +- .../populator/AbstractWorkbookPopulator.java | 4 +- .../LoanRepaymentWorkbookPopulator.java | 7 +- .../domain/ConfigurationDomainService.java | 3 + .../domain/ConfigurationDomainServiceJpa.java | 9 + .../organisation/staff/domain/Staff.java | 5 +- ...sReadPlatformServiceJpaRepositoryImpl.java | 13 +- .../client/api/ClientApiConstants.java | 3 + .../client/api/ClientsApiResource.java | 434 ++++++++++++------ .../client/api/ClientsApiResourceSwagger.java | 48 ++ .../portfolio/client/data/ClientData.java | 132 +++--- .../client/domain/AccountNumberGenerator.java | 16 +- .../portfolio/client/domain/Client.java | 306 ++---------- .../client/domain/ClientRepository.java | 15 + .../domain/ClientRepositoryWrapper.java | 16 +- .../exception/ClientNotFoundException.java | 4 +- .../portfolio/client/mapper/ClientMapper.java | 159 +++++++ .../service/ClientReadPlatformService.java | 4 +- .../ClientReadPlatformServiceImpl.java | 399 ++++++++-------- ...WritePlatformServiceJpaRepositoryImpl.java | 220 ++++++++- .../group/api/GroupsApiResource.java | 2 +- .../loanaccount/data/LoanAccountData.java | 6 +- .../guarantor/data/GuarantorData.java | 2 +- .../LoanChargeWritePlatformServiceImpl.java | 2 - .../service/LoanReadPlatformServiceImpl.java | 4 +- .../savings/data/SavingsAccountData.java | 2 +- ...DepositAccountReadPlatformServiceImpl.java | 2 +- ...SavingsAccountReadPlatformServiceImpl.java | 2 +- .../SearchReadPlatformServiceImpl.java | 8 +- gradle.properties | 2 +- .../ClientExternalIdTest.java | 324 +++++++++++++ .../integrationtests/ClientStatusChecker.java | 6 + .../integrationtests/common/ClientHelper.java | 192 +++++--- .../common/GlobalConfigurationHelper.java | 15 + 35 files changed, 1573 insertions(+), 819 deletions(-) create mode 100644 fineract-provider/src/main/java/org/apache/fineract/portfolio/client/mapper/ClientMapper.java create mode 100644 integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientExternalIdTest.java diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/client/ClientEntityImportHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/client/ClientEntityImportHandler.java index dfcd26d4e..104892d03 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/client/ClientEntityImportHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/client/ClientEntityImportHandler.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; +import lombok.AllArgsConstructor; import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; @@ -34,7 +35,9 @@ import org.apache.fineract.infrastructure.bulkimport.data.Count; import org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandler; import org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandlerUtils; import org.apache.fineract.infrastructure.bulkimport.importhandler.helper.DateSerializer; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper; +import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; import org.apache.fineract.portfolio.address.data.AddressData; import org.apache.fineract.portfolio.client.data.ClientData; import org.apache.fineract.portfolio.client.data.ClientNonPersonData; @@ -45,20 +48,16 @@ import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service +@AllArgsConstructor public class ClientEntityImportHandler implements ImportHandler { public static final String SEPARATOR = "-"; private static final Logger LOG = LoggerFactory.getLogger(ClientEntityImportHandler.class); private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; - - @Autowired - public ClientEntityImportHandler(final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { - this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; - } + private final ExternalIdFactory externalIdFactory; @Override public Count process(final Workbook workbook, final String locale, final String dateFormat) { @@ -141,7 +140,7 @@ public class ClientEntityImportHandler implements ImportHandler { ClientNonPersonData clientNonPersonData = ClientNonPersonData.importInstance(incorporationNo, incorporationTill, remarks, mainBusinessId, constitutionId, locale, dateFormat); - String externalId = ImportHandlerUtils.readAsString(ClientEntityConstants.EXTERNAL_ID_COL, row); + ExternalId externalId = externalIdFactory.create(ImportHandlerUtils.readAsString(ClientEntityConstants.EXTERNAL_ID_COL, row)); Boolean active = ImportHandlerUtils.readAsBoolean(ClientEntityConstants.ACTIVE_COL, row); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/client/ClientPersonImportHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/client/ClientPersonImportHandler.java index 3f76565a5..8e23a9ff5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/client/ClientPersonImportHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/client/ClientPersonImportHandler.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; +import lombok.AllArgsConstructor; import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; @@ -34,7 +35,9 @@ import org.apache.fineract.infrastructure.bulkimport.data.Count; import org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandler; import org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandlerUtils; import org.apache.fineract.infrastructure.bulkimport.importhandler.helper.DateSerializer; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper; +import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; import org.apache.fineract.portfolio.address.data.AddressData; import org.apache.fineract.portfolio.client.data.ClientData; import org.apache.poi.ss.usermodel.Cell; @@ -44,20 +47,16 @@ import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service +@AllArgsConstructor public class ClientPersonImportHandler implements ImportHandler { public static final String SEPARATOR = "-"; private static final Logger LOG = LoggerFactory.getLogger(ClientPersonImportHandler.class); private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; - - @Autowired - public ClientPersonImportHandler(final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { - this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; - } + private final ExternalIdFactory externalIdFactory; @Override public Count process(final Workbook workbook, final String locale, final String dateFormat) { @@ -95,7 +94,7 @@ public class ClientPersonImportHandler implements ImportHandler { if (staffId == 0L) { staffId = null; } - String externalId = ImportHandlerUtils.readAsString(ClientPersonConstants.EXTERNAL_ID_COL, row); + ExternalId externalId = externalIdFactory.create(ImportHandlerUtils.readAsString(ClientPersonConstants.EXTERNAL_ID_COL, row)); LocalDate submittedOn = ImportHandlerUtils.readAsDate(ClientPersonConstants.SUBMITTED_ON_COL, row); LocalDate activationDate = ImportHandlerUtils.readAsDate(ClientPersonConstants.ACTIVATION_DATE_COL, row); Boolean active = ImportHandlerUtils.readAsBoolean(ClientPersonConstants.ACTIVE_COL, row); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/AbstractWorkbookPopulator.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/AbstractWorkbookPopulator.java index 244ba125d..f47d29b5f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/AbstractWorkbookPopulator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/AbstractWorkbookPopulator.java @@ -129,8 +129,8 @@ public abstract class AbstractWorkbookPopulator implements WorkbookPopulator { writeDate(activationDateCol, row, outputFormat.format(client.getActivationDate()), dateCellStyle, dateFormat); } if (containsClientExtId) { - if (client.getExternalId() != null) { - writeString(nameCol + 1, row, client.getExternalId()); + if (!client.getExternalId().isEmpty()) { + writeString(nameCol + 1, row, client.getExternalId().getValue()); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/loanrepayment/LoanRepaymentWorkbookPopulator.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/loanrepayment/LoanRepaymentWorkbookPopulator.java index 5ed83bc73..c097ae9ab 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/loanrepayment/LoanRepaymentWorkbookPopulator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/populator/loanrepayment/LoanRepaymentWorkbookPopulator.java @@ -46,12 +46,9 @@ import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.CellRangeAddressList; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class LoanRepaymentWorkbookPopulator extends AbstractWorkbookPopulator { - private static final Logger LOG = LoggerFactory.getLogger(LoanRepaymentWorkbookPopulator.class); private final OfficeSheetPopulator officeSheetPopulator; private final ClientSheetPopulator clientSheetPopulator; private final ExtrasSheetPopulator extrasSheetPopulator; @@ -83,8 +80,8 @@ public class LoanRepaymentWorkbookPopulator extends AbstractWorkbookPopulator { clientIdToClientExternalId = new HashMap<>(); List allclients = clientSheetPopulator.getClients(); for (ClientData client : allclients) { - if (client.getExternalId() != null) { - clientIdToClientExternalId.put(client.getId(), client.getExternalId()); + if (!client.getExternalId().isEmpty()) { + clientIdToClientExternalId.put(client.getId(), client.getExternalId().getValue()); } } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java index e3ac140e4..fe6622325 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java @@ -128,4 +128,7 @@ public interface ConfigurationDomainService { Long retrieveRepaymentOverdueDays(); boolean isExternalIdAutoGenerationEnabled(); + + boolean isAddressEnabled(); + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java index 36fe9e933..5b483251d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java @@ -46,6 +46,8 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService private static final String DAYS_BEFORE_REPAYMENT_IS_DUE = "days-before-repayment-is-due"; private static final String DAYS_AFTER_REPAYMENT_IS_OVERDUE = "days-after-repayment-is-overdue"; private static final String ENABLE_EXTERNAL_ID_AUTO_GENERATION = "enable-auto-generated-external-id"; + private static final String ENABLE_ADDRESS = "Enable-Address"; + private final PermissionRepository permissionRepository; private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository; private final PlatformCacheRepository cacheTypeRepository; @@ -489,4 +491,11 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(ENABLE_EXTERNAL_ID_AUTO_GENERATION); return property.isEnabled(); } + + @Override + public boolean isAddressEnabled() { + final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(ENABLE_ADDRESS); + return property.isEnabled(); + } + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/staff/domain/Staff.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/staff/domain/Staff.java index 258139b0d..3c61b55be 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/staff/domain/Staff.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/staff/domain/Staff.java @@ -28,6 +28,7 @@ import javax.persistence.ManyToOne; import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.UniqueConstraint; +import lombok.Getter; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.EnumOptionData; @@ -35,6 +36,7 @@ import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import org.apache.fineract.infrastructure.documentmanagement.domain.Image; import org.apache.fineract.organisation.office.domain.Office; +@Getter @Entity @Table(name = "m_staff", uniqueConstraints = { @UniqueConstraint(columnNames = { "display_name" }, name = "display_name"), @UniqueConstraint(columnNames = { "external_id" }, name = "external_id_UNIQUE"), @@ -264,7 +266,4 @@ public class Staff extends AbstractPersistableCustom { this.image = image; } - public Image getImage() { - return this.image; - } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java index ff1f30313..0a8ffcae1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java @@ -24,6 +24,7 @@ import java.sql.SQLException; import java.time.LocalDate; import java.util.Collection; import java.util.List; +import lombok.AllArgsConstructor; import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.infrastructure.core.domain.JdbcSupport; import org.apache.fineract.infrastructure.security.utils.ColumnValidator; @@ -45,12 +46,12 @@ import org.apache.fineract.portfolio.savings.service.SavingsEnumerations; import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountApplicationTimelineData; import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountStatusEnumData; import org.apache.fineract.portfolio.shareaccounts.service.SharesEnumerations; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Service; @Service +@AllArgsConstructor public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements AccountDetailsReadPlatformService { private final JdbcTemplate jdbcTemplate; @@ -58,16 +59,6 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou private final GroupReadPlatformService groupReadPlatformService; private final ColumnValidator columnValidator; - @Autowired - public AccountDetailsReadPlatformServiceJpaRepositoryImpl(final ClientReadPlatformService clientReadPlatformService, - final JdbcTemplate jdbcTemplate, final GroupReadPlatformService groupReadPlatformService, - final ColumnValidator columnValidator) { - this.clientReadPlatformService = clientReadPlatformService; - this.jdbcTemplate = jdbcTemplate; - this.groupReadPlatformService = groupReadPlatformService; - this.columnValidator = columnValidator; - } - @Override public AccountSummaryCollectionData retrieveClientAccountDetails(final Long clientId) { // Check if client exists diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientApiConstants.java index 6d0797658..334a12992 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientApiConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientApiConstants.java @@ -185,6 +185,9 @@ public class ClientApiConstants { public static final String clientEntityName = "clients"; + public static final Set CLIENT_ACCOUNTS_DATA_PARAMETERS = new HashSet<>( + Arrays.asList("loanAccounts", "savingsAccounts", "shareAccounts")); + /** * These parameters will match the class level parameters of {@link ClientData}. Where possible, we try to get * response parameters to match those of request parameters. 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 b083761e1..0229590d8 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 @@ -28,11 +28,8 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import java.io.InputStream; import java.time.LocalDate; -import java.util.Arrays; import java.util.Collection; -import java.util.HashSet; import java.util.List; -import java.util.Set; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; @@ -48,7 +45,6 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.StringUtils; import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; @@ -57,15 +53,19 @@ import org.apache.fineract.infrastructure.bulkimport.service.BulkImportWorkbookS import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.UploadRequest; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException; import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer; +import org.apache.fineract.infrastructure.core.service.CommandParameterUtil; +import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.core.service.SearchParameters; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData; import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService; 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.loanaccount.guarantor.data.ObligeeData; import org.apache.fineract.portfolio.loanaccount.guarantor.service.GuarantorReadPlatformService; @@ -111,13 +111,13 @@ public class ClientsApiResource { ClientData clientData = null; context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME); - if (is(commandParam, "close")) { + if (CommandParameterUtil.is(commandParam, "close")) { clientData = clientReadPlatformService.retrieveAllNarrations(ClientApiConstants.CLIENT_CLOSURE_REASON); - } else if (is(commandParam, "acceptTransfer")) { + } else if (CommandParameterUtil.is(commandParam, "acceptTransfer")) { clientData = clientReadPlatformService.retrieveAllNarrations(ClientApiConstants.CLIENT_CLOSURE_REASON); - } else if (is(commandParam, "reject")) { + } else if (CommandParameterUtil.is(commandParam, "reject")) { clientData = clientReadPlatformService.retrieveAllNarrations(ClientApiConstants.CLIENT_REJECT_REASON); - } else if (is(commandParam, "withdraw")) { + } else if (CommandParameterUtil.is(commandParam, "withdraw")) { clientData = clientReadPlatformService.retrieveAllNarrations(ClientApiConstants.CLIENT_WITHDRAW_REASON); } else { clientData = clientReadPlatformService.retrieveTemplate(officeId, staffInSelectedOfficeOnly); @@ -154,18 +154,6 @@ public class ClientsApiResource { orderBy, sortOrder, orphansOnly, false); } - public String retrieveAll(final UriInfo uriInfo, final String sqlSearch, final Long officeId, final String externalId, - final String displayName, final String firstname, final String lastname, final String status, final String hierarchy, - final Integer offset, final Integer limit, final String orderBy, final String sortOrder, final Boolean orphansOnly, - final boolean isSelfUser) { - context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME); - final SearchParameters searchParameters = SearchParameters.forClients(sqlSearch, officeId, externalId, displayName, firstname, - lastname, status, hierarchy, offset, limit, orderBy, sortOrder, orphansOnly, isSelfUser); - final Page clientData = clientReadPlatformService.retrieveAll(searchParameters); - final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); - return toApiJsonSerializer.serialize(settings, clientData, ClientApiConstants.CLIENT_RESPONSE_DATA_PARAMETERS); - } - @GET @Path("{clientId}") @Consumes({ MediaType.APPLICATION_JSON }) @@ -177,22 +165,7 @@ public class ClientsApiResource { public String retrieveOne(@PathParam("clientId") @Parameter(description = "clientId") final Long clientId, @Context final UriInfo uriInfo, @DefaultValue("false") @QueryParam("staffInSelectedOfficeOnly") @Parameter(description = "staffInSelectedOfficeOnly") final boolean staffInSelectedOfficeOnly) { - - context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME); - - final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); - - ClientData clientData = clientReadPlatformService.retrieveOne(clientId); - if (settings.isTemplate()) { - final ClientData templateData = clientReadPlatformService.retrieveTemplate(clientData.getOfficeId(), staffInSelectedOfficeOnly); - clientData = ClientData.templateOnTop(clientData, templateData); - Collection savingAccountOptions = savingsAccountReadPlatformService.retrieveForLookup(clientId, null); - if (savingAccountOptions != null && savingAccountOptions.size() > 0) { - clientData = ClientData.templateWithSavingAccountOptions(clientData, savingAccountOptions); - } - } - - return toApiJsonSerializer.serialize(settings, clientData, ClientApiConstants.CLIENT_RESPONSE_DATA_PARAMETERS); + return retrieveClient(clientId, null, staffInSelectedOfficeOnly, uriInfo); } @POST @@ -231,15 +204,7 @@ public class ClientsApiResource { @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientsApiResourceSwagger.PutClientsClientIdResponse.class))) }) public String update(@Parameter(description = "clientId") @PathParam("clientId") final Long clientId, @Parameter(hidden = true) final String apiRequestBodyAsJson) { - - final CommandWrapper commandRequest = new CommandWrapperBuilder() // - .updateClient(clientId) // - .withJson(apiRequestBodyAsJson) // - .build(); // - - final CommandProcessingResult result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - - return toApiJsonSerializer.serialize(result); + return updateClient(clientId, null, apiRequestBodyAsJson); } @DELETE @@ -251,14 +216,7 @@ public class ClientsApiResource { @ApiResponses({ @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientsApiResourceSwagger.DeleteClientsClientIdResponse.class))) }) public String delete(@PathParam("clientId") @Parameter(description = "clientId") final Long clientId) { - - final CommandWrapper commandRequest = new CommandWrapperBuilder() // - .deleteClient(clientId) // - .build(); // - - final CommandProcessingResult result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - - return toApiJsonSerializer.serialize(result); + return deleteClient(clientId, null); } @POST @@ -301,71 +259,7 @@ public class ClientsApiResource { public String activate(@PathParam("clientId") @Parameter(description = "clientId") final Long clientId, @QueryParam("command") @Parameter(description = "command") final String commandParam, @Parameter(hidden = true) final String apiRequestBodyAsJson) { - - final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson); - - CommandProcessingResult result = null; - CommandWrapper commandRequest = null; - if (is(commandParam, "activate")) { - commandRequest = builder.activateClient(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - } else if (is(commandParam, "assignStaff")) { - commandRequest = builder.assignClientStaff(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "unassignStaff")) { - commandRequest = builder.unassignClientStaff(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "close")) { - commandRequest = builder.closeClient(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - } else if (is(commandParam, "proposeTransfer")) { - commandRequest = builder.proposeClientTransfer(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - } else if (is(commandParam, "proposeAndAcceptTransfer")) { - commandRequest = builder.proposeAndAcceptClientTransfer(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - } else if (is(commandParam, "withdrawTransfer")) { - commandRequest = builder.withdrawClientTransferRequest(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - } else if (is(commandParam, "acceptTransfer")) { - commandRequest = builder.acceptClientTransfer(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - } else if (is(commandParam, "rejectTransfer")) { - commandRequest = builder.rejectClientTransfer(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - } else if (is(commandParam, "updateSavingsAccount")) { - commandRequest = builder.updateClientSavingsAccount(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - } else if (is(commandParam, "reject")) { - commandRequest = builder.rejectClient(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - } else if (is(commandParam, "withdraw")) { - commandRequest = builder.withdrawClient(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - } else if (is(commandParam, "reactivate")) { - commandRequest = builder.reActivateClient(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - } else if (is(commandParam, "undoRejection")) { - commandRequest = builder.undoRejection(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - } else if (is(commandParam, "undoWithdrawal")) { - commandRequest = builder.undoWithdrawal(clientId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - } - - if (result == null) { - throw new UnrecognizedQueryParamException("command", commandParam, - new Object[] { "activate", "unassignStaff", "assignStaff", "close", "proposeTransfer", "withdrawTransfer", - "acceptTransfer", "rejectTransfer", "updateSavingsAccount", "reject", "withdraw", "reactivate" }); - } - - return toApiJsonSerializer.serialize(result); - } - - private boolean is(final String commandParam, final String commandValue) { - return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue); + return applyCommandOverClient(clientId, null, commandParam, apiRequestBodyAsJson); } @GET @@ -380,16 +274,7 @@ public class ClientsApiResource { @ApiResponse(responseCode = "400", description = "Bad Request") }) public String retrieveAssociatedAccounts(@PathParam("clientId") @Parameter(description = "clientId") final Long clientId, @Context final UriInfo uriInfo) { - - context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME); - - final AccountSummaryCollectionData clientAccount = accountDetailsReadPlatformService.retrieveClientAccountDetails(clientId); - - final Set CLIENT_ACCOUNTS_DATA_PARAMETERS = new HashSet<>( - Arrays.asList("loanAccounts", "savingsAccounts", "shareAccounts")); - - final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); - return clientAccountSummaryToApiJsonSerializer.serialize(settings, clientAccount, CLIENT_ACCOUNTS_DATA_PARAMETERS); + return retrieveClientAccounts(clientId, null, uriInfo); } @GET @@ -415,25 +300,302 @@ public class ClientsApiResource { @GET @Path("{clientId}/obligeedetails") - @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Retrieve client obligee details", description = "Retrieve client obligee details") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientsApiResourceSwagger.GetClientObligeeDetailsResponse.class))), + @ApiResponse(responseCode = "400", description = "Bad Request") }) public String retrieveObligeeDetails(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) { - - context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME); - - final List ObligeeList = guarantorReadPlatformService.retrieveObligeeDetails(clientId); - - return toApiJsonSerializer.serialize(ObligeeList); + return retrieveClientObligeeDetails(clientId, null); } @GET @Path("{clientId}/transferproposaldate") + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Retrieve client transfer template", description = "Retrieve client transfer template") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientsApiResourceSwagger.GetClientTransferProposalDateResponse.class))), + @ApiResponse(responseCode = "400", description = "Bad Request") }) + public String retrieveTransferTemplate(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) { + return retrieveClientTransferTemplate(clientId, null); + } + + @GET + @Path("/external-id/{externalId}") + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Retrieve a Client by External Id", description = "Example Requests:\n" + "\n" + "clients/123-456\n" + "\n" + "\n" + + "clients/123-456?template=true\n" + "\n" + "\n" + "clients/123-456?fields=id,displayName,officeName") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientsApiResourceSwagger.GetClientsClientIdResponse.class))) }) + public String retrieveOne(@PathParam("externalId") @Parameter(description = "externalId") final String externalId, + @Context final UriInfo uriInfo, + @DefaultValue("false") @QueryParam("staffInSelectedOfficeOnly") @Parameter(description = "staffInSelectedOfficeOnly") final boolean staffInSelectedOfficeOnly) { + return retrieveClient(null, externalId, staffInSelectedOfficeOnly, uriInfo); + } + + @GET + @Path("/external-id/{externalId}/accounts") + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Retrieve client accounts overview", description = "An example of how a loan portfolio summary can be provided. This is requested in a specific use case of the community application.\n" + + "It is quite reasonable to add resources like this to simplify User Interface development.\n" + "\n" + "Example Requests:\n " + + "\n" + "clients/123-456/accounts\n" + "\n" + "clients/123-456/accounts?fields=loanAccounts,savingsAccounts") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientsApiResourceSwagger.GetClientsClientIdAccountsResponse.class))), + @ApiResponse(responseCode = "400", description = "Bad Request") }) + public String retrieveAssociatedAccounts(@PathParam("externalId") @Parameter(description = "externalId") final String externalId, + @Context final UriInfo uriInfo) { + return retrieveClientAccounts(null, externalId, uriInfo); + } + + @PUT + @Path("/external-id/{externalId}") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) - public String retrieveTransferTemplate(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) { + @Operation(summary = "Update a Client using the External Id", description = "Note: You can update any of the basic attributes of a client (but not its associations) using this API.\n" + + "\n" + + "Changing the relationship between a client and its office is not supported through this API. An API specific to handling transfers of clients between offices is available for the same.\n" + + "\n" + "The relationship between a client and a group must be removed through the Groups API.") + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ClientsApiResourceSwagger.PutClientsClientIdRequest.class))) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientsApiResourceSwagger.PutClientsClientIdResponse.class))) }) + public String update(@Parameter(description = "externalId") @PathParam("externalId") final String externalId, + @Parameter(hidden = true) final String apiRequestBodyAsJson) { + return updateClient(null, externalId, apiRequestBodyAsJson); + } + @POST + @Path("/external-id/{externalId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Activate a Client | Close a Client | Reject a Client | Withdraw a Client | Reactivate a Client | UndoReject a Client | UndoWithdraw a Client | Assign a Staff | Unassign a Staff | Update Default Savings Account | Propose a Client Transfer | Withdraw a Client Transfer | Reject a Client Transfer | Accept a Client Transfer | Propose and Accept a Client Transfer", description = "Activate a Client:\n\n" + + "Clients can be created in a Pending state. This API exists to enable client activation (for when a client becomes an approved member of the financial Institution).\n" + + "\n" + "If the client happens to be already active this API will result in an error.\n\n" + "Close a Client:\n\n" + + "Clients can be closed if they do not have any non-closed loans/savingsAccount. This API exists to close a client .\n" + "\n" + + "If the client have any active loans/savingsAccount this API will result in an error.\n\n" + "Reject a Client:\n\n" + + "Clients can be rejected when client is in pending for activation status.\n" + "\n" + + "If the client is any other status, this API throws an error.\n\n" + "Mandatory Fields: rejectionDate, rejectionReasonId\n\n" + + "Withdraw a Client:\n\n" + "Client applications can be withdrawn when client is in a pending for activation status.\n" + "\n" + + "If the client is any other status, this API throws an error.\n\n" + + "Mandatory Fields: withdrawalDate, withdrawalReasonId\n\n" + + "Reactivate a Client: Clients can be reactivated after they have been closed.\n" + "\n" + + "Trying to reactivate a client in any other state throws an error.\n\n" + "Mandatory Fields: reactivationDate\n\n" + + "UndoReject a Client:\n\n" + "Clients can be reactivated after they have been rejected.\n" + "\n" + + "Trying to reactivate a client in any other state throws an error.\n\n" + "Mandatory Fields: reopenedDate" + + "UndoWithdraw a Client:\n\n" + "Clients can be reactivated after they have been withdrawn.\n" + "\n" + + "Trying to reactivate a client in any other state throws an error.\n\n" + "Mandatory Fields: reopenedDate\n\n" + + "Assign a Staff:\n\n" + "Allows you to assign a Staff for existed Client.\n" + "\n" + + "The selected Staff should belong to the same office (or an officer higher up in the hierarchy) as the Client he manages.\n\n" + + "Unassign a Staff:\n\n" + "Allows you to unassign the Staff assigned to a Client.\n\n" + "Update Default Savings Account:\n\n" + + "Allows you to modify or assign a default savings account for an existing Client.\n" + "\n" + + "The selected savings account should be one among the existing savings account for a particular customer.\n\n" + + "Propose a Client Transfer:\n\n" + "Allows you to propose the transfer of a Client to a different Office.\n\n" + + "Withdraw a Client Transfer:\n\n" + "Allows you to withdraw the proposed transfer of a Client to a different Office.\n" + "\n" + + "Withdrawal can happen only if the destination Branch (to which the transfer was proposed) has not already accepted the transfer proposal\n\n" + + "Reject a Client Transfer:\n\n" + "Allows the Destination Branch to reject the proposed Client Transfer.\n\n" + + "Accept a Client Transfer:\n\n" + "Allows the Destination Branch to accept the proposed Client Transfer.\n" + "\n" + + "The destination branch may also choose to link this client to a group (in which case, any existing active JLG loan of the client is rescheduled to match the meeting frequency of the group) and loan Officer at the time of accepting the transfer\n\n" + + "Propose and Accept a Client Transfer:\n\n" + + "Abstraction over the Propose and Accept Client Transfer API's which enable a user with Data Scope over both the Target and Destination Branches to directly transfer a Client to the destination Office.\n\n" + + "Showing request/response for 'Reject a Client Transfer'") + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ClientsApiResourceSwagger.PostClientsClientIdRequest.class))) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientsApiResourceSwagger.PostClientsClientIdResponse.class))) }) + public String applyCommand(@PathParam("externalId") @Parameter(description = "externalId") final String externalId, + @QueryParam("command") @Parameter(description = "command") final String commandParam, + @Parameter(hidden = true) final String apiRequestBodyAsJson) { + return applyCommandOverClient(null, externalId, commandParam, apiRequestBodyAsJson); + } + + @DELETE + @Path("/external-id/{externalId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Delete a Client", description = "If a client is in Pending state, you are allowed to Delete it. The delete is a 'hard delete' and cannot be recovered from. Once clients become active or have loans or savings associated with them, you cannot delete the client but you may Close the client if they have left the program.") + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = ClientsApiResourceSwagger.DeleteClientsClientIdRequest.class))) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientsApiResourceSwagger.DeleteClientsClientIdResponse.class))) }) + public String delete(@PathParam("externalId") @Parameter(description = "externalId") final String externalId) { + return deleteClient(null, externalId); + } + + @GET + @Path("/external-id/{externalId}/obligeedetails") + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Retrieve client obligee details", description = "Retrieve client obligee details using the client external Id") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientsApiResourceSwagger.GetClientObligeeDetailsResponse.class))), + @ApiResponse(responseCode = "400", description = "Bad Request") }) + public String retrieveObligeeDetails(@PathParam("externalId") final String externalId, @Context final UriInfo uriInfo) { + return retrieveClientObligeeDetails(null, externalId); + } + + @GET + @Path("/external-id/{externalId}/transferproposaldate") + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Retrieve client transfer template", description = "Retrieve client transfer template using the client external Id") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientsApiResourceSwagger.GetClientTransferProposalDateResponse.class))), + @ApiResponse(responseCode = "400", description = "Bad Request") }) + public String retrieveTransferTemplate(@PathParam("externalId") final String externalId, @Context final UriInfo uriInfo) { + return retrieveClientTransferTemplate(null, externalId); + } + + public String retrieveAll(final UriInfo uriInfo, final String sqlSearch, final Long officeId, final String externalId, + final String displayName, final String firstname, final String lastname, final String status, final String hierarchy, + final Integer offset, final Integer limit, final String orderBy, final String sortOrder, final Boolean orphansOnly, + final boolean isSelfUser) { context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME); + final SearchParameters searchParameters = SearchParameters.forClients(sqlSearch, officeId, externalId, displayName, firstname, + lastname, status, hierarchy, offset, limit, orderBy, sortOrder, orphansOnly, isSelfUser); + final Page clientData = clientReadPlatformService.retrieveAll(searchParameters); + final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return toApiJsonSerializer.serialize(settings, clientData, ClientApiConstants.CLIENT_RESPONSE_DATA_PARAMETERS); + } + + 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); + clientData = ClientData.templateOnTop(clientData, templateData); + Collection savingAccountOptions = savingsAccountReadPlatformService.retrieveForLookup(clientId, null); + if (savingAccountOptions != null && savingAccountOptions.size() > 0) { + clientData = ClientData.templateWithSavingAccountOptions(clientData, savingAccountOptions); + } + } + return clientData; + } + + private Long getResolvedClientId(final Long clientId, final ExternalId clientExternalId) { + Long resolvedClientId = clientId; + if (resolvedClientId == null) { + clientExternalId.throwExceptionIfEmpty(); + resolvedClientId = clientReadPlatformService.retrieveClientIdByExternalId(clientExternalId); + if (resolvedClientId == null) { + throw new ClientNotFoundException(resolvedClientId); + } + } + return resolvedClientId; + } + + private CommandWrapper evaluateCommand(final Long clientId, final String commandParam, final CommandWrapperBuilder builder) { + CommandWrapper commandRequest = null; + if (CommandParameterUtil.is(commandParam, "activate")) { + commandRequest = builder.activateClient(clientId).build(); + } else if (CommandParameterUtil.is(commandParam, "assignStaff")) { + commandRequest = builder.assignClientStaff(clientId).build(); + } else if (CommandParameterUtil.is(commandParam, "unassignStaff")) { + commandRequest = builder.unassignClientStaff(clientId).build(); + } else if (CommandParameterUtil.is(commandParam, "close")) { + commandRequest = builder.closeClient(clientId).build(); + } else if (CommandParameterUtil.is(commandParam, "proposeTransfer")) { + commandRequest = builder.proposeClientTransfer(clientId).build(); + } else if (CommandParameterUtil.is(commandParam, "proposeAndAcceptTransfer")) { + commandRequest = builder.proposeAndAcceptClientTransfer(clientId).build(); + } else if (CommandParameterUtil.is(commandParam, "withdrawTransfer")) { + commandRequest = builder.withdrawClientTransferRequest(clientId).build(); + } else if (CommandParameterUtil.is(commandParam, "acceptTransfer")) { + commandRequest = builder.acceptClientTransfer(clientId).build(); + } else if (CommandParameterUtil.is(commandParam, "rejectTransfer")) { + commandRequest = builder.rejectClientTransfer(clientId).build(); + } else if (CommandParameterUtil.is(commandParam, "updateSavingsAccount")) { + commandRequest = builder.updateClientSavingsAccount(clientId).build(); + } else if (CommandParameterUtil.is(commandParam, "reject")) { + commandRequest = builder.rejectClient(clientId).build(); + } else if (CommandParameterUtil.is(commandParam, "withdraw")) { + commandRequest = builder.withdrawClient(clientId).build(); + } else if (CommandParameterUtil.is(commandParam, "reactivate")) { + commandRequest = builder.reActivateClient(clientId).build(); + } else if (CommandParameterUtil.is(commandParam, "undoRejection")) { + commandRequest = builder.undoRejection(clientId).build(); + } else if (CommandParameterUtil.is(commandParam, "undoWithdrawal")) { + commandRequest = builder.undoWithdrawal(clientId).build(); + } + + if (commandRequest == null) { + throw new UnrecognizedQueryParamException("command", commandParam, + new Object[] { "activate", "unassignStaff", "assignStaff", "close", "proposeTransfer", "withdrawTransfer", + "acceptTransfer", "rejectTransfer", "updateSavingsAccount", "reject", "withdraw", "reactivate" }); + } + + return commandRequest; + } + + private String retrieveClient(Long clientId, final String externalId, final boolean staffInSelectedOfficeOnly, final UriInfo uriInfo) { + context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME); + + ExternalId clientExternalId = ExternalIdFactory.produce(externalId); + clientId = getResolvedClientId(clientId, clientExternalId); + + final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + final ClientData clientData = retrieveClientData(clientId, staffInSelectedOfficeOnly, settings.isTemplate()); + return toApiJsonSerializer.serialize(settings, clientData, ClientApiConstants.CLIENT_RESPONSE_DATA_PARAMETERS); + } + + private String updateClient(Long clientId, final String externalId, final String jsonPayload) { + ExternalId clientExternalId = ExternalIdFactory.produce(externalId); + clientId = getResolvedClientId(clientId, clientExternalId); + + final CommandWrapper commandRequest = new CommandWrapperBuilder() // + .updateClient(clientId) // + .withJson(jsonPayload) // + .build(); // + + final CommandProcessingResult result = commandsSourceWritePlatformService.logCommandSource(commandRequest); + return toApiJsonSerializer.serialize(result); + } + + private String deleteClient(Long clientId, final String externalId) { + ExternalId clientExternalId = ExternalIdFactory.produce(externalId); + clientId = getResolvedClientId(clientId, clientExternalId); + + final CommandWrapper commandRequest = new CommandWrapperBuilder() // + .deleteClient(clientId) // + .build(); // + + final CommandProcessingResult result = commandsSourceWritePlatformService.logCommandSource(commandRequest); + return toApiJsonSerializer.serialize(result); + } + + private String retrieveClientAccounts(Long clientId, final String externalId, final UriInfo uriInfo) { + context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME); + ExternalId clientExternalId = ExternalIdFactory.produce(externalId); + clientId = getResolvedClientId(clientId, clientExternalId); + + final AccountSummaryCollectionData clientAccount = accountDetailsReadPlatformService.retrieveClientAccountDetails(clientId); + + final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return clientAccountSummaryToApiJsonSerializer.serialize(settings, clientAccount, + ClientApiConstants.CLIENT_ACCOUNTS_DATA_PARAMETERS); + } + + private String applyCommandOverClient(Long clientId, final String externalId, final String command, final String jsonPayload) { + ExternalId clientExternalId = ExternalIdFactory.produce(externalId); + clientId = getResolvedClientId(clientId, clientExternalId); + + final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(jsonPayload); + final CommandWrapper commandRequest = evaluateCommand(clientId, command, builder); + CommandProcessingResult result = commandsSourceWritePlatformService.logCommandSource(commandRequest); + return toApiJsonSerializer.serialize(result); + } + + private String retrieveClientObligeeDetails(Long clientId, final String externalId) { + context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME); + + ExternalId clientExternalId = ExternalIdFactory.produce(externalId); + clientId = getResolvedClientId(clientId, clientExternalId); + + final List ObligeeList = guarantorReadPlatformService.retrieveObligeeDetails(clientId); + return toApiJsonSerializer.serialize(ObligeeList); + } + + private String retrieveClientTransferTemplate(Long clientId, final String externalId) { + context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME); + + ExternalId clientExternalId = ExternalIdFactory.produce(externalId); + clientId = getResolvedClientId(clientId, clientExternalId); + final LocalDate transferDate = clientReadPlatformService.retrieveClientTransferProposalDate(clientId); return toApiJsonSerializer.serialize(transferDate); } + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResourceSwagger.java index 799f69706..a8a237b11 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResourceSwagger.java @@ -252,6 +252,8 @@ final class ClientsApiResourceSwagger { public List groups; @Schema(example = "test@test.com") public String emailAddress; + @Schema(example = "123") + public String externalId; } @Schema(description = "PostClientsRequest") @@ -341,6 +343,8 @@ final class ClientsApiResourceSwagger { public Long clientId; @Schema(example = "2") public Integer resourceId; + @Schema(example = "123-456") + public String resourceExternalId; } @Schema(description = "PutClientsClientIdRequest") @@ -350,6 +354,8 @@ final class ClientsApiResourceSwagger { @Schema(example = "786444UUUYYH7") public String externalId; + @Schema(example = "123-456") + public String resourceExternalId; } @Schema(description = "PutClientsClientIdResponse") @@ -363,6 +369,8 @@ final class ClientsApiResourceSwagger { public Integer clientId; @Schema(example = "1") public Integer resourceId; + @Schema(example = "123-456") + public String resourceExternalId; public PutClientsClientIdRequest changes; } @@ -383,6 +391,8 @@ final class ClientsApiResourceSwagger { public Integer clientId; @Schema(example = "3") public Integer resourceId; + @Schema(example = "123-456") + public String resourceExternalId; } @Schema(description = "PostClientsClientIdRequest") @@ -409,6 +419,44 @@ final class ClientsApiResourceSwagger { public Integer clientId; @Schema(example = "2") public Integer resourceId; + @Schema(example = "123-456") + public String resourceExternalId; + } + + @Schema(description = "GetClientTransferProposalDateResponse") + public static final class GetClientTransferProposalDateResponse { + + @Schema(example = "[2013, 1, 1]") + public LocalDate proposedTransferDate; + } + + @Schema(description = "GetClientObligeeDetailsResponse") + public static final class GetClientObligeeDetailsResponse { + + static final class GetObligeeData { + + private GetObligeeData() {} + + @Schema(example = "John") + public String firstName; + @Schema(example = "Doe") + public String lastName; + @Schema(example = "John Doe") + public String displayName; + @Schema(example = "00000002") + public String accountNumber; + @Schema(example = "12000.00") + public Double loanAmount; + @Schema(example = "100.00") + public Double guaranteeAmount; + @Schema(example = "10000.00") + public Double amountReleased; + @Schema(example = "1000.00") + public Double amountTransferred; + + } + + public Set obligees; } @Schema(description = "GetClientsClientIdAccountsResponse") diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientData.java index 054d65184..4bf87374f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/data/ClientData.java @@ -24,17 +24,19 @@ import java.util.Collection; import java.util.List; import java.util.Set; import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.builder.CompareToBuilder; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; import org.apache.fineract.organisation.office.data.OfficeData; import org.apache.fineract.organisation.staff.data.StaffData; import org.apache.fineract.portfolio.address.data.AddressData; -import org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollateralManagement; import org.apache.fineract.portfolio.group.data.GroupGeneralData; import org.apache.fineract.portfolio.savings.data.SavingsAccountData; import org.apache.fineract.portfolio.savings.data.SavingsProductData; @@ -42,74 +44,76 @@ import org.apache.fineract.portfolio.savings.data.SavingsProductData; /** * Immutable data object representing client data. */ +@NoArgsConstructor @Getter +@Setter public final class ClientData implements Comparable, Serializable { - private final Long id; - private final String accountNo; - private final String externalId; + private Long id; + private String accountNo; + private ExternalId externalId; - private final EnumOptionData status; - private final CodeValueData subStatus; + private EnumOptionData status; + private CodeValueData subStatus; - private final Boolean active; - private final LocalDate activationDate; + private Boolean active; + private LocalDate activationDate; - private final String firstname; - private final String middlename; - private final String lastname; - private final String fullname; - private final String displayName; - private final String mobileNo; - private final String emailAddress; - private final LocalDate dateOfBirth; - private final CodeValueData gender; - private final CodeValueData clientType; - private final CodeValueData clientClassification; - private final Boolean isStaff; + private String firstname; + private String middlename; + private String lastname; + private String fullname; + private String displayName; + private String mobileNo; + private String emailAddress; + private LocalDate dateOfBirth; + private CodeValueData gender; + private CodeValueData clientType; + private CodeValueData clientClassification; + private Boolean isStaff; - private final Long officeId; - private final String officeName; - private final Long transferToOfficeId; - private final String transferToOfficeName; + private Long officeId; + private String officeName; + private Long transferToOfficeId; + private String transferToOfficeName; - private final Long imageId; - private final Boolean imagePresent; - private final Long staffId; - private final String staffName; - private final ClientTimelineData timeline; + private Long imageId; + private Boolean imagePresent; + private Long staffId; + private String staffName; + private ClientTimelineData timeline; - private final Long savingsProductId; - private final String savingsProductName; + private Long savingsProductId; + private String savingsProductName; - private final Long savingsAccountId; - private final EnumOptionData legalForm; - private final Set clientCollateralManagements; + private Long savingsAccountId; + private EnumOptionData legalForm; + private Set clientCollateralManagements; // associations - private final Collection groups; + private Collection groups; // template - private final Collection officeOptions; - private final Collection staffOptions; - private final Collection narrations; - private final Collection savingProductOptions; - private final Collection savingAccountOptions; - private final Collection genderOptions; - private final Collection clientTypeOptions; - private final Collection clientClassificationOptions; - private final Collection clientNonPersonConstitutionOptions; - private final Collection clientNonPersonMainBusinessLineOptions; - private final List clientLegalFormOptions; - private final ClientFamilyMembersData familyMemberOptions; + private Collection officeOptions; + private Collection staffOptions; + private Collection narrations; + private Collection savingProductOptions; + private Collection savingAccountOptions; + private Collection genderOptions; + private Collection clientTypeOptions; + private Collection clientClassificationOptions; + private Collection clientNonPersonConstitutionOptions; + private Collection clientNonPersonMainBusinessLineOptions; + private List clientLegalFormOptions; + private ClientFamilyMembersData familyMemberOptions; - private final ClientNonPersonData clientNonPersonDetails; + private ClientNonPersonData clientNonPersonDetails; - private final Collection address; + private Collection address; - private final Boolean isAddressEnabled; + private Boolean isAddressEnabled; - private final List datatables; + private List datatables; // import fields private transient Integer rowIndex; @@ -123,7 +127,7 @@ public final class ClientData implements Comparable, Serializable { public static ClientData importClientEntityInstance(Long legalFormId, Integer rowIndex, String fullname, Long officeId, Long clientTypeId, Long clientClassificationId, Long staffId, Boolean active, LocalDate activationDate, - LocalDate submittedOnDate, String externalId, LocalDate dateOfBirth, String mobileNo, + LocalDate submittedOnDate, ExternalId externalId, LocalDate dateOfBirth, String mobileNo, ClientNonPersonData clientNonPersonDetails, Collection address, String locale, String dateFormat) { return new ClientData(legalFormId, rowIndex, fullname, null, null, null, submittedOnDate, activationDate, active, externalId, officeId, staffId, mobileNo, dateOfBirth, clientTypeId, null, clientClassificationId, null, address, clientNonPersonDetails, @@ -196,7 +200,7 @@ public final class ClientData implements Comparable, Serializable { } public static ClientData importClientPersonInstance(Long legalFormId, Integer rowIndex, String firstname, String lastname, - String middlename, LocalDate submittedOn, LocalDate activationDate, Boolean active, String externalId, Long officeId, + String middlename, LocalDate submittedOn, LocalDate activationDate, Boolean active, ExternalId externalId, Long officeId, Long staffId, String mobileNo, LocalDate dob, Long clientTypeId, Long genderId, Long clientClassificationId, Boolean isStaff, Collection address, String locale, String dateFormat) { @@ -210,7 +214,7 @@ public final class ClientData implements Comparable, Serializable { } private ClientData(Long legalFormId, Integer rowIndex, String fullname, String firstname, String lastname, String middlename, - LocalDate submittedOn, LocalDate activationDate, Boolean active, String externalId, Long officeId, Long staffId, + LocalDate submittedOn, LocalDate activationDate, Boolean active, ExternalId externalId, Long officeId, Long staffId, String mobileNo, LocalDate dob, Long clientTypeId, Long genderId, Long clientClassificationId, Boolean isStaff, Collection address, ClientNonPersonData clientNonPersonDetails, String locale, String dateFormat) { this.rowIndex = rowIndex; @@ -293,7 +297,7 @@ public final class ClientData implements Comparable, Serializable { final String lastname = null; final String fullname = null; final String displayName = null; - final String externalId = null; + final ExternalId externalId = ExternalId.empty(); final String mobileNo = null; final String emailAddress = null; final LocalDate dateOfBirth = null; @@ -379,7 +383,7 @@ public final class ClientData implements Comparable, Serializable { final Long transferToOfficeId = null; final String transferToOfficeName = null; - final String externalId = null; + final ExternalId externalId = ExternalId.empty(); final String mobileNo = null; final String emailAddress = null; final LocalDate dateOfBirth = null; @@ -432,7 +436,7 @@ public final class ClientData implements Comparable, Serializable { final String middlename = null; final String lastname = null; final String fullname = null; - final String externalId = null; + final ExternalId externalId = ExternalId.empty(); final String mobileNo = null; final String emailAddress = null; final LocalDate dateOfBirth = null; @@ -483,7 +487,7 @@ public final class ClientData implements Comparable, Serializable { public static ClientData instance(final String accountNo, final EnumOptionData status, final CodeValueData subStatus, final Long officeId, final String officeName, final Long transferToOfficeId, final String transferToOfficeName, final Long id, final String firstname, final String middlename, final String lastname, final String fullname, final String displayName, - final String externalId, final String mobileNo, final String emailAddress, final LocalDate dateOfBirth, + final ExternalId externalId, final String mobileNo, final String emailAddress, final LocalDate dateOfBirth, final CodeValueData gender, final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName, final ClientTimelineData timeline, final Long savingsProductId, final String savingsProductName, final Long savingsAccountId, final CodeValueData clientType, final CodeValueData clientClassification, final EnumOptionData legalForm, @@ -501,7 +505,6 @@ public final class ClientData implements Comparable, Serializable { final Collection clientNonPersonMainBusinessLineOptions = null; final List clientLegalFormOptions = null; final ClientFamilyMembersData familyMemberOptions = null; - final Collection clientCollateralManagements = null; return new ClientData(accountNo, status, subStatus, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname, middlename, lastname, fullname, displayName, externalId, mobileNo, emailAddress, dateOfBirth, gender, activationDate, imageId, staffId, staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline, @@ -514,7 +517,7 @@ public final class ClientData implements Comparable, Serializable { private ClientData(final String accountNo, final EnumOptionData status, final CodeValueData subStatus, final Long officeId, final String officeName, final Long transferToOfficeId, final String transferToOfficeName, final Long id, final String firstname, final String middlename, final String lastname, final String fullname, final String displayName, - final String externalId, final String mobileNo, final String emailAddress, final LocalDate dateOfBirth, + final ExternalId externalId, final String mobileNo, final String emailAddress, final LocalDate dateOfBirth, final CodeValueData gender, final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName, final Collection allowedOffices, final Collection groups, final Collection staffOptions, final Collection narrations, @@ -546,7 +549,7 @@ public final class ClientData implements Comparable, Serializable { this.lastname = StringUtils.defaultIfEmpty(lastname, null); this.fullname = StringUtils.defaultIfEmpty(fullname, null); this.displayName = StringUtils.defaultIfEmpty(displayName, null); - this.externalId = StringUtils.defaultIfEmpty(externalId, null); + this.externalId = externalId; this.mobileNo = StringUtils.defaultIfEmpty(mobileNo, null); this.emailAddress = StringUtils.defaultIfEmpty(emailAddress, null); this.activationDate = activationDate; @@ -596,6 +599,13 @@ public final class ClientData implements Comparable, Serializable { this.clientCollateralManagements = clientCollateralManagements; } + public ExternalId getExternalId() { + if (this.externalId == null) { + return ExternalId.empty(); + } + return this.externalId; + } + @Override public int compareTo(final ClientData obj) { if (obj == null) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/AccountNumberGenerator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/AccountNumberGenerator.java index 0a8cbae74..3ebe684ba 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/AccountNumberGenerator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/AccountNumberGenerator.java @@ -21,11 +21,11 @@ package org.apache.fineract.portfolio.client.domain; import java.math.BigInteger; import java.util.HashMap; import java.util.Map; +import lombok.AllArgsConstructor; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormat; import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatEnumerations.AccountNumberPrefixType; -import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatRepository; import org.apache.fineract.infrastructure.codes.domain.CodeValue; import org.apache.fineract.infrastructure.configuration.data.GlobalConfigurationPropertyData; import org.apache.fineract.infrastructure.configuration.service.ConfigurationReadPlatformService; @@ -35,7 +35,6 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository; import org.apache.fineract.portfolio.savings.domain.SavingsAccount; import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepository; import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccount; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** @@ -43,6 +42,7 @@ import org.springframework.stereotype.Component; * it ensuring the identifier is always of a given maxLength. */ @Component +@AllArgsConstructor public class AccountNumberGenerator { private static final int maxLength = 9; @@ -55,23 +55,11 @@ public class AccountNumberGenerator { private static final String SAVINGS_PRODUCT_SHORT_NAME = "savingsProductShortName"; private static final String SHARE_PRODUCT_SHORT_NAME = "sharesProductShortName"; private static final String PREFIX_SHORT_NAME = "prefixShortName"; - private final AccountNumberFormatRepository accountNumberFormatRepository; private final ConfigurationReadPlatformService configurationReadPlatformService; private final ClientRepository clientRepository; private final LoanRepository loanRepository; private final SavingsAccountRepository savingsAccountRepository; - @Autowired - public AccountNumberGenerator(final ConfigurationReadPlatformService configurationReadPlatformService, - final AccountNumberFormatRepository accountNumberFormatRepository, final ClientRepository clientRepository, - final LoanRepository loanRepository, final SavingsAccountRepository savingsAccountRepository) { - this.configurationReadPlatformService = configurationReadPlatformService; - this.accountNumberFormatRepository = accountNumberFormatRepository; - this.clientRepository = clientRepository; - this.loanRepository = loanRepository; - this.savingsAccountRepository = savingsAccountRepository; - } - public String generate(Client client, AccountNumberFormat accountNumberFormat) { Map propertyMap = new HashMap<>(); propertyMap.put(ID, client.getId().toString()); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/Client.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/Client.java index bb5429663..6cca1cc6a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/Client.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/Client.java @@ -22,9 +22,7 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; @@ -39,12 +37,14 @@ import javax.persistence.OneToOne; import javax.persistence.Table; import javax.persistence.Transient; import javax.persistence.UniqueConstraint; +import lombok.Getter; +import lombok.Setter; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.codes.domain.CodeValue; -import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.documentmanagement.domain.Image; @@ -57,6 +57,8 @@ import org.apache.fineract.portfolio.group.domain.Group; import org.apache.fineract.useradministration.domain.AppUser; @Entity +@Getter +@Setter @Table(name = "m_client", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "account_no_UNIQUE"), // @UniqueConstraint(columnNames = { "mobile_no" }, name = "mobile_no_UNIQUE") }) public class Client extends AbstractAuditableWithUTCDateTimeCustom { @@ -117,7 +119,7 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { private boolean isStaff; @Column(name = "external_id", length = 100, unique = true) - private String externalId; + private ExternalId externalId; @Column(name = "date_of_birth") private LocalDate dateOfBirth; @@ -224,56 +226,22 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { @OneToMany(mappedBy = "client", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) private Set clientCollateralManagements = new HashSet<>(); - public static Client createNew(final AppUser currentUser, final Office clientOffice, final Group clientParentGroup, final Staff staff, - final Long savingsProductId, final CodeValue gender, final CodeValue clientType, final CodeValue clientClassification, - final Integer legalForm, final JsonCommand command) { - - final String accountNo = command.stringValueOfParameterNamed(ClientApiConstants.accountNoParamName); - final String externalId = command.stringValueOfParameterNamed(ClientApiConstants.externalIdParamName); - final String mobileNo = command.stringValueOfParameterNamed(ClientApiConstants.mobileNoParamName); - final String emailAddress = command.stringValueOfParameterNamed(ClientApiConstants.emailAddressParamName); - - final String firstname = command.stringValueOfParameterNamed(ClientApiConstants.firstnameParamName); - final String middlename = command.stringValueOfParameterNamed(ClientApiConstants.middlenameParamName); - final String lastname = command.stringValueOfParameterNamed(ClientApiConstants.lastnameParamName); - final String fullname = command.stringValueOfParameterNamed(ClientApiConstants.fullnameParamName); - - final boolean isStaff = command.booleanPrimitiveValueOfParameterNamed(ClientApiConstants.isStaffParamName); - - final LocalDate dataOfBirth = command.localDateValueOfParameterNamed(ClientApiConstants.dateOfBirthParamName); - - ClientStatus status = ClientStatus.PENDING; - boolean active = false; - if (command.hasParameter("active")) { - active = command.booleanPrimitiveValueOfParameterNamed(ClientApiConstants.activeParamName); - } - - LocalDate activationDate = null; - LocalDate officeJoiningDate = null; - if (active) { - status = ClientStatus.ACTIVE; - activationDate = command.localDateValueOfParameterNamed(ClientApiConstants.activationDateParamName); - officeJoiningDate = activationDate; - } - - LocalDate submittedOnDate = DateUtils.getBusinessLocalDate(); - if (command.hasParameter(ClientApiConstants.submittedOnDateParamName)) { - submittedOnDate = command.localDateValueOfParameterNamed(ClientApiConstants.submittedOnDateParamName); - } - if (active && submittedOnDate.isAfter(activationDate)) { - submittedOnDate = activationDate; - } - final Long savingsAccountId = null; - return new Client(currentUser, status, clientOffice, clientParentGroup, accountNo, firstname, middlename, lastname, fullname, + public static Client instance(final AppUser currentUser, final ClientStatus status, final Office office, final Group clientParentGroup, + final String accountNo, final String firstname, final String middlename, final String lastname, final String fullname, + final LocalDate activationDate, final LocalDate officeJoiningDate, final ExternalId externalId, final String mobileNo, + final String emailAddress, final Staff staff, final LocalDate submittedOnDate, final Long savingsProductId, + final Long savingsAccountId, final LocalDate dateOfBirth, final CodeValue gender, final CodeValue clientType, + final CodeValue clientClassification, final Integer legalForm, final Boolean isStaff) { + return new Client(currentUser, status, office, clientParentGroup, accountNo, firstname, middlename, lastname, fullname, activationDate, officeJoiningDate, externalId, mobileNo, emailAddress, staff, submittedOnDate, savingsProductId, - savingsAccountId, dataOfBirth, gender, clientType, clientClassification, legalForm, isStaff); + savingsAccountId, dateOfBirth, gender, clientType, clientClassification, legalForm, isStaff); } protected Client() {} private Client(final AppUser currentUser, final ClientStatus status, final Office office, final Group clientParentGroup, final String accountNo, final String firstname, final String middlename, final String lastname, final String fullname, - final LocalDate activationDate, final LocalDate officeJoiningDate, final String externalId, final String mobileNo, + final LocalDate activationDate, final LocalDate officeJoiningDate, final ExternalId externalId, final String mobileNo, final String emailAddress, final Staff staff, final LocalDate submittedOnDate, final Long savingsProductId, final Long savingsAccountId, final LocalDate dateOfBirth, final CodeValue gender, final CodeValue clientType, final CodeValue clientClassification, final Integer legalForm, final Boolean isStaff) { @@ -289,9 +257,7 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { this.status = status.getValue(); this.office = office; - if (StringUtils.isNotBlank(externalId)) { - this.externalId = externalId.trim(); - } + this.externalId = externalId; if (StringUtils.isNotBlank(mobileNo)) { this.mobileNo = mobileNo.trim(); @@ -358,7 +324,7 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { } - private void validateUpdate() { + public void validateUpdate() { final List dataValidationErrors = new ArrayList<>(); // Not validating name parts while update request as firstname/lastname // can be along with fullname @@ -380,10 +346,6 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { this.accountNumberRequiresAutoGeneration = accountNumberRequiresAutoGeneration; } - public boolean identifiedBy(final String identifier) { - return identifier.equalsIgnoreCase(this.externalId); - } - public boolean identifiedBy(final Long clientId) { return getId().equals(clientId); } @@ -463,156 +425,6 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { return ClientStatus.fromInt(this.status).isWithdrawn(); } - public Map update(final JsonCommand command) { - - final Map actualChanges = new LinkedHashMap<>(9); - - if (command.isChangeInIntegerParameterNamed(ClientApiConstants.statusParamName, this.status)) { - final Integer newValue = command.integerValueOfParameterNamed(ClientApiConstants.statusParamName); - actualChanges.put(ClientApiConstants.statusParamName, ClientEnumerations.status(newValue)); - this.status = ClientStatus.fromInt(newValue).getValue(); - } - - if (command.isChangeInStringParameterNamed(ClientApiConstants.accountNoParamName, this.accountNumber)) { - final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.accountNoParamName); - actualChanges.put(ClientApiConstants.accountNoParamName, newValue); - this.accountNumber = StringUtils.defaultIfEmpty(newValue, null); - } - - if (command.isChangeInStringParameterNamed(ClientApiConstants.externalIdParamName, this.externalId)) { - final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.externalIdParamName); - actualChanges.put(ClientApiConstants.externalIdParamName, newValue); - this.externalId = StringUtils.defaultIfEmpty(newValue, null); - } - - if (command.isChangeInStringParameterNamed(ClientApiConstants.mobileNoParamName, this.mobileNo)) { - final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.mobileNoParamName); - actualChanges.put(ClientApiConstants.mobileNoParamName, newValue); - this.mobileNo = StringUtils.defaultIfEmpty(newValue, null); - } - - if (command.isChangeInStringParameterNamed(ClientApiConstants.emailAddressParamName, this.emailAddress)) { - final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.emailAddressParamName); - actualChanges.put(ClientApiConstants.emailAddressParamName, newValue); - this.emailAddress = StringUtils.defaultIfEmpty(newValue, null); - } - - if (command.isChangeInStringParameterNamed(ClientApiConstants.firstnameParamName, this.firstname)) { - final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.firstnameParamName); - actualChanges.put(ClientApiConstants.firstnameParamName, newValue); - this.firstname = StringUtils.defaultIfEmpty(newValue, null); - } - - if (command.isChangeInStringParameterNamed(ClientApiConstants.middlenameParamName, this.middlename)) { - final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.middlenameParamName); - actualChanges.put(ClientApiConstants.middlenameParamName, newValue); - this.middlename = StringUtils.defaultIfEmpty(newValue, null); - } - - if (command.isChangeInStringParameterNamed(ClientApiConstants.lastnameParamName, this.lastname)) { - final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.lastnameParamName); - actualChanges.put(ClientApiConstants.lastnameParamName, newValue); - this.lastname = StringUtils.defaultIfEmpty(newValue, null); - } - - if (command.isChangeInStringParameterNamed(ClientApiConstants.fullnameParamName, this.fullname)) { - final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.fullnameParamName); - actualChanges.put(ClientApiConstants.fullnameParamName, newValue); - this.fullname = newValue; - } - - if (command.isChangeInLongParameterNamed(ClientApiConstants.staffIdParamName, staffId())) { - final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.staffIdParamName); - actualChanges.put(ClientApiConstants.staffIdParamName, newValue); - } - - if (command.isChangeInLongParameterNamed(ClientApiConstants.genderIdParamName, genderId())) { - final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.genderIdParamName); - actualChanges.put(ClientApiConstants.genderIdParamName, newValue); - } - - if (command.isChangeInLongParameterNamed(ClientApiConstants.savingsProductIdParamName, savingsProductId())) { - final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName); - actualChanges.put(ClientApiConstants.savingsProductIdParamName, newValue); - } - - if (command.isChangeInLongParameterNamed(ClientApiConstants.genderIdParamName, genderId())) { - final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.genderIdParamName); - actualChanges.put(ClientApiConstants.genderIdParamName, newValue); - } - - if (command.isChangeInLongParameterNamed(ClientApiConstants.clientTypeIdParamName, clientTypeId())) { - final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.clientTypeIdParamName); - actualChanges.put(ClientApiConstants.clientTypeIdParamName, newValue); - } - - if (command.isChangeInLongParameterNamed(ClientApiConstants.clientClassificationIdParamName, clientClassificationId())) { - final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.clientClassificationIdParamName); - actualChanges.put(ClientApiConstants.clientClassificationIdParamName, newValue); - } - - if (command.isChangeInIntegerParameterNamed(ClientApiConstants.legalFormIdParamName, this.getLegalForm())) { - final Integer newValue = command.integerValueOfParameterNamed(ClientApiConstants.legalFormIdParamName); - if (newValue != null) { - LegalForm legalForm = LegalForm.fromInt(newValue); - if (legalForm != null) { - actualChanges.put(ClientApiConstants.legalFormIdParamName, ClientEnumerations.legalForm(newValue)); - this.setLegalForm(legalForm.getValue()); - if (legalForm.isPerson()) { - this.fullname = null; - } else if (legalForm.isEntity()) { - this.firstname = null; - this.lastname = null; - this.displayName = null; - } - } else { - actualChanges.put(ClientApiConstants.legalFormIdParamName, null); - this.setLegalForm(null); - } - } else { - actualChanges.put(ClientApiConstants.legalFormIdParamName, null); - this.setLegalForm(null); - } - } - - final String dateFormatAsInput = command.dateFormat(); - final String localeAsInput = command.locale(); - - if (command.isChangeInLocalDateParameterNamed(ClientApiConstants.activationDateParamName, getActivationLocalDate())) { - final String valueAsInput = command.stringValueOfParameterNamed(ClientApiConstants.activationDateParamName); - actualChanges.put(ClientApiConstants.activationDateParamName, valueAsInput); - actualChanges.put(ClientApiConstants.dateFormatParamName, dateFormatAsInput); - actualChanges.put(ClientApiConstants.localeParamName, localeAsInput); - - this.activationDate = command.localDateValueOfParameterNamed(ClientApiConstants.activationDateParamName); - this.officeJoiningDate = this.activationDate; - } - - if (command.isChangeInLocalDateParameterNamed(ClientApiConstants.dateOfBirthParamName, dateOfBirthLocalDate())) { - final String valueAsInput = command.stringValueOfParameterNamed(ClientApiConstants.dateOfBirthParamName); - actualChanges.put(ClientApiConstants.dateOfBirthParamName, valueAsInput); - actualChanges.put(ClientApiConstants.dateFormatParamName, dateFormatAsInput); - actualChanges.put(ClientApiConstants.localeParamName, localeAsInput); - - this.dateOfBirth = command.localDateValueOfParameterNamed(ClientApiConstants.dateOfBirthParamName); - } - - if (command.isChangeInLocalDateParameterNamed(ClientApiConstants.submittedOnDateParamName, getSubmittedOnDate())) { - final String valueAsInput = command.stringValueOfParameterNamed(ClientApiConstants.submittedOnDateParamName); - actualChanges.put(ClientApiConstants.submittedOnDateParamName, valueAsInput); - actualChanges.put(ClientApiConstants.dateFormatParamName, dateFormatAsInput); - actualChanges.put(ClientApiConstants.localeParamName, localeAsInput); - - this.submittedOnDate = command.localDateValueOfParameterNamed(ClientApiConstants.submittedOnDateParamName); - } - - validateUpdate(); - - deriveDisplayName(); - - return actualChanges; - } - private void validateNameParts(final List dataValidationErrors) { final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("client"); @@ -686,7 +498,7 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { } } - private void deriveDisplayName() { + public void deriveDisplayName() { StringBuilder nameBuilder = new StringBuilder(); Integer legalForm = this.getLegalForm(); @@ -715,10 +527,6 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { this.displayName = nameBuilder.toString(); } - public LocalDate getSubmittedOnDate() { - return this.submittedOnDate; - } - public LocalDate getActivationLocalDate() { return this.activationDate; } @@ -739,10 +547,6 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { this.image = image; } - public Image getImage() { - return this.image; - } - public String mobileNo() { return this.mobileNo; } @@ -763,30 +567,14 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { return this.isStaff; } - public String getExternalId() { - return this.externalId; - } - public void setEmailAddress(final String emailAddress) { this.emailAddress = emailAddress; } - public String getDisplayName() { - return this.displayName; - } - public void setDisplayName(final String displayName) { this.displayName = displayName; } - public Office getOffice() { - return this.office; - } - - public Office getTransferToOffice() { - return this.transferToOffice; - } - public void updateOffice(final Office office) { this.office = office; } @@ -799,7 +587,7 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { this.officeJoiningDate = date; } - private Long staffId() { + public Long staffId() { Long staffId = null; if (this.staff != null) { staffId = this.staff.getId(); @@ -811,10 +599,6 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { this.staff = staff; } - public Staff getStaff() { - return this.staff; - } - public void unassignStaff() { this.staff = null; } @@ -823,10 +607,6 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { this.staff = staff; } - public Set getGroups() { - return this.groups; - } - public void close(final AppUser currentUser, final CodeValue closureReason, final LocalDate closureDate) { this.closureReason = closureReason; this.closureDate = closureDate; @@ -834,10 +614,6 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { this.status = ClientStatus.CLOSED.getValue(); } - public Integer getStatus() { - return this.status; - } - public CodeValue subStatus() { return this.subStatus; } @@ -850,10 +626,6 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { return subStatusId; } - public void setStatus(final Integer status) { - this.status = status; - } - public boolean isActivatedAfter(final LocalDate submittedOn) { return getActivationLocalDate().isAfter(submittedOn); } @@ -913,22 +685,10 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { return clientClassificationId; } - public LocalDate getClosureDate() { - return this.closureDate; - } - public LocalDate getRejectedDate() { return this.rejectionDate; } - public LocalDate getWithdrawalDate() { - return this.withdrawalDate; - } - - public LocalDate getReopenedDate() { - return this.reopenedDate; - } - public CodeValue gender() { return this.gender; } @@ -983,18 +743,12 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { this.reactivateDate = reactivateDate; this.reactivatedBy = currentUser; this.status = ClientStatus.PENDING.getValue(); - } public void reOpened(AppUser currentUser, LocalDate reopenedDate) { this.reopenedDate = reopenedDate; this.reopenedBy = currentUser; this.status = ClientStatus.PENDING.getValue(); - - } - - public Integer getLegalForm() { - return legalForm; } public void setLegalForm(Integer legalForm) { @@ -1005,18 +759,6 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { this.groups.size(); } - public String getFirstname() { - return this.firstname; - } - - public String getMiddlename() { - return this.middlename; - } - - public String getLastname() { - return this.lastname; - } - public LocalDate getProposedTransferDate() { return proposedTransferDate; } @@ -1025,4 +767,14 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom { this.proposedTransferDate = proposedTransferDate; } + public void resetDerivedNames(final LegalForm legalForm) { + if (legalForm.isPerson()) { + setFullname(null); + } else if (legalForm.isEntity()) { + setFirstname(null); + setLastname(null); + setDisplayName(null); + } + } + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientRepository.java index b2554b12e..7d09ec67c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientRepository.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientRepository.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.portfolio.client.domain; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Query; @@ -29,4 +30,18 @@ interface ClientRepository extends JpaRepository, JpaSpecification @Query(FIND_CLIENT_BY_ACCOUNT_NUMBER) Client getClientByAccountNumber(@Param("accountNumber") String accountNumber); + + @Query(""" + SELECT client + FROM Client client + JOIN client.office office + LEFT JOIN client.transferToOffice transferToOffice + WHERE client.id = :clientId + AND (office.hierarchy LIKE :officeHierarchy OR transferToOffice.hierarchy LIKE :transferToOfficeHierarchy) + """) + Client fetchByClientIdAndHierarchy(Long clientId, String officeHierarchy, String transferToOfficeHierarchy); + + @Query("SELECT c.id FROM Client c WHERE c.externalId = :externalId") + Long findIdByExternalId(@Param("externalId") ExternalId externalId); + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientRepositoryWrapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientRepositoryWrapper.java index 5620c838b..ba8c23953 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientRepositoryWrapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientRepositoryWrapper.java @@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.client.domain; import java.util.Collection; import java.util.List; import lombok.RequiredArgsConstructor; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.client.exception.ClientNotActiveException; import org.apache.fineract.portfolio.client.exception.ClientNotFoundException; @@ -86,8 +87,21 @@ public class ClientRepositoryWrapper { public Client getClientByAccountNumber(String accountNumber) { Client client = this.repository.getClientByAccountNumber(accountNumber); if (client == null) { - throw new ClientNotFoundException(accountNumber); + throw new ClientNotFoundException(accountNumber, "account.number"); } return client; } + + public Client getClientByClientIdAndHierarchy(final Long clientId, final String hierarchySearchString) { + Client client = this.repository.fetchByClientIdAndHierarchy(clientId, hierarchySearchString, hierarchySearchString); + if (client == null) { + throw new ClientNotFoundException(clientId.toString(), "client.id"); + } + return client; + } + + public Long findIdByExternalId(final ExternalId externalId) { + return this.repository.findIdByExternalId(externalId); + } + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/exception/ClientNotFoundException.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/exception/ClientNotFoundException.java index 88627f7da..26aad1be5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/exception/ClientNotFoundException.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/exception/ClientNotFoundException.java @@ -34,8 +34,8 @@ public class ClientNotFoundException extends AbstractPlatformResourceNotFoundExc super("error.msg.client.not.found.with.basic.details", "Client not found with basic details."); } - public ClientNotFoundException(String accountNumber) { - super("error.msg.client.not.found.with.account.number", "Client not found with account number " + accountNumber + "."); + public ClientNotFoundException(String value, String valueType) { + super("error.msg.client.not.found.with." + valueType, "Client not found with valuer " + value + ".", value); } public ClientNotFoundException(Long id, EmptyResultDataAccessException e) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/mapper/ClientMapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/mapper/ClientMapper.java new file mode 100644 index 000000000..56df58435 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/mapper/ClientMapper.java @@ -0,0 +1,159 @@ +/** + * 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.mapper; + +import org.apache.fineract.infrastructure.codes.data.CodeValueData; +import org.apache.fineract.infrastructure.codes.domain.CodeValue; +import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig; +import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.portfolio.client.data.ClientData; +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.useradministration.domain.AppUser; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; + +@Mapper(config = MapstructMapperConfig.class) +public interface ClientMapper { + + @Mapping(target = "accountNo", source = "source.accountNumber") + @Mapping(target = "status", source = "source", qualifiedByName = "clientStatusEnum") + @Mapping(target = "subStatus", source = "source", qualifiedByName = "clientSubStatusCode") + @Mapping(target = "officeId", source = "source.office.id") + @Mapping(target = "officeName", source = "source.office.name") + @Mapping(target = "transferToOfficeId", source = "source.transferToOffice.id") + @Mapping(target = "transferToOfficeName", source = "source.transferToOffice.name") + @Mapping(target = "externalId", source = "source.externalId") + @Mapping(target = "gender", source = "source", qualifiedByName = "clientGenderCode") + @Mapping(target = "imageId", source = "source.image.id") + @Mapping(target = "staffId", source = "source.staff.id") + @Mapping(target = "staffName", source = "source.staff.displayName") + @Mapping(target = "timeline", source = "source", qualifiedByName = "clientTimelineData") + @Mapping(target = "savingsProductId", source = "source.savingsProductId") + @Mapping(target = "savingsProductName", source = "source.id") + @Mapping(target = "savingsAccountId", source = "source.savingsAccountId") + @Mapping(target = "clientType", source = "source", qualifiedByName = "clientTypeCode") + @Mapping(target = "clientClassification", source = "source", qualifiedByName = "clientClassificationCode") + @Mapping(target = "legalForm", source = "source", qualifiedByName = "clientLegalFormEnum") + @Mapping(target = "isStaff", source = "source", qualifiedByName = "clientIsStaff") + @Mapping(target = "imagePresent", ignore = true) + @Mapping(target = "officeOptions", ignore = true) + @Mapping(target = "staffOptions", ignore = true) + @Mapping(target = "narrations", ignore = true) + @Mapping(target = "savingProductOptions", ignore = true) + @Mapping(target = "savingAccountOptions", ignore = true) + @Mapping(target = "genderOptions", ignore = true) + @Mapping(target = "clientTypeOptions", ignore = true) + @Mapping(target = "clientClassificationOptions", ignore = true) + @Mapping(target = "clientNonPersonConstitutionOptions", ignore = true) + @Mapping(target = "clientNonPersonMainBusinessLineOptions", ignore = true) + @Mapping(target = "clientLegalFormOptions", ignore = true) + @Mapping(target = "familyMemberOptions", ignore = true) + @Mapping(target = "clientNonPersonDetails", ignore = true) + @Mapping(target = "address", ignore = true) + @Mapping(target = "isAddressEnabled", ignore = true) + @Mapping(target = "datatables", ignore = true) + @Mapping(target = "rowIndex", ignore = true) + @Mapping(target = "dateFormat", ignore = true) + @Mapping(target = "locale", ignore = true) + @Mapping(target = "clientTypeId", ignore = true) + @Mapping(target = "genderId", ignore = true) + @Mapping(target = "clientClassificationId", ignore = true) + @Mapping(target = "legalFormId", ignore = true) + @Mapping(target = "clientCollateralManagements", ignore = true) + @Mapping(target = "groups", ignore = true) + ClientData map(Client source); + + @Named("clientTypeCode") + default CodeValueData clientTypeCode(Client client) { + final CodeValue code = client.getClientType(); + if (code == null) { + return null; + } + return CodeValueData.instance(code.getId(), code.getLabel()); + } + + @Named("clientClassificationCode") + default CodeValueData clientClassificationCode(Client client) { + final CodeValue code = client.getClientClassification(); + if (code == null) { + return null; + } + return CodeValueData.instance(code.getId(), code.getLabel()); + } + + @Named("clientSubStatusCode") + default CodeValueData clientSubStatusCode(Client client) { + final CodeValue code = client.getSubStatus(); + if (code == null) { + return null; + } + return CodeValueData.instance(code.getId(), code.getLabel()); + } + + @Named("clientGenderCode") + default CodeValueData clientGenderCode(Client client) { + final CodeValue code = client.getGender(); + if (code == null) { + return null; + } + return CodeValueData.instance(code.getId(), code.getLabel()); + } + + @Named("clientLegalFormEnum") + default EnumOptionData clientLegalFormEnum(Client client) { + return ClientEnumerations.legalForm(client.getLegalForm()); + } + + @Named("clientStatusEnum") + default EnumOptionData clientStatusEnum(Client client) { + return ClientEnumerations.status(client.getStatus()); + } + + @Named("clientTimelineData") + default ClientTimelineData clientTimelineData(Client client) { + if (client.isClosed()) { + final AppUser activatedBy = client.getActivatedBy(); + if (activatedBy != null) { + return new ClientTimelineData(client.getSubmittedOnDate(), null, null, null, client.getActivationDate(), + activatedBy.getUsername(), activatedBy.getFirstname(), activatedBy.getLastname(), client.getClosureDate(), + client.getClosedBy().getUsername(), client.getClosedBy().getFirstname(), client.getClosedBy().getLastname()); + } else { + return new ClientTimelineData(client.getSubmittedOnDate(), null, null, null, client.getActivationDate(), null, null, null, + client.getClosureDate(), client.getClosedBy().getUsername(), client.getClosedBy().getFirstname(), + client.getClosedBy().getLastname()); + + } + } else if (client.isActive()) { + return new ClientTimelineData(client.getSubmittedOnDate(), null, null, null, client.getActivationDate(), + client.getActivatedBy().getUsername(), client.getActivatedBy().getFirstname(), client.getActivatedBy().getLastname(), + null, null, null, null); + } else { + return new ClientTimelineData(client.getSubmittedOnDate(), null, null, null, null, null, null, null, null, null, null, null); + } + } + + @Named("clientIsStaff") + default Boolean clientIsStaff(Client client) { + return Boolean.valueOf(client.isStaff()); + } + +} 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 5c74e7ec0..60514e729 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 @@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.client.service; import java.time.LocalDate; import java.util.Collection; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.service.Page; import org.apache.fineract.infrastructure.core.service.SearchParameters; import org.apache.fineract.portfolio.client.data.ClientData; @@ -59,5 +60,6 @@ public interface ClientReadPlatformService { LocalDate retrieveClientTransferProposalDate(Long clientId); - void validateClient(Long clientId); + Long retrieveClientIdByExternalId(ExternalId externalId); + } 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 5804fb96f..855dc25b9 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,13 +32,14 @@ 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.data.GlobalConfigurationPropertyData; -import org.apache.fineract.infrastructure.configuration.service.ConfigurationReadPlatformService; +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; @@ -61,10 +62,13 @@ 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; @@ -90,17 +94,19 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService // data mappers private final PaginationHelper paginationHelper; private final DatabaseSpecificSQLGenerator sqlGenerator; - private final ClientMapper clientMapper = new ClientMapper(); + private final ClientToDataMapper clientToDataMapper = new ClientToDataMapper(); private final ClientLookupMapper lookupMapper = new ClientLookupMapper(); private final ClientMembersOfGroupMapper membersOfGroupMapper = new ClientMembersOfGroupMapper(); private final ParentGroupsMapper clientGroupsMapper = new ParentGroupsMapper(); private final AddressReadPlatformService addressReadPlatformService; private final ClientFamilyMembersReadPlatformService clientFamilyMembersReadPlatformService; - private final ConfigurationReadPlatformService configurationReadPlatformService; 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) { @@ -113,10 +119,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService final Collection savingsProductDatas = this.savingsProductReadPlatformService.retrieveAllForLookupByType(null); - final GlobalConfigurationPropertyData configuration = this.configurationReadPlatformService - .retrieveGlobalConfiguration("Enable-Address"); - - final Boolean isAddressEnabled = configuration.isEnabled(); + final Boolean isAddressEnabled = configurationDomainService.isAddressEnabled(); if (isAddressEnabled) { address = this.addressReadPlatformService.retrieveTemplate(); } @@ -162,7 +165,6 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService } @Override - // @Transactional(readOnly=true) public Page retrieveAll(final SearchParameters searchParameters) { if (searchParameters != null && searchParameters.getStatus() != null @@ -186,7 +188,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService List paramList = new ArrayList<>(Arrays.asList(underHierarchySearchString, underHierarchySearchString)); final StringBuilder sqlBuilder = new StringBuilder(200); sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " "); - sqlBuilder.append(this.clientMapper.schema()); + sqlBuilder.append(this.clientToDataMapper.schema()); sqlBuilder.append(" where (o.hierarchy like ? or transferToOffice.hierarchy like ?) "); if (searchParameters != null) { @@ -196,7 +198,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService paramList.add(appUserID); } - final String extraCriteria = buildSqlStringFromClientCriteria(this.clientMapper.schema(), searchParameters, paramList); + final String extraCriteria = buildSqlStringFromClientCriteria(this.clientToDataMapper.schema(), searchParameters, paramList); if (StringUtils.isNotBlank(extraCriteria)) { sqlBuilder.append(" and (").append(extraCriteria).append(")"); @@ -220,7 +222,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService } } } - return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), paramList.toArray(), this.clientMapper); + return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), paramList.toArray(), this.clientToDataMapper); } private String buildSqlStringFromClientCriteria(String schemaSql, final SearchParameters searchParameters, List paramList) { @@ -294,10 +296,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService final String hierarchy = this.context.officeHierarchy(); final String hierarchySearchString = hierarchy + "%"; - final String sql = "select " + this.clientMapper.schema() - + " where ( o.hierarchy like ? or transferToOffice.hierarchy like ?) and c.id = ?"; - final ClientData clientData = this.jdbcTemplate.queryForObject(sql, this.clientMapper, // NOSONAR - hierarchySearchString, hierarchySearchString, clientId); + final Client client = clientRepositoryWrapper.getClientByClientIdAndHierarchy(clientId, hierarchySearchString); + final ClientData clientData = clientMapper.map(client); // Get client collaterals final Collection clientCollateralManagements = this.clientCollateralManagementRepositoryWrapper @@ -473,7 +473,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService final String lastname = rs.getString("lastname"); final String fullname = rs.getString("fullname"); final String displayName = rs.getString("displayName"); - final String externalId = rs.getString("externalId"); + final ExternalId externalId = ExternalIdFactory.produce(rs.getString("externalId")); final String mobileNo = rs.getString("mobileNo"); final boolean isStaff = rs.getBoolean("isStaff"); final String emailAddress = rs.getString("emailAddress"); @@ -559,179 +559,6 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService hierarchySearchString, centerId, ClientStatus.ACTIVE.getValue()); } - private static final class ClientMapper implements RowMapper { - - private final String schema; - - ClientMapper() { - final StringBuilder builder = new StringBuilder(400); - - builder.append( - "c.id as id, c.account_no as accountNo, c.external_id as externalId, c.status_enum as statusEnum,c.sub_status as subStatus, "); - builder.append( - "cvSubStatus.code_value as subStatusValue,cvSubStatus.code_description as subStatusDesc,c.office_id as officeId, o.name as officeName, "); - builder.append("c.transfer_to_office_id as transferToOfficeId, transferToOffice.name as transferToOfficeName, "); - builder.append("c.firstname as firstname, c.middlename as middlename, c.lastname as lastname, "); - builder.append("c.fullname as fullname, c.display_name as displayName, "); - builder.append("c.mobile_no as mobileNo, "); - builder.append("c.is_staff as isStaff, "); - builder.append("c.email_address as emailAddress, "); - builder.append("c.date_of_birth as dateOfBirth, "); - builder.append("c.gender_cv_id as genderId, "); - builder.append("cv.code_value as genderValue, "); - builder.append("c.client_type_cv_id as clienttypeId, "); - builder.append("cvclienttype.code_value as clienttypeValue, "); - builder.append("c.client_classification_cv_id as classificationId, "); - builder.append("cvclassification.code_value as classificationValue, "); - builder.append("c.legal_form_enum as legalFormEnum, "); - - builder.append("c.submittedon_date as submittedOnDate, "); - builder.append("sbu.username as submittedByUsername, "); - builder.append("sbu.firstname as submittedByFirstname, "); - builder.append("sbu.lastname as submittedByLastname, "); - - builder.append("c.closedon_date as closedOnDate, "); - builder.append("clu.username as closedByUsername, "); - builder.append("clu.firstname as closedByFirstname, "); - builder.append("clu.lastname as closedByLastname, "); - - // builder.append("c.submittedon as submittedOnDate, "); - builder.append("acu.username as activatedByUsername, "); - builder.append("acu.firstname as activatedByFirstname, "); - builder.append("acu.lastname as activatedByLastname, "); - - builder.append("cnp.constitution_cv_id as constitutionId, "); - builder.append("cvConstitution.code_value as constitutionValue, "); - builder.append("cnp.incorp_no as incorpNo, "); - builder.append("cnp.incorp_validity_till as incorpValidityTill, "); - builder.append("cnp.main_business_line_cv_id as mainBusinessLineId, "); - builder.append("cvMainBusinessLine.code_value as mainBusinessLineValue, "); - builder.append("cnp.remarks as remarks, "); - - builder.append("c.activation_date as activationDate, c.image_id as imageId, "); - builder.append("c.staff_id as staffId, s.display_name as staffName, "); - builder.append("c.default_savings_product as savingsProductId, sp.name as savingsProductName, "); - builder.append("c.default_savings_account as savingsAccountId "); - builder.append("from m_client c "); - builder.append("join m_office o on o.id = c.office_id "); - builder.append("left join m_client_non_person cnp on cnp.client_id = c.id "); - builder.append("left join m_staff s on s.id = c.staff_id "); - builder.append("left join m_savings_product sp on sp.id = c.default_savings_product "); - builder.append("left join m_office transferToOffice on transferToOffice.id = c.transfer_to_office_id "); - builder.append("left join m_appuser sbu on sbu.id = c.created_by "); - builder.append("left join m_appuser acu on acu.id = c.activatedon_userid "); - builder.append("left join m_appuser clu on clu.id = c.closedon_userid "); - builder.append("left join m_code_value cv on cv.id = c.gender_cv_id "); - builder.append("left join m_code_value cvclienttype on cvclienttype.id = c.client_type_cv_id "); - builder.append("left join m_code_value cvclassification on cvclassification.id = c.client_classification_cv_id "); - builder.append("left join m_code_value cvSubStatus on cvSubStatus.id = c.sub_status "); - builder.append("left join m_code_value cvConstitution on cvConstitution.id = cnp.constitution_cv_id "); - builder.append("left join m_code_value cvMainBusinessLine on cvMainBusinessLine.id = cnp.main_business_line_cv_id "); - - this.schema = builder.toString(); - } - - public String schema() { - return this.schema; - } - - @Override - public ClientData mapRow(final ResultSet rs, final int rowNum) throws SQLException { - - final String accountNo = rs.getString("accountNo"); - - final Integer statusEnum = JdbcSupport.getInteger(rs, "statusEnum"); - final EnumOptionData status = ClientEnumerations.status(statusEnum); - - final Long subStatusId = JdbcSupport.getLong(rs, "subStatus"); - final String subStatusValue = rs.getString("subStatusValue"); - final String subStatusDesc = rs.getString("subStatusDesc"); - final boolean isActive = false; - final CodeValueData subStatus = CodeValueData.instance(subStatusId, subStatusValue, subStatusDesc, isActive); - - final Long officeId = JdbcSupport.getLong(rs, "officeId"); - final String officeName = rs.getString("officeName"); - - final Long transferToOfficeId = JdbcSupport.getLong(rs, "transferToOfficeId"); - final String transferToOfficeName = rs.getString("transferToOfficeName"); - - final Long id = JdbcSupport.getLong(rs, "id"); - final String firstname = rs.getString("firstname"); - final String middlename = rs.getString("middlename"); - final String lastname = rs.getString("lastname"); - final String fullname = rs.getString("fullname"); - final String displayName = rs.getString("displayName"); - final String externalId = rs.getString("externalId"); - final String mobileNo = rs.getString("mobileNo"); - final boolean isStaff = rs.getBoolean("isStaff"); - final String emailAddress = rs.getString("emailAddress"); - final LocalDate dateOfBirth = JdbcSupport.getLocalDate(rs, "dateOfBirth"); - final Long genderId = JdbcSupport.getLong(rs, "genderId"); - final String genderValue = rs.getString("genderValue"); - final CodeValueData gender = CodeValueData.instance(genderId, genderValue); - - final Long clienttypeId = JdbcSupport.getLong(rs, "clienttypeId"); - final String clienttypeValue = rs.getString("clienttypeValue"); - final CodeValueData clienttype = CodeValueData.instance(clienttypeId, clienttypeValue); - - final Long classificationId = JdbcSupport.getLong(rs, "classificationId"); - final String classificationValue = rs.getString("classificationValue"); - final CodeValueData classification = CodeValueData.instance(classificationId, classificationValue); - - final LocalDate activationDate = JdbcSupport.getLocalDate(rs, "activationDate"); - final Long imageId = JdbcSupport.getLong(rs, "imageId"); - final Long staffId = JdbcSupport.getLong(rs, "staffId"); - final String staffName = rs.getString("staffName"); - - final Long savingsProductId = JdbcSupport.getLong(rs, "savingsProductId"); - final String savingsProductName = rs.getString("savingsProductName"); - final Long savingsAccountId = JdbcSupport.getLong(rs, "savingsAccountId"); - - final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate"); - final String closedByUsername = rs.getString("closedByUsername"); - final String closedByFirstname = rs.getString("closedByFirstname"); - final String closedByLastname = rs.getString("closedByLastname"); - - final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate"); - final String submittedByUsername = rs.getString("submittedByUsername"); - final String submittedByFirstname = rs.getString("submittedByFirstname"); - final String submittedByLastname = rs.getString("submittedByLastname"); - - final String activatedByUsername = rs.getString("activatedByUsername"); - final String activatedByFirstname = rs.getString("activatedByFirstname"); - final String activatedByLastname = rs.getString("activatedByLastname"); - - final Integer legalFormEnum = JdbcSupport.getInteger(rs, "legalFormEnum"); - EnumOptionData legalForm = null; - if (legalFormEnum != null) { - legalForm = ClientEnumerations.legalForm(legalFormEnum); - } - - final Long constitutionId = JdbcSupport.getLong(rs, "constitutionId"); - final String constitutionValue = rs.getString("constitutionValue"); - final CodeValueData constitution = CodeValueData.instance(constitutionId, constitutionValue); - final String incorpNo = rs.getString("incorpNo"); - final LocalDate incorpValidityTill = JdbcSupport.getLocalDate(rs, "incorpValidityTill"); - final Long mainBusinessLineId = JdbcSupport.getLong(rs, "mainBusinessLineId"); - final String mainBusinessLineValue = rs.getString("mainBusinessLineValue"); - final CodeValueData mainBusinessLine = CodeValueData.instance(mainBusinessLineId, mainBusinessLineValue); - final String remarks = rs.getString("remarks"); - - final ClientNonPersonData clientNonPerson = new ClientNonPersonData(constitution, incorpNo, incorpValidityTill, - mainBusinessLine, remarks); - - final ClientTimelineData timeline = new ClientTimelineData(submittedOnDate, submittedByUsername, submittedByFirstname, - submittedByLastname, activationDate, activatedByUsername, activatedByFirstname, activatedByLastname, closedOnDate, - closedByUsername, closedByFirstname, closedByLastname); - - return ClientData.instance(accountNo, status, subStatus, officeId, officeName, transferToOfficeId, transferToOfficeName, id, - firstname, middlename, lastname, fullname, displayName, externalId, mobileNo, emailAddress, dateOfBirth, gender, - activationDate, imageId, staffId, staffName, timeline, savingsProductId, savingsProductName, savingsAccountId, - clienttype, classification, legalForm, clientNonPerson, isStaff); - - } - } - private static final class ParentGroupsMapper implements RowMapper { public String parentGroupsSchema() { @@ -845,8 +672,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService @Override public LocalDate retrieveClientTransferProposalDate(Long clientId) { - validateClient(clientId); - final String sql = "SELECT cl.proposed_transfer_date FROM m_client cl WHERE cl.id =? "; + final String sql = "SELECT cl.proposed_transfer_date FROM m_client cl WHERE cl.id = ? "; try { return this.jdbcTemplate.queryForObject(sql, LocalDate.class, clientId); } catch (final EmptyResultDataAccessException e) { @@ -854,19 +680,188 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService } } - @Override - public void validateClient(Long clientId) { - try { - final String sql = "SELECT cl.id FROM m_client cl WHERE cl.id =? "; - this.jdbcTemplate.queryForObject(sql, Long.class, clientId); - } catch (final EmptyResultDataAccessException e) { - throw new ClientNotFoundException(clientId, e); - } - } - @Override public Collection retrieveUserClients(Long aUserID) { String sql = "SELECT m.client_id FROM m_selfservice_user_client_mapping m INNER JOIN m_client c ON c.id = m.client_id WHERE m.appuser_id = ?"; return jdbcTemplate.queryForList(sql, Long.class, aUserID); } + + @Override + public Long retrieveClientIdByExternalId(final ExternalId externalId) { + return clientRepositoryWrapper.findIdByExternalId(externalId); + } + + private static final class ClientToDataMapper implements RowMapper { + + private final String schema; + + ClientToDataMapper() { + final StringBuilder builder = new StringBuilder(400); + + builder.append( + "c.id as id, c.account_no as accountNo, c.external_id as externalId, c.status_enum as statusEnum,c.sub_status as subStatus, "); + builder.append( + "cvSubStatus.code_value as subStatusValue,cvSubStatus.code_description as subStatusDesc,c.office_id as officeId, o.name as officeName, "); + builder.append("c.transfer_to_office_id as transferToOfficeId, transferToOffice.name as transferToOfficeName, "); + builder.append("c.firstname as firstname, c.middlename as middlename, c.lastname as lastname, "); + builder.append("c.fullname as fullname, c.display_name as displayName, "); + builder.append("c.mobile_no as mobileNo, "); + builder.append("c.is_staff as isStaff, "); + builder.append("c.email_address as emailAddress, "); + builder.append("c.date_of_birth as dateOfBirth, "); + builder.append("c.gender_cv_id as genderId, "); + builder.append("cv.code_value as genderValue, "); + builder.append("c.client_type_cv_id as clienttypeId, "); + builder.append("cvclienttype.code_value as clienttypeValue, "); + builder.append("c.client_classification_cv_id as classificationId, "); + builder.append("cvclassification.code_value as classificationValue, "); + builder.append("c.legal_form_enum as legalFormEnum, "); + + builder.append("c.submittedon_date as submittedOnDate, "); + builder.append("sbu.username as submittedByUsername, "); + builder.append("sbu.firstname as submittedByFirstname, "); + builder.append("sbu.lastname as submittedByLastname, "); + + builder.append("c.closedon_date as closedOnDate, "); + builder.append("clu.username as closedByUsername, "); + builder.append("clu.firstname as closedByFirstname, "); + builder.append("clu.lastname as closedByLastname, "); + + // builder.append("c.submittedon as submittedOnDate, "); + builder.append("acu.username as activatedByUsername, "); + builder.append("acu.firstname as activatedByFirstname, "); + builder.append("acu.lastname as activatedByLastname, "); + + builder.append("cnp.constitution_cv_id as constitutionId, "); + builder.append("cvConstitution.code_value as constitutionValue, "); + builder.append("cnp.incorp_no as incorpNo, "); + builder.append("cnp.incorp_validity_till as incorpValidityTill, "); + builder.append("cnp.main_business_line_cv_id as mainBusinessLineId, "); + builder.append("cvMainBusinessLine.code_value as mainBusinessLineValue, "); + builder.append("cnp.remarks as remarks, "); + + builder.append("c.activation_date as activationDate, c.image_id as imageId, "); + builder.append("c.staff_id as staffId, s.display_name as staffName, "); + builder.append("c.default_savings_product as savingsProductId, sp.name as savingsProductName, "); + builder.append("c.default_savings_account as savingsAccountId "); + builder.append("from m_client c "); + builder.append("join m_office o on o.id = c.office_id "); + builder.append("left join m_client_non_person cnp on cnp.client_id = c.id "); + builder.append("left join m_staff s on s.id = c.staff_id "); + builder.append("left join m_savings_product sp on sp.id = c.default_savings_product "); + builder.append("left join m_office transferToOffice on transferToOffice.id = c.transfer_to_office_id "); + builder.append("left join m_appuser sbu on sbu.id = c.created_by "); + builder.append("left join m_appuser acu on acu.id = c.activatedon_userid "); + builder.append("left join m_appuser clu on clu.id = c.closedon_userid "); + builder.append("left join m_code_value cv on cv.id = c.gender_cv_id "); + builder.append("left join m_code_value cvclienttype on cvclienttype.id = c.client_type_cv_id "); + builder.append("left join m_code_value cvclassification on cvclassification.id = c.client_classification_cv_id "); + builder.append("left join m_code_value cvSubStatus on cvSubStatus.id = c.sub_status "); + builder.append("left join m_code_value cvConstitution on cvConstitution.id = cnp.constitution_cv_id "); + builder.append("left join m_code_value cvMainBusinessLine on cvMainBusinessLine.id = cnp.main_business_line_cv_id "); + + this.schema = builder.toString(); + } + + public String schema() { + return this.schema; + } + + @Override + public ClientData mapRow(final ResultSet rs, final int rowNum) throws SQLException { + + final String accountNo = rs.getString("accountNo"); + + final Integer statusEnum = JdbcSupport.getInteger(rs, "statusEnum"); + final EnumOptionData status = ClientEnumerations.status(statusEnum); + + final Long subStatusId = JdbcSupport.getLong(rs, "subStatus"); + final String subStatusValue = rs.getString("subStatusValue"); + final String subStatusDesc = rs.getString("subStatusDesc"); + final boolean isActive = false; + final CodeValueData subStatus = CodeValueData.instance(subStatusId, subStatusValue, subStatusDesc, isActive); + + final Long officeId = JdbcSupport.getLong(rs, "officeId"); + final String officeName = rs.getString("officeName"); + + final Long transferToOfficeId = JdbcSupport.getLong(rs, "transferToOfficeId"); + final String transferToOfficeName = rs.getString("transferToOfficeName"); + + final Long id = JdbcSupport.getLong(rs, "id"); + final String firstname = rs.getString("firstname"); + final String middlename = rs.getString("middlename"); + final String lastname = rs.getString("lastname"); + final String fullname = rs.getString("fullname"); + final String displayName = rs.getString("displayName"); + final ExternalId externalId = ExternalIdFactory.produce(rs.getString("externalId")); + final String mobileNo = rs.getString("mobileNo"); + final boolean isStaff = rs.getBoolean("isStaff"); + final String emailAddress = rs.getString("emailAddress"); + final LocalDate dateOfBirth = JdbcSupport.getLocalDate(rs, "dateOfBirth"); + final Long genderId = JdbcSupport.getLong(rs, "genderId"); + final String genderValue = rs.getString("genderValue"); + final CodeValueData gender = CodeValueData.instance(genderId, genderValue); + + final Long clienttypeId = JdbcSupport.getLong(rs, "clienttypeId"); + final String clienttypeValue = rs.getString("clienttypeValue"); + final CodeValueData clienttype = CodeValueData.instance(clienttypeId, clienttypeValue); + + final Long classificationId = JdbcSupport.getLong(rs, "classificationId"); + final String classificationValue = rs.getString("classificationValue"); + final CodeValueData classification = CodeValueData.instance(classificationId, classificationValue); + + final LocalDate activationDate = JdbcSupport.getLocalDate(rs, "activationDate"); + final Long imageId = JdbcSupport.getLong(rs, "imageId"); + final Long staffId = JdbcSupport.getLong(rs, "staffId"); + final String staffName = rs.getString("staffName"); + + final Long savingsProductId = JdbcSupport.getLong(rs, "savingsProductId"); + final String savingsProductName = rs.getString("savingsProductName"); + final Long savingsAccountId = JdbcSupport.getLong(rs, "savingsAccountId"); + + final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate"); + final String closedByUsername = rs.getString("closedByUsername"); + final String closedByFirstname = rs.getString("closedByFirstname"); + final String closedByLastname = rs.getString("closedByLastname"); + + final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate"); + final String submittedByUsername = rs.getString("submittedByUsername"); + final String submittedByFirstname = rs.getString("submittedByFirstname"); + final String submittedByLastname = rs.getString("submittedByLastname"); + + final String activatedByUsername = rs.getString("activatedByUsername"); + final String activatedByFirstname = rs.getString("activatedByFirstname"); + final String activatedByLastname = rs.getString("activatedByLastname"); + + final Integer legalFormEnum = JdbcSupport.getInteger(rs, "legalFormEnum"); + EnumOptionData legalForm = null; + if (legalFormEnum != null) { + legalForm = ClientEnumerations.legalForm(legalFormEnum); + } + + final Long constitutionId = JdbcSupport.getLong(rs, "constitutionId"); + final String constitutionValue = rs.getString("constitutionValue"); + final CodeValueData constitution = CodeValueData.instance(constitutionId, constitutionValue); + final String incorpNo = rs.getString("incorpNo"); + final LocalDate incorpValidityTill = JdbcSupport.getLocalDate(rs, "incorpValidityTill"); + final Long mainBusinessLineId = JdbcSupport.getLong(rs, "mainBusinessLineId"); + final String mainBusinessLineValue = rs.getString("mainBusinessLineValue"); + final CodeValueData mainBusinessLine = CodeValueData.instance(mainBusinessLineId, mainBusinessLineValue); + final String remarks = rs.getString("remarks"); + + final ClientNonPersonData clientNonPerson = new ClientNonPersonData(constitution, incorpNo, incorpValidityTill, + mainBusinessLine, remarks); + + final ClientTimelineData timeline = new ClientTimelineData(submittedOnDate, submittedByUsername, submittedByFirstname, + submittedByLastname, activationDate, activatedByUsername, activatedByFirstname, activatedByLastname, closedOnDate, + closedByUsername, closedByFirstname, closedByLastname); + + return ClientData.instance(accountNo, status, subStatus, officeId, officeName, transferToOfficeId, transferToOfficeName, id, + firstname, middlename, lastname, fullname, displayName, externalId, mobileNo, emailAddress, dateOfBirth, gender, + activationDate, imageId, staffId, staffName, timeline, savingsProductId, savingsProductName, savingsAccountId, + clienttype, classification, legalForm, clientNonPerson, isStaff); + + } + } + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index 6268e9e74..a44b6cad7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -28,6 +28,7 @@ import java.util.Map; import javax.persistence.PersistenceException; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandProcessingService; @@ -37,14 +38,15 @@ import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumb import org.apache.fineract.infrastructure.accountnumberformat.domain.EntityAccountType; import org.apache.fineract.infrastructure.codes.domain.CodeValue; import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper; -import org.apache.fineract.infrastructure.configuration.data.GlobalConfigurationPropertyData; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; -import org.apache.fineract.infrastructure.configuration.service.ConfigurationReadPlatformService; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; +import org.apache.fineract.infrastructure.core.service.DateUtils; +import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService; @@ -62,6 +64,7 @@ import org.apache.fineract.portfolio.client.api.ClientApiConstants; import org.apache.fineract.portfolio.client.data.ClientDataValidator; import org.apache.fineract.portfolio.client.domain.AccountNumberGenerator; import org.apache.fineract.portfolio.client.domain.Client; +import org.apache.fineract.portfolio.client.domain.ClientEnumerations; import org.apache.fineract.portfolio.client.domain.ClientNonPerson; import org.apache.fineract.portfolio.client.domain.ClientNonPersonRepositoryWrapper; import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; @@ -115,11 +118,11 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP private final ConfigurationDomainService configurationDomainService; private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository; private final FromJsonHelper fromApiJsonHelper; - private final ConfigurationReadPlatformService configurationReadPlatformService; private final AddressWritePlatformService addressWritePlatformService; private final ClientFamilyMembersWritePlatformService clientFamilyMembersWritePlatformService; private final BusinessEventNotifierService businessEventNotifierService; private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService; + private final ExternalIdFactory externalIdFactory; @Transactional @Override @@ -142,6 +145,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP this.clientRepository.flush(); return new CommandProcessingResultBuilder() // .withOfficeId(client.officeId()) // + .withEntityExternalId(client.getExternalId()) // .withClientId(clientId) // .withEntityId(clientId) // .build(); @@ -187,10 +191,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP this.fromApiJsonDeserializer.validateForCreate(command.json()); - final GlobalConfigurationPropertyData configuration = this.configurationReadPlatformService - .retrieveGlobalConfiguration("Enable-Address"); - - final Boolean isAddressEnabled = configuration.isEnabled(); + final Boolean isAddressEnabled = configurationDomainService.isAddressEnabled(); final Long officeId = command.longValueOfParameterNamed(ClientApiConstants.officeIdParamName); @@ -235,20 +236,59 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP .orElseThrow(() -> new SavingsProductNotFoundException(savingsProductId)); } - final Integer legalFormParamValue = command.integerValueOfParameterNamed(ClientApiConstants.legalFormIdParamName); boolean isEntity = false; - Integer legalFormValue = null; - LegalForm legalForm = LegalForm.PERSON; + LegalForm legalForm = null; + final Integer legalFormParamValue = command.integerValueOfParameterNamed(ClientApiConstants.legalFormIdParamName); if (legalFormParamValue != null) { legalForm = LegalForm.fromInt(legalFormParamValue); if (legalForm != null) { - legalFormValue = legalForm.getValue(); isEntity = legalForm.isEntity(); } } + if (legalForm == null) { + legalForm = LegalForm.PERSON; + } + + final String accountNo = command.stringValueOfParameterNamed(ClientApiConstants.accountNoParamName); + final String mobileNo = command.stringValueOfParameterNamed(ClientApiConstants.mobileNoParamName); + final String emailAddress = command.stringValueOfParameterNamed(ClientApiConstants.emailAddressParamName); + final String firstname = command.stringValueOfParameterNamed(ClientApiConstants.firstnameParamName); + final String middlename = command.stringValueOfParameterNamed(ClientApiConstants.middlenameParamName); + final String lastname = command.stringValueOfParameterNamed(ClientApiConstants.lastnameParamName); + final String fullname = command.stringValueOfParameterNamed(ClientApiConstants.fullnameParamName); + final boolean isStaff = command.booleanPrimitiveValueOfParameterNamed(ClientApiConstants.isStaffParamName); + final LocalDate dataOfBirth = command.localDateValueOfParameterNamed(ClientApiConstants.dateOfBirthParamName); + + ClientStatus status = ClientStatus.PENDING; + boolean active = false; + if (command.hasParameter("active")) { + active = command.booleanPrimitiveValueOfParameterNamed(ClientApiConstants.activeParamName); + } + + LocalDate activationDate = null; + LocalDate officeJoiningDate = null; + if (active) { + status = ClientStatus.ACTIVE; + activationDate = command.localDateValueOfParameterNamed(ClientApiConstants.activationDateParamName); + officeJoiningDate = activationDate; + } + + LocalDate submittedOnDate = DateUtils.getBusinessLocalDate(); + if (command.hasParameter(ClientApiConstants.submittedOnDateParamName)) { + submittedOnDate = command.localDateValueOfParameterNamed(ClientApiConstants.submittedOnDateParamName); + } + if (active && submittedOnDate.isAfter(activationDate)) { + submittedOnDate = activationDate; + } + final Long savingsAccountId = null; + + final ExternalId externalId = externalIdFactory.createFromCommand(command, ClientApiConstants.externalIdParamName); + + final Client newClient = Client.instance(currentUser, status, clientOffice, clientParentGroup, accountNo, firstname, middlename, + lastname, fullname, activationDate, officeJoiningDate, externalId, mobileNo, emailAddress, staff, submittedOnDate, + savingsProductId, savingsAccountId, dataOfBirth, gender, clientType, clientClassification, legalForm.getValue(), + isStaff); - final Client newClient = Client.createNew(currentUser, clientOffice, clientParentGroup, staff, savingsProductId, gender, - clientType, clientClassification, legalFormValue, command); this.clientRepository.saveAndFlush(newClient); boolean rollbackTransaction = false; if (newClient.isActive()) { @@ -270,7 +310,6 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP CommandProcessingResult result = openSavingsAccount(newClient, fmt); if (result.getSavingsId() != null) { this.clientRepository.saveAndFlush(newClient); - } if (isEntity) { @@ -298,8 +337,10 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP if (newClient.isActive()) { businessEventNotifierService.notifyPostBusinessEvent(new ClientActivateBusinessEvent(newClient)); } + return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // + .withEntityExternalId(newClient.getExternalId()) // .withOfficeId(clientOffice.getId()) // .withClientId(newClient.getId()) // .withGroupId(groupId) // @@ -335,9 +376,6 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP final LocalDate incorpValidityTill = this.fromApiJsonHelper .extractLocalDateNamed(ClientApiConstants.incorpValidityTillParamName, clientNonPersonElement); - // JsonCommand clientNonPersonCommand = - // JsonCommand.fromExistingCommand(command, - // command.arrayOfParameterNamed(ClientApiConstants.clientNonPersonDetailsParamName).getAsJsonObject()); CodeValue clientNonPersonConstitution = null; final Long clientNonPersonConstitutionId = this.fromApiJsonHelper.extractLongNamed(ClientApiConstants.constitutionIdParamName, clientNonPersonElement); @@ -377,7 +415,142 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP this.context.validateAccessRights(clientHierarchy); - final Map changes = clientForUpdate.update(command); + final Map changes = new LinkedHashMap<>(9); + + if (command.isChangeInIntegerParameterNamed(ClientApiConstants.statusParamName, clientForUpdate.getStatus())) { + final Integer newValue = command.integerValueOfParameterNamed(ClientApiConstants.statusParamName); + changes.put(ClientApiConstants.statusParamName, ClientEnumerations.status(newValue)); + clientForUpdate.setStatus(ClientStatus.fromInt(newValue).getValue()); + } + + if (command.isChangeInStringParameterNamed(ClientApiConstants.accountNoParamName, clientForUpdate.getAccountNumber())) { + final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.accountNoParamName); + changes.put(ClientApiConstants.accountNoParamName, newValue); + clientForUpdate.setAccountNumber(StringUtils.defaultIfEmpty(newValue, null)); + } + + final ExternalId externalId = externalIdFactory.createFromCommand(command, ClientApiConstants.externalIdParamName); + if (command.isChangeInStringParameterNamed(ClientApiConstants.externalIdParamName, externalId.getValue())) { + changes.put(ClientApiConstants.externalIdParamName, externalId.getValue()); + clientForUpdate.setExternalId(externalId); + } + + if (command.isChangeInStringParameterNamed(ClientApiConstants.mobileNoParamName, clientForUpdate.getMobileNo())) { + final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.mobileNoParamName); + changes.put(ClientApiConstants.mobileNoParamName, newValue); + clientForUpdate.setMobileNo(StringUtils.defaultIfEmpty(newValue, null)); + } + + if (command.isChangeInStringParameterNamed(ClientApiConstants.emailAddressParamName, clientForUpdate.getEmailAddress())) { + final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.emailAddressParamName); + changes.put(ClientApiConstants.emailAddressParamName, newValue); + clientForUpdate.setEmailAddress(StringUtils.defaultIfEmpty(newValue, null)); + } + + if (command.isChangeInStringParameterNamed(ClientApiConstants.firstnameParamName, clientForUpdate.getFirstname())) { + final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.firstnameParamName); + changes.put(ClientApiConstants.firstnameParamName, newValue); + clientForUpdate.setFirstname(StringUtils.defaultIfEmpty(newValue, null)); + } + + if (command.isChangeInStringParameterNamed(ClientApiConstants.middlenameParamName, clientForUpdate.getMiddlename())) { + final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.middlenameParamName); + changes.put(ClientApiConstants.middlenameParamName, newValue); + clientForUpdate.setMiddlename(StringUtils.defaultIfEmpty(newValue, null)); + } + + if (command.isChangeInStringParameterNamed(ClientApiConstants.lastnameParamName, clientForUpdate.getLastname())) { + final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.lastnameParamName); + changes.put(ClientApiConstants.lastnameParamName, newValue); + clientForUpdate.setLastname(StringUtils.defaultIfEmpty(newValue, null)); + } + + if (command.isChangeInStringParameterNamed(ClientApiConstants.fullnameParamName, clientForUpdate.getFullname())) { + final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.fullnameParamName); + changes.put(ClientApiConstants.fullnameParamName, newValue); + clientForUpdate.setFullname(newValue); + } + + if (command.isChangeInLongParameterNamed(ClientApiConstants.staffIdParamName, clientForUpdate.staffId())) { + final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.staffIdParamName); + changes.put(ClientApiConstants.staffIdParamName, newValue); + } + + if (command.isChangeInLongParameterNamed(ClientApiConstants.genderIdParamName, clientForUpdate.genderId())) { + final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.genderIdParamName); + changes.put(ClientApiConstants.genderIdParamName, newValue); + } + + if (command.isChangeInLongParameterNamed(ClientApiConstants.savingsProductIdParamName, clientForUpdate.savingsProductId())) { + final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName); + changes.put(ClientApiConstants.savingsProductIdParamName, newValue); + } + + if (command.isChangeInLongParameterNamed(ClientApiConstants.clientTypeIdParamName, clientForUpdate.clientTypeId())) { + final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.clientTypeIdParamName); + changes.put(ClientApiConstants.clientTypeIdParamName, newValue); + } + + if (command.isChangeInLongParameterNamed(ClientApiConstants.clientClassificationIdParamName, + clientForUpdate.clientClassificationId())) { + final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.clientClassificationIdParamName); + changes.put(ClientApiConstants.clientClassificationIdParamName, newValue); + } + + if (command.isChangeInIntegerParameterNamed(ClientApiConstants.legalFormIdParamName, clientForUpdate.getLegalForm())) { + final Integer newValue = command.integerValueOfParameterNamed(ClientApiConstants.legalFormIdParamName); + if (newValue != null) { + LegalForm legalForm = LegalForm.fromInt(newValue); + if (legalForm != null) { + changes.put(ClientApiConstants.legalFormIdParamName, ClientEnumerations.legalForm(newValue)); + clientForUpdate.setLegalForm(legalForm.getValue()); + clientForUpdate.resetDerivedNames(legalForm); + } else { + changes.put(ClientApiConstants.legalFormIdParamName, null); + clientForUpdate.setLegalForm(null); + } + } else { + changes.put(ClientApiConstants.legalFormIdParamName, null); + clientForUpdate.setLegalForm(null); + } + } + + final String dateFormatAsInput = command.dateFormat(); + final String localeAsInput = command.locale(); + + if (command.isChangeInLocalDateParameterNamed(ClientApiConstants.activationDateParamName, + clientForUpdate.getActivationDate())) { + final String valueAsInput = command.stringValueOfParameterNamed(ClientApiConstants.activationDateParamName); + changes.put(ClientApiConstants.activationDateParamName, valueAsInput); + changes.put(ClientApiConstants.dateFormatParamName, dateFormatAsInput); + changes.put(ClientApiConstants.localeParamName, localeAsInput); + + clientForUpdate.setActivationDate(command.localDateValueOfParameterNamed(ClientApiConstants.activationDateParamName)); + clientForUpdate.setOfficeJoiningDate(clientForUpdate.getActivationDate()); + } + + if (command.isChangeInLocalDateParameterNamed(ClientApiConstants.dateOfBirthParamName, clientForUpdate.getDateOfBirth())) { + final String valueAsInput = command.stringValueOfParameterNamed(ClientApiConstants.dateOfBirthParamName); + changes.put(ClientApiConstants.dateOfBirthParamName, valueAsInput); + changes.put(ClientApiConstants.dateFormatParamName, dateFormatAsInput); + changes.put(ClientApiConstants.localeParamName, localeAsInput); + + clientForUpdate.setDateOfBirth(command.localDateValueOfParameterNamed(ClientApiConstants.dateOfBirthParamName)); + } + + if (command.isChangeInLocalDateParameterNamed(ClientApiConstants.submittedOnDateParamName, + clientForUpdate.getSubmittedOnDate())) { + final String valueAsInput = command.stringValueOfParameterNamed(ClientApiConstants.submittedOnDateParamName); + changes.put(ClientApiConstants.submittedOnDateParamName, valueAsInput); + changes.put(ClientApiConstants.dateFormatParamName, dateFormatAsInput); + changes.put(ClientApiConstants.localeParamName, localeAsInput); + + clientForUpdate.setSubmittedOnDate(command.localDateValueOfParameterNamed(ClientApiConstants.submittedOnDateParamName)); + } + + clientForUpdate.validateUpdate(); + + clientForUpdate.deriveDisplayName(); if (changes.containsKey(ClientApiConstants.staffIdParamName)) { @@ -515,6 +688,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP } return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // + .withEntityExternalId(clientForUpdate.getExternalId()) // .withOfficeId(clientForUpdate.officeId()) // .withClientId(clientId) // .withEntityId(clientId) // @@ -552,6 +726,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // .withOfficeId(client.officeId()) // + .withEntityExternalId(client.getExternalId()) // .withClientId(clientId) // .withEntityId(clientId) // .withSavingsId(result.getSavingsId())// @@ -612,6 +787,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP .withCommandId(command.commandId()) // .withOfficeId(clientForUpdate.officeId()) // .withEntityId(clientForUpdate.getId()) // + .withEntityExternalId(clientForUpdate.getExternalId()) // .withClientId(clientId) // .with(actualChanges) // .build(); @@ -644,6 +820,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // .withOfficeId(clientForUpdate.officeId()) // + .withEntityExternalId(clientForUpdate.getExternalId()) // .withEntityId(clientForUpdate.getId()) // .withClientId(clientId) // .with(actualChanges) // @@ -712,6 +889,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP .withCommandId(command.commandId()) // .withClientId(clientId) // .withEntityId(clientId) // + .withEntityExternalId(client.getExternalId()) // .build(); } catch (final JpaSystemException | DataIntegrityViolationException dve) { handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve); @@ -750,6 +928,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP .withCommandId(command.commandId()) // .withOfficeId(clientForUpdate.officeId()) // .withEntityId(clientForUpdate.getId()) // + .withEntityExternalId(clientForUpdate.getExternalId()) // .withClientId(clientId) // .with(actualChanges) // .build(); @@ -808,6 +987,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP .withCommandId(command.commandId()) // .withClientId(entityId) // .withEntityId(entityId) // + .withEntityExternalId(client.getExternalId()) // .build(); } @@ -838,6 +1018,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP .withCommandId(command.commandId()) // .withClientId(entityId) // .withEntityId(entityId) // + .withEntityExternalId(client.getExternalId()) // .build(); } @@ -863,6 +1044,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP .withCommandId(command.commandId()) // .withClientId(entityId) // .withEntityId(entityId) // + .withEntityExternalId(client.getExternalId()) // .build(); } @@ -890,6 +1072,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP .withCommandId(command.commandId()) // .withClientId(entityId) // .withEntityId(entityId) // + .withEntityExternalId(client.getExternalId()) // .build(); } @@ -916,6 +1099,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP .withCommandId(command.commandId()) // .withClientId(entityId) // .withEntityId(entityId) // + .withEntityExternalId(client.getExternalId()) // .build(); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java index 873928014..371e8bfe2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java @@ -305,7 +305,7 @@ public class GroupsApiResource { final boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters()); if (template) { - final GroupGeneralData templateGroup = groupReadPlatformService.retrieveTemplate(group.officeId(), false, + final GroupGeneralData templateGroup = groupReadPlatformService.retrieveTemplate(group.getOfficeId(), false, staffInSelectedOfficeOnly); group = GroupGeneralData.withTemplate(templateGroup, group); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java index c2cf973e3..1953568c4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java @@ -76,7 +76,7 @@ public class LoanAccountData { private Long clientId; private String clientAccountNo; private String clientName; - private String clientExternalId; + private ExternalId clientExternalId; private Long clientOfficeId; private GroupGeneralData group; private Long loanProductId; @@ -315,7 +315,7 @@ public class LoanAccountData { * Used to produce a {@link LoanAccountData} with only client information defaulted. */ public static LoanAccountData clientDefaults(final Long clientId, final String clientAccountNo, final String clientName, - final Long clientOfficeId, final String clientExternalId, final LocalDate expectedDisbursementDate) { + final Long clientOfficeId, final ExternalId clientExternalId, final LocalDate expectedDisbursementDate) { return new LoanAccountData().setTimeline(LoanApplicationTimelineData.templateDefault(expectedDisbursementDate)) .setIsVariableInstallmentsAllowed(false).setDelinquent(CollectionData.template()).setClientId(clientId) @@ -628,7 +628,7 @@ public class LoanAccountData { */ public static LoanAccountData basicLoanDetails(final Long id, final String accountNo, final LoanStatusEnumData status, final ExternalId externalId, final Long clientId, final String clientAccountNo, final String clientName, - final Long clientOfficeId, final String clientExternalId, final GroupGeneralData group, final EnumOptionData loanType, + final Long clientOfficeId, final ExternalId clientExternalId, final GroupGeneralData group, final EnumOptionData loanType, final Long loanProductId, final String loanProductName, final String loanProductDescription, final boolean isLoanProductLinkedToFloatingRate, final Long fundId, final String fundName, final Long loanPurposeId, final String loanPurposeName, final Long loanOfficerId, final String loanOfficerName, final CurrencyData currencyData, diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/guarantor/data/GuarantorData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/guarantor/data/GuarantorData.java index f46351126..f4cf7a987 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/guarantor/data/GuarantorData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/guarantor/data/GuarantorData.java @@ -146,7 +146,7 @@ public class GuarantorData { public static GuarantorData mergeClientData(final ClientData clientData, final GuarantorData guarantorData) { return new GuarantorData(guarantorData.id, guarantorData.loanId, guarantorData.clientRelationshipType, guarantorData.entityId, guarantorData.guarantorType, clientData.getFirstname(), clientData.getLastname(), null, null, null, null, null, null, null, - null, null, null, clientData.getOfficeName(), clientData.getActivationDate(), clientData.getExternalId(), + null, null, null, clientData.getOfficeName(), clientData.getActivationDate(), clientData.getExternalId().getValue(), guarantorData.status, guarantorData.guarantorFundingDetails, null, guarantorData.allowedClientRelationshipTypes, guarantorData.accountLinkingOptions); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java index 7f4dc2fef..e755b481d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanChargeWritePlatformServiceImpl.java @@ -33,7 +33,6 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; @@ -129,7 +128,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service -@Slf4j @RequiredArgsConstructor public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatformService { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index db9333d41..5d8b3cff6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -454,6 +454,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final BigDecimal outstandingLoanBalance = loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency).getAmount(); final BigDecimal unrecognizedIncomePortion = null; BigDecimal adjustedChargeAmount = adjustPrepayInstallmentCharge(loan, onDate); + return new LoanTransactionData(null, null, null, transactionType, null, currencyData, earliestUnpaidInstallmentDate, loanRepaymentScheduleInstallment.getTotalOutstanding(currency).getAmount().subtract(adjustedChargeAmount), loan.getNetDisbursalAmount(), loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency).getAmount(), @@ -496,6 +497,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final BigDecimal amount = waiveOfInterest.getAmount(currency).getAmount(); final BigDecimal outstandingLoanBalance = null; final BigDecimal unrecognizedIncomePortion = null; + return new LoanTransactionData(null, null, null, transactionType, null, currencyData, waiveOfInterest.getTransactionDate(), amount, loan.getNetDisbursalAmount(), null, null, null, null, null, ExternalId.empty(), null, null, outstandingLoanBalance, unrecognizedIncomePortion, false, loanId, loan.getExternalId()); @@ -702,7 +704,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final Long clientId = JdbcSupport.getLong(rs, "clientId"); final String clientAccountNo = rs.getString("clientAccountNo"); final Long clientOfficeId = JdbcSupport.getLong(rs, "clientOfficeId"); - final String clientExternalId = rs.getString("clientExternalId"); + final ExternalId clientExternalId = ExternalIdFactory.produce(rs.getString("clientExternalId")); final String clientName = rs.getString("clientName"); final Long groupId = JdbcSupport.getLong(rs, "groupId"); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java index 292ccde24..7791c7272 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/data/SavingsAccountData.java @@ -389,7 +389,7 @@ public final class SavingsAccountData implements Serializable { if (this.clientData != null) { officeId = this.clientData.getOfficeId(); } else if (this.groupId != null) { - officeId = this.groupGeneralData.officeId(); + officeId = this.groupGeneralData.getOfficeId(); } return officeId; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java index c968a691c..52bc1433d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/DepositAccountReadPlatformServiceImpl.java @@ -338,7 +338,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead GroupGeneralData group = null; if (groupId != null) { group = this.groupReadPlatformService.retrieveOne(groupId); - officeId = group.officeId(); + officeId = group.getOfficeId(); } final Collection preClosurePenalInterestOnTypeOptions = this.depositsDropdownReadPlatformService 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 7a8d19d9d..9aa6e543e 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 @@ -1125,7 +1125,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead GroupGeneralData group = null; if (groupId != null) { group = this.groupReadPlatformService.retrieveOne(groupId); - officeId = group.officeId(); + officeId = group.getOfficeId(); } final Collection productOptions = this.savingsProductReadPlatformService.retrieveAllForLookup(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/service/SearchReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/service/SearchReadPlatformServiceImpl.java index af7cfb98a..4bb98aaa7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/service/SearchReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/search/service/SearchReadPlatformServiceImpl.java @@ -110,9 +110,11 @@ public class SearchReadPlatformServiceImpl implements SearchReadPlatformService + " null as entityExternalId, null as entityAccountNo, c.id as parentId, c.display_name as parentName,null as entityMobileNo, c.status_enum as entityStatusEnum, null as subEntityType, null as parentType " + " from m_client_identifier ci join m_client c on ci.client_id=c.id join m_office o on o.id = c.office_id " + " where o.hierarchy like :hierarchy and ci.document_key like :search ) "; - final String groupMatchSql = " (select IF(g.level_id=1,'CENTER','GROUP') as entityType, g.id as entityId, g.display_name as entityName, g.external_id as entityExternalId, g.account_no as entityAccountNo " - + " , g.office_id as parentId, o.name as parentName, null as entityMobileNo, g.status_enum as entityStatusEnum, null as subEntityType, null as parentType " + + final String groupMatchSql = " (select CASE WHEN g.level_id=1 THEN 'CENTER' ELSE 'GROUP' END as entityType, g.id as entityId, g.display_name as entityName, g.external_id as entityExternalId, g.account_no as entityAccountNo, " + + " g.office_id as parentId, o.name as parentName, null as entityMobileNo, g.status_enum as entityStatusEnum, null as subEntityType, null as parentType " + " from m_group g join m_office o on o.id = g.office_id where o.hierarchy like :hierarchy and (g.account_no like :search or g.display_name like :search or g.external_id like :search or g.id like :search )) "; + final StringBuilder sql = new StringBuilder(); if (searchConditions.isClientSearch()) { @@ -139,9 +141,9 @@ public class SearchReadPlatformServiceImpl implements SearchReadPlatformService sql.append(groupMatchSql).append(union); } + // remove last occurrence of "union all" string sql.replace(sql.lastIndexOf(union), sql.length(), ""); - // remove last occurrence of "union all" string return sql.toString(); } diff --git a/gradle.properties b/gradle.properties index 7d886728a..f700a74fd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,7 +16,7 @@ # specific language governing permissions and limitations # under the License. # -org.gradle.jvmargs=-Xmx2g --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED --add-opens=java.rmi/sun.rmi.transport=null +org.gradle.jvmargs=-Xmx4g --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED --add-opens=java.rmi/sun.rmi.transport=null buildType=BUILD org.gradle.caching=true org.gradle.parallel=true diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientExternalIdTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientExternalIdTest.java new file mode 100644 index 000000000..ba283d7bc --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientExternalIdTest.java @@ -0,0 +1,324 @@ +/** + * 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.integrationtests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import io.restassured.builder.RequestSpecBuilder; +import io.restassured.builder.ResponseSpecBuilder; +import io.restassured.http.ContentType; +import io.restassured.specification.RequestSpecification; +import io.restassured.specification.ResponseSpecification; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.client.models.DeleteClientsClientIdResponse; +import org.apache.fineract.client.models.GetClientTransferProposalDateResponse; +import org.apache.fineract.client.models.GetClientsClientIdAccountsResponse; +import org.apache.fineract.client.models.GetClientsClientIdResponse; +import org.apache.fineract.client.models.GetObligeeData; +import org.apache.fineract.client.models.PostClientsClientIdResponse; +import org.apache.fineract.client.models.PostClientsResponse; +import org.apache.fineract.client.models.PutClientsClientIdResponse; +import org.apache.fineract.integrationtests.common.ClientHelper; +import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper; +import org.apache.fineract.integrationtests.common.Utils; +import org.apache.fineract.portfolio.client.domain.ClientStatus; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +@Slf4j +public class ClientExternalIdTest { + + private ResponseSpecification responseSpec; + private RequestSpecification requestSpec; + + @BeforeEach + public void setup() { + Utils.initializeRESTAssured(); + requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); + responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + } + + @Test + public void whenAutoExternalIdConfigIsOffCreateClient() { + // given + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, false); + final String jsonPayload = ClientHelper.getBasicClientAsJSON(ClientHelper.DEFAULT_OFFICE_ID, ClientHelper.LEGALFORM_ID_PERSON, + null); + // when + final PostClientsResponse clientResponse = ClientHelper.addClientAsPerson(requestSpec, responseSpec, jsonPayload); + // then + assertNotNull(clientResponse); + assertNull(clientResponse.getResourceExternalId()); + } + + @Test + public void whenAutoExternalIdConfigIsOffCreateClientWithValue() { + // given + final String externalId = Utils.randomStringGenerator("ID_", 7); + final String jsonPayload = ClientHelper.getBasicClientAsJSON(ClientHelper.DEFAULT_OFFICE_ID, ClientHelper.LEGALFORM_ID_PERSON, + externalId); + // when + final PostClientsResponse clientResponse = ClientHelper.addClientAsPerson(requestSpec, responseSpec, jsonPayload); + // then + assertNotNull(clientResponse); + assertNotNull(clientResponse.getResourceExternalId()); + assertEquals(externalId, clientResponse.getResourceExternalId()); + + fetchClientByExternalId(clientResponse.getResourceExternalId()); + } + + @Test + public void whenAutoExternalIdConfigIsOnCreateClient() { + // given + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, true); + final String jsonPayload = ClientHelper.getBasicClientAsJSON(ClientHelper.DEFAULT_OFFICE_ID, ClientHelper.LEGALFORM_ID_PERSON, + null); + // when + final PostClientsResponse clientResponse = ClientHelper.addClientAsPerson(requestSpec, responseSpec, jsonPayload); + // then + assertNotNull(clientResponse); + assertNotNull(clientResponse.getResourceExternalId()); + assertEquals(36, clientResponse.getResourceExternalId().length()); + + fetchClientByExternalId(clientResponse.getResourceExternalId()); + + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, false); + } + + @Test + public void whenAutoExternalIdConfigIsOnCreateClientWithValue() { + // given + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, true); + final String externalId = Utils.randomStringGenerator("ID_", 7); + final String jsonPayload = ClientHelper.getBasicClientAsJSON(ClientHelper.DEFAULT_OFFICE_ID, ClientHelper.LEGALFORM_ID_PERSON, + externalId); + // when + final PostClientsResponse clientResponse = ClientHelper.addClientAsPerson(requestSpec, responseSpec, jsonPayload); + // then + assertNotNull(clientResponse); + assertNotNull(clientResponse.getResourceExternalId()); + assertEquals(externalId, clientResponse.getResourceExternalId()); + + fetchClientByExternalId(clientResponse.getResourceExternalId()); + + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, false); + } + + @Test + public void testClientStatusUsingExternalId() { + ClientHelper clientHelper = new ClientHelper(requestSpec, responseSpec); + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, true); + String jsonPayload = ClientHelper.getBasicClientAsJSON(ClientHelper.DEFAULT_OFFICE_ID, ClientHelper.LEGALFORM_ID_PERSON, null); + final PostClientsResponse addClientResponse = ClientHelper.addClientAsPerson(requestSpec, responseSpec, jsonPayload); + final String clientExternalId = addClientResponse.getResourceExternalId(); + final Long clientId = addClientResponse.getClientId(); + assertNotNull(clientExternalId); + log.info("Client data id {} and external Id {}", clientId, clientExternalId); + + GetClientsClientIdResponse clientResponse = ClientHelper.getClientByExternalId(requestSpec, responseSpec, clientExternalId); + ClientStatusChecker.verifyClientStatus(ClientStatus.ACTIVE, clientResponse); + log.info("Client data id {} and status {}", clientExternalId, clientResponse.getStatus().getCode()); + + // Close Client action + jsonPayload = clientHelper.getCloseClientAsJSON(); + PostClientsClientIdResponse commandResponse = ClientHelper.performClientActionUsingExternalId(requestSpec, responseSpec, + clientExternalId, ClientHelper.CLOSE_CLIENT_COMMAND, jsonPayload); + assertNotNull(commandResponse); + assertNotNull(commandResponse.getResourceExternalId()); + assertEquals(clientExternalId, commandResponse.getResourceExternalId()); + log.info("Client data id {} and external Id {}", commandResponse.getResourceId(), clientExternalId); + assertEquals(clientId.intValue(), commandResponse.getResourceId()); + + clientResponse = ClientHelper.getClientByExternalId(requestSpec, responseSpec, clientExternalId); + ClientStatusChecker.verifyClientStatus(ClientStatus.CLOSED, clientResponse); + log.info("Client data id {} and status {}", clientExternalId, clientResponse.getStatus().getCode()); + + // Reactivate Client action + jsonPayload = clientHelper.getReactivateClientAsJSON(); + commandResponse = ClientHelper.performClientActionUsingExternalId(requestSpec, responseSpec, clientExternalId, + ClientHelper.REACTIVATE_CLIENT_COMMAND, jsonPayload); + assertNotNull(commandResponse); + assertNotNull(commandResponse.getResourceExternalId()); + assertEquals(clientExternalId, commandResponse.getResourceExternalId()); + log.info("Client data id {} and external Id {}", commandResponse.getResourceId(), clientExternalId); + assertEquals(clientId.intValue(), commandResponse.getResourceId()); + + clientResponse = ClientHelper.getClientByExternalId(requestSpec, responseSpec, clientExternalId); + ClientStatusChecker.verifyClientStatus(ClientStatus.PENDING, clientResponse); + log.info("Client data id {} and status {}", clientExternalId, clientResponse.getStatus().getCode()); + + // Reject Client action + jsonPayload = clientHelper.getRejectClientAsJSON(); + commandResponse = ClientHelper.performClientActionUsingExternalId(requestSpec, responseSpec, clientExternalId, + ClientHelper.REJECT_CLIENT_COMMAND, jsonPayload); + assertNotNull(commandResponse); + assertNotNull(commandResponse.getResourceExternalId()); + assertEquals(clientExternalId, commandResponse.getResourceExternalId()); + log.info("Client data id {} and external Id {}", commandResponse.getResourceId(), clientExternalId); + assertEquals(clientId.intValue(), commandResponse.getResourceId()); + + clientResponse = ClientHelper.getClientByExternalId(requestSpec, responseSpec, clientExternalId); + ClientStatusChecker.verifyClientStatus(ClientStatus.REJECTED, clientResponse); + log.info("Client data id {} and status {}", clientExternalId, clientResponse.getStatus().getCode()); + + // Activate Client action + jsonPayload = ClientHelper.getActivateClientAsJSON(ClientHelper.DEFAULT_DATE); + commandResponse = ClientHelper.performClientActionUsingExternalId(requestSpec, responseSpec, clientExternalId, + ClientHelper.ACTIVATE_CLIENT_COMMAND, jsonPayload); + assertNotNull(commandResponse); + assertNotNull(commandResponse.getResourceExternalId()); + assertEquals(clientExternalId, commandResponse.getResourceExternalId()); + log.info("Client data id {} and external Id {}", commandResponse.getResourceId(), clientExternalId); + assertEquals(clientId.intValue(), commandResponse.getResourceId()); + + clientResponse = ClientHelper.getClientByExternalId(requestSpec, responseSpec, clientExternalId); + ClientStatusChecker.verifyClientStatus(ClientStatus.ACTIVE, clientResponse); + log.info("Client data id {} and status {}", clientExternalId, clientResponse.getStatus().getCode()); + + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, false); + } + + @Test + public void testUpdateClientUsingExternalId() { + // given + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, true); + String jsonPayload = ClientHelper.getBasicClientAsJSON(ClientHelper.DEFAULT_OFFICE_ID, ClientHelper.LEGALFORM_ID_PERSON, null); + // when + final PostClientsResponse clientResponse = ClientHelper.addClientAsPerson(requestSpec, responseSpec, jsonPayload); + final String clientExternalId = clientResponse.getResourceExternalId(); + jsonPayload = ClientHelper.getBasicClientAsJSON(null, ClientHelper.LEGALFORM_ID_PERSON, clientExternalId); + final PutClientsClientIdResponse clientUpdateResponse = ClientHelper.updateClient(requestSpec, responseSpec, clientExternalId, + jsonPayload); + // then + assertNotNull(clientUpdateResponse); + assertNotNull(clientUpdateResponse.getResourceExternalId()); + assertEquals(clientExternalId, clientUpdateResponse.getResourceExternalId()); + + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, false); + } + + @Test + public void testDeleteClientUsingExternalId() { + // given + ClientHelper clientHelper = new ClientHelper(requestSpec, responseSpec); + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, true); + String jsonPayload = ClientHelper.getBasicClientAsJSON(ClientHelper.DEFAULT_OFFICE_ID, ClientHelper.LEGALFORM_ID_PERSON, null); + // when + final PostClientsResponse clientResponse = ClientHelper.addClientAsPerson(requestSpec, responseSpec, jsonPayload); + final String clientExternalId = clientResponse.getResourceExternalId(); + jsonPayload = clientHelper.getCloseClientAsJSON(); + PostClientsClientIdResponse commandResponse = ClientHelper.performClientActionUsingExternalId(requestSpec, responseSpec, + clientExternalId, ClientHelper.CLOSE_CLIENT_COMMAND, jsonPayload); + jsonPayload = clientHelper.getReactivateClientAsJSON(); + commandResponse = ClientHelper.performClientActionUsingExternalId(requestSpec, responseSpec, clientExternalId, + ClientHelper.REACTIVATE_CLIENT_COMMAND, jsonPayload); + + // then + final DeleteClientsClientIdResponse clientDeleteResponse = ClientHelper.deleteClient(requestSpec, responseSpec, clientExternalId); + assertNotNull(clientDeleteResponse); + assertNotNull(clientDeleteResponse.getResourceExternalId()); + assertEquals(clientExternalId, clientDeleteResponse.getResourceExternalId()); + + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, false); + } + + @Test + public void testGetClientAccountsUsingExternalId() { + // given + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, true); + final String jsonPayload = ClientHelper.getBasicClientAsJSON(ClientHelper.DEFAULT_OFFICE_ID, ClientHelper.LEGALFORM_ID_PERSON, + null); + // when + final PostClientsResponse clientResponse = ClientHelper.addClientAsPerson(requestSpec, responseSpec, jsonPayload); + final String clientExternalId = clientResponse.getResourceExternalId(); + + GetClientsClientIdAccountsResponse clientAccountsResponse = ClientHelper.getClientAccounts(requestSpec, responseSpec, + clientExternalId); + + // then + assertNotNull(clientAccountsResponse); + + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, false); + } + + @Test + public void testGetClientTransferProposalDate() { + // given + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, true); + final String jsonPayload = ClientHelper.getBasicClientAsJSON(ClientHelper.DEFAULT_OFFICE_ID, ClientHelper.LEGALFORM_ID_PERSON, + null); + final PostClientsResponse clientResponse = ClientHelper.addClientAsPerson(requestSpec, responseSpec, jsonPayload); + ResponseSpecification response204Spec = new ResponseSpecBuilder().expectStatusCode(204).build(); + + // when + final String clientExternalId = clientResponse.getResourceExternalId(); + final GetClientTransferProposalDateResponse transferProposalDateResponse = ClientHelper.getProposedTransferDate(requestSpec, + response204Spec, clientExternalId); + + fetchClientByExternalId(clientResponse.getResourceExternalId()); + + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, false); + } + + @Test + public void testGetClientObligeeData() { + // given + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, true); + final String jsonPayload = ClientHelper.getBasicClientAsJSON(ClientHelper.DEFAULT_OFFICE_ID, ClientHelper.LEGALFORM_ID_PERSON, + null); + // when + final PostClientsResponse clientResponse = ClientHelper.addClientAsPerson(requestSpec, responseSpec, jsonPayload); + final String clientExternalId = clientResponse.getResourceExternalId(); + final List obligeeDataResponse = ClientHelper.getObligeeData(requestSpec, responseSpec, clientExternalId); + + // then + assertNotNull(obligeeDataResponse); + + fetchClientByExternalId(clientResponse.getResourceExternalId()); + + GlobalConfigurationHelper.manageConfigurations(requestSpec, responseSpec, + GlobalConfigurationHelper.ENABLE_AUTOGENERATED_EXTERNAL_ID, false); + } + + private void fetchClientByExternalId(final String externalId) { + GetClientsClientIdResponse clientResponse = ClientHelper.getClientByExternalId(requestSpec, responseSpec, externalId); + assertNotNull(clientResponse); + assertEquals(externalId, clientResponse.getExternalId()); + } +} diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientStatusChecker.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientStatusChecker.java index a9724f50d..a1945e054 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientStatusChecker.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientStatusChecker.java @@ -21,6 +21,8 @@ package org.apache.fineract.integrationtests; import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.HashMap; +import org.apache.fineract.client.models.GetClientsClientIdResponse; +import org.apache.fineract.portfolio.client.domain.ClientStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,6 +38,10 @@ public final class ClientStatusChecker { assertEquals(300, (int) clientStatusHashMap.get("id")); } + public static void verifyClientStatus(final ClientStatus status, final GetClientsClientIdResponse clientResponse) { + assertEquals(status.getValue(), clientResponse.getStatus().getId()); + } + public static void verifyClientClosed(final HashMap clientStatusHashMap) { LOG.info("\n-------------------------------------- VERIFYING CLIENT IS CLOSED ------------------------------------"); assertEquals(600, (int) clientStatusHashMap.get("id")); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ClientHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ClientHelper.java index 00b51347a..e90414223 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ClientHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ClientHelper.java @@ -37,12 +37,18 @@ import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.client.models.DeleteClientsClientIdResponse; import org.apache.fineract.client.models.GetClientClientIdAddressesResponse; +import org.apache.fineract.client.models.GetClientTransferProposalDateResponse; +import org.apache.fineract.client.models.GetClientsClientIdAccountsResponse; import org.apache.fineract.client.models.GetClientsClientIdResponse; +import org.apache.fineract.client.models.GetObligeeData; import org.apache.fineract.client.models.PostClientClientIdAddressesRequest; import org.apache.fineract.client.models.PostClientClientIdAddressesResponse; +import org.apache.fineract.client.models.PostClientsClientIdResponse; import org.apache.fineract.client.models.PostClientsRequest; import org.apache.fineract.client.models.PostClientsResponse; +import org.apache.fineract.client.models.PutClientsClientIdResponse; import org.apache.fineract.client.util.JSON; import org.apache.fineract.infrastructure.bulkimport.data.GlobalEntityType; import org.apache.fineract.integrationtests.client.IntegrationTest; @@ -54,20 +60,26 @@ import org.apache.poi.ss.usermodel.Workbook; @RequiredArgsConstructor public class ClientHelper extends IntegrationTest { - private static final String CREATE_CLIENT_URL = "/fineract-provider/api/v1/clients?" + Utils.TENANT_IDENTIFIER; private static final String CLIENT_URL = "/fineract-provider/api/v1/clients"; - private static final String CLOSE_CLIENT_COMMAND = "close"; - private static final String REACTIVATE_CLIENT_COMMAND = "reactivate"; - private static final String REJECT_CLIENT_COMMAND = "reject"; - private static final String ACTIVATE_CLIENT_COMMAND = "activate"; - private static final String WITHDRAW_CLIENT_COMMAND = "withdraw"; - private static final String UNDOREJECT_CLIENT_COMMAND = "undoRejection"; - private static final String UNDOWITHDRAWN_CLIENT_COMMAND = "undoWithdrawal"; - private static final Integer LEGALFORM_ID_PERSON = 1; + private static final String CREATE_CLIENT_URL = CLIENT_URL + "?" + Utils.TENANT_IDENTIFIER; + private static final String CLIENT_EXTERNALID_URL = CLIENT_URL + "/external-id"; + + public static final String CLOSE_CLIENT_COMMAND = "close"; + public static final String REACTIVATE_CLIENT_COMMAND = "reactivate"; + public static final String REJECT_CLIENT_COMMAND = "reject"; + public static final String ACTIVATE_CLIENT_COMMAND = "activate"; + public static final String WITHDRAW_CLIENT_COMMAND = "withdraw"; + public static final String UNDOREJECT_CLIENT_COMMAND = "undoRejection"; + public static final String UNDOWITHDRAWN_CLIENT_COMMAND = "undoWithdrawal"; + public static final String DEFAULT_OFFICE_ID = "1"; + public static final Integer LEGALFORM_ID_PERSON = 1; + public static final Integer LEGALFORM_ID_ENTITY = 2; public static final String CREATED_DATE = Utils.getLocalDateOfTenant().minusDays(5).format(Utils.dateFormatter); public static final String CREATED_DATE_PLUS_ONE = Utils.getLocalDateOfTenant().minusDays(4).format(Utils.dateFormatter); public static final String CREATED_DATE_PLUS_TWO = Utils.getLocalDateOfTenant().minusDays(3).format(Utils.dateFormatter); + public static final String DEFAULT_DATE = "04 March 2011"; + private static final Gson GSON = new JSON().getGson(); private final RequestSpecification requestSpec; @@ -84,8 +96,55 @@ public class ClientHelper extends IntegrationTest { return ok(fineract().clients.create6(request)); } + public static PostClientsResponse addClientAsPerson(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final String jsonPayload) { + final String response = Utils.performServerPost(requestSpec, responseSpec, CREATE_CLIENT_URL, jsonPayload); + log.info("{}", response); + return GSON.fromJson(response, PostClientsResponse.class); + } + + public static PutClientsClientIdResponse updateClient(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final String externalId, final String jsonPayload) { + final String url = CLIENT_EXTERNALID_URL + "/" + externalId + "?" + Utils.TENANT_IDENTIFIER; + final String response = Utils.performServerPut(requestSpec, responseSpec, url, jsonPayload); + log.info("{}", response); + return GSON.fromJson(response, PutClientsClientIdResponse.class); + } + + public static DeleteClientsClientIdResponse deleteClient(final RequestSpecification requestSpec, + final ResponseSpecification responseSpec, final String externalId) { + final String url = CLIENT_EXTERNALID_URL + "/" + externalId + "?" + Utils.TENANT_IDENTIFIER; + final String response = Utils.performServerDelete(requestSpec, responseSpec, url, Utils.emptyJson(), null); + log.info("{}", response); + return GSON.fromJson(response, DeleteClientsClientIdResponse.class); + } + + public static GetClientsClientIdAccountsResponse getClientAccounts(final RequestSpecification requestSpec, + final ResponseSpecification responseSpec, final String externalId) { + final String url = CLIENT_EXTERNALID_URL + "/" + externalId + "/accounts?" + Utils.TENANT_IDENTIFIER; + final String response = Utils.performServerGet(requestSpec, responseSpec, url); + log.info("{}", response); + return GSON.fromJson(response, GetClientsClientIdAccountsResponse.class); + } + + public static GetClientTransferProposalDateResponse getProposedTransferDate(final RequestSpecification requestSpec, + final ResponseSpecification responseSpec, final String externalId) { + final String url = CLIENT_EXTERNALID_URL + "/" + externalId + "/transferproposaldate?" + Utils.TENANT_IDENTIFIER; + final String response = Utils.performServerGet(requestSpec, responseSpec, url); + log.info("{}", response); + return GSON.fromJson(response, GetClientTransferProposalDateResponse.class); + } + + public static List getObligeeData(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final String externalId) { + final String url = CLIENT_EXTERNALID_URL + "/" + externalId + "/obligeedetails?" + Utils.TENANT_IDENTIFIER; + final String response = Utils.performServerGet(requestSpec, responseSpec, url); + log.info("{}", response); + return GSON.fromJson(response, new TypeToken>() {}.getType()); + } + public static Integer createClient(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { - return createClient(requestSpec, responseSpec, "04 March 2011"); + return createClient(requestSpec, responseSpec, DEFAULT_DATE); } public static Integer createClient(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, @@ -100,6 +159,14 @@ public class ClientHelper extends IntegrationTest { "clientId"); } + public static PostClientsResponse createClient(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final String activationDate, final String officeId, final String externalId) { + log.info("---------------------------------CREATING A CLIENT---------------------------------------------"); + final String response = Utils.performServerPost(requestSpec, responseSpec, CREATE_CLIENT_URL, + getTestClientAsJSON(activationDate, officeId)); + return GSON.fromJson(response, PostClientsResponse.class); + } + public static PostClientClientIdAddressesResponse createClientAddress(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, long clientId, long addressTypeId, PostClientClientIdAddressesRequest request) { final String CREATE_CLIENT_ADDRESS_URL = "/fineract-provider/api/v1/client/" + clientId + "/addresses?type=" + addressTypeId + "&" @@ -140,7 +207,7 @@ public class ClientHelper extends IntegrationTest { } public static Integer createClientAsPerson(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { - return createClientAsPerson(requestSpec, responseSpec, "04 March 2011"); + return createClientAsPerson(requestSpec, responseSpec, DEFAULT_DATE); } public static Integer createClientAsPerson(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, @@ -153,7 +220,7 @@ public class ClientHelper extends IntegrationTest { log.info( "---------------------------------CREATING A CLIENT NON PERSON(ORGANISATION)---------------------------------------------"); - return Utils.performServerPost(requestSpec, responseSpec, CREATE_CLIENT_URL, getTestPersonClientAsJSON(activationDate, officeId), + return Utils.performServerPost(requestSpec, responseSpec, CREATE_CLIENT_URL, getTestClientAsJSON(activationDate, officeId), "clientId"); } @@ -167,7 +234,7 @@ public class ClientHelper extends IntegrationTest { } public static Integer createClientAsEntity(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { - return createClientAsEntity(requestSpec, responseSpec, "04 March 2011"); + return createClientAsEntity(requestSpec, responseSpec, DEFAULT_DATE); } public static Integer createClientAsEntity(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, @@ -190,7 +257,7 @@ public class ClientHelper extends IntegrationTest { public static Integer createClientForAccountPreference(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final Integer clientType, String jsonAttributeToGetBack) { - final String activationDate = "04 March 2011"; + final String activationDate = DEFAULT_DATE; final String officeId = "1"; log.info( "---------------------------------CREATING A CLIENT BASED ON ACCOUNT PREFERENCE---------------------------------------------"); @@ -212,15 +279,36 @@ public class ClientHelper extends IntegrationTest { return (Integer) getClient(requestSpec, responseSpec, clientId, "staffId"); } - public static String getTestClientAsJSON(final String dateOfJoining, final String officeId) { - final HashMap map = new HashMap<>(); + public static HashMap setInitialClientValues(final String officeId, final Integer legalFormId) { + return setInitialClientValues(officeId, legalFormId, randomIDGenerator("ID_", 7)); + } + + public static HashMap setInitialClientValues(final String officeId, final Integer legalFormId, + final String externalId) { + HashMap map = new HashMap<>(); map.put("officeId", officeId); - map.put("legalFormId", LEGALFORM_ID_PERSON); + map.put("legalFormId", legalFormId); map.put("firstname", Utils.randomNameGenerator("Client_FirstName_", 5)); map.put("lastname", Utils.randomNameGenerator("Client_LastName_", 4)); - map.put("externalId", randomIDGenerator("ID_", 7)); + if (externalId != null) { + map.put("externalId", externalId); + } map.put("dateFormat", Utils.DATE_FORMAT); map.put("locale", "en"); + return map; + } + + public static String getBasicClientAsJSON(final String officeId, final Integer legalFormId, final String externalId) { + HashMap map = setInitialClientValues(officeId, legalFormId, externalId); + map.put("active", "true"); + map.put("activationDate", DEFAULT_DATE); + final String basicClientAsJson = GSON.toJson(map); + log.info("Client JSON : {}", basicClientAsJson); + return basicClientAsJson; + } + + public static String getTestClientAsJSON(final String dateOfJoining, final String officeId) { + HashMap map = setInitialClientValues(officeId, LEGALFORM_ID_PERSON); map.put("active", "true"); map.put("activationDate", dateOfJoining); final String testClientAsJson = GSON.toJson(map); @@ -229,14 +317,7 @@ public class ClientHelper extends IntegrationTest { } public static String getTestClientAsJSONPending(final String submittedOnDate, final String officeId) { - final HashMap map = new HashMap<>(); - map.put("officeId", officeId); - map.put("legalFormId", LEGALFORM_ID_PERSON); - map.put("firstname", Utils.randomNameGenerator("Client_FirstName_", 5)); - map.put("lastname", Utils.randomNameGenerator("Client_LastName_", 4)); - map.put("externalId", randomIDGenerator("ID_", 7)); - map.put("dateFormat", Utils.DATE_FORMAT); - map.put("locale", "en"); + HashMap map = setInitialClientValues(officeId, LEGALFORM_ID_PERSON); map.put("active", "false"); map.put("submittedOnDate", submittedOnDate); log.info("map : {}", map); @@ -244,14 +325,7 @@ public class ClientHelper extends IntegrationTest { } public static String getTestPendingClientWithDatatableAsJson(final String registeredTableName) { - final HashMap map = new HashMap<>(); - map.put("officeId", "1"); - map.put("legalFormId", LEGALFORM_ID_PERSON); - map.put("firstname", Utils.randomNameGenerator("Client_FirstName_", 5)); - map.put("lastname", Utils.randomNameGenerator("Client_LastName_", 4)); - map.put("externalId", randomIDGenerator("ID_", 7)); - map.put("dateFormat", Utils.DATE_FORMAT); - map.put("locale", "en"); + HashMap map = setInitialClientValues("1", LEGALFORM_ID_PERSON); map.put("active", "false"); map.put("submittedOnDate", "04 March 2014"); String requestJson = getTestDatatableAsJson(map, registeredTableName); @@ -320,7 +394,7 @@ public class ClientHelper extends IntegrationTest { map.put("locale", "en"); map.put("active", "true"); map.put("activationDate", dateOfJoining); - map.put("legalFormId", 2); + map.put("legalFormId", LEGALFORM_ID_ENTITY); final HashMap clientNonPersonMap = new HashMap<>(); clientNonPersonMap.put("constitutionId", soleProprietorCodeValueId); @@ -331,14 +405,7 @@ public class ClientHelper extends IntegrationTest { } public static String getTestClientWithClientTypeAsJSON(final String dateOfJoining, final String officeId, final String clientType) { - final HashMap map = new HashMap<>(); - map.put("officeId", officeId); - map.put("legalFormId", LEGALFORM_ID_PERSON); - map.put("firstname", Utils.randomNameGenerator("Client_FirstName_", 5)); - map.put("lastname", Utils.randomNameGenerator("Client_LastName_", 4)); - map.put("externalId", randomIDGenerator("ID_", 7)); - map.put("dateFormat", Utils.DATE_FORMAT); - map.put("locale", "en"); + HashMap map = setInitialClientValues("1", LEGALFORM_ID_PERSON); map.put("active", "true"); map.put("activationDate", dateOfJoining); map.put("clientTypeId", clientType); @@ -367,6 +434,13 @@ public class ClientHelper extends IntegrationTest { return GSON.fromJson(clientResponseStr, GetClientsClientIdResponse.class); } + public static GetClientsClientIdResponse getClientByExternalId(final RequestSpecification requestSpec, + final ResponseSpecification responseSpec, final String externalId) { + final String url = CLIENT_EXTERNALID_URL + "/" + externalId + "?" + Utils.TENANT_IDENTIFIER; + final String response = Utils.performServerGet(requestSpec, responseSpec, url); + return GSON.fromJson(response, GetClientsClientIdResponse.class); + } + public static List getClientAddresses(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final int clientId) { final String GET_CLIENT_ADDRESSES_URL = "/fineract-provider/api/v1/client/" + clientId + "/addresses?" + Utils.TENANT_IDENTIFIER; @@ -400,7 +474,7 @@ public class ClientHelper extends IntegrationTest { return Utils.randomStringGenerator(prefix, lenOfRandomSuffix, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); } - private String getCloseClientAsJSON() { + public String getCloseClientAsJSON() { final HashMap map = new HashMap<>(); /* Retrieve Code id for the Code "ClientClosureReason" */ @@ -418,20 +492,18 @@ public class ClientHelper extends IntegrationTest { map.put("closureDate", CREATED_DATE_PLUS_ONE); String clientJson = GSON.toJson(map); - log.info(clientJson); + log.info("{}", clientJson); return clientJson; - } - private String getReactivateClientAsJSON() { + public String getReactivateClientAsJSON() { final HashMap map = new HashMap<>(); map.put("locale", CommonConstants.LOCALE); map.put("dateFormat", CommonConstants.DATE_FORMAT); map.put("reactivationDate", CREATED_DATE_PLUS_ONE); String clientJson = GSON.toJson(map); - log.info(clientJson); + log.info("{}", clientJson); return clientJson; - } private String getUndoRejectClientAsJSON(final String date) { @@ -440,7 +512,7 @@ public class ClientHelper extends IntegrationTest { map.put("dateFormat", CommonConstants.DATE_FORMAT); map.put("reopenedDate", date); String clientJson = GSON.toJson(map); - log.info(clientJson); + log.info("{}", clientJson); return clientJson; } @@ -451,12 +523,12 @@ public class ClientHelper extends IntegrationTest { map.put("dateFormat", CommonConstants.DATE_FORMAT); map.put("reopenedDate", date); String clientJson = GSON.toJson(map); - log.info(clientJson); + log.info("{}", clientJson); return clientJson; } - private String getRejectClientAsJSON() { + public String getRejectClientAsJSON() { final HashMap map = new HashMap<>(); /* Retrieve Code id for the Code "ClientRejectReason" */ String codeName = "ClientRejectReason"; @@ -473,18 +545,18 @@ public class ClientHelper extends IntegrationTest { map.put("rejectionDate", CREATED_DATE_PLUS_ONE); map.put("rejectionReasonId", rejectionReasonId.toString()); String clientJson = GSON.toJson(map); - log.info(clientJson); + log.info("{}", clientJson); return clientJson; } - private static String getActivateClientAsJSON(String date) { + public static String getActivateClientAsJSON(String date) { final HashMap map = new HashMap<>(); map.put("locale", CommonConstants.LOCALE); map.put("dateFormat", CommonConstants.DATE_FORMAT); map.put("activationDate", date); String clientJson = GSON.toJson(map); - log.info(clientJson); + log.info("{}", clientJson); return clientJson; } @@ -507,7 +579,6 @@ public class ClientHelper extends IntegrationTest { String clientJson = GSON.toJson(map); log.info(clientJson); return clientJson; - } public static String getSpecifiedDueDateChargesClientAsJSON(final String chargeId, final String dueDate) { @@ -622,6 +693,13 @@ public class ClientHelper extends IntegrationTest { return response; } + public static PostClientsClientIdResponse performClientActionUsingExternalId(final RequestSpecification requestSpec, + final ResponseSpecification responseSpec, final String externalId, final String command, final String jsonPayload) { + final String url = CLIENT_EXTERNALID_URL + "/" + externalId + "?" + Utils.TENANT_IDENTIFIER + "&command=" + command; + final String response = Utils.performServerPost(requestSpec, responseSpec, url, jsonPayload); + return GSON.fromJson(response, PostClientsClientIdResponse.class); + } + public static Integer addChargesForClient(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final Integer clientId, final String request) { log.info("--------------------------------- ADD CHARGES FOR Client --------------------------------"); @@ -711,6 +789,6 @@ public class ClientHelper extends IntegrationTest { return new PostClientsRequest().officeId(1).legalFormId(LEGALFORM_ID_PERSON) .firstname(Utils.randomNameGenerator("Client_FirstName_", 5)).lastname(Utils.randomNameGenerator("Client_LastName_", 5)) .externalId(randomIDGenerator("ID_", 7)).dateFormat(Utils.DATE_FORMAT).locale("en").active(true) - .activationDate("04 March 2011"); + .activationDate(DEFAULT_DATE); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java index 22192a84f..041e0b1f1 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java @@ -18,6 +18,9 @@ */ package org.apache.fineract.integrationtests.common; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import com.google.gson.Gson; import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; @@ -38,6 +41,8 @@ public class GlobalConfigurationHelper { private final RequestSpecification requestSpec; private final ResponseSpecification responseSpec; + public static final String ENABLE_AUTOGENERATED_EXTERNAL_ID = "enable-auto-generated-external-id"; + public static ArrayList getAllGlobalConfigurations(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { final String GET_ALL_GLOBAL_CONFIG_URL = "/fineract-provider/api/v1/configurations?" + Utils.TENANT_IDENTIFIER; @@ -614,4 +619,14 @@ public class GlobalConfigurationHelper { long configId = 44; return updateEnabledFlagForGlobalConfiguration(requestSpec, responseSpec, configId, enabled); } + + public static void manageConfigurations(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final String configurationName, final boolean enabled) { + GlobalConfigurationPropertyData configuration = getGlobalConfigurationByName(requestSpec, responseSpec, configurationName); + assertNotNull(configuration); + updateEnabledFlagForGlobalConfiguration(requestSpec, responseSpec, configuration.getId(), enabled); + GlobalConfigurationPropertyData updatedConfiguration = getGlobalConfigurationByName(requestSpec, responseSpec, configurationName); + assertEquals(updatedConfiguration.getEnabled(), enabled); + } + }