public static long InsertOrUpdateErxMedication(RxPat rxOld, RxPat rx, long rxCui, string strDrugName, string strGenericName, bool isProv, bool canInsertRx = true) { if (rxOld == null) { if (canInsertRx) { rx.IsNew = true; //Might not be necessary, but does not hurt. rx.IsErxOld = false; SecurityLogs.MakeLogEntry(Permissions.RxCreate, rx.PatNum, "eRx automatically created: " + rx.Drug); RxPats.Insert(rx); } } else //The prescription was already in our database. Update it. { rx.RxNum = rxOld.RxNum; //Preserve the pharmacy on the existing prescription, in case the user set the value manually. //We do not pull pharmacy back from eRx yet. rx.PharmacyNum = rxOld.PharmacyNum; if (rxOld.IsErxOld) { rx.IsErxOld = true; rx.SendStatus = RxSendStatus.SentElect; //To maintain backward compatibility. } RxPats.Update(rx); } //If rxCui==0, then third party eRx option (DoseSpot, NewCrop, etc) did not provide an RxCui. //Attempt to locate an RxCui using the other provided drug information. An RxCui is not required for our program. //Meds missing an RxCui are not exported in CCD messages. if (rxCui == 0 && strDrugName != "") { List <RxNorm> listRxNorms = RxNorms.GetListByCodeOrDesc(strDrugName, true, true); //Exact case insensitive match ignoring numbers. if (listRxNorms.Count > 0) { rxCui = PIn.Long(listRxNorms[0].RxCui); } } //If rxCui==0, then third party eRx option (DoseSpot, NewCrop, etc) did not provide an RxCui and we could not locate an RxCui by DrugName //Try searching by GenericName. if (rxCui == 0 && strGenericName != "") { List <RxNorm> listRxNorms = RxNorms.GetListByCodeOrDesc(strGenericName, true, true); //Exact case insensitive match ignoring numbers. if (listRxNorms.Count > 0) { rxCui = PIn.Long(listRxNorms[0].RxCui); } } //If rxCui==0, then third party eRx option (DoseSpot, NewCrop, etc) did not provide an RxCui and we could not //locate an RxCui by DrugName or GenericName. if (rxCui == 0) { //We may need to enhance in future to support more advanced RxNorm searches. //For example: DrugName=Cafatine, DrugInfo=Cafatine 1 mg-100 mg Tab, GenericName=ergotamine-caffeine. //This drug could not be found by DrugName nor GenericName, but could be found when the GenericName was split by non-alpha characters, //then the words in the generic name were swapped. //Namely, "caffeine ergotamine" is in the RxNorm table. } //MedicationNum of 0, because we do not want to bloat the medication list in OD. //In this special situation, we instead set the MedDescript, RxCui and ErxGuid columns. return(MedicationPats.InsertOrUpdateMedOrderForRx(rx, rxCui, isProv)); }
///<summary>Called after file is downloaded. Throws exceptions. It is assumed that this is called from a worker thread. Progress delegate will be called every 100th iteration to inform thread of current progress. Quit flag can be set at any time in order to quit importing prematurely.</summary> public static void ImportRxNorm(string tempFileName, ProgressArgs progress, ref bool quit) { if (tempFileName == null) { return; } HashSet <string> codeHash = new HashSet <string>(RxNorms.GetAllCodes()); string[] lines = File.ReadAllLines(tempFileName); string[] arrayRxNorm; RxNorm rxNorm = new RxNorm(); for (int i = 0; i < lines.Length; i++) //each loop should read exactly one line of code. and each line of code should be a unique code { if (quit) { return; } if (i % 100 == 0) { progress(i + 1, lines.Length); } arrayRxNorm = lines[i].Split('\t'); if (codeHash.Contains(arrayRxNorm[0])) //code already exists { continue; } rxNorm.RxCui = arrayRxNorm[0]; rxNorm.MmslCode = arrayRxNorm[1]; rxNorm.Description = arrayRxNorm[2]; RxNorms.Insert(rxNorm); } }
///<summary>Called after file is downloaded. Throws exceptions. It is assumed that this is called from a worker thread. Progress delegate will be called every 100th iteration to inform thread of current progress. Quit flag can be set at any time in order to quit importing prematurely.</summary> public static void ImportRxNorm(string tempFileName, ProgressArgs progress, ref bool quit, ref int numCodesImported, ref int numCodesUpdated, bool updateExisting) { if (tempFileName == null) { return; } //RxNorms can have two codes for each RxCui. One RxNorm will have a value in the MmslCode and a blank description and the other will have a //value in the Description and a blank MmslCode. List <RxNorm> listRxNorms = RxNorms.GetAll(); Dictionary <string, RxNorm> dictRxNormsMmslCodes = listRxNorms.Where(x => x.MmslCode != "").ToDictionary(x => x.RxCui, x => x); Dictionary <string, RxNorm> dictRxNormsDefinitions = listRxNorms.Where(x => x.Description != "").ToDictionary(x => x.RxCui, x => x); string[] lines = File.ReadAllLines(tempFileName); string[] arrayRxNorm; RxNorm rxNorm = new RxNorm(); for (int i = 0; i < lines.Length; i++) //Each loop should read exactly one line of code. Each line will NOT be a unique code. { if (quit) { return; } if (i % 100 == 0) { progress(i + 1, lines.Length); } arrayRxNorm = lines[i].Split('\t'); if (dictRxNormsMmslCodes.ContainsKey(arrayRxNorm[0])) //code with an MmslCode already exists { rxNorm = dictRxNormsMmslCodes[arrayRxNorm[0]]; if (updateExisting) { if (arrayRxNorm[1] != "" && arrayRxNorm[1] != rxNorm.MmslCode) { rxNorm.MmslCode = arrayRxNorm[1]; rxNorm.Description = ""; //Should be blank for all MMSL code entries. See below for non-MMSL entries with descriptions. RxNorms.Update(rxNorm); numCodesUpdated++; } } continue; } if (dictRxNormsDefinitions.ContainsKey(arrayRxNorm[0])) //code with a Description already exists { rxNorm = dictRxNormsDefinitions[arrayRxNorm[0]]; if (updateExisting) { string newDescript = arrayRxNorm[2]; //if(newDescript.Length>255) { // newDescript=newDescript.Substring(0,255);//Description column is only varchar(255) so some descriptions will get truncated. //} //if(arrayRxNorm[2]!="" && newDescript!=rxNorm.Description) { if (arrayRxNorm[2] != "" && arrayRxNorm[2] != rxNorm.Description) { rxNorm.MmslCode = ""; //should be blank for all entries that have a description. rxNorm.Description = arrayRxNorm[2]; RxNorms.Update(rxNorm); numCodesUpdated++; } } continue; } rxNorm.RxCui = arrayRxNorm[0]; rxNorm.MmslCode = arrayRxNorm[1]; rxNorm.Description = arrayRxNorm[2]; RxNorms.Insert(rxNorm); numCodesImported++; } }
/// <summary>If the CodeValue of the EhrCode exists in its respective code table (I.e. Snomed, Loinc, Cpt, etc.) this will set IsInDb=true otherwise false.</summary> private static void updateCodeExistsHelper() { //No need to check RemotingRole; no call to db. if (listt.Count == 0) { return; } //Cache lists of codes. HashSet <string> cdcrecHS = new HashSet <string>(Cdcrecs.GetAllCodes()); HashSet <string> cdtHS = new HashSet <string>(ProcedureCodes.GetAllCodes()); HashSet <string> cptHS = new HashSet <string>(Cpts.GetAllCodes()); HashSet <string> cvxHS = new HashSet <string>(Cvxs.GetAllCodes()); HashSet <string> hcpcsHS = new HashSet <string>(Hcpcses.GetAllCodes()); HashSet <string> icd10HS = new HashSet <string>(Icd10s.GetAllCodes()); HashSet <string> icd9HS = new HashSet <string>(ICD9s.GetAllCodes()); HashSet <string> loincHS = new HashSet <string>(Loincs.GetAllCodes()); HashSet <string> rxnormHS = new HashSet <string>(RxNorms.GetAllCodes()); HashSet <string> snomedHS = new HashSet <string>(Snomeds.GetAllCodes()); HashSet <string> sopHS = new HashSet <string>(Sops.GetAllCodes()); for (int i = 0; i < listt.Count; i++) { switch (listt[i].CodeSystem) { case "AdministrativeSex": //always "in DB", even though there is no DB table listt[i].IsInDb = true; break; case "CDCREC": listt[i].IsInDb = cdcrecHS.Contains(listt[i].CodeValue); break; case "CDT": listt[i].IsInDb = cdtHS.Contains(listt[i].CodeValue); break; case "CPT": listt[i].IsInDb = cptHS.Contains(listt[i].CodeValue); break; case "CVX": listt[i].IsInDb = cvxHS.Contains(listt[i].CodeValue); break; case "HCPCS": listt[i].IsInDb = hcpcsHS.Contains(listt[i].CodeValue); break; case "ICD9CM": listt[i].IsInDb = icd9HS.Contains(listt[i].CodeValue); break; case "ICD10CM": listt[i].IsInDb = icd10HS.Contains(listt[i].CodeValue); break; case "LOINC": listt[i].IsInDb = loincHS.Contains(listt[i].CodeValue); break; case "RXNORM": listt[i].IsInDb = rxnormHS.Contains(listt[i].CodeValue); break; case "SNOMEDCT": listt[i].IsInDb = snomedHS.Contains(listt[i].CodeValue); break; case "SOP": listt[i].IsInDb = sopHS.Contains(listt[i].CodeValue); break; } } //This updates the last column "ExistsInDatabse" based on weather or not the code is found in another table in the database. }
/// <summary>If the number of codes in the code tables (I.e. Snomed, Loinc, Cpt, etc.) are greater than the number we expect then this will set IsInDb=true otherwise false.</summary> private static void updateCodeExistsHelper() { //No need to check RemotingRole; no call to db. if (listt.Count == 0) { return; } //Cache lists of codes. #region Count Variables //Counts from the DB long countCdcDB = -1; long countCdtDB = -1; long countCptDB = -1; long countCvxDB = -1; long countHcpcsDB = -1; long countIcd9DB = -1; long countIcd10DB = -1; long countLoincDB = -1; long countRxNormDB = -1; long countSnomedDB = -1; long countSopDB = -1; //Counts hard-coded from the EhrCodes.Listt. Lowered slightly to give a buffer, in case we decide to remove some codes later. const long countCdcList = 5; const long countCdtList = 10; const long countCptList = 300; const long countCvxList = 5; const long countHcpcsList = 20; const long countIcd9List = 1500; const long countIcd10List = 2000; const long countLoincList = 20; const long countRxNormList = 40; const long countSnomedList = 700; const long countSopList = 100; #endregion for (int i = 0; i < listt.Count; i++) { if (listt[i].IsInDb) { continue; //The codes are already present in the database, so we don't need to check again. } switch (listt[i].CodeSystem) { case "AdministrativeSex": //always "in DB", even though there is no DB table listt[i].IsInDb = true; break; case "CDCREC": if (countCdcDB == -1) { countCdcDB = Cdcrecs.GetCodeCount(); } if (countCdcDB > countCdcList) { listt[i].IsInDb = true; } break; case "CDT": if (countCdtDB == -1) { countCdtDB = ProcedureCodes.GetCodeCount(); } if (countCdtDB > countCdtList) { listt[i].IsInDb = true; } break; case "CPT": if (countCptDB == -1) { countCptDB = Cpts.GetCodeCount(); } if (countCptDB > countCptList) { listt[i].IsInDb = true; } break; case "CVX": if (countCvxDB == -1) { countCvxDB = Cvxs.GetCodeCount(); } if (countCvxDB > countCvxList) { listt[i].IsInDb = true; } break; case "HCPCS": if (countHcpcsDB == -1) { countHcpcsDB = Hcpcses.GetCodeCount(); } if (countHcpcsDB > countHcpcsList) { listt[i].IsInDb = true; } break; case "ICD9CM": if (countIcd9DB == -1) { countIcd9DB = ICD9s.GetCodeCount(); } if (countIcd9DB > countIcd9List) { listt[i].IsInDb = true; } break; case "ICD10CM": if (countIcd10DB == -1) { countIcd10DB = Icd10s.GetCodeCount(); } if (countIcd10DB > countIcd10List) { listt[i].IsInDb = true; } break; case "LOINC": if (countLoincDB == -1) { countLoincDB = Loincs.GetCodeCount(); } if (countLoincDB > countLoincList) { listt[i].IsInDb = true; } break; case "RXNORM": if (countRxNormDB == -1) { countRxNormDB = RxNorms.GetCodeCount(); } if (countRxNormDB > countRxNormList) { listt[i].IsInDb = true; } break; case "SNOMEDCT": if (countSnomedDB == -1) { countSnomedDB = Snomeds.GetCodeCount(); } if (countSnomedDB > countSnomedList) { listt[i].IsInDb = true; } break; case "SOP": if (countSopDB == -1) { countSopDB = Sops.GetCodeCount(); } if (countSopDB > countSopList) { listt[i].IsInDb = true; } break; } } //This updates the last column "ExistsInDatabse" based on weather or not the code is found in another table in the database. }
///<summary>This is the first step of automation, this checks to see if the new object matches one of the trigger conditions. </summary> /// <param name="triggerObject">Can be DiseaseDef, ICD9, Icd10, Snomed, Medication, RxNorm, Cvx, AllerfyDef, EHRLabResult, Patient, or VitalSign.</param> /// <param name="PatCur">Triggers and intervention are currently always dependant on current patient. </param> /// <returns>Returns a dictionary keyed on triggers and a list of all the objects that the trigger matched on. Should be used to generate CDS intervention message and later be passed to FormInfobutton for knowledge request.</returns> public static List <CDSIntervention> TriggerMatch(object triggerObject, Patient PatCur) { if (RemotingClient.RemotingRole == RemotingRole.ClientWeb) { return(Meth.GetObject <List <CDSIntervention> >(MethodBase.GetCurrentMethod(), triggerObject, PatCur)); } //Dictionary<string,List<object>> retVal=new Dictionary<string,List<object>>(); List <CDSIntervention> retVal = new List <CDSIntervention>(); //Define objects to be used in matching triggers. DiseaseDef diseaseDef; ICD9 icd9; Icd10 icd10; Snomed snomed; Medication medication; RxNorm rxNorm; Cvx cvx; AllergyDef allergyDef; EhrLabResult ehrLabResult; Patient pat; Vitalsign vitalsign; string triggerObjectMessage = ""; string command = ""; switch (triggerObject.GetType().Name) { case "DiseaseDef": diseaseDef = (DiseaseDef)triggerObject; command = "SELECT * FROM ehrtrigger" + " WHERE ProblemDefNumList LIKE '% " + POut.String(diseaseDef.DiseaseDefNum.ToString()) + " %'"; // '% <code> %' so that we can get exact matches. if (diseaseDef.ICD9Code != "") { command += " OR ProblemIcd9List LIKE '% " + POut.String(diseaseDef.ICD9Code) + " %'"; triggerObjectMessage += " -" + diseaseDef.ICD9Code + "(Icd9) " + ICD9s.GetByCode(diseaseDef.ICD9Code).Description + "\r\n"; } if (diseaseDef.Icd10Code != "") { command += " OR ProblemIcd10List LIKE '% " + POut.String(diseaseDef.Icd10Code) + " %'"; triggerObjectMessage += " -" + diseaseDef.Icd10Code + "(Icd10) " + Icd10s.GetByCode(diseaseDef.Icd10Code).Description + "\r\n"; } if (diseaseDef.SnomedCode != "") { command += " OR ProblemSnomedList LIKE '% " + POut.String(diseaseDef.SnomedCode) + " %'"; triggerObjectMessage += " -" + diseaseDef.SnomedCode + "(Snomed) " + Snomeds.GetByCode(diseaseDef.SnomedCode).Description + "\r\n"; } break; case "ICD9": icd9 = (ICD9)triggerObject; //TODO: TriggerObjectMessage command = "SELECT * FROM ehrtrigger" + " WHERE Icd9List LIKE '% " + POut.String(icd9.ICD9Code) + " %'"; // '% <code> %' so that we can get exact matches. break; case "Icd10": icd10 = (Icd10)triggerObject; //TODO: TriggerObjectMessage command = "SELECT * FROM ehrtrigger" + " WHERE Icd10List LIKE '% " + POut.String(icd10.Icd10Code) + " %'"; // '% <code> %' so that we can get exact matches. break; case "Snomed": snomed = (Snomed)triggerObject; //TODO: TriggerObjectMessage command = "SELECT * FROM ehrtrigger" + " WHERE SnomedList LIKE '% " + POut.String(snomed.SnomedCode) + " %'"; // '% <code> %' so that we can get exact matches. break; case "Medication": medication = (Medication)triggerObject; triggerObjectMessage = " - " + medication.MedName + (medication.RxCui == 0?"":" (RxCui:" + RxNorms.GetByRxCUI(medication.RxCui.ToString()).RxCui + ")") + "\r\n"; command = "SELECT * FROM ehrtrigger" + " WHERE MedicationNumList LIKE '% " + POut.String(medication.MedicationNum.ToString()) + " %'"; // '% <code> %' so that we can get exact matches. if (medication.RxCui != 0) { command += " OR RxCuiList LIKE '% " + POut.String(medication.RxCui.ToString()) + " %'"; // '% <code> %' so that we can get exact matches. } break; case "RxNorm": rxNorm = (RxNorm)triggerObject; triggerObjectMessage = " - " + rxNorm.Description + "(RxCui:" + rxNorm.RxCui + ")\r\n"; command = "SELECT * FROM ehrtrigger" + " WHERE RxCuiList LIKE '% " + POut.String(rxNorm.RxCui) + " %'"; // '% <code> %' so that we can get exact matches. break; case "Cvx": cvx = (Cvx)triggerObject; //TODO: TriggerObjectMessage command = "SELECT * FROM ehrtrigger" + " WHERE CvxList LIKE '% " + POut.String(cvx.CvxCode) + " %'"; // '% <code> %' so that we can get exact matches. break; case "AllergyDef": allergyDef = (AllergyDef)triggerObject; //TODO: TriggerObjectMessage command = "SELECT * FROM ehrtrigger" + " WHERE AllergyDefNumList LIKE '% " + POut.String(allergyDef.AllergyDefNum.ToString()) + " %'"; // '% <code> %' so that we can get exact matches. break; case "EhrLabResult": //match loinc only, no longer ehrLabResult = (EhrLabResult)triggerObject; //TODO: TriggerObjectMessage command = "SELECT * FROM ehrtrigger WHERE " + "(LabLoincList LIKE '% " + ehrLabResult.ObservationIdentifierID + " %'" //LOINC may be in one of two fields + "OR LabLoincList LIKE '% " + ehrLabResult.ObservationIdentifierIDAlt + " %')"; //LOINC may be in one of two fields break; case "Patient": pat = (Patient)triggerObject; List <string> triggerNums = new List <string>(); //TODO: TriggerObjectMessage command = "SELECT * FROM ehrtrigger WHERE DemographicsList !=''"; List <EhrTrigger> triggers = Crud.EhrTriggerCrud.SelectMany(command); for (int i = 0; i < triggers.Count; i++) { string[] arrayDemoItems = triggers[i].DemographicsList.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); for (int j = 0; j < arrayDemoItems.Length; j++) { switch (arrayDemoItems[j].Split(',')[0]) { case "age": int val = PIn.Int(Regex.Match(arrayDemoItems[j], @"\d+").Value); if (arrayDemoItems[j].Contains("=")) //=, >=, or <= { if (val == pat.Age) { triggerNums.Add(triggers[i].EhrTriggerNum.ToString()); break; } } if (arrayDemoItems[j].Contains("<")) { if (pat.Age < val) { triggerNums.Add(triggers[i].EhrTriggerNum.ToString()); break; } } if (arrayDemoItems[j].Contains(">")) { if (pat.Age > val) { triggerNums.Add(triggers[i].EhrTriggerNum.ToString()); break; } } //should never happen, age element didn't contain a comparator break; case "gender": if (arrayDemoItems[j].Split(',')[0].StartsWith(pat.Gender.ToString())) { triggerNums.Add(triggers[i].EhrTriggerNum.ToString()); } break; default: break; //should never happen } } } triggerNums.Add("-1"); //to ensure the querry is valid. command = "SELECT * FROM ehrTrigger WHERE EhrTriggerNum IN (" + String.Join(",", triggerNums) + ")"; break; case "Vitalsign": List <string> trigNums = new List <string>(); vitalsign = (Vitalsign)triggerObject; command = "SELECT * FROM ehrtrigger WHERE VitalLoincList !=''"; List <EhrTrigger> triggersVit = Crud.EhrTriggerCrud.SelectMany(command); for (int i = 0; i < triggersVit.Count; i++) { string[] arrayVitalItems = triggersVit[i].VitalLoincList.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); for (int j = 0; j < arrayVitalItems.Length; j++) { double val = PIn.Double(Regex.Match(arrayVitalItems[j], @"\d+(.(\d+))*").Value); //decimal value w or w/o decimal. switch (arrayVitalItems[j].Split(',')[0]) { case "height": if (arrayVitalItems[j].Contains("=")) //=, >=, or <= { if (vitalsign.Height == val) { trigNums.Add(triggersVit[i].EhrTriggerNum.ToString()); break; } } if (arrayVitalItems[j].Contains("<")) { if (vitalsign.Height < val) { trigNums.Add(triggersVit[i].EhrTriggerNum.ToString()); break; } } if (arrayVitalItems[j].Contains(">")) { if (vitalsign.Height > val) { trigNums.Add(triggersVit[i].EhrTriggerNum.ToString()); break; } } //should never happen, Height element didn't contain a comparator break; case "weight": if (arrayVitalItems[j].Contains("=")) //=, >=, or <= { if (vitalsign.Weight == val) { trigNums.Add(triggersVit[i].EhrTriggerNum.ToString()); break; } } if (arrayVitalItems[j].Contains("<")) { if (vitalsign.Weight < val) { trigNums.Add(triggersVit[i].EhrTriggerNum.ToString()); break; } } if (arrayVitalItems[j].Contains(">")) { if (vitalsign.Weight > val) { trigNums.Add(triggersVit[i].EhrTriggerNum.ToString()); break; } } break; case "BMI": float BMI = Vitalsigns.CalcBMI(vitalsign.Weight, vitalsign.Height); if (arrayVitalItems[j].Contains("=")) //=, >=, or <= { if (BMI == val) { trigNums.Add(triggersVit[i].EhrTriggerNum.ToString()); break; } } if (arrayVitalItems[j].Contains("<")) { if (BMI < val) { trigNums.Add(triggersVit[i].EhrTriggerNum.ToString()); break; } } if (arrayVitalItems[j].Contains(">")) { if (BMI > val) { trigNums.Add(triggersVit[i].EhrTriggerNum.ToString()); break; } } break; case "BP": //TODO break; } //end switch } } //End Triggers Vit trigNums.Add("-1"); //to ensure the querry is valid. command = "SELECT * FROM ehrTrigger WHERE EhrTriggerNum IN (" + String.Join(",", trigNums) + ")"; break; default: //command="SELECT * FROM ehrtrigger WHERE false";//should not return any results. return(null); #if DEBUG throw new Exception(triggerObject.GetType().ToString() + " object not implemented as intervention trigger yet. Add to the list above to handle."); #endif //break; } List <EhrTrigger> listEhrTriggers = Crud.EhrTriggerCrud.SelectMany(command); if (listEhrTriggers.Count == 0) { return(null); //no triggers matched. } //Check for MatchCardinality.One type triggers.---------------------------------------------------------------------------- for (int i = 0; i < listEhrTriggers.Count; i++) { if (listEhrTriggers[i].Cardinality != MatchCardinality.One) { continue; } string triggerMessage = listEhrTriggers[i].Description + ":\r\n"; //Example:"Patient over 55:\r\n" triggerMessage += triggerObjectMessage; //Example:" -Patient Age 67\r\n" List <object> ListObjectMatches = new List <object>(); ListObjectMatches.Add(triggerObject); CDSIntervention cdsi = new CDSIntervention(); cdsi.EhrTrigger = listEhrTriggers[i]; cdsi.InterventionMessage = triggerMessage; cdsi.TriggerObjects = ListObjectMatches; retVal.Add(cdsi); } //Fill object lists to be checked------------------------------------------------------------------------------------------------- List <Allergy> ListAllergy = Allergies.GetAll(PatCur.PatNum, false); List <Disease> ListDisease = Diseases.Refresh(PatCur.PatNum, true); List <DiseaseDef> ListDiseaseDef = new List <DiseaseDef>(); List <EhrLab> ListEhrLab = EhrLabs.GetAllForPat(PatCur.PatNum); //List<EhrLabResult> ListEhrLabResults=null;//Lab results are stored in a list in the EhrLab object. List <MedicationPat> ListMedicationPat = MedicationPats.Refresh(PatCur.PatNum, false); List <AllergyDef> ListAllergyDef = new List <AllergyDef>(); for (int i = 0; i < ListAllergy.Count; i++) { ListAllergyDef.Add(AllergyDefs.GetOne(ListAllergy[i].AllergyDefNum)); } for (int i = 0; i < ListDisease.Count; i++) { ListDiseaseDef.Add(DiseaseDefs.GetItem(ListDisease[i].DiseaseDefNum)); } for (int i = 0; i < listEhrTriggers.Count; i++) { if (listEhrTriggers[i].Cardinality == MatchCardinality.One) { continue; //we handled these above. } string triggerMessage = listEhrTriggers[i].Description + ":\r\n"; triggerMessage += triggerObjectMessage; List <object> ListObjectMatches = new List <object>(); //Allergy, Disease, LabPanels, MedicationPat, Patient, VaccinePat ListObjectMatches.Add(triggerObject); //Allergy----------------------------------------------------------------------------------------------------------------------- //allergy.snomedreaction //allergy.AllergyDefNum>>AllergyDef.SnomedType //allergy.AllergyDefNum>>AllergyDef.SnomedAllergyTo //allergy.AllergyDefNum>>AllergyDef.MedicationNum>>Medication.RxCui //Disease----------------------------------------------------------------------------------------------------------------------- //Disease.DiseaseDefNum>>DiseaseDef.ICD9Code //Disease.DiseaseDefNum>>DiseaseDef.SnomedCode //Disease.DiseaseDefNum>>DiseaseDef.Icd10Code //LabPanels--------------------------------------------------------------------------------------------------------------------- //LabPanel.LabPanelNum<<LabResult.TestId (Loinc) //LabPanel.LabPanelNum<<LabResult.ObsValue (Loinc) //LabPanel.LabPanelNum<<LabResult.ObsRange (Loinc) //MedicationPat----------------------------------------------------------------------------------------------------------------- //MedicationPat.RxCui //MedicationPat.MedicationNum>>Medication.RxCui //Patient>>Demographics--------------------------------------------------------------------------------------------------------- //Patient.Gender //Patient.Birthdate (Loinc age?) //Patient.SmokingSnoMed //RxPat------------------------------------------------------------------------------------------------------------------------- //Do not check RxPat. It is useless. //VaccinePat-------------------------------------------------------------------------------------------------------------------- //VaccinePat.VaccineDefNum>>VaccineDef.CVXCode //VitalSign--------------------------------------------------------------------------------------------------------------------- //VitalSign.Height (Loinc) //VitalSign.Weight (Loinc) //VitalSign.BpSystolic (Loinc) //VitalSign.BpDiastolic (Loinc) //VitalSign.WeightCode (Snomed) //VitalSign.PregDiseaseNum (Snomed) //Use object matches to check if required conditions are met------------------------------------------------------------------------------- switch (listEhrTriggers[i].Cardinality) { case MatchCardinality.One: //should never get here, handled above. continue; case MatchCardinality.OneOfEachCategory: //falls through to two or more, but then branches at the end of the case statement. case MatchCardinality.TwoOrMore: //if(ListObjectMatches.Count<2) { // continue;//Must match at least two objects for this category. //} //Medication for (int m = 0; m < ListMedicationPat.Count; m++) { if (listEhrTriggers[i].MedicationNumList.Contains(" " + ListMedicationPat[m].MedicationNum + " ")) { ListObjectMatches.Add(ListMedicationPat[m]); continue; } if (ListMedicationPat[m].RxCui != 0 && listEhrTriggers[i].RxCuiList.Contains(" " + ListMedicationPat[m].RxCui + " ")) { ListObjectMatches.Add(ListMedicationPat[m]); continue; } } //Allergy for (int a = 0; a < ListAllergy.Count; a++) { if (listEhrTriggers[i].AllergyDefNumList.Contains(" " + ListAllergy[a].AllergyDefNum + " ")) { ListObjectMatches.Add(AllergyDefs.GetOne(ListAllergy[a].AllergyDefNum)); triggerMessage += " -(Allergy) " + AllergyDefs.GetOne(ListAllergy[a].AllergyDefNum).Description + "\r\n"; continue; } } //Problem for (int d = 0; d < ListDiseaseDef.Count; d++) { if (ListDiseaseDef[d].ICD9Code != "" && listEhrTriggers[i].ProblemIcd9List.Contains(" " + ListDiseaseDef[d].ICD9Code + " ")) { ListObjectMatches.Add(ListDiseaseDef[d]); triggerMessage += " -(ICD9) " + ICD9s.GetByCode(ListDiseaseDef[d].ICD9Code).Description + "\r\n"; continue; } if (ListDiseaseDef[d].Icd10Code != "" && listEhrTriggers[i].ProblemIcd10List.Contains(" " + ListDiseaseDef[d].Icd10Code + " ")) { ListObjectMatches.Add(ListDiseaseDef[d]); triggerMessage += " -(Icd10) " + Icd10s.GetByCode(ListDiseaseDef[d].Icd10Code).Description + "\r\n"; continue; } if (ListDiseaseDef[d].SnomedCode != "" && listEhrTriggers[i].ProblemSnomedList.Contains(" " + ListDiseaseDef[d].SnomedCode + " ")) { ListObjectMatches.Add(ListDiseaseDef[d]); triggerMessage += " -(Snomed) " + Snomeds.GetByCode(ListDiseaseDef[d].SnomedCode).Description + "\r\n"; continue; } if (listEhrTriggers[i].ProblemDefNumList.Contains(" " + ListDiseaseDef[d].DiseaseDefNum + " ")) { ListObjectMatches.Add(ListDiseaseDef[d]); triggerMessage += " -(Problem Def) " + ListDiseaseDef[d].DiseaseName + "\r\n"; continue; } } //Vital //TODO //Age //TODO //Gender //TODO //Lab Result for (int l = 0; l < ListEhrLab.Count; l++) { for (int r = 0; r < ListEhrLab[l].ListEhrLabResults.Count; r++) { if (listEhrTriggers[i].LabLoincList.Contains(" " + ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierID + " ") || listEhrTriggers[i].LabLoincList.Contains(" " + ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierIDAlt + " ")) { ListObjectMatches.Add(ListEhrLab[l].ListEhrLabResults[r]); if (ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierID != "") //should almost always be the case. { triggerMessage += " -(LOINC) " + Loincs.GetByCode(ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierID).NameShort + "\r\n"; } else if (ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierID != "") { triggerMessage += " -(LOINC) " + Loincs.GetByCode(ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierIDAlt).NameShort + "\r\n"; } else if (ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierText != "") { triggerMessage += " -(LOINC) " + ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierText + "\r\n"; } else if (ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierTextAlt != "") { triggerMessage += " -(LOINC) " + ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierTextAlt + "\r\n"; } else if (ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierID != "") { triggerMessage += " -(LOINC) " + ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierID + "\r\n"; } else if (ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierIDAlt != "") { triggerMessage += " -(LOINC) " + ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierIDAlt + "\r\n"; } else if (ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierTextOriginal != "") { triggerMessage += " -(LOINC) " + ListEhrLab[l].ListEhrLabResults[r].ObservationIdentifierTextOriginal + "\r\n"; } else { triggerMessage += " -(LOINC) Unknown code.\r\n"; //should never happen. } continue; } } } ListObjectMatches = RemoveDuplicateObjectsHelper(ListObjectMatches); if (listEhrTriggers[i].Cardinality == MatchCardinality.TwoOrMore && ListObjectMatches.Count < 2) { continue; //next trigger, do not add to retVal } if (listEhrTriggers[i].Cardinality == MatchCardinality.OneOfEachCategory && !OneOfEachCategoryHelper(listEhrTriggers[i], ListObjectMatches)) { continue; } break; case MatchCardinality.All: bool allConditionsMet = true; List <string> MatchedCodes = getCodesFromListHelper(ListObjectMatches); //new List<string>(); //Match all Icd9Codes------------------------------------------------------------------------------------------------------------------------------------------------- string[] arrayIcd9Codes = listEhrTriggers[i].ProblemIcd9List.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); for (int c = 0; c < arrayIcd9Codes.Length; c++) { if (MatchedCodes.Contains(arrayIcd9Codes[i])) { continue; //found required code } //required code not found, set allConditionsMet to false and continue to next trigger allConditionsMet = false; break; } if (!allConditionsMet) { continue; //next trigger } //Match all Icd10Codes------------------------------------------------------------------------------------------------------------------------------------------------ string[] arrayIcd10Codes = listEhrTriggers[i].ProblemIcd10List.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); for (int c = 0; c < arrayIcd10Codes.Length; c++) { if (MatchedCodes.Contains(arrayIcd10Codes[i])) { continue; //found required code } //required code not found, set allConditionsMet to false and continue to next trigger allConditionsMet = false; break; } if (!allConditionsMet) { continue; //next trigger } //Match all SnomedCodes----------------------------------------------------------------------------------------------------------------------------------------------- string[] arraySnomedCodes = listEhrTriggers[i].ProblemSnomedList.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); for (int c = 0; c < arraySnomedCodes.Length; c++) { if (MatchedCodes.Contains(arraySnomedCodes[i])) { continue; //found required code } //required code not found, set allConditionsMet to false and continue to next trigger allConditionsMet = false; break; } if (!allConditionsMet) { continue; //next trigger } //Match all CvxCodes-------------------------------------------------------------------------------------------------------------------------------------------------- string[] arrayCvxCodes = listEhrTriggers[i].CvxList.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); for (int c = 0; c < arrayCvxCodes.Length; c++) { if (MatchedCodes.Contains(arrayCvxCodes[i])) { continue; //found required code } //required code not found, set allConditionsMet to false and continue to next trigger allConditionsMet = false; break; } if (!allConditionsMet) { continue; //next trigger, do not add to retval } //Match all LoincCodes------------------------------------------------------------------------------------------------------------------------------------------------ string[] arrayLoincCodes = listEhrTriggers[i].LabLoincList.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); for (int c = 0; c < arrayLoincCodes.Length; c++) { if (MatchedCodes.Contains(arrayLoincCodes[i])) { continue; //found required code } //required code not found, set allConditionsMet to false and continue to next trigger allConditionsMet = false; break; } if (!allConditionsMet) { continue; //next trigger, do not add to retval } //TODO:with values //Match all Vitals---------------------------------------------------------------------------------------------------------------------------------------------------- //TODO:with values //Match all Demographics--------------------------------------------------------------------------------------------------------------------------------------------- //if(listEhrTriggers[i].DemographicAgeGreaterThan!=0){ // if(PatCur.Birthdate.Year>1880 && PatCur.Birthdate.AddYears(listEhrTriggers[i].DemographicAgeGreaterThan)>DateTime.Now){//patient too young // continue;//next trigger // } //} //if(listEhrTriggers[i].DemographicAgeLessThan!=0){ // if(PatCur.Birthdate.Year>1880 && PatCur.Birthdate.AddYears(listEhrTriggers[i].DemographicAgeGreaterThan)<DateTime.Now){//patient too old // continue;//next trigger // } //} //if(listEhrTriggers[i].DemographicGender!=""){ // if(!listEhrTriggers[i].DemographicGender.Contains(PatCur.Gender.ToString())){//Patient Gender not in gender list of trigger // continue;//next trigger // } //} //TODO: construct trigger message using all the codes in the trigger. break; } //end switch trigger cardinality //retVal.Add(triggerMessage,ListObjectMatches); CDSIntervention cdsi = new CDSIntervention(); cdsi.EhrTrigger = listEhrTriggers[i]; cdsi.InterventionMessage = triggerMessage; cdsi.TriggerObjects = ListObjectMatches; retVal.Add(cdsi); } //end triggers return(retVal); }