/* 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.Query; import com.google.inject.Inject; import com.google.inject.name.Named; import femr.business.helpers.QueryProvider; import femr.business.services.core.IEncounterService; import femr.common.IItemModelMapper; import femr.common.dtos.ServiceResponse; import femr.common.models.*; import femr.data.IDataModelMapper; import femr.data.daos.IRepository; import femr.data.daos.core.IUserRepository; import femr.data.models.core.*; import femr.data.models.mysql.*; import femr.util.calculations.dateUtils; import femr.util.stringhelpers.StringUtils; import org.joda.time.DateTime; import java.util.*; public class EncounterService implements IEncounterService { private final IRepository<IChiefComplaint> chiefComplaintRepository; private final IRepository<IPatientAgeClassification> patientAgeClassificationRepository; private final IRepository<IPatientEncounter> patientEncounterRepository; private final IRepository<IPatientEncounterTabField> patientEncounterTabFieldRepository; private final IRepository<ITabField> tabFieldRepository; private final IUserRepository userRepository; private final IDataModelMapper dataModelMapper; private final IItemModelMapper itemModelMapper; @Inject public EncounterService(IRepository<IChiefComplaint> chiefComplaintRepository, IRepository<IPatientAgeClassification> patientAgeClassificationRepository, IRepository<IPatientEncounter> patientEncounterRepository, IRepository<IPatientEncounterTabField> patientEncounterTabFieldRepository, IRepository<ITabField> tabFieldRepository, IUserRepository userRepository, IDataModelMapper dataModelMapper, @Named("identified") IItemModelMapper itemModelMapper) { this.chiefComplaintRepository = chiefComplaintRepository; this.patientAgeClassificationRepository = patientAgeClassificationRepository; this.patientEncounterRepository = patientEncounterRepository; this.patientEncounterTabFieldRepository = patientEncounterTabFieldRepository; this.tabFieldRepository = tabFieldRepository; this.userRepository = userRepository; this.dataModelMapper = dataModelMapper; this.itemModelMapper = itemModelMapper; } /** * {@inheritDoc} */ @Override public ServiceResponse<PatientEncounterItem> createPatientEncounter(int patientId, int userId, Integer tripId, String ageClassification, List<String> chiefComplaints) { ServiceResponse<PatientEncounterItem> response = new ServiceResponse<>(); try { //find the nurse that checked in the patient IUser nurseUser = userRepository.retrieveUserById(userId); //find the age classification of the patient, if it exists ExpressionList<PatientAgeClassification> patientAgeClassificationExpressionList = QueryProvider.getPatientAgeClassificationQuery() .where() .eq("name", ageClassification); IPatientAgeClassification patientAgeClassification = patientAgeClassificationRepository.findOne(patientAgeClassificationExpressionList); Integer patientAgeClassificationId = null; if (patientAgeClassification != null) patientAgeClassificationId = patientAgeClassification.getId(); IPatientEncounter newPatientEncounter = dataModelMapper.createPatientEncounter(patientId, dateUtils.getCurrentDateTime(), nurseUser.getId(), patientAgeClassificationId, tripId); newPatientEncounter = patientEncounterRepository.create(newPatientEncounter); List<IChiefComplaint> chiefComplaintBeans = new ArrayList<>(); Integer chiefComplaintSortOrder = 0; for (String cc : chiefComplaints) { chiefComplaintBeans.add(dataModelMapper.createChiefComplaint(cc, newPatientEncounter.getId(), chiefComplaintSortOrder)); chiefComplaintSortOrder++; } if (chiefComplaintBeans.size() > 0) { chiefComplaintRepository.createAll(chiefComplaintBeans); } response.setResponseObject(itemModelMapper.createPatientEncounterItem(newPatientEncounter)); } catch (Exception ex) { response.addError("exception", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<PatientEncounterItem> checkPatientInToMedical(int encounterId, int userId) { ServiceResponse<PatientEncounterItem> response = new ServiceResponse<>(); if (encounterId < 1) { response.addError("", "encounterId must be greater than 0"); return response; } ExpressionList<PatientEncounter> query = QueryProvider.getPatientEncounterQuery() .where() .eq("id", encounterId); try { IPatientEncounter patientEncounter = patientEncounterRepository.findOne(query); patientEncounter.setDateOfMedicalVisit(DateTime.now()); IUser user = userRepository.retrieveUserById(userId); patientEncounter.setDoctor(user); patientEncounter = patientEncounterRepository.update(patientEncounter); response.setResponseObject(itemModelMapper.createPatientEncounterItem(patientEncounter)); } catch (Exception ex) { response.addError("exception", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<IPatientEncounter> checkPatientInToPharmacy(int encounterId, int userId) { ServiceResponse<IPatientEncounter> response = new ServiceResponse<>(); if (encounterId < 1) { response.addError("", "encounterId can not be less than 1"); return response; } try { ExpressionList<PatientEncounter> query = QueryProvider.getPatientEncounterQuery().where().eq("id", encounterId); IPatientEncounter patientEncounter = patientEncounterRepository.findOne(query); patientEncounter.setDateOfPharmacyVisit(DateTime.now()); IUser user = userRepository.retrieveUserById(userId); patientEncounter.setPharmacist(user); patientEncounter = patientEncounterRepository.update(patientEncounter); response.setResponseObject(patientEncounter); } catch (Exception ex) { response.addError("exception", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<UserItem> retrievePhysicianThatCheckedInPatientToMedical(int encounterId) { ServiceResponse<UserItem> response = new ServiceResponse<>(); if (encounterId < 1) { response.addError("", "encounter id must be greater than 0"); return response; } try { ExpressionList<PatientEncounter> patientEncounterQuery = QueryProvider.getPatientEncounterQuery() .where() .eq("id", encounterId); IPatientEncounter patientEncounter = patientEncounterRepository.findOne(patientEncounterQuery); if (patientEncounter.getDoctor() == null) { response.setResponseObject(null); } else { UserItem userItem = itemModelMapper.createUserItem(patientEncounter.getDoctor()); response.setResponseObject(userItem); } } catch (Exception ex) { response.addError("", "error finding encounter"); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<List<ProblemItem>> createProblems(List<String> problemValues, int encounterId, int userId) { ServiceResponse<List<ProblemItem>> response = new ServiceResponse<>(); //get the current tab field item ExpressionList<TabField> query = QueryProvider.getTabFieldQuery() .where() .eq("name", "problem"); try { ITabField tabField = tabFieldRepository.findOne(query); List<IPatientEncounterTabField> patientEncounterTabFields = new ArrayList<>(); DateTime dateTaken = dateUtils.getCurrentDateTime(); for (String problemval : problemValues) { IPatientEncounterTabField patientEncounterTabField = dataModelMapper.createPatientEncounterTabField(tabField.getId(), userId, problemval, encounterId, dateTaken, null); patientEncounterTabFields.add(patientEncounterTabField); } patientEncounterTabFieldRepository.createAll(patientEncounterTabFields); } catch (Exception ex) { response.addError("", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<List<TabFieldItem>> createPatientEncounterTabFields(Map<String, String> tabFieldNameValues, int encounterId, int userId, String chiefComplaint){ ServiceResponse<List<TabFieldItem>> response = new ServiceResponse<>(); if (tabFieldNameValues.isEmpty() || StringUtils.isNullOrWhiteSpace(chiefComplaint)){ response.addError("", "no fields"); return response; } try { ExpressionList<PatientEncounterTabField> patientEncounterTabFieldExpressionList = QueryProvider.getPatientEncounterTabFieldQuery() .where() .eq("patient_encounter_id", encounterId); ExpressionList<ChiefComplaint> chiefComplaintExpressionList = QueryProvider.getChiefComplaintQuery() .where() .eq("patient_encounter_id", encounterId); //the object we will use to populate to put in the ServiceResponse List<TabFieldItem> tabFieldItemsForResponse; //get all chief complaints for an encounter to find reference IDs List<? extends IChiefComplaint> chiefComplaints = chiefComplaintRepository.find(chiefComplaintExpressionList); //removes a tab field from the map to be saved if it contains the same name and value as an entry that //already exists in the database. This can be a problem if a user tries to change the value then change it back. List<? extends IPatientEncounterTabField> existingPatientEncounterTabFields = patientEncounterTabFieldRepository.find(patientEncounterTabFieldExpressionList); for (Iterator<Map.Entry<String, String>> it = tabFieldNameValues.entrySet().iterator(); it.hasNext(); ) { Map.Entry<String, String> entry = it.next(); for (IPatientEncounterTabField petf : existingPatientEncounterTabFields) { if (petf.getTabField().getName().equals(entry.getKey()) && petf.getTabFieldValue().equals(entry.getValue())) { if (petf.getChiefComplaint() == null) { it.remove(); break; } else if (petf.getChiefComplaint().getValue().equals(chiefComplaint)) { it.remove(); break; } break; } } } //get all tab fields to use in finding reference Ids List<? extends ITabField> tabFields = tabFieldRepository.findAll(TabField.class); //one datetime field to put in everything DateTime dateTaken = dateUtils.getCurrentDateTime(); //the fields that we will be saving to the database after all is said and (almost) done List<IPatientEncounterTabField> patientEncounterTabFieldsForSaving = new ArrayList<>(); //foreign key IDs for patientEncounterTabField referencing Integer tabFieldId; Integer chiefComplaintId = null; for (Map.Entry<String, String> entry : tabFieldNameValues.entrySet()){ if (StringUtils.isNotNullOrWhiteSpace(entry.getKey()) || StringUtils.isNotNullOrWhiteSpace(entry.getValue())) { //find reference ID for tabfield tabFieldId = getTabFieldIdByTabFieldName(tabFields, entry.getKey()); //find reference ID for chief complaint for (IChiefComplaint cc : chiefComplaints) { if (chiefComplaint.equals(cc.getValue())) { chiefComplaintId = cc.getId(); break; } } if (tabFieldId != null) { patientEncounterTabFieldsForSaving.add(dataModelMapper.createPatientEncounterTabField(tabFieldId, userId, entry.getValue(), encounterId, dateTaken, chiefComplaintId)); } else { response.addError("name", "one of the tabfields had an invalid name"); } } } //SAVE EM List<? extends IPatientEncounterTabField> savedPatientEncounterTabFields = patientEncounterTabFieldRepository.createAll(patientEncounterTabFieldsForSaving); //RETURN EM tabFieldItemsForResponse = getTabFieldItemsFromPatientEncounterTabFields(savedPatientEncounterTabFields); response.setResponseObject(tabFieldItemsForResponse); } catch (Exception ex) { response.addError("", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<List<TabFieldItem>> createPatientEncounterTabFields(Map<String, String> tabFieldNameValues, int encounterId, int userId){ ServiceResponse<List<TabFieldItem>> response = new ServiceResponse<>(); if (tabFieldNameValues.isEmpty()){ response.addError("", "no fields"); return response; } try { ExpressionList<PatientEncounterTabField> patientEncounterTabFieldExpressionList = QueryProvider.getPatientEncounterTabFieldQuery() .where() .eq("patient_encounter_id", encounterId); //the object we will use to populate to put in the ServiceResponse List<TabFieldItem> tabFieldItemsForResponse; //removes a tab field from the map to be saved if it contains the same name and value as an entry that //already exists in the database. This can be a problem if a user tries to change the value then change it back. List<? extends IPatientEncounterTabField> existingPatientEncounterTabFields = patientEncounterTabFieldRepository.find(patientEncounterTabFieldExpressionList); for (Iterator<Map.Entry<String, String>> it = tabFieldNameValues.entrySet().iterator(); it.hasNext(); ) { Map.Entry<String, String> entry = it.next(); for (IPatientEncounterTabField petf : existingPatientEncounterTabFields) { if (petf.getTabField().getName().equals(entry.getKey()) && petf.getTabFieldValue().equals(entry.getValue())) { it.remove(); break; } } } //get all tab fields to use in finding reference Ids List<? extends ITabField> tabFields = tabFieldRepository.findAll(TabField.class); //one datetime field to put in everything DateTime dateTaken = dateUtils.getCurrentDateTime(); //the fields that we will be saving to the database after all is said and (almost) done List<IPatientEncounterTabField> patientEncounterTabFieldsForSaving = new ArrayList<>(); //foreign key IDs for patientEncounterTabField referencing Integer tabFieldId; for (Map.Entry<String, String> entry : tabFieldNameValues.entrySet()){ if (StringUtils.isNotNullOrWhiteSpace(entry.getKey()) || StringUtils.isNotNullOrWhiteSpace(entry.getValue())) { //find reference ID for tabfield tabFieldId = getTabFieldIdByTabFieldName(tabFields, entry.getKey()); if (tabFieldId != null) { patientEncounterTabFieldsForSaving.add(dataModelMapper.createPatientEncounterTabField(tabFieldId, userId, entry.getValue(), encounterId, dateTaken, null)); } else { response.addError("name", "one of the tabfields had an invalid name"); } } } //SAVE EM List<? extends IPatientEncounterTabField> savedPatientEncounterTabFields = patientEncounterTabFieldRepository.createAll(patientEncounterTabFieldsForSaving); //RETURN EM tabFieldItemsForResponse = getTabFieldItemsFromPatientEncounterTabFields(savedPatientEncounterTabFields); response.setResponseObject(tabFieldItemsForResponse); } catch (Exception ex) { response.addError("", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<List<ProblemItem>> retrieveProblemItems(int encounterId) { ServiceResponse<List<ProblemItem>> response = new ServiceResponse<>(); List<ProblemItem> problemItems = new ArrayList<>(); Query<PatientEncounterTabField> query = QueryProvider.getPatientEncounterTabFieldQuery() .fetch("tabField") .where() .isNull("IsDeleted") .eq("patient_encounter_id", encounterId) .eq("tabField.name", "problem") .order() .asc("date_taken"); try { List<? extends IPatientEncounterTabField> patientEncounterTreatmentFields = patientEncounterTabFieldRepository.find(query); if (patientEncounterTreatmentFields == null) { response.addError("", "bad query"); } else { for (IPatientEncounterTabField petf : patientEncounterTreatmentFields) { if (petf.getTabField() != null) problemItems.add(itemModelMapper.createProblemItem(petf.getTabFieldValue())); } response.setResponseObject(problemItems); } } catch (Exception ex) { response.addError("", "error"); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<PatientEncounterItem> screenPatientForDiabetes(int encounterId, int userId, Boolean isScreened) { ServiceResponse<PatientEncounterItem> response = new ServiceResponse<>(); ExpressionList<PatientEncounter> patientEncounterQuery = QueryProvider.getPatientEncounterQuery() .where() .eq("id", encounterId); try { IPatientEncounter patientEncounter = patientEncounterRepository.findOne(patientEncounterQuery); dataModelMapper.updatePatientEncounterWithDiabetesScreening(patientEncounter, userId, isScreened); patientEncounter = patientEncounterRepository.update(patientEncounter); PatientEncounterItem patientEncounterItem = itemModelMapper.createPatientEncounterItem(patientEncounter); response.setResponseObject(patientEncounterItem); } catch (Exception ex) { response.addError("", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<List<PatientEncounterItem>> retrieveCurrentDayPatientEncounters(int tripID) { ServiceResponse<List<PatientEncounterItem>> response = new ServiceResponse<>(); List<PatientEncounterItem> patientEncounterItems = new ArrayList<>(); //gets dates for today and tommorrow DateTime today= DateTime.now(); today=today.withTimeAtStartOfDay(); DateTime tommorrow=today; tommorrow=tommorrow.plusDays(1); //query todays patients ExpressionList<PatientEncounter> query = QueryProvider.getPatientEncounterQuery() .where() .ge("date_of_triage_visit", today) .le("date_of_triage_visit", tommorrow) .eq("mission_trip_id",tripID); try{ List<PatientItem> patientItems=null; List<? extends IPatientEncounter> patient = patientEncounterRepository.find(query); for (IPatientEncounter patient1 : patient) { patientEncounterItems.add(itemModelMapper.createPatientEncounterItem(patient1)); } response.setResponseObject(patientEncounterItems); } catch (Exception ex) { response.addError("", ex.getMessage()); } return response; } /** * {@inheritDoc} */ @Override public ServiceResponse<Boolean> deleteExistingProblem(int encounterId, String problem, int userId){ ServiceResponse<Boolean> response = new ServiceResponse<>(); try { //PatientEncounterTabField fieldData ExpressionList<PatientEncounterTabField> query = QueryProvider.getPatientEncounterTabFieldQuery() .fetch("tabField") .where() .eq("patient_encounter_id", encounterId) .eq("tabField.name", "problem") .eq("tab_field_value", problem) .isNull("IsDeleted") .isNull("DeletedByUserId"); // Query gets an entire list in case of duplicate rows of the same problem, will then only set the first instance to deleted IPatientEncounterTabField fieldData = patientEncounterTabFieldRepository.find(query).get(0); fieldData.setIsDeleted(dateUtils.getCurrentDateTime()); fieldData.setDeletedByUserId(userId); fieldData = patientEncounterTabFieldRepository.update(fieldData); response.setResponseObject(true); } catch(Exception e){ response.setResponseObject(false); } return response; } /** * Translates a list of PatientEncounterTabFields into a list of TabFieldItems */ private List<TabFieldItem> getTabFieldItemsFromPatientEncounterTabFields(List<? extends IPatientEncounterTabField> patientEncounterTabFields){ List<TabFieldItem> tabFieldItems = new ArrayList<>(); String chiefComplaint = null; String size = null; boolean isCustom; for (IPatientEncounterTabField petf : patientEncounterTabFields) { isCustom = petf.getTabField().getTab().getIsCustom(); if (petf.getChiefComplaint() != null) chiefComplaint = petf.getChiefComplaint().getValue(); if (petf.getTabField().getTabFieldSize() != null) size = petf.getTabField().getTabFieldSize().getName(); tabFieldItems.add(itemModelMapper.createTabFieldItem( petf.getTabField().getName(), petf.getTabField().getTabFieldType().getName(), size, petf.getTabField().getOrder(), petf.getTabField().getPlaceholder(), petf.getTabFieldValue(), chiefComplaint, isCustom ) ); } return tabFieldItems; } /** * Gets the ID of a TabField so a foreign key can be set up when saving in eBean. * * @param tabFields a list of all available TabFields * @param tabFieldName the name of the requested TabField * @return the ID of the requested tab field or null if none are found */ private Integer getTabFieldIdByTabFieldName(List<? extends ITabField> tabFields, String tabFieldName){ Integer tabFieldId = null; for (ITabField tf : tabFields) { if (tabFieldName.equals(tf.getName())) { tabFieldId = tf.getId(); break; } } return tabFieldId; } }