/*******************************************************************************
* Open Behavioral Health Information Technology Architecture (OBHITA.org)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package gov.samhsa.consent2share.service.patient;
import gov.samhsa.consent2share.common.AuthenticatedUser;
import gov.samhsa.consent2share.common.UserContext;
import gov.samhsa.consent2share.domain.account.Users;
import gov.samhsa.consent2share.domain.account.UsersRepository;
import gov.samhsa.consent2share.domain.commondomainservices.EmailSender;
import gov.samhsa.consent2share.domain.commondomainservices.EmailType;
import gov.samhsa.consent2share.domain.consent.Consent;
import gov.samhsa.consent2share.domain.consent.ConsentIndividualProviderDisclosureIsMadeTo;
import gov.samhsa.consent2share.domain.consent.ConsentIndividualProviderPermittedToDisclose;
import gov.samhsa.consent2share.domain.consent.ConsentOrganizationalProviderDisclosureIsMadeTo;
import gov.samhsa.consent2share.domain.consent.ConsentOrganizationalProviderPermittedToDisclose;
import gov.samhsa.consent2share.domain.patient.Patient;
import gov.samhsa.consent2share.domain.patient.PatientLegalRepresentativeAssociation;
import gov.samhsa.consent2share.domain.patient.PatientLegalRepresentativeAssociationRepository;
import gov.samhsa.consent2share.domain.patient.PatientRepository;
import gov.samhsa.consent2share.domain.provider.IndividualProvider;
import gov.samhsa.consent2share.domain.provider.OrganizationalProvider;
import gov.samhsa.consent2share.infrastructure.DtoToDomainEntityMapper;
import gov.samhsa.consent2share.infrastructure.PixService;
import gov.samhsa.consent2share.infrastructure.security.AuthenticationFailedException;
import gov.samhsa.consent2share.pixclient.util.PixManagerBean;
import gov.samhsa.consent2share.service.dto.AddConsentIndividualProviderDto;
import gov.samhsa.consent2share.service.dto.AddConsentOrganizationalProviderDto;
import gov.samhsa.consent2share.service.dto.IndividualProviderDto;
import gov.samhsa.consent2share.service.dto.OrganizationalProviderDto;
import gov.samhsa.consent2share.service.dto.PatientAdminDto;
import gov.samhsa.consent2share.service.dto.PatientConnectionDto;
import gov.samhsa.consent2share.service.dto.PatientProfileDto;
import gov.samhsa.consent2share.service.dto.RecentPatientDto;
import gov.samhsa.consent2share.service.util.TypeConverter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.mail.MessagingException;
import org.modelmapper.ModelMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* The Class PatientServiceImpl.
*/
@Transactional
public class PatientServiceImpl implements PatientService {
/** The logger. */
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/** The Constant LAST_N_DIGITS_OF_SSN. */
public static final Integer LAST_N_DIGITS_OF_SSN = 4;
/** The patient repository. */
protected PatientRepository patientRepository;
/** The patient legal representative association repository. */
protected PatientLegalRepresentativeAssociationRepository patientLegalRepresentativeAssociationRepository;
/** The model mapper. */
protected ModelMapper modelMapper;
/** The user context. */
protected UserContext userContext;
/** The patient profile dto to patient mapper. */
protected DtoToDomainEntityMapper<PatientProfileDto, Patient> patientProfileDtoToPatientMapper;
/** The users repository. */
protected UsersRepository usersRepository;
/** The password encoder. */
protected PasswordEncoder passwordEncoder;
/** The email sender. */
protected EmailSender emailSender;
/** The pix service. */
protected PixService pixService;
/**
* Instantiates a new patient service impl.
*
* @param patientRepository
* the patient repository
* @param patientLegalRepresentativeAssociationRepository
* the patient legal representative association repository
* @param modelMapper
* the model mapper
* @param userContext
* the user context
* @param patientProfileDtoToPatientMapper
* the patient profile dto to patient mapper
* @param usersRepository
* the users repository
* @param passwordEncoder
* the password encoder
* @param emailSender
* the email sender
* @param pixService
* the pix service
*/
public PatientServiceImpl(
PatientRepository patientRepository,
PatientLegalRepresentativeAssociationRepository patientLegalRepresentativeAssociationRepository,
ModelMapper modelMapper,
UserContext userContext,
DtoToDomainEntityMapper<PatientProfileDto, Patient> patientProfileDtoToPatientMapper,
UsersRepository usersRepository, PasswordEncoder passwordEncoder,
EmailSender emailSender, PixService pixService) {
super();
this.patientRepository = patientRepository;
this.patientLegalRepresentativeAssociationRepository = patientLegalRepresentativeAssociationRepository;
this.modelMapper = modelMapper;
this.userContext = userContext;
this.patientProfileDtoToPatientMapper = patientProfileDtoToPatientMapper;
this.usersRepository = usersRepository;
this.passwordEncoder = passwordEncoder;
this.emailSender = emailSender;
this.pixService = pixService;
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.patient.PatientService#countAllPatients
* ()
*/
@Override
public long countAllPatients() {
return patientRepository.count();
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.patient.PatientService#findPatient(java
* .lang.Long)
*/
@Override
public PatientProfileDto findPatient(Long id) {
Patient patient = patientRepository.findOne(id);
PatientProfileDto patientDto = modelMapper.map(patient,
PatientProfileDto.class);
return patientDto;
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.patient.PatientService#
* findAllPatientByFirstNameAndLastName(java.lang.String[])
*/
@Override
public List<PatientAdminDto> findAllPatientByFirstNameAndLastName(
String[] tokens) {
List<Patient> patients;
if (tokens.length == 1) {
patients = patientRepository
.findAllByFirstNameLikesAndLastNameLikes("%" + tokens[0]
+ "%");
} else if (tokens.length >= 2) {
patients = patientRepository
.findAllByFirstNameLikesAndLastNameLikes("%" + tokens[0]
+ "%", "%" + tokens[1] + "%");
} else {
patients = new ArrayList<Patient>();
}
List<PatientAdminDto> PatientAdminDtoList = mapPatientListToPatientAdminDtoList(patients);
return PatientAdminDtoList;
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.patient.PatientService#findByUsername
* (java.lang.String)
*/
@Override
public PatientProfileDto findByUsername(String username) {
Patient patient = patientRepository.findByUsername(username);
PatientProfileDto patientDto = modelMapper.map(patient,
PatientProfileDto.class);
return patientDto;
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.patient.PatientService#findIdByUsername
* (java.lang.String)
*/
@Override
public Long findIdByUsername(String username) {
return patientRepository.findByUsername(username).getId();
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.patient.PatientService#findUsernameById
* (java.lang.Long)
*/
@Override
public String findUsernameById(long id) {
return patientRepository.findOne(id).getUsername();
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.patient.PatientService#
* findPatientEmailByUsername(java.lang.String)
*/
@Override
public String findPatientEmailByUsername(String username) {
return patientRepository.findByUsername(username).getEmail();
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.patient.PatientService#
* findPatientProfileByUsername(java.lang.String)
*/
@Override
public PatientProfileDto findPatientProfileByUsername(String username) {
Patient patient = patientRepository.findByUsername(username);
PatientProfileDto patientDto = modelMapper.map(patient,
PatientProfileDto.class);
return patientDto;
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.patient.PatientService#
* findPatientConnectionByUsername(java.lang.String)
*/
@Override
public PatientConnectionDto findPatientConnectionByUsername(String username) {
Patient patient = patientRepository.findByUsername(username);
return findPatientConnectionByPatient(patient);
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.patient.PatientService#
* findPatientConnectionByPatient
* (gov.samhsa.consent2share.domain.patient.Patient)
*/
@Override
public PatientConnectionDto findPatientConnectionByPatient(Patient patient) {
PatientConnectionDto patientConnectionDto = modelMapper.map(patient,
PatientConnectionDto.class);
Set<IndividualProvider> consentIndividualProviders = new HashSet<IndividualProvider>();
Set<OrganizationalProvider> consentOrganizationalProviders = new HashSet<OrganizationalProvider>();
if (patient.getConsents() != null) {
Set<Consent> consents = patient.getConsents();
for (Consent consent : consents) {
Set<ConsentOrganizationalProviderDisclosureIsMadeTo> consentOrganizationalProviderDisclosureIsMadeTos = consent
.getOrganizationalProvidersDisclosureIsMadeTo();
if (consentOrganizationalProviderDisclosureIsMadeTos.size() != 0)
for (ConsentOrganizationalProviderDisclosureIsMadeTo cop : consentOrganizationalProviderDisclosureIsMadeTos) {
consentOrganizationalProviders.add(cop
.getOrganizationalProvider());
}
Set<ConsentOrganizationalProviderPermittedToDisclose> consentOrganizationalProviderPermittedToDiscloses = consent
.getOrganizationalProvidersPermittedToDisclose();
if (consentOrganizationalProviderPermittedToDiscloses.size() != 0)
for (ConsentOrganizationalProviderPermittedToDisclose copp : consentOrganizationalProviderPermittedToDiscloses) {
consentOrganizationalProviders.add(copp
.getOrganizationalProvider());
}
Set<ConsentIndividualProviderDisclosureIsMadeTo> consentIndividualProviderDisclosureIsMadeTos = consent
.getProvidersDisclosureIsMadeTo();
if (consentIndividualProviderDisclosureIsMadeTos.size() != 0)
for (ConsentIndividualProviderDisclosureIsMadeTo cip : consentIndividualProviderDisclosureIsMadeTos) {
consentIndividualProviders.add(cip
.getIndividualProvider());
}
Set<ConsentIndividualProviderPermittedToDisclose> consentIndividualProviderPermittedToDiscloses = consent
.getProvidersPermittedToDisclose();
if (consentIndividualProviderPermittedToDiscloses.size() != 0)
for (ConsentIndividualProviderPermittedToDisclose cipp : consentIndividualProviderPermittedToDiscloses) {
consentIndividualProviders.add(cipp
.getIndividualProvider());
}
}
}
// check whether the providers in the consent provider list
Set<IndividualProviderDto> individualProviderDtos = patientConnectionDto
.getIndividualProviders();
Set<OrganizationalProviderDto> organizationalProviderDtos = patientConnectionDto
.getOrganizationalProviders();
if (individualProviderDtos.size() != 0)
for (IndividualProviderDto individualProviderDto : individualProviderDtos) {
individualProviderDto.setDeletable(true);
for (IndividualProvider individualProvider : consentIndividualProviders) {
if (Long.parseLong(individualProviderDto.getId()) == individualProvider
.getId()
&& individualProviderDto.getNpi().equals(
individualProvider.getNpi()))
individualProviderDto.setDeletable(false);
}
}
if (organizationalProviderDtos.size() != 0)
for (OrganizationalProviderDto organizationalProviderDto : organizationalProviderDtos) {
organizationalProviderDto.setDeletable(true);
for (OrganizationalProvider organizationalProvider : consentOrganizationalProviders) {
if (Long.parseLong(organizationalProviderDto.getId()) == organizationalProvider
.getId()
&& organizationalProviderDto.getNpi().equals(
organizationalProvider.getNpi()))
organizationalProviderDto.setDeletable(false);
}
}
return patientConnectionDto;
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.patient.PatientService#
* findPatientConnectionById(long)
*/
@Override
public PatientConnectionDto findPatientConnectionById(long id) {
Patient patient = patientRepository.findOne(id);
return findPatientConnectionByPatient(patient);
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.patient.PatientService#findPatientEntries
* (int, int)
*/
@Override
public List<PatientProfileDto> findPatientEntries(int pageNumber,
int pageSize) {
List<Patient> patientList = patientRepository.findAll(
new PageRequest(pageNumber, pageSize)).getContent();
List<PatientProfileDto> patientDtoList = new ArrayList<PatientProfileDto>();
for (Patient patient : patientList) {
PatientProfileDto patientProfileDto = modelMapper.map(patient,
PatientProfileDto.class);
patientDtoList.add(patientProfileDto);
}
return patientDtoList;
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.patient.PatientService#savePatient(gov
* .samhsa.consent2share.service.dto.PatientProfileDto)
*/
@Override
@Transactional
public PatientProfileDto savePatient(PatientProfileDto patientDto) {
Patient patient = patientProfileDtoToPatientMapper.map(patientDto);
patientRepository.save(patient);
PatientProfileDto patientProfileDto = modelMapper.map(patient,
PatientProfileDto.class);
return patientProfileDto;
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.patient.PatientService#updatePatient
* (gov.samhsa.consent2share.service.dto.PatientProfileDto)
*/
@Override
@Transactional
public void updatePatient(PatientProfileDto patientDto)
throws AuthenticationFailedException {
AuthenticatedUser currentUser = userContext.getCurrentUser();
String username = patientDto.getUsername();
if (!currentUser.getUsername().equals(username))
throw new AuthenticationFailedException(
"Username does not match current active user.");
Users user = usersRepository.loadUserByUsername(username);
if (user != null)
if (!passwordEncoder.matches(patientDto.getPassword(),
user.getPassword()))
throw new AuthenticationFailedException(
"Password is incorrect.");
logger.info("{} being run...", "updatePatient");
Patient patient = patientProfileDtoToPatientMapper.map(patientDto);
// Find MRN
final String mrn = patient.getMedicalRecordNumber();
Assert.hasText(mrn, "MRN cannot be retrieved from database!");
// Update patient profile on MPI
PixManagerBean pixManagerBean = pixService.updatePatient(TypeConverter
.patientProfileDtoToPixPatientDto(patientDto, mrn));
Assert.isTrue(
pixManagerBean.isSuccess(),
"Patient cannot be updated on MPI! Error: "
+ pixManagerBean.getUpdateMessage());
// Get EID
final String eid = pixService.getEid(mrn);
Assert.hasText(eid, "EID cannot be retrieved from MPI!");
patient.setEnterpriseIdentifier(eid);
// Save
patientRepository.save(patient);
try {
emailSender.sendMessage(patientDto.getFirstName() + " "
+ patientDto.getLastName(), patientDto.getEmail(),
EmailType.USER_PROFILE_CHANGE, null, null);
} catch (MessagingException e) {
logger.warn("Error when sending the email message.");
}
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.patient.PatientService#updateEid(java
* .lang.String)
*/
@Override
@Transactional
public void updateEid(String username) {
Patient patient = patientRepository.findByUsername(username);
updateEid(patient);
}
/*
* (non-Javadoc)
*
* @see
* gov.samhsa.consent2share.service.patient.PatientService#updateEid(long)
*/
@Override
@Transactional
public void updateEid(long id) {
Patient patient = patientRepository.findOne(id);
updateEid(patient);
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.patient.PatientService#
* findAddConsentIndividualProviderDtoByUsername(java.lang.String)
*/
@Override
public List<AddConsentIndividualProviderDto> findAddConsentIndividualProviderDtoByUsername(
String username) {
Patient patient = patientRepository.findByUsername(username);
List<AddConsentIndividualProviderDto> individualProvidersDto = new ArrayList<AddConsentIndividualProviderDto>();
Set<IndividualProvider> individualProviders = patient
.getIndividualProviders();
Iterator<IndividualProvider> individualProvidersIterator = individualProviders
.iterator();
while (individualProvidersIterator.hasNext()) {
individualProvidersDto.add(modelMapper.map(
individualProvidersIterator.next(),
AddConsentIndividualProviderDto.class));
}
return individualProvidersDto;
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.patient.PatientService#
* findAddConsentOrganizationalProviderDtoByUsername(java.lang.String)
*/
@Override
public List<AddConsentOrganizationalProviderDto> findAddConsentOrganizationalProviderDtoByPatientId(
long pateintId) {
Patient patient = patientRepository.findOne(pateintId);
List<AddConsentOrganizationalProviderDto> organizationalProvidersDto = new ArrayList<AddConsentOrganizationalProviderDto>();
Set<OrganizationalProvider> organizationalProviders = patient
.getOrganizationalProviders();
Iterator<OrganizationalProvider> organizationalProvidersIterator = organizationalProviders
.iterator();
while (organizationalProvidersIterator.hasNext()) {
organizationalProvidersDto.add(modelMapper.map(
organizationalProvidersIterator.next(),
AddConsentOrganizationalProviderDto.class));
}
return organizationalProvidersDto;
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.patient.PatientService#
* findAddConsentIndividualProviderDtoByPatientId(long)
*/
@Override
public List<AddConsentIndividualProviderDto> findAddConsentIndividualProviderDtoByPatientId(
long pateintId) {
Patient patient = patientRepository.findOne(pateintId);
List<AddConsentIndividualProviderDto> individualProvidersDto = new ArrayList<AddConsentIndividualProviderDto>();
Set<IndividualProvider> individualProviders = patient
.getIndividualProviders();
Iterator<IndividualProvider> individualProvidersIterator = individualProviders
.iterator();
while (individualProvidersIterator.hasNext()) {
individualProvidersDto.add(modelMapper.map(
individualProvidersIterator.next(),
AddConsentIndividualProviderDto.class));
}
return individualProvidersDto;
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.patient.PatientService#
* findAddConsentOrganizationalProviderDtoByUsername(java.lang.String)
*/
@Override
public List<AddConsentOrganizationalProviderDto> findAddConsentOrganizationalProviderDtoByUsername(
String username) {
Patient patient = patientRepository.findByUsername(username);
List<AddConsentOrganizationalProviderDto> organizationalProvidersDto = new ArrayList<AddConsentOrganizationalProviderDto>();
Set<OrganizationalProvider> organizationalProviders = patient
.getOrganizationalProviders();
Iterator<OrganizationalProvider> organizationalProvidersIterator = organizationalProviders
.iterator();
while (organizationalProvidersIterator.hasNext()) {
organizationalProvidersDto.add(modelMapper.map(
organizationalProvidersIterator.next(),
AddConsentOrganizationalProviderDto.class));
}
return organizationalProvidersDto;
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.patient.PatientService#
* isLegalRepForCurrentUser(java.lang.Long)
*/
@Override
public boolean isLegalRepForCurrentUser(Long legalRepId) {
String username = userContext.getCurrentUser().getUsername();
Patient patient = patientRepository.findByUsername(username);
List<PatientLegalRepresentativeAssociation> associations = patientLegalRepresentativeAssociationRepository
.findByPatientLegalRepresentativeAssociationPkLegalRepresentativeId(legalRepId);
for (PatientLegalRepresentativeAssociation association : associations) {
if (association.getPatientLegalRepresentativeAssociationPk()
.getPatient().getId().longValue() == patient.getId()
.longValue()) {
return true;
}
}
return false;
}
/*
* (non-Javadoc)
*
* @see gov.samhsa.consent2share.service.patient.PatientService#
* findRecentPatientDtosById(java.util.List)
*/
@Override
public List<RecentPatientDto> findRecentPatientDtosById(List<String> ids) {
List<RecentPatientDto> patients = new ArrayList<RecentPatientDto>();
for (String id : ids) {
patients.add(modelMapper.map(
patientRepository.findOne(Long.parseLong(id)),
RecentPatientDto.class));
}
return patients;
}
/**
* Map patient list to patient admin dto list.
*
* @param patients
* the patients
* @return the list
*/
private List<PatientAdminDto> mapPatientListToPatientAdminDtoList(
List<Patient> patients) {
List<PatientAdminDto> patientAdminDtoList = new ArrayList<PatientAdminDto>();
for (Patient patient : patients) {
PatientAdminDto patientAdminDto = modelMapper.map(patient,
PatientAdminDto.class);
String fullSSN = patientAdminDto.getSocialSecurityNumber();
if (fullSSN != null)
patientAdminDto
.setSocialSecurityNumber(fullSSN.length() > LAST_N_DIGITS_OF_SSN ? fullSSN
.substring(fullSSN.length()
- LAST_N_DIGITS_OF_SSN) : fullSSN);
patientAdminDtoList.add(patientAdminDto);
}
return patientAdminDtoList;
}
/**
* Update eid.
*
* @param patient
* the patient
*/
private void updateEid(Patient patient) {
String mrn = patient.getMedicalRecordNumber();
Assert.hasText(mrn, "MRN cannot be null!");
String eid = null;
try {
eid = pixService.getEid(mrn);
} catch (Exception e) {
logger.error(
"Error retrieving EID from MPI. Cause: " + e.getMessage(),
e);
}
if (StringUtils.hasText(eid)) {
patient.setEnterpriseIdentifier(eid);
}
patientRepository.save(patient);
}
}