Java tutorial
/* fEMR - fast Electronic Medical Records Copyright (C) 2014 Team fEMR fEMR is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. fEMR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with fEMR. If not, see <http://www.gnu.org/licenses/>. If you have any questions, contact <info@teamfemr.org>. */ package femr.business.services.system; import com.avaje.ebean.ExpressionList; import com.avaje.ebean.FetchConfig; import com.avaje.ebean.Query; import com.google.inject.Inject; import com.google.inject.name.Named; import femr.business.helpers.QueryHelper; import femr.business.helpers.QueryProvider; import femr.business.services.core.IInventoryService; import femr.business.services.core.ISearchService; import femr.common.IItemModelMapper; import femr.common.dtos.ServiceResponse; import femr.common.models.*; import femr.data.daos.IRepository; import femr.data.daos.core.IPatientRepository; import femr.data.models.core.*; import femr.data.models.mysql.*; import femr.data.models.mysql.concepts.ConceptDiagnosis; import femr.util.calculations.LocaleUnitConverter; import femr.util.stringhelpers.StringUtils; import play.Logger; import java.util.*; import java.util.stream.Collectors; import static org.apache.commons.lang3.StringUtils.isNumeric; public class SearchService implements ISearchService { private final IRepository<IConceptDiagnosis> diagnosisRepository; private final IRepository<IMissionTrip> missionTripRepository; private final IPatientRepository patientRepository; private final IRepository<IPatientEncounter> patientEncounterRepository; private final IRepository<IPatientEncounterVital> patientEncounterVitalRepository; private final IRepository<IPatientPrescription> patientPrescriptionRepository; private final IRepository<ISystemSetting> systemSettingRepository; private final IItemModelMapper itemModelMapper; private final IInventoryService inventoryService; private final IRepository<IPatientPrescriptionReplacement> patientPrescriptionReplacementRepository; private final IRepository<IMissionCity> cityRepository; @Inject public SearchService(IRepository<IConceptDiagnosis> diagnosisRepository, IRepository<IMissionTrip> missionTripRepository, IPatientRepository patientRepository, IRepository<IPatientEncounter> patientEncounterRepository, IRepository<IPatientEncounterVital> patientEncounterVitalRepository, IRepository<IPatientPrescription> patientPrescriptionRepository, IRepository<ISystemSetting> systemSettingRepository, IInventoryService inventoryService, IRepository<IPatientPrescriptionReplacement> patientPrescriptionReplacementRepository, IRepository<IMissionCity> cityRepository, @Named("identified") IItemModelMapper itemModelMapper) { this.diagnosisRepository = diagnosisRepository; this.missionTripRepository = missionTripRepository; this.patientRepository = patientRepository; this.patientEncounterRepository = patientEncounterRepository; this.patientEncounterVitalRepository = patientEncounterVitalRepository; this.patientPrescriptionRepository = patientPrescriptionRepository; this.systemSettingRepository = systemSettingRepository; this.itemModelMapper = itemModelMapper; this.inventoryService = inventoryService; this.patientPrescriptionReplacementRepository = patientPrescriptionReplacementRepository; this.cityRepository = cityRepository; } /** * {@inheritDoc} */ @Override public ServiceResponse<PatientItem> retrievePatientItemByPatientId(int patientId) { ServiceResponse<PatientItem> response = new ServiceResponse<>(); if (patientId < 0) { response.addError("", "id can not be null or less than 1"); return response; } //get patient encounters so we can use the newest one Query<PatientEncounter> peQuery = QueryProvider.getPatientEncounterQuery().where() .eq("patient_id", patientId).order().desc("date_of_triage_visit"); try { //IPatient savedPatient = patientRepository.findOne(query); List<? extends IPatientEncounter> patientEncounters = patientEncounterRepository.find(peQuery); if (patientEncounters.size() < 1) throw new Exception(); IPatientEncounter recentEncounter = patientEncounters.get(0); IPatient savedPatient = patientEncounters.get(0).getPatient(); Integer patientHeightFeet = QueryHelper.findPatientHeightFeet(patientEncounterVitalRepository, recentEncounter.getId()); Integer patientHeightInches = QueryHelper.findPatientHeightInches(patientEncounterVitalRepository, recentEncounter.getId()); Float patientWeight = QueryHelper.findPatientWeight(patientEncounterVitalRepository, recentEncounter.getId()); Integer weeksPregnant = QueryHelper.findWeeksPregnant(patientEncounterVitalRepository, recentEncounter.getId()); String ageClassification = null; if (recentEncounter.getPatientAgeClassification() != null) { ageClassification = recentEncounter.getPatientAgeClassification().getName(); } String pathToPhoto = null; Integer photoId = null; if (savedPatient.getPhoto() != null) { pathToPhoto = savedPatient.getPhoto().getFilePath(); photoId = savedPatient.getPhoto().getId(); } PatientItem patientItem = itemModelMapper.createPatientItem(savedPatient.getId(), savedPatient.getFirstName(), savedPatient.getLastName(), savedPatient.getPhoneNumber(), savedPatient.getCity(), savedPatient.getAddress(), savedPatient.getUserId(), savedPatient.getAge(), savedPatient.getSex(), weeksPregnant, patientHeightFeet, patientHeightInches, patientWeight, pathToPhoto, photoId, ageClassification); //TODO: why is this being repeated? if (savedPatient.getPhoto() != null) { patientItem.setPathToPhoto("/photo/patient/" + patientId + "?showDefault=false"); } // If metric setting enabled convert response patientItem to metric if (isMetric()) { patientItem = LocaleUnitConverter.toMetric(patientItem); } else { //added for femr-136 - dual unit display patientItem = LocaleUnitConverter.forDualUnitDisplay(patientItem); } response.setResponseObject(patientItem); } catch (Exception ex) { response.addError("exception", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<PatientItem> retrievePatientItemByEncounterId(int encounterId) { ServiceResponse<PatientItem> response = new ServiceResponse<>(); if (encounterId < 0) { response.addError("", "invalid id"); return response; } ExpressionList<PatientEncounter> patientEncounterQuery = QueryProvider.getPatientEncounterQuery().where() .eq("id", encounterId); try { IPatientEncounter patientEncounter = patientEncounterRepository.findOne(patientEncounterQuery); IPatient patient = patientEncounter.getPatient(); Integer patientHeightFeet = QueryHelper.findPatientHeightFeet(patientEncounterVitalRepository, patientEncounter.getId()); Integer patientHeightInches = QueryHelper.findPatientHeightInches(patientEncounterVitalRepository, patientEncounter.getId()); Float patientWeight = QueryHelper.findPatientWeight(patientEncounterVitalRepository, patientEncounter.getId()); Integer weeksPregnant = QueryHelper.findWeeksPregnant(patientEncounterVitalRepository, patientEncounter.getId()); String ageClassification = null; if (patientEncounter.getPatientAgeClassification() != null) { ageClassification = patientEncounter.getPatientAgeClassification().getName(); } String pathToPhoto = null; Integer photoId = null; if (patient.getPhoto() != null) { pathToPhoto = patient.getPhoto().getFilePath(); photoId = patient.getPhoto().getId(); } PatientItem patientItem = itemModelMapper.createPatientItem(patient.getId(), patient.getFirstName(), patient.getLastName(), patient.getPhoneNumber(), patient.getCity(), patient.getAddress(), patient.getUserId(), patient.getAge(), patient.getSex(), weeksPregnant, patientHeightFeet, patientHeightInches, patientWeight, pathToPhoto, photoId, ageClassification); // If metric setting enabled convert response patientItem to metric if (isMetric()) patientItem = LocaleUnitConverter.toMetric(patientItem); response.setResponseObject(patientItem); } catch (Exception ex) { response.addError("exception", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<PatientEncounterItem> retrievePatientEncounterItemByEncounterId(int encounterId) { ServiceResponse<PatientEncounterItem> response = new ServiceResponse<>(); if (encounterId < 1) { response.addError("", "invalid ID"); return response; } ExpressionList<PatientEncounter> patientEncounterQuery = QueryProvider.getPatientEncounterQuery().where() .eq("id", encounterId); try { IPatientEncounter patientEncounter = patientEncounterRepository.findOne(patientEncounterQuery); PatientEncounterItem patientEncounterItem = itemModelMapper .createPatientEncounterItem(patientEncounter); response.setResponseObject(patientEncounterItem); } catch (Exception ex) { response.addError("exception", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<PatientEncounterItem> retrieveRecentPatientEncounterItemByPatientId(int patientId) { ServiceResponse<PatientEncounterItem> response = new ServiceResponse<>(); if (patientId < 1) { response.addError("", "Invalid patient ID."); return response; } Query<PatientEncounter> query = QueryProvider.getPatientEncounterQuery().where().eq("patient_id", patientId) .order().asc("date_of_triage_visit"); try { List<? extends IPatientEncounter> patientEncounters = patientEncounterRepository.find(query); if (patientEncounters.size() < 1) { response.addError("", "That patient does not exist."); return response; } IPatientEncounter currentPatientEncounter = patientEncounters.get(patientEncounters.size() - 1); PatientEncounterItem patientEncounterItem = itemModelMapper .createPatientEncounterItem(currentPatientEncounter); response.setResponseObject(patientEncounterItem); } catch (Exception ex) { response.addError("exception", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<List<PatientEncounterItem>> retrievePatientEncounterItemsByPatientId(int patientId) { ServiceResponse<List<PatientEncounterItem>> response = new ServiceResponse<>(); Query<PatientEncounter> query = QueryProvider.getPatientEncounterQuery().where().eq("patient_id", patientId) .order().desc("date_of_triage_visit"); try { List<? extends IPatientEncounter> patientEncounters = patientEncounterRepository.find(query); List<PatientEncounterItem> patientEncounterItems = new ArrayList<>(); for (IPatientEncounter pe : patientEncounters) { patientEncounterItems.add(itemModelMapper.createPatientEncounterItem(pe)); } response.setResponseObject(patientEncounterItems); } catch (Exception ex) { response.addError("", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<List<PrescriptionItem>> retrieveUnreplacedPrescriptionItems(int encounterId, Integer tripId) { ServiceResponse<List<PrescriptionItem>> response = new ServiceResponse<>(); ExpressionList<PatientPrescription> query = QueryProvider.getPatientPrescriptionQuery() .fetch("medication.medicationInventory").fetch("patientEncounter").where() .eq("encounter_id", encounterId); try { List<? extends IPatientPrescription> patientPrescriptions = patientPrescriptionRepository.find(query); List<PrescriptionItem> prescriptionItems = new ArrayList<>(); for (IPatientPrescription pp : patientPrescriptions) { // Don't get prescriptions with a replacement if (pp.getPatientPrescriptionReplacements() != null && pp.getPatientPrescriptionReplacements().size() > 0) continue; Integer quantityCurrent = null; Integer quantityInitial = null; //if the medication resides in inventory and the user is on the trip using that inventory //this will make sure that information about the current state of inventory is included //in the PrescriptionItem being created below. if (pp.getMedication().getMedicationInventory().size() > 0 && tripId != null) { //need to get the specific inventory for this medication (a medication can have multiple inventories if diferent trips are using it) ServiceResponse<MedicationItem> inventoryResponse = inventoryService .retrieveMedicationInventoryByMedicationIdAndTripId(pp.getMedication().getId(), tripId); //if this trip has an inventory for this medication if (inventoryResponse.getResponseObject() != null) { quantityCurrent = inventoryResponse.getResponseObject().getQuantityCurrent(); quantityInitial = inventoryResponse.getResponseObject().getQuantityTotal(); } } PrescriptionItem item = itemModelMapper.createPrescriptionItem( pp.getId(), pp.getMedication().getName(), null, pp.getPhysician().getFirstName(), pp.getPhysician().getLastName(), pp.getConceptPrescriptionAdministration(), pp.getAmount(), pp.getMedication(), quantityCurrent, quantityInitial, pp.isCounseled()); prescriptionItems.add(item); } response.setResponseObject(prescriptionItems); } catch (Exception ex) { Logger.error("Attempted and failed to execute retrieveUnreplacedPrescriptionItems(" + encounterId + ") in SearchService. Stack trace to follow."); ex.printStackTrace(); response.addError("exception", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<List<PrescriptionItem>> retrieveDispensedPrescriptionItems(int encounterId) { ServiceResponse<List<PrescriptionItem>> response = new ServiceResponse<>(); ExpressionList<PatientPrescription> query = QueryProvider.getPatientPrescriptionQuery() .fetch("patientEncounter").where().eq("encounter_id", encounterId).ne("user_id_pharmacy", null); try { List<? extends IPatientPrescription> patientPrescriptions = patientPrescriptionRepository.find(query); List<PrescriptionItem> prescriptionItems = patientPrescriptions.stream() .filter(pp -> pp.getDateDispensed() != null) .map(pp -> itemModelMapper.createPrescriptionItem(pp.getId(), pp.getMedication().getName(), null, pp.getPhysician().getFirstName(), pp.getPhysician().getLastName(), pp.getConceptPrescriptionAdministration(), pp.getAmount(), pp.getMedication(), null, null, pp.isCounseled())) .collect(Collectors.toList()); List<PrescriptionItem> replacedPrescriptions = patientPrescriptions.stream() .filter(pp -> pp.getPatientPrescriptionReplacements().size() > 0) .map(pp -> itemModelMapper.createPrescriptionItemWithReplacement(pp.getId(), pp.getMedication().getName(), pp.getPatientPrescriptionReplacements().get(0).getReplacementPrescription() .getMedication().getName(), pp.getPatientPrescriptionReplacements().get(0).getReplacementPrescription().getAmount(), pp.getPatientPrescriptionReplacements().get(0).getReplacementPrescription().getId(), pp.getPhysician().getFirstName(), pp.getPhysician().getLastName(), pp.getConceptPrescriptionAdministration(), pp.getAmount(), pp.getMedication(), null, null, pp.isCounseled())) .collect(Collectors.toList()); prescriptionItems.addAll(replacedPrescriptions); response.setResponseObject(prescriptionItems); } catch (Exception ex) { response.addError("exception", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<Integer> parseIdFromQueryString(String query) { ServiceResponse<Integer> response = new ServiceResponse<>(); if (StringUtils.isNullOrWhiteSpace(query)) { response.addError("", "No patient ID provided."); } else { try { query = query.trim(); Integer id = Integer.parseInt(query); response.setResponseObject(id); } catch (NumberFormatException ex) { response.addError("", "Could not read patient ID."); } } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<List<PatientItem>> retrievePatientsFromQueryString(String patientSearchQuery) { ServiceResponse<List<PatientItem>> response = new ServiceResponse<>(); if (StringUtils.isNullOrWhiteSpace(patientSearchQuery)) { response.addError("", "bad parameters"); return response; } String[] words = patientSearchQuery.trim().split(" "); Integer id = null; String firstName = null; String lastName = null; String phoneNumber = null; if (words.length == 0) { //nothing was in the query response.addError("", "query string empty"); return response; } else if (words.length == 1) { //could be an ID, name, or phone number try { //see if it is a number if (isNumeric(words[0]) && words[0].length() > 5) phoneNumber = words[0]; else id = Integer.parseInt(words[0]); } catch (NumberFormatException ex) { //see if it it a string firstName = words[0]; } } else if (words.length == 2) { firstName = words[0]; lastName = words[1]; } else { response.addError("", "too many words in query string"); return response; } List<? extends IPatient> patients; try { //Build the Query //TODO: filter these by the current country of the team if (id != null) { //if we have an id, that is all we need. //this is the most ideal scenario IPatient patient = patientRepository.retrievePatientById(id); List<IPatient> iPatients = new ArrayList<>(); iPatients.add(patient); patients = iPatients; } else if (phoneNumber != null) { patients = patientRepository.retrievePatientsByPhoneNumber(phoneNumber); } else { patients = patientRepository.retrievePatientsByName(firstName, lastName); } //Execute the query List<PatientItem> patientItems = new ArrayList<>(); for (IPatient patient : patients) { //patientItems.add(DomainMapper.createPatientItem(p, null, null, null, null)); String pathToPhoto = null; Integer photoId = null; if (patient.getPhoto() != null) { pathToPhoto = patient.getPhoto().getFilePath(); photoId = patient.getPhoto().getId(); } patientItems.add(itemModelMapper.createPatientItem(patient.getId(), patient.getFirstName(), patient.getLastName(), patient.getPhoneNumber(), patient.getCity(), patient.getAddress(), patient.getUserId(), patient.getAge(), patient.getSex(), null, null, null, null, pathToPhoto, photoId, null)); } response.setResponseObject(patientItems); } catch (Exception ex) { response.addError("", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<SettingItem> retrieveSystemSettings() { ServiceResponse<SettingItem> response = new ServiceResponse<>(); try { List<? extends ISystemSetting> systemSettings = systemSettingRepository.findAll(SystemSetting.class); if (systemSettings == null || systemSettings.size() == 0) { response.addError("", "no settings exist at this time"); } else { SettingItem settingItem = itemModelMapper.createSettingItem(systemSettings); response.setResponseObject(settingItem); } } catch (Exception ex) { response.addError("", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<List<PatientItem>> retrievePatientsForSearch(Integer tripId) { ServiceResponse<List<PatientItem>> response = new ServiceResponse<>(); try { ExpressionList<SystemSetting> expressionList = QueryProvider.getSystemSettingQuery().where().eq("name", "Country Filter"); ISystemSetting systemSetting = systemSettingRepository.findOne(expressionList); IMissionTrip missionTrip = null; List<? extends IPatient> allPatients; if (tripId != null) { //If the trip ID is not null then we can try to figure out which trip ExpressionList<MissionTrip> missionTripExpressionList = QueryProvider.getMissionTripQuery().where() .eq("id", tripId); missionTrip = missionTripRepository.findOne(missionTripExpressionList); if (missionTrip == null) response.addError("", "a trip was not found with that tripId"); } if (systemSetting != null && systemSetting.isActive() && missionTrip != null && missionTrip.getMissionCity() != null && missionTrip.getMissionCity().getMissionCountry() != null && StringUtils .isNotNullOrWhiteSpace(missionTrip.getMissionCity().getMissionCountry().getName())) { allPatients = patientRepository .retrievePatientsInCountry(missionTrip.getMissionCity().getMissionCountry().getName()); } else { //Otherwise we can just get ALL OF THE PATIENTS EVER MADE allPatients = patientRepository.retrieveAllPatients(); } List<PatientItem> patientItems = new ArrayList<>(); for (IPatient patient : allPatients) { String pathToPhoto = null; Integer photoId = null; if (patient.getPhoto() != null) { pathToPhoto = patient.getPhoto().getFilePath(); photoId = patient.getPhoto().getId(); } PatientItem currPatient = itemModelMapper.createPatientItem(patient.getId(), patient.getFirstName(), patient.getLastName(), patient.getPhoneNumber(), patient.getCity(), patient.getAddress(), patient.getUserId(), patient.getAge(), patient.getSex(), null, null, null, null, pathToPhoto, photoId, null); currPatient.setPathToPhoto("/photo/patient/" + currPatient.getId() + "?showDefault=true"); patientItems.add(currPatient); } response.setResponseObject(patientItems); } catch (Exception ex) { response.addError("exception", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<List<String>> findDiagnosisForSearch() { ServiceResponse<List<String>> response = new ServiceResponse<>(); try { List<? extends IConceptDiagnosis> allDiagnoses = diagnosisRepository.findAll(ConceptDiagnosis.class); List<String> diagnoses = new ArrayList<>(); for (IConceptDiagnosis d : allDiagnoses) { if (StringUtils.isNotNullOrWhiteSpace(d.getName())) diagnoses.add(d.getName()); } response.setResponseObject(diagnoses); } catch (Exception ex) { response.addError("", ex.getMessage()); } return response; } /** * Gets isActive of the metric setting * * @return */ private boolean isMetric() { ExpressionList<SystemSetting> query = QueryProvider.getSystemSettingQuery().where().eq("name", "Metric System Option"); ISystemSetting isMetric = systemSettingRepository.findOne(query); return isMetric.isActive(); } /** AJ Saclayan * {@inheritDoc} */ @Override public ServiceResponse<List<CityItem>> retrieveCitiesFromQueryString(String citySearchQuery) { ServiceResponse<List<CityItem>> response = new ServiceResponse<>(); if (StringUtils.isNullOrWhiteSpace(citySearchQuery)) { response.addError("", "bad parameters"); return response; } // String[] words = citySearchQuery.trim().split(" "); // String city = citySearchQuery // if (words.length == 0) { // //nothing was in the query // response.addError("", "query string empty"); // return response; // } else if (words.length == 2) { // city = words[0]; // } else { // response.addError("", "too many words in query string"); // return response; // } //Build the Query //TODO: filter these by the current country of the team Query<MissionCity> query = null; query = QueryProvider.getMissionCityQuery().where().eq("name", citySearchQuery).order().desc("id"); //Execute the query try { List<? extends IMissionCity> cities = cityRepository.find(query); List<CityItem> cityItems = new ArrayList<>(); for (IMissionCity city : cities) { //patientItems.add(DomainMapper.createPatientItem(p, null, null, null, null)); cityItems.add(itemModelMapper.createCityItem(city.getName(), city.getMissionCountry().getName())); } response.setResponseObject(cityItems); } catch (Exception ex) { response.addError("", ex.getMessage()); } return response; } /** * AJ Saclayan * @return */ @Override public ServiceResponse<List<CityItem>> retrieveCitiesForSearch() { ServiceResponse<List<CityItem>> response = new ServiceResponse<>(); try { List<? extends IMissionCity> allCities; //Make sure that none of the values we will be checking are null. //If they are, just get all of the possible patients. // allPatients = QueryHelper.findPatients(patientRepository, missionTrip.getMissionCity().getMissionCountry().getName()); // }else{ allCities = QueryHelper.findCities(cityRepository); // } List<CityItem> cityItems = new ArrayList<>(); for (IMissionCity city : allCities) { CityItem currCity = itemModelMapper.createCityItem(city.getName(), city.getMissionCountry().getName()); cityItems.add(currCity); } response.setResponseObject(cityItems); } catch (Exception ex) { response.addError("exception", ex.getMessage()); } return response; } }