diff --git a/mifosng-db/patches/00003-drop-recreate-client-indentifier-table.sql b/mifosng-db/patches/00003-drop-recreate-client-indentifier-table.sql new file mode 100644 index 000000000..d2369e7f1 --- /dev/null +++ b/mifosng-db/patches/00003-drop-recreate-client-indentifier-table.sql @@ -0,0 +1,20 @@ +drop table `m_client_identifier`; + +CREATE TABLE `m_client_identifier` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `client_id` bigint(20) NOT NULL, + `document_type_id` int(11) NOT NULL, + `document_key` varchar(50) NOT NULL, + `description` varchar(500) DEFAULT NULL, + `createdby_id` bigint(20) DEFAULT NULL, + `lastmodifiedby_id` bigint(20) DEFAULT NULL, + `created_date` datetime DEFAULT NULL, + `lastmodified_date` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `unique_identifier_key` (`document_type_id`, `document_key`), + UNIQUE KEY `unique_client_identifier` (`client_id`,`document_type_id`), + KEY `FK_m_client_document_m_client` (`client_id`), + KEY `FK_m_client_document_m_code_value` (`document_type_id`), + CONSTRAINT `FK_m_client_document_m_client` FOREIGN KEY (`client_id`) REFERENCES `m_client` (`id`), + CONSTRAINT `FK_m_client_document_m_code_value` FOREIGN KEY (`document_type_id`) REFERENCES `m_code_value` (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8; \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/ClientIdentifiersApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/ClientIdentifiersApiResource.java index eb251c9a1..11b94e3c1 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/ClientIdentifiersApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/ClientIdentifiersApiResource.java @@ -19,6 +19,7 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import org.mifosng.platform.api.commands.ClientIdentifierCommand; +import org.mifosng.platform.api.data.ClientData; import org.mifosng.platform.api.data.ClientIdentifierData; import org.mifosng.platform.api.data.EntityIdentifier; import org.mifosng.platform.api.infrastructure.ApiDataConversionService; @@ -26,6 +27,7 @@ import org.mifosng.platform.api.infrastructure.ApiJsonSerializerService; import org.mifosng.platform.api.infrastructure.ApiParameterHelper; import org.mifosng.platform.client.service.ClientReadPlatformService; import org.mifosng.platform.client.service.ClientWritePlatformService; +import org.mifosng.platform.exceptions.DuplicateClientIdentifierException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -35,8 +37,6 @@ import org.springframework.stereotype.Component; @Scope("singleton") public class ClientIdentifiersApiResource { -// private final static Logger logger = LoggerFactory.getLogger(ClientIdentifiersApiResource.class); - @Autowired private ClientReadPlatformService clientReadPlatformService; @@ -105,15 +105,22 @@ public class ClientIdentifiersApiResource { @PathParam("clientId") final Long clientId, final String jsonRequestBody) { - ClientIdentifierCommand command = this.apiDataConversionService - .convertJsonToClientIdentifierCommand(null, clientId, - jsonRequestBody); - - Long clientIdentifierId = this.clientWritePlatformService - .addClientIdentifier(command); - - return Response.ok().entity(new EntityIdentifier(clientIdentifierId)) - .build(); + try { + final ClientIdentifierCommand command = this.apiDataConversionService.convertJsonToClientIdentifierCommand(null, clientId, jsonRequestBody); + + Long clientIdentifierId = this.clientWritePlatformService.addClientIdentifier(command); + + return Response.ok().entity(new EntityIdentifier(clientIdentifierId)).build(); + } + catch (DuplicateClientIdentifierException e) { + DuplicateClientIdentifierException rethrowas = e; + if (e.getDocumentTypeId() != null) { + // need to fetch client info + ClientData clientInfo = this.clientReadPlatformService.retrieveClientByIdentifier(e.getDocumentTypeId(), e.getIdentifierKey()); + rethrowas = new DuplicateClientIdentifierException(clientInfo.displayName(), clientInfo.officeName(), e.getIdentifierType(), e.getIdentifierKey()); + } + throw rethrowas; + } } @GET @@ -125,24 +132,18 @@ public class ClientIdentifiersApiResource { @PathParam("identifierId") final Long clientIdentifierId, @Context final UriInfo uriInfo) { - Set responseParameters = ApiParameterHelper - .extractFieldsForResponseIfProvided(uriInfo - .getQueryParameters()); + final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); if (responseParameters.isEmpty()) { responseParameters.addAll(typicalResponseParameters); } - boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo - .getQueryParameters()); - boolean template = ApiParameterHelper.template(uriInfo - .getQueryParameters()); - + boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters()); if (template) { responseParameters.add("allowedDocumentTypes"); } - ClientIdentifierData clientIdentifierData = this.clientReadPlatformService - .retrieveClientIdentifier(clientId, clientIdentifierId); + final ClientIdentifierData clientIdentifierData = this.clientReadPlatformService.retrieveClientIdentifier(clientId, clientIdentifierId); return this.apiJsonSerializerService .serializeClientIdentifierDataToJson(prettyPrint, @@ -151,21 +152,28 @@ public class ClientIdentifiersApiResource { @PUT @Path("{identifierId}") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) public Response updateClientIdentifer( @PathParam("clientId") final Long clientId, @PathParam("identifierId") final Long clientIdentifierId, final String jsonRequestBody) { - ClientIdentifierCommand command = this.apiDataConversionService - .convertJsonToClientIdentifierCommand(clientIdentifierId, - clientId, jsonRequestBody); + try { + final ClientIdentifierCommand command = this.apiDataConversionService.convertJsonToClientIdentifierCommand(clientIdentifierId, clientId, jsonRequestBody); - EntityIdentifier identifier = this.clientWritePlatformService - .updateClientIdentifier(command); + final EntityIdentifier identifier = this.clientWritePlatformService.updateClientIdentifier(command); - return Response.ok().entity(identifier).build(); + return Response.ok().entity(identifier).build(); + } + catch (DuplicateClientIdentifierException e) { + DuplicateClientIdentifierException reThrowAs = e; + if (e.getDocumentTypeId() != null) { + ClientData clientInfo = this.clientReadPlatformService.retrieveClientByIdentifier(e.getDocumentTypeId(), e.getIdentifierKey()); + reThrowAs = new DuplicateClientIdentifierException(clientInfo.displayName(), clientInfo.officeName(), e.getIdentifierType(), e.getIdentifierKey()); + } + throw reThrowAs; + } } @DELETE @@ -173,13 +181,10 @@ public class ClientIdentifiersApiResource { @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) public Response deleteClientIdentifier( -// @PathParam("clientId") final Long clientId, @PathParam("identifierId") final Long clientIdentifierId) { - this.clientWritePlatformService - .deleteClientIdentifier(clientIdentifierId); + this.clientWritePlatformService.deleteClientIdentifier(clientIdentifierId); return Response.ok(new EntityIdentifier(clientIdentifierId)).build(); } - } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientData.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientData.java index 88346b222..58f78e4ce 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientData.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientData.java @@ -6,6 +6,9 @@ import java.util.List; import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; +/** + * FIXME - KW - make ClientData immutable without needs for getter/setters as is mostly intended for conversion back to JSON. + */ public class ClientData { private final Long id; @@ -19,6 +22,22 @@ public class ClientData { private final LocalDate joinedDate; private List allowedOffices = new ArrayList(); + + public static ClientData clientIdentifier( + final Long id, + final String firstname, + final String lastname, + final Long officeId, + final String officeName) { + + StringBuilder displayNameBuilder = new StringBuilder(firstname); + if (StringUtils.isNotBlank(displayNameBuilder.toString())) { + displayNameBuilder.append(' '); + } + displayNameBuilder.append(lastname); + + return new ClientData(officeId, officeName, id, firstname, lastname, displayNameBuilder.toString(), null, null); + } public ClientData(final Long officeId, final String officeName, final Long id, final String firstname, final String lastname, @@ -100,4 +119,12 @@ public class ClientData { public void setAllowedOffices(List allowedOffices) { this.allowedOffices = allowedOffices; } + + public String displayName() { + return this.displayName; + } + + public String officeName() { + return this.officeName; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientLookup.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientLookup.java index 46797c270..b967a6fed 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientLookup.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ClientLookup.java @@ -65,6 +65,4 @@ public class ClientLookup { public String getOfficeName() { return officeName; } - - } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/ClientIdentifier.java b/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/ClientIdentifier.java index 7f3f113e4..82299bb37 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/ClientIdentifier.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/ClientIdentifier.java @@ -55,8 +55,10 @@ public class ClientIdentifier extends AbstractAuditableCustom { this.description = StringUtils.defaultIfEmpty(description, null); } - public void update(final ClientIdentifierCommand command, + public void update( + final ClientIdentifierCommand command, final CodeValue documentType) { + if (command.isDocumentTypeChanged()) { this.documentType = documentType; } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/ClientIdentifierRepository.java b/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/ClientIdentifierRepository.java index 58c82fec2..23a0ca932 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/ClientIdentifierRepository.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/client/domain/ClientIdentifierRepository.java @@ -2,15 +2,9 @@ package org.mifosng.platform.client.domain; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; public interface ClientIdentifierRepository extends JpaRepository, JpaSpecificationExecutor { - - @Query("from ClientIdentifier ci where ci.documentType.id= :documentTypeId and ci.documentKey= :documentKey") - ClientIdentifier getClientIdentifierByDocumentTypeAndKey( - @Param("documentTypeId") Long documentTypeId, - @Param("documentKey") String documentKey); + // no behaviour } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformService.java index 4f1563a17..e0b689f8f 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformService.java @@ -26,19 +26,11 @@ public interface ClientReadPlatformService { NoteData retrieveClientNote(Long clientId, Long noteId); - - /** - * @param clientId - * @return - */ Collection retrieveClientIdentifiers(Long clientId); ClientIdentifierData retrieveClientIdentifier(Long clientId,Long clientIdentifierId); - /** - * @return - */ ClientIdentifierData retrieveNewClientIdentifierDetails(); - Boolean existsClientIdentifier(Long clientId,Long identifierTypeId); - ClientLookup getClientByIdentifier(Long identifierTypeId, String identifierKey); + + ClientData retrieveClientByIdentifier(Long identifierTypeId, String identifierKey); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformServiceImpl.java index 5e142cc72..5ed3f4a22 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientReadPlatformServiceImpl.java @@ -178,14 +178,6 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService "from m_client c join m_office o on o.id = c.office_id where c.is_deleted=0 "; } - public String clientLookupByIdentifierSchema() { - return "c.id as id, c.firstname as firstname, c.lastname as lastname, " + - "c.office_id as officeId, o.name as officeName " + - "from m_client c, m_office o, m_client_identifier ci " + - "where o.id = c.office_id and c.id=ci.client_id " + - "and ci.document_type_id= ? and ci.document_key like ?"; - } - @Override public ClientLookup mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { Long id = rs.getLong("id"); @@ -528,42 +520,46 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService } @Override - public Boolean existsClientIdentifier(Long clientId, Long identifierTypeId) { + public ClientData retrieveClientByIdentifier( + final Long identifierTypeId, + final String identifierKey) { try { - AppUser currentUser = context.authenticatedUser(); - String hierarchy = currentUser.getOffice().getHierarchy(); - String hierarchySearchString = hierarchy + "%"; + final ClientIdentifierMapper mapper = new ClientIdentifierMapper(); - ClientIdentityMapper rm = new ClientIdentityMapper(); + final String sql = "select " + mapper.clientLookupByIdentifierSchema(); - String sql = "select " + rm.schema() + " and ci.document_type_id=?"; - /****query for Object throws an exception if exactly one row is not returned***/ - this.jdbcTemplate.queryForObject(sql, rm, new Object[] { clientId, - hierarchySearchString, identifierTypeId }); - return true; - } catch (EmptyResultDataAccessException e) { - return false; - } - } - - - @Override - public ClientLookup getClientByIdentifier(Long identifierTypeId, - String identifierKey) { - try { - ClientLookupMapper mapper = new ClientLookupMapper(); - - String sql = "select " + mapper.clientLookupByIdentifierSchema(); - /**** - * query for Object throws an exception if exactly one row is not - * returned - ***/ - ClientLookup clientLookup = jdbcTemplate.queryForObject(sql, - mapper, new Object[] { identifierTypeId, identifierKey }); - return clientLookup; + return jdbcTemplate.queryForObject(sql, mapper, new Object[] { identifierTypeId, identifierKey }); } catch (EmptyResultDataAccessException e) { return null; } } + private static final class ClientIdentifierMapper implements RowMapper { + + public String clientLookupByIdentifierSchema() { + return "c.id as id, c.firstname as firstname, c.lastname as lastname, " + + "c.office_id as officeId, o.name as officeName " + + "from m_client c, m_office o, m_client_identifier ci " + + "where o.id = c.office_id and c.id=ci.client_id " + + "and ci.document_type_id= ? and ci.document_key like ?"; + } + + @Override + public ClientData mapRow(final ResultSet rs, + @SuppressWarnings("unused") final int rowNum) + throws SQLException { + + final Long id = rs.getLong("id"); + String firstname = rs.getString("firstname"); + if (StringUtils.isBlank(firstname)) { + firstname = ""; + } + final String lastname = rs.getString("lastname"); + + final Long officeId = rs.getLong("officeId"); + final String officeName = rs.getString("officeName"); + + return ClientData.clientIdentifier(id, firstname, lastname, officeId, officeName); + } + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index 1a80fd5d1..2107a6bc6 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -31,11 +31,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service -public class ClientWritePlatformServiceJpaRepositoryImpl implements - ClientWritePlatformService { +public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWritePlatformService { - private final static Logger logger = LoggerFactory - .getLogger(ClientWritePlatformServiceJpaRepositoryImpl.class); + private final static Logger logger = LoggerFactory.getLogger(ClientWritePlatformServiceJpaRepositoryImpl.class); private final PlatformSecurityContext context; private final ClientRepository clientRepository; @@ -64,7 +62,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements @Override public EntityIdentifier deleteClient(final Long clientId) { - Client client = this.clientRepository.findOne(clientId); + final Client client = this.clientRepository.findOne(clientId); if (client == null || client.isDeleted()) { throw new ClientNotFoundException(clientId); } @@ -104,12 +102,10 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements try { context.authenticatedUser(); - ClientCommandValidator validator = new ClientCommandValidator( - command); + final ClientCommandValidator validator = new ClientCommandValidator(command); validator.validateForCreate(); - Office clientOffice = this.officeRepository.findOne(command - .getOfficeId()); + final Office clientOffice = this.officeRepository.findOne(command.getOfficeId()); if (clientOffice == null) { throw new OfficeNotFoundException(command.getOfficeId()); } @@ -141,8 +137,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements try { context.authenticatedUser(); - ClientCommandValidator validator = new ClientCommandValidator( - command); + final ClientCommandValidator validator = new ClientCommandValidator(command); validator.validateForUpdate(); Office clientOffice = null; @@ -154,8 +149,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements } } - Client clientForUpdate = this.clientRepository.findOne(command - .getId()); + final Client clientForUpdate = this.clientRepository.findOne(command.getId()); if (clientForUpdate == null || clientForUpdate.isDeleted()) { throw new ClientNotFoundException(command.getId()); } @@ -176,13 +170,12 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements context.authenticatedUser(); - Client clientForUpdate = this.clientRepository.findOne(command - .getClientId()); + final Client clientForUpdate = this.clientRepository.findOne(command.getClientId()); if (clientForUpdate == null) { throw new ClientNotFoundException(command.getClientId()); } - Note note = Note.clientNote(clientForUpdate, command.getNote()); + final Note note = Note.clientNote(clientForUpdate, command.getNote()); this.noteRepository.save(note); @@ -195,12 +188,10 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements context.authenticatedUser(); - Note noteForUpdate = this.noteRepository.findOne(command.getId()); + final Note noteForUpdate = this.noteRepository.findOne(command.getId()); if (noteForUpdate == null - || noteForUpdate.isNotAgainstClientWithIdOf(command - .getClientId())) { - throw new NoteNotFoundException(command.getId(), - command.getClientId(), "client"); + || noteForUpdate.isNotAgainstClientWithIdOf(command.getClientId())) { + throw new NoteNotFoundException(command.getId(),command.getClientId(), "client"); } noteForUpdate.update(command.getNote()); @@ -210,131 +201,117 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements @Transactional @Override - public Long addClientIdentifier( - ClientIdentifierCommand clientIdentifierCommand) { - CodeValue documentType = null; - String documentKey = null; + public Long addClientIdentifier(final ClientIdentifierCommand command) { + + String documentTypeLabel = null; + Long documentTypeId = null; + final String documentKey = command.getDocumentKey(); + try { context.authenticatedUser(); - ClientIdentifierCommandValidator validator = new ClientIdentifierCommandValidator( - clientIdentifierCommand); + final ClientIdentifierCommandValidator validator = new ClientIdentifierCommandValidator(command); validator.validateForCreate(); - Client client = this.clientRepository - .findOne(clientIdentifierCommand.getClientId()); - if (client == null) { - throw new ClientNotFoundException( - clientIdentifierCommand.getClientId()); + final Client client = this.clientRepository.findOne(command.getClientId()); + if (client == null || client.isDeleted()) { + throw new ClientNotFoundException(command.getClientId()); } - documentType = this.codeValueRepository - .findOne(clientIdentifierCommand.getDocumentTypeId()); + final CodeValue documentType = this.codeValueRepository.findOne(command.getDocumentTypeId()); if (documentType == null) { - throw new CodeValueNotFoundException( - clientIdentifierCommand.getDocumentTypeId()); + throw new CodeValueNotFoundException(command.getDocumentTypeId()); } + documentTypeId = documentType.getId(); + documentTypeLabel = documentType.getLabel(); - documentKey = clientIdentifierCommand.getDocumentKey(); - String description = clientIdentifierCommand.getDescription(); - - ClientIdentifier clientIdentifier = ClientIdentifier.createNew( - client, documentType, documentKey, description); + final ClientIdentifier clientIdentifier = ClientIdentifier.createNew(client, documentType, documentKey, command.getDescription()); this.clientIdentifierRepository.save(clientIdentifier); return clientIdentifier.getId(); } catch (DataIntegrityViolationException dve) { - logger.error(dve.getMessage(), dve); - if (dve.getMostSpecificCause().getMessage().contains("unique_client_identifier")) { - throw new DuplicateClientIdentifierException( - documentType.getLabel()); - }else if(dve.getMostSpecificCause().getMessage().contains("unique_identifier_key")){ - handleDuplicateClientIdentifierKeyScenario(documentType.getId(), - documentType.getLabel(), documentKey); - } - throw new PlatformDataIntegrityException( - "error.msg.clientIdentifier.unknown.data.integrity.issue", - "Unknown data integrity issue with resource."); + handleClientIdentifierDataIntegrityViolation(documentTypeLabel, documentTypeId, documentKey, dve); + return Long.valueOf(-1); } } - @Transactional @Override - public EntityIdentifier updateClientIdentifier( - ClientIdentifierCommand clientIdentifierCommand) { - CodeValue documentType = null; - Long documentTypeId = null; - ClientIdentifier clientIdentifierForUpdate = null; + public EntityIdentifier updateClientIdentifier(final ClientIdentifierCommand command) { + + String documentTypeLabel = null; + Long documentTypeId = null; + String documentKey = command.getDocumentKey(); + try { context.authenticatedUser(); - ClientIdentifierCommandValidator validator = new ClientIdentifierCommandValidator( - clientIdentifierCommand); + final ClientIdentifierCommandValidator validator = new ClientIdentifierCommandValidator(command); validator.validateForUpdate(); - documentTypeId = clientIdentifierCommand.getDocumentTypeId(); - if (clientIdentifierCommand.isDocumentTypeChanged() - && documentTypeId != null) { + CodeValue documentType = null; + documentTypeId = command.getDocumentTypeId(); + if (command.isDocumentTypeChanged() && documentTypeId != null) { documentType = this.codeValueRepository.findOne(documentTypeId); if (documentType == null) { - throw new CodeValueNotFoundException( - clientIdentifierCommand.getDocumentTypeId()); + throw new CodeValueNotFoundException(command.getDocumentTypeId()); } + documentTypeId = documentType.getId(); + documentTypeLabel = documentType.getLabel(); } - clientIdentifierForUpdate = this.clientIdentifierRepository - .findOne(clientIdentifierCommand.getId()); + final ClientIdentifier clientIdentifierForUpdate = this.clientIdentifierRepository.findOne(command.getId()); if (clientIdentifierForUpdate == null) { - throw new ClientIdentifierNotFoundException( - clientIdentifierCommand.getId()); + throw new ClientIdentifierNotFoundException(command.getId()); } - clientIdentifierForUpdate.update(clientIdentifierCommand, - documentType); + // TODO - KW - why need to check what changed when integrity violation occurs? + if (command.isDocumentTypeChanged() && command.isDocumentKeyChanged()) { + documentTypeId = command.getDocumentTypeId(); + documentKey = command.getDocumentKey(); + } else if (command.isDocumentTypeChanged() && !command.isDocumentKeyChanged()) { + documentTypeId = command.getDocumentTypeId(); + documentKey = clientIdentifierForUpdate.getDocumentKey(); + } else if (!command.isDocumentTypeChanged() && command.isDocumentKeyChanged()) { + documentTypeId = clientIdentifierForUpdate.getDocumentType().getId(); + documentKey = clientIdentifierForUpdate.getDocumentKey(); + } + + clientIdentifierForUpdate.update(command, documentType); - this.clientIdentifierRepository - .saveAndFlush(clientIdentifierForUpdate); + this.clientIdentifierRepository.saveAndFlush(clientIdentifierForUpdate); return new EntityIdentifier(clientIdentifierForUpdate.getId()); } catch (DataIntegrityViolationException dve) { - logger.error(dve.getMessage(), dve); - if (dve.getMostSpecificCause().getMessage().contains("unique_client_identifier")) { - throw new DuplicateClientIdentifierException( - documentType.getLabel()); - }else if(dve.getMostSpecificCause().getMessage().contains("unique_identifier_key")){ - /*** Throw error with details of existing customer with same identifier ***/ - if (clientIdentifierCommand.isDocumentTypeChanged() - && clientIdentifierCommand.isDocumentKeyChanged()) { - handleDuplicateClientIdentifierKeyScenario( - clientIdentifierCommand.getDocumentTypeId(), - documentType.getLabel(), - clientIdentifierCommand.getDocumentKey()); - } else if (clientIdentifierCommand.isDocumentTypeChanged() - && !clientIdentifierCommand.isDocumentKeyChanged()) { - handleDuplicateClientIdentifierKeyScenario( - clientIdentifierCommand.getDocumentTypeId(), - documentType.getLabel(), - clientIdentifierForUpdate.getDocumentKey()); - } else if (!clientIdentifierCommand.isDocumentTypeChanged() - && clientIdentifierCommand.isDocumentKeyChanged()) { - handleDuplicateClientIdentifierKeyScenario(clientIdentifierForUpdate - .getDocumentType().getId(), documentType.getLabel(), - clientIdentifierCommand.getDocumentKey()); - } - } - throw new PlatformDataIntegrityException( - "error.msg.clientIdentifier.unknown.data.integrity.issue", - "Unknown data integrity issue with resource."); + handleClientIdentifierDataIntegrityViolation(documentTypeLabel, documentTypeId, documentKey, dve); + return new EntityIdentifier(Long.valueOf(-1)); } } + private void handleClientIdentifierDataIntegrityViolation( + final String documentTypeLabel, + final Long documentTypeId, + final String documentKey, + final DataIntegrityViolationException dve) { + + if (dve.getMostSpecificCause().getMessage().contains("unique_client_identifier")) { + throw new DuplicateClientIdentifierException(documentTypeLabel); + } else if (dve.getMostSpecificCause().getMessage().contains("unique_identifier_key")) { + throw new DuplicateClientIdentifierException(documentTypeId, documentTypeLabel, documentKey); + } + + // only log as error if unexpected data integrity violation. + logger.error(dve.getMessage(), dve); + throw new PlatformDataIntegrityException( + "error.msg.clientIdentifier.unknown.data.integrity.issue", + "Unknown data integrity issue with resource."); + } + @Transactional @Override - public EntityIdentifier deleteClientIdentifier(Long clientIdentifierId) { - ClientIdentifier clientIdentifier = this.clientIdentifierRepository - .findOne(clientIdentifierId); + public EntityIdentifier deleteClientIdentifier(final Long clientIdentifierId) { + final ClientIdentifier clientIdentifier = this.clientIdentifierRepository.findOne(clientIdentifierId); if (clientIdentifier == null) { throw new ClientIdentifierNotFoundException(clientIdentifierId); } @@ -342,18 +319,4 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements return new EntityIdentifier(clientIdentifierId); } - - /** - * @param documentTypeId - * @param documentTypeLabel - * @param documentKey - */ - private void handleDuplicateClientIdentifierKeyScenario(Long documentTypeId, - String documentTypeLabel, String documentKey) { - Client client = this.clientIdentifierRepository - .getClientIdentifierByDocumentTypeAndKey(documentTypeId, documentKey).getClient(); - throw new DuplicateClientIdentifierException( - client.getDisplayName(), client.getOffice().getName(), - documentTypeLabel, documentKey); - } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DuplicateClientIdentifierException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DuplicateClientIdentifierException.java index 6f7dc9122..a11444841 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DuplicateClientIdentifierException.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DuplicateClientIdentifierException.java @@ -1,23 +1,52 @@ package org.mifosng.platform.exceptions; /** - * A {@link RuntimeException} thrown when a client Identifer of the particular - * type is already present + * A {@link RuntimeException} thrown when a client identifier of the particular type is already present */ -public class DuplicateClientIdentifierException extends - AbstractPlatformDomainRuleException { +public class DuplicateClientIdentifierException extends AbstractPlatformDomainRuleException { - public DuplicateClientIdentifierException(String identifierType) { + private Long documentTypeId; + private String identifierKey; + private String identifierType; + + public DuplicateClientIdentifierException(final String identifierType) { super("error.msg.clientIdentifier.type.duplicate", - "Client Identifier of type " + identifierType + "Client identifier of type " + identifierType + " is already present for this client", identifierType); + this.identifierType = identifierType; + } + + public DuplicateClientIdentifierException(final Long documentTypeId, final String identifierType, final String identifierKey) { + super("error.msg.clientIdentifier.identityKey.duplicate", + "Client identifier of type " + identifierType + + " with value of " + identifierKey + " already exists.", identifierType, identifierKey); + this.documentTypeId = documentTypeId; + this.identifierType = identifierType; + this.identifierKey = identifierKey; } - public DuplicateClientIdentifierException(String clientName, - String officeName, String identifierType, String identifierKey) { + public DuplicateClientIdentifierException( + final String clientName, + final String officeName, + final String identifierType, + final String identifierKey) { super("error.msg.clientIdentifier.identityKey.duplicate", "Client " + clientName + "under " + officeName + " Branch already has a " + identifierType + " with unique key " + identifierKey, clientName, officeName, identifierType, identifierKey); + this.identifierType = identifierType; + this.identifierKey = identifierKey; + } + + public Long getDocumentTypeId() { + return documentTypeId; + } + + public String getIdentifierKey() { + return identifierKey; + } + + public String getIdentifierType() { + return identifierType; } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/staff/service/StaffReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/staff/service/StaffReadPlatformServiceImpl.java index 8f4079d9d..d3c816757 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/staff/service/StaffReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/staff/service/StaffReadPlatformServiceImpl.java @@ -22,7 +22,8 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService { private final PlatformSecurityContext context; @Autowired - public StaffReadPlatformServiceImpl(final PlatformSecurityContext context, + public StaffReadPlatformServiceImpl( + final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource) { this.context = context; this.jdbcTemplate = new JdbcTemplate(dataSource); @@ -37,7 +38,7 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService { } @Override - public StaffData mapRow(final ResultSet rs, final int rowNum) + public StaffData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { Long id = rs.getLong("id");