Exemple #1
0
        public MessageHL7(string msgtext)
        {
            AckCode         = "";
            ControlId       = "";
            AckEvent        = "";
            originalMsgText = msgtext;
            Segments        = new List <SegmentHL7>();
            string[]   rows = msgtext.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
            SegmentHL7 segment;

            for (int i = 0; i < rows.Length; i++)
            {
                segment = new SegmentHL7(rows[i]);              //this creates the field objects.
                Segments.Add(segment);
                if (i == 0 && segment.Name == SegmentNameHL7.MSH)
                {
//js 7/3/12 Make this more intelligent because we also now need the suffix
                    string msgtype  = segment.GetFieldComponent(8, 0); //We force the user to leave the 'messageType' field in this position, position 8 of the MSH segment
                    string evnttype = segment.GetFieldComponent(8, 1);
                    AckEvent = evnttype;                               //We will use this when constructing the acknowledgment to echo back to sender the same event type sent to us
                    //If message type or event type are not in this list, they will default to the not supported type and will not be processed
                    if (msgtype == MessageTypeHL7.ADT.ToString())
                    {
                        MsgType = MessageTypeHL7.ADT;
                    }
                    else if (msgtype == MessageTypeHL7.ACK.ToString())
                    {
                        MsgType = MessageTypeHL7.ACK;
                    }
                    else if (msgtype == MessageTypeHL7.SIU.ToString())
                    {
                        MsgType = MessageTypeHL7.SIU;
                    }
                    else if (msgtype == MessageTypeHL7.DFT.ToString())
                    {
                        MsgType = MessageTypeHL7.DFT;
                    }
                    if (evnttype == EventTypeHL7.A04.ToString())
                    {
                        EventType = EventTypeHL7.A04;
                    }
                    else if (evnttype == EventTypeHL7.P03.ToString())
                    {
                        EventType = EventTypeHL7.P03;
                    }
                    else if (evnttype == EventTypeHL7.S12.ToString())
                    {
                        EventType = EventTypeHL7.S12;
                    }
                }
            }
        }
Exemple #2
0
        ///<summary>PatNum will not be altered here.  The pat passed in must either have PatNum=0, or must have a PatNum matching the segment.  The reason that isStandalone is passed in is because if using tight integration mode (isStandalone=false), then we need to store the "alternate patient id" aka Account No. that comes in on PID.4 in the ChartNumber field so we can pass it back in PID.2 of the DFT charge message.  However, if not using tight integration (isStandalone=true), the ChartNumber field is already occupied by the eCW patient ID, and we do not want to overwrite it.</summary>
        public static void ProcessPID(Patient pat, SegmentHL7 seg, bool isStandalone)
        {
            long patNum = PIn.Long(seg.GetFieldFullText(2));

            //if(pat.PatNum==0) {
            //	pat.PatNum=patNum;
            //}
            //else
            if (pat.PatNum != 0 && pat.PatNum != patNum)
            {
                throw new ApplicationException("Invalid patNum");
            }
            if (!isStandalone)             //when in tight integration mode
            {
                pat.ChartNumber = seg.GetFieldFullText(4);
            }
            pat.LName     = seg.GetFieldComponent(5, 0);
            pat.FName     = seg.GetFieldComponent(5, 1);
            pat.MiddleI   = seg.GetFieldComponent(5, 2);
            pat.Birthdate = DateParse(seg.GetFieldFullText(7));
            pat.Gender    = GenderParse(seg.GetFieldFullText(8));
            pat.Race      = RaceParse(seg.GetFieldFullText(10));
            pat.Address   = seg.GetFieldComponent(11, 0);
            pat.Address2  = seg.GetFieldComponent(11, 1);
            pat.City      = seg.GetFieldComponent(11, 2);
            pat.State     = seg.GetFieldComponent(11, 3);
            pat.Zip       = seg.GetFieldComponent(11, 4);
            pat.HmPhone   = PhoneParse(seg.GetFieldFullText(13));
            pat.WkPhone   = PhoneParse(seg.GetFieldFullText(14));
            pat.Position  = MaritalStatusParse(seg.GetFieldFullText(16));
            //pat.ChartNumber=seg.GetFieldFullText(18);//this is wrong.  Would also break standalone mode
            pat.SSN      = seg.GetFieldFullText(19);
            pat.FeeSched = FeeScheduleParse(seg.GetFieldFullText(22));
        }
Exemple #3
0
		public MessageHL7(string msgtext) {
			AckCode="";
			ControlId="";
			AckEvent="";
			originalMsgText=msgtext;
			Segments=new List<SegmentHL7>();
			string[] rows=msgtext.Split(new string[] { "\r","\n" },StringSplitOptions.RemoveEmptyEntries);
			//We need to get the separator characters in order to create the field objects.
			//The separators are part of the MSH segment and we force users to leave them in position 1 for incoming messages.
			Delimiters=new char[] { '^','~','\\','&' };//this is the default, but we will get them from the MSH segment of the incoming message in case they are using something unique.
			for(int i=0;i<rows.Length;i++) {
				string[] fields=rows[i].Split(new string[] { "|" },StringSplitOptions.None);
				if(fields.Length>1 && fields[0]=="MSH" && fields[1].Length>0) {
					//Encoding characters are in the following order:  component separator, repetition separator, escape character, subcomponent separator
					Delimiters=fields[1].ToCharArray();//we force users to leave the delimiters in position 1 of the MSH segment
					break;
				}
			}
			SegmentHL7 segment;
			for(int i=0;i<rows.Length;i++) {
				segment=new SegmentHL7(rows[i],Delimiters);//this creates the field objects.
				Segments.Add(segment);
				if(i==0 && segment.Name==SegmentNameHL7.MSH) {
//js 7/3/12 Make this more intelligent because we also now need the suffix
					string msgtype=segment.GetFieldComponent(8,0);//We force the user to leave the 'messageType' field in this position, position 8 of the MSH segment
					string evnttype=segment.GetFieldComponent(8,1);
					string msgStructure=segment.GetFieldComponent(8,2);
					AckEvent=evnttype;//We will use this when constructing the acknowledgment to echo back to sender the same event type sent to us
					//If message type or event type are not in this list, they will default to the not supported type and will not be processed
					try {
						MsgType=(MessageTypeHL7)Enum.Parse(typeof(MessageTypeHL7),msgtype,true);
					}
					catch(Exception ex) {
						MsgType=MessageTypeHL7.NotDefined;
					}
					try {
						EventType=(EventTypeHL7)Enum.Parse(typeof(EventTypeHL7),evnttype,true);
					}
					catch(Exception ex) {
						EventType=EventTypeHL7.NotDefined;
					}
					try {
						MsgStructure=(MessageStructureHL7)Enum.Parse(typeof(MessageStructureHL7),msgStructure,true);
					}
					catch(Exception ex) {
						MsgStructure=MessageStructureHL7.NotDefined;
					}
				}
			}
		}
Exemple #4
0
        public MessageHL7(string msgtext)
        {
            originalMsgText = msgtext;
            Segments        = new List <SegmentHL7>();
            string[]   rows = msgtext.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
            SegmentHL7 segment;

            for (int i = 0; i < rows.Length; i++)
            {
                segment = new SegmentHL7(rows[i]);              //this creates the field objects.
                Segments.Add(segment);
                if (i == 0 && segment.Name == SegmentName.MSH)
                {
                    string msgtype = segment.GetFieldComponent(8, 0);
                    if (msgtype == "ADT")
                    {
                        MsgType = MessageType.ADT;
                    }
                    else if (msgtype == "SIU")
                    {
                        MsgType = MessageType.SIU;
                    }
                    else if (msgtype == "DFT")
                    {
                        MsgType = MessageType.DFT;
                    }
                }
            }
        }
		public MessageHL7(string msgtext) {
			AckCode="";
			ControlId="";
			AckEvent="";
			originalMsgText=msgtext;
			Segments=new List<SegmentHL7>();
			string[] rows=msgtext.Split(new string[] { "\r","\n" },StringSplitOptions.RemoveEmptyEntries);
			SegmentHL7 segment;
			for(int i=0;i<rows.Length;i++) {
				segment=new SegmentHL7(rows[i]);//this creates the field objects.
				Segments.Add(segment);
				if(i==0 && segment.Name==SegmentNameHL7.MSH) {
//js 7/3/12 Make this more intelligent because we also now need the suffix
					string msgtype=segment.GetFieldComponent(8,0);//We force the user to leave the 'messageType' field in this position, position 8 of the MSH segment
					string evnttype=segment.GetFieldComponent(8,1);
					AckEvent=evnttype;//We will use this when constructing the acknowledgment to echo back to sender the same event type sent to us
					//If message type or event type are not in this list, they will default to the not supported type and will not be processed
					if(msgtype==MessageTypeHL7.ADT.ToString()) {
						MsgType=MessageTypeHL7.ADT;
					}
					else if(msgtype==MessageTypeHL7.ACK.ToString()) {
						MsgType=MessageTypeHL7.ACK;
					}
					else if(msgtype==MessageTypeHL7.SIU.ToString()) {
						MsgType=MessageTypeHL7.SIU;
					}
					else if(msgtype==MessageTypeHL7.DFT.ToString()) {
						MsgType=MessageTypeHL7.DFT;
					}
					if(evnttype==EventTypeHL7.A04.ToString()) {
						EventType=EventTypeHL7.A04;
					}
					else if(evnttype==EventTypeHL7.P03.ToString()) {
						EventType=EventTypeHL7.P03;
					}
					else if(evnttype==EventTypeHL7.S12.ToString()) {
						EventType=EventTypeHL7.S12;
					}
				}
			}
		}
Exemple #6
0
        ///<summary>PatNum will not be altered here.  The pat passed in must either have PatNum=0, or must have a PatNum matching the segment.  The reason that isStandalone is passed in is because if using tight integration mode (isStandalone=false), then we need to store the "alternate patient id" aka Account No. that comes in on PID.4 in the ChartNumber field so we can pass it back in PID.2 of the DFT charge message.  However, if not using tight integration (isStandalone=true), the ChartNumber field is already occupied by the eCW patient ID, and we do not want to overwrite it.</summary>
        public static void ProcessPID(Patient pat, SegmentHL7 seg, bool isStandalone, List <PatientRace> listPatRaces)
        {
            long patNum = PIn.Long(seg.GetFieldFullText(2));

            //Standalone mode may not have found a matching patient within the database and will be inserted later in the message processing.
            if (isStandalone && pat != null)
            {
                patNum = pat.PatNum;              //Standalone mode cannot always trust the PatNum in field 2.  Always use pat.PatNum because that will the OD PatNum.
            }
            //if(pat.PatNum==0) {
            //	pat.PatNum=patNum;
            //}
            //else
            if (!isStandalone &&         //in standalone, the patnums won't match, so don't check
                pat.PatNum != 0 && pat.PatNum != patNum)
            {
                throw new ApplicationException("Invalid patNum");
            }
            if (!isStandalone)             //when in tight integration mode
            {
                pat.ChartNumber = seg.GetFieldFullText(4);
            }
            pat.LName     = seg.GetFieldComponent(5, 0);
            pat.FName     = seg.GetFieldComponent(5, 1);
            pat.MiddleI   = seg.GetFieldComponent(5, 2);
            pat.Birthdate = DateParse(seg.GetFieldFullText(7));
            pat.Gender    = GenderParse(seg.GetFieldFullText(8));
            if (patNum > 0)
            {
                listPatRaces.Clear();
                listPatRaces.AddRange(RaceParse(seg.GetFieldFullText(10), patNum));
            }
            pat.Address  = seg.GetFieldComponent(11, 0);
            pat.Address2 = seg.GetFieldComponent(11, 1);
            pat.City     = seg.GetFieldComponent(11, 2);
            pat.State    = seg.GetFieldComponent(11, 3);
            pat.Zip      = seg.GetFieldComponent(11, 4);
            pat.HmPhone  = PhoneParse(seg.GetFieldFullText(13));
            pat.WkPhone  = PhoneParse(seg.GetFieldFullText(14));
            pat.Position = MaritalStatusParse(seg.GetFieldFullText(16));
            //pat.ChartNumber=seg.GetFieldFullText(18);//this is wrong.  Would also break standalone mode
            pat.SSN = seg.GetFieldFullText(19);
            if (ProgramProperties.GetPropVal(ProgramName.eClinicalWorks, "FeeSchedulesSetManually") == "0")          //if !FeeSchedulesSetManually
            {
                pat.FeeSched = FeeScheduleParse(seg.GetFieldFullText(22));
            }
        }
Exemple #7
0
        ///<summary>PatNum will not be altered here.  The pat passed in must either have PatNum=0, or must have a PatNum matching the segment.  The reason that isStandalone is passed in is because if using tight integration mode (isStandalone=false), then we need to store the "alternate patient id" aka Account No. that comes in on PID.4 in the ChartNumber field so we can pass it back in PID.2 of the DFT charge message.  However, if not using tight integration (isStandalone=true), the ChartNumber field is already occupied by the eCW patient ID, and we do not want to overwrite it.</summary>
        public static void ProcessPID(Patient pat, SegmentHL7 seg, bool isStandalone)
        {
            long patNum = PIn.Long(seg.GetFieldFullText(2));

            //if(pat.PatNum==0) {
            //	pat.PatNum=patNum;
            //}
            //else
            if (!isStandalone &&         //in standalone, the patnums won't match, so don't check
                pat.PatNum != 0 && pat.PatNum != patNum)
            {
                throw new ApplicationException("Invalid patNum");
            }
            if (!isStandalone)             //when in tight integration mode
            {
                pat.ChartNumber = seg.GetFieldFullText(4);
            }
            pat.LName     = seg.GetFieldComponent(5, 0);
            pat.FName     = seg.GetFieldComponent(5, 1);
            pat.MiddleI   = seg.GetFieldComponent(5, 2);
            pat.Birthdate = DateParse(seg.GetFieldFullText(7));
            pat.Gender    = GenderParse(seg.GetFieldFullText(8));
            PatientRaceOld patientRaceOld = RaceParse(seg.GetFieldFullText(10));

            //Converts PatientRaceOld to new Patient Races, and adds them o the PatientRace table.
            PatientRaces.Reconcile(pat.PatNum, PatientRaces.GetPatRacesFromPatientRaceOld(patientRaceOld));
            pat.Address  = seg.GetFieldComponent(11, 0);
            pat.Address2 = seg.GetFieldComponent(11, 1);
            pat.City     = seg.GetFieldComponent(11, 2);
            pat.State    = seg.GetFieldComponent(11, 3);
            pat.Zip      = seg.GetFieldComponent(11, 4);
            pat.HmPhone  = PhoneParse(seg.GetFieldFullText(13));
            pat.WkPhone  = PhoneParse(seg.GetFieldFullText(14));
            pat.Position = MaritalStatusParse(seg.GetFieldFullText(16));
            //pat.ChartNumber=seg.GetFieldFullText(18);//this is wrong.  Would also break standalone mode
            pat.SSN = seg.GetFieldFullText(19);
            if (ProgramProperties.GetPropVal(ProgramName.eClinicalWorks, "FeeSchedulesSetManually") == "0")          //if !FeeSchedulesSetManually
            {
                pat.FeeSched = FeeScheduleParse(seg.GetFieldFullText(22));
            }
        }
Exemple #8
0
		///<summary>PatNum will not be altered here.  The pat passed in must either have PatNum=0, or must have a PatNum matching the segment.  The reason that isStandalone is passed in is because if using tight integration mode (isStandalone=false), then we need to store the "alternate patient id" aka Account No. that comes in on PID.4 in the ChartNumber field so we can pass it back in PID.2 of the DFT charge message.  However, if not using tight integration (isStandalone=true), the ChartNumber field is already occupied by the eCW patient ID, and we do not want to overwrite it.</summary>
		public static void ProcessPID(Patient pat,SegmentHL7 seg,bool isStandalone,List<PatRace> listPatRaces) {
			long patNum=PIn.Long(seg.GetFieldFullText(2));
			//if(pat.PatNum==0) {
			//	pat.PatNum=patNum;
			//}
			//else 
			if(!isStandalone //in standalone, the patnums won't match, so don't check
				&& pat.PatNum!=0 && pat.PatNum!=patNum) 
			{
				throw new ApplicationException("Invalid patNum");
			}
			if(!isStandalone) {//when in tight integration mode
				pat.ChartNumber=seg.GetFieldFullText(4);
			}
			pat.LName=seg.GetFieldComponent(5,0);
			pat.FName=seg.GetFieldComponent(5,1);
			pat.MiddleI=seg.GetFieldComponent(5,2);
			pat.Birthdate=DateParse(seg.GetFieldFullText(7));
			pat.Gender=GenderParse(seg.GetFieldFullText(8));
			PatientRaceOld patientRaceOld=RaceParse(seg.GetFieldFullText(10));
			//Converts PatientRaceOld to new Patient Races, and adds them to the PatientRace table.
			listPatRaces.AddRange(PatientRaces.GetPatRacesFromPatientRaceOld(patientRaceOld));
			pat.Address=seg.GetFieldComponent(11,0);
			pat.Address2=seg.GetFieldComponent(11,1);
			pat.City=seg.GetFieldComponent(11,2);
			pat.State=seg.GetFieldComponent(11,3);
			pat.Zip=seg.GetFieldComponent(11,4);
			pat.HmPhone=PhoneParse(seg.GetFieldFullText(13));
			pat.WkPhone=PhoneParse(seg.GetFieldFullText(14));
			pat.Position=MaritalStatusParse(seg.GetFieldFullText(16));
			//pat.ChartNumber=seg.GetFieldFullText(18);//this is wrong.  Would also break standalone mode
			pat.SSN=seg.GetFieldFullText(19);
			if(ProgramProperties.GetPropVal(ProgramName.eClinicalWorks,"FeeSchedulesSetManually")=="0") {//if !FeeSchedulesSetManually
				pat.FeeSched=FeeScheduleParse(seg.GetFieldFullText(22));
			}
		}
Exemple #9
0
        private string originalMsgText; //We'll store this for now, but I don't think we'll use it.

        #endregion Fields

        #region Constructors

        public MessageHL7(string msgtext)
        {
            originalMsgText=msgtext;
            Segments=new List<SegmentHL7>();
            string[] rows=msgtext.Split(new string[] { "\r\n" },StringSplitOptions.RemoveEmptyEntries);
            SegmentHL7 segment;
            for(int i=0;i<rows.Length;i++) {
                segment=new SegmentHL7(rows[i]);//this creates the field objects.
                Segments.Add(segment);
                if(i==0 && segment.Name==SegmentName.MSH) {
                    string msgtype=segment.GetFieldComponent(8,0);
                    if(msgtype=="ADT") {
                        MsgType=MessageType.ADT;
                    }
                    else if(msgtype=="SIU") {
                        MsgType=MessageType.SIU;
                    }
                    else if(msgtype=="DFT") {
                        MsgType=MessageType.DFT;
                    }
                }
            }
        }
Exemple #10
0
		///<summary></summary>
		public static void ProcessOBR(HL7DefSegment segDef,SegmentHL7 obrSeg,MessageHL7 obrMsg) {
			char subcompChar='&';
			if(obrMsg.Delimiters.Length>3) {//it is possible they did not send all 4 of the delimiter chars, in which case we will use the default &
				subcompChar=obrMsg.Delimiters[3];
			}
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				HL7DefField fieldDefCur=segDef.hl7DefFields[i];
				FieldHL7 fieldCur=obrSeg.GetField(fieldDefCur.OrdinalPos);//fieldCur can be null
				if(fieldCur==null) {
					continue;
				}
				switch(fieldDefCur.FieldName) {
					case "clinicalInfo":
						if(_isFirstObr) {
							_medLabCur.ClinicalInfo=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos).Trim();
						}
						continue;
					case "dateTimeCollected":
						_medLabCur.DateTimeCollected=FieldParserMedLab.DateTimeParse(obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						continue;
					case "dateTimeEntered":
						_medLabCur.DateTimeEntered=FieldParserMedLab.DateTimeParse(obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						continue;
					case "dateTimeReported":
						_medLabCur.DateTimeReported=FieldParserMedLab.DateTimeParse(obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						continue;
					case "facilityID":
						string facIdCur=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						if(facIdCur=="") {
							continue;
						}
						if(!_dictFacilityCodeNum.ContainsKey(facIdCur)) {//no ZPS segments with this footnote ID
							continue;
						}
						List<long> facNumList=_dictFacilityCodeNum[facIdCur];//should only be one facility with this footnote ID in this message
						for(int j=0;j<facNumList.Count;j++) {
							MedLabFacAttach medLabAttachCur=new MedLabFacAttach();
							medLabAttachCur.MedLabFacilityNum=facNumList[j];
							medLabAttachCur.MedLabNum=_medLabCur.MedLabNum;
							MedLabFacAttaches.Insert(medLabAttachCur);
						}
						continue;
					case "obsTestID":
						if(obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos,2).ToLower()=="l") {
							_medLabCur.ObsTestID=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
							_medLabCur.ObsTestDescript=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos,1);
						}
						if(obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos,5).ToLower()=="ln") {
							_medLabCur.ObsTestLoinc=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos,3);
							_medLabCur.ObsTestLoincText=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos,4);
						}
						continue;
					case "orderingProv":
						if(_medLabCur.OrderingProvNPI==null || _medLabCur.OrderingProvNPI=="") {//may be filled from the ORC segment
							_medLabCur.OrderingProvNPI=FieldParserMedLab.OrderingProvIDParse(fieldCur,"N");
						}
						if(_medLabCur.OrderingProvLocalID==null || _medLabCur.OrderingProvLocalID=="") {//may be filled from the ORC segment
							_medLabCur.OrderingProvLocalID=FieldParserMedLab.OrderingProvIDParse(fieldCur,"L");
						}
						int k=0;
						if(_medLabCur.OrderingProvLName==null || _medLabCur.OrderingProvLName=="") {//may be filled from the ORC segment
							_medLabCur.OrderingProvLName=fieldCur.GetComponentVal(1).Trim();
							while(_medLabCur.OrderingProvLName=="" && k<fieldCur.ListRepeatFields.Count) {//if LName is not present in first repetition check others
								_medLabCur.OrderingProvLName=fieldCur.ListRepeatFields[k].GetComponentVal(1).Trim();
								k++;
							}
						}
						k=0;
						if(_medLabCur.OrderingProvFName==null || _medLabCur.OrderingProvFName=="") {//may be filled from the ORC segment
							_medLabCur.OrderingProvFName=fieldCur.GetComponentVal(2).Trim();
							while(_medLabCur.OrderingProvFName=="" && k<fieldCur.ListRepeatFields.Count) {//if FName is not present in first repetition check others
								_medLabCur.OrderingProvFName=fieldCur.ListRepeatFields[k].GetComponentVal(2).Trim();
								k++;
							}
						}
						#region Locate Provider
						if(_medLabCur.ProvNum!=0) {//may have located the provider from the ORC segment, nothing left to do
							continue;
						}
						_medicaidIdCur=FieldParserMedLab.OrderingProvIDParse(fieldCur,"P");
						List<Provider> listProvs=Providers.GetProvsByNpiOrMedicaidId(_medLabCur.OrderingProvNPI,_medicaidIdCur);
						listProvs.Sort(SortByNpiMedicaidIdMatch);
						if(listProvs.Count>0) {//if a provider with either a matching NPI or Medicaid ID is found, use the first matching prov
							_medLabCur.ProvNum=listProvs[0].ProvNum;
						}
						else {//no provider match based on NPI or MedicaidID
							listProvs=Providers.GetProvsByFLName(_medLabCur.OrderingProvLName,_medLabCur.OrderingProvFName);//must have both LName and FName
							if(listProvs.Count>0) {//use the first provider found with matching LName and FName
								_medLabCur.ProvNum=listProvs[0].ProvNum;
							}
						}
						#endregion Locate Provider
						continue;
					case "parentObsID":
						_medLabCur.ParentObsID=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "parentObsTestID":
						_medLabCur.ParentObsTestID=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "resultStatus":
						_medLabCur.ResultStatus=FieldParserMedLab.ResultStatusParse(obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						continue;
					case "specimenAction":
						_medLabCur.ActionCode=FieldParserMedLab.ResultActionParse(obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						continue;
					case "specimenID":
						if(_medLabCur.SpecimenID!=null && _medLabCur.SpecimenID!="") {//could be filled by value in ORC
							continue;
						}
						_medLabCur.SpecimenID=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "specimenIDAlt":
						_medLabCur.SpecimenIDAlt=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "specimenIDFiller":
						if(_medLabCur.SpecimenIDFiller!=null && _medLabCur.SpecimenIDFiller!="") {//could be filled by value in ORC
							continue;
						}
						_medLabCur.SpecimenIDFiller=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "totalVolume":
						_medLabCur.TotalVolume=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						if(_medLabCur.TotalVolume=="") {
							continue;
						}
						string[] unitsSubComp=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos,1).Split(new char[] { subcompChar },StringSplitOptions.None);
						if(unitsSubComp.Length==0 || unitsSubComp[0]=="") {
							_medLabCur.TotalVolume+=" ml";
							continue;
						}
						_medLabCur.TotalVolume+=" "+unitsSubComp[0];
						continue;
					default:
						continue;
				}
			}
			_isFirstObr=false;
			return;
		}
Exemple #11
0
		///<summary>This will insert a new MedLab object and set _medLabCur.</summary>
		public static void ProcessMSH(HL7DefSegment segDef,SegmentHL7 mshSeg,MessageHL7 msg) {
			string firstObrClinicalInfo="";
			if(_medLabCur!=null) {
				//if _medLabCur already exists and we are about to start another ORC/OBR group, save the changes to _medLabCur before instantiating a new one
				MedLabs.Update(_medLabCur);
				firstObrClinicalInfo=_medLabCur.ClinicalInfo;//this is populated with processing the OBR segment of the first OBR in the message
			}
			_medLabCur=new MedLab();
			_medLabCur.FileName=_msgArchiveFileName;
			_medLabCur.ClinicalInfo=firstObrClinicalInfo;//the clinical information from the first OBR, will be on each report generated by this message
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				HL7DefField fieldDefCur=segDef.hl7DefFields[i];
				switch(fieldDefCur.FieldName) {
					case "messageControlId":
						msg.ControlId=mshSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "sendingApp":
						_medLabCur.SendingApp=mshSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "sendingFacility":
						_medLabCur.SendingFacility=mshSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					default:
						continue;
				}
			}
			_medLabCur.MedLabNum=MedLabs.Insert(_medLabCur);
			_medLabNumList.Add(_medLabCur.MedLabNum);
		}
Exemple #12
0
		///<summary>This will be used to set the clinic and confirmation status of the appointment.  If apt is null, does nothing.</summary>
		public static void ProcessAIL(Patient pat,Appointment apt,HL7DefSegment segDef,SegmentHL7 seg) {
			if(apt==null) {//We have to have an appt to process the AIL segment
				return;
			}
			Appointment aptOld=apt.Clone();	
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int intItemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "apt.confirmStatus":
						long aptConfirmDefNum=0;
						Def[] listConfirmStats=DefC.GetList(DefCat.ApptConfirmed);
						for(int j=0;j<listConfirmStats.Length;j++) {
							if(seg.GetFieldComponent(intItemOrder,1).ToLower()==listConfirmStats[j].ItemName.ToLower()//ItemName is the confirmation name
								|| (listConfirmStats[j].ItemValue!="" && seg.GetFieldComponent(intItemOrder,1).ToLower()==listConfirmStats[j].ItemValue.ToLower()))//ItemValue is the confirmation abbreviation, which may be blank
							{
								aptConfirmDefNum=listConfirmStats[j].DefNum;
								break;
							}
						}
						if(aptConfirmDefNum>0) {
							apt.Confirmed=aptConfirmDefNum;
						}
						continue;
					case "apt.location":
						if(seg.GetFieldComponent(intItemOrder,5).ToLower()!="c") {
							continue;
						}
						long clinicNum=Clinics.GetByDesc(seg.GetFieldComponent(intItemOrder,0));//0 if field is blank or description doesn't match clinic description in the db
						if(clinicNum>0) {
							apt.ClinicNum=clinicNum;//the pat.ClinicNum may be set based on a different segment, like the PV1 segment
						}
						continue;
					default:
						continue;
				}
			}
			Appointments.Update(apt,aptOld);
			_aptProcessed=apt;
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated appointment for patient "+pat.GetNameFLnoPref()+" due to an incoming AIL segment.",EventLogEntryType.Information);
			}
			return;
		}
Exemple #13
0
		///<summary>Appointment request segment.  Included in inbound SRM, Schedule Request Messages.  When OD is the filler application, this will identify the appointment that the placer or auxiliary aplication is trying to update.  We only support event S03 - Appt Modification requests or event S04 - Appt Cancellation requests for now.</summary>
		public static void ProcessARQ(Patient pat,Appointment apt,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			long aptNum=0;
			string externAptId="";
			string externRoot="";
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int intItemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "apt.externalAptID":
						externAptId=seg.GetFieldComponent(intItemOrder,0);
						externRoot=seg.GetFieldComponent(intItemOrder,2);
						continue;
					case "apt.AptNum":
						try {
							aptNum=PIn.Long(seg.GetFieldComponent(intItemOrder,0));
						}
						catch(Exception ex) {
							//do nothing, aptNum will remain 0
						}
						if(apt!=null && apt.AptNum!=aptNum) {
							//an appointment was located from the inbound message, but the AptNum on the appointment is not the same as the AptNum in this ARQ segment (should never happen)
							throw new Exception("Invalid appointment number.");
						}
						continue;
					default:
						continue;
				}
			}
			if(externAptId!="" && externRoot!="" && OIDExternals.GetByRootAndExtension(externRoot,externAptId)==null) {
				OIDExternal oidExtCur=new OIDExternal();
				oidExtCur.IDType=IdentifierType.Appointment;
				oidExtCur.IDInternal=apt.AptNum;
				oidExtCur.IDExternal=externAptId;
				oidExtCur.rootExternal=externRoot;
				OIDExternals.Insert(oidExtCur);
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Added an external appointment ID to the oidexternals table due to an incoming ARQ segment.\r\n"
						+"AptNum: "+apt.AptNum.ToString()+", External AptID: "+externAptId+", External root: "+externRoot+".",EventLogEntryType.Information);
				}
			}
			_hl7MsgCur.AptNum=apt.AptNum;
			HL7Msgs.Update(_hl7MsgCur);
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated hl7msg to include AptNum for "+pat.GetNameFLnoPref()+" due to an incoming SCH segment.",EventLogEntryType.Information);
			}
			_aptProcessed=apt;
			return;
		}
Exemple #14
0
		public static void ProcessPRB(Patient pat,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			int probActionOrder=-1;
			int probCodeOrder=-1;
			int probStartDateOrder=-1;
			int probStopDateOrder=-1;
			int probUniqueIdOrder=-1;
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "problemAction":
						probActionOrder=itemOrder;
						continue;
					case "problemCode":
						probCodeOrder=itemOrder;
						continue;
					case "problemStartDate":
						probStartDateOrder=itemOrder;
						continue;
					case "problemStopDate":
						probStopDateOrder=itemOrder;
						continue;
					case "problemUniqueId":
						probUniqueIdOrder=itemOrder;
						continue;
					default:
						continue;
				}
			}
			//we need these 3 items defined in order to process the problem
			if(probActionOrder<0 || probCodeOrder<0 || probUniqueIdOrder<0) {
				EventLog.WriteEntry("OpenDentHL7","The PRB segment was not processed.  The segment must have an action, code, and unique ID defined.",EventLogEntryType.Information);
				return;
			}
			//get values from defined locations within the segment and validate info
			//We only add or update problems.  Other actions like delete or correct are not yet supported
			if(seg.GetFieldComponent(probActionOrder).ToLower()!="ad" && seg.GetFieldComponent(probActionOrder).ToLower()!="up") {
				EventLog.WriteEntry("OpenDentHL7","The PRB segment was not processed.  The action codes supported are 'AD' for add or 'UP' for update.",EventLogEntryType.Information);
				return;
			}
			long probDefNum=DiseaseDefs.GetNumFromSnomed(PIn.String(seg.GetFieldComponent(probCodeOrder,0)));
			//The problem must be a SNOMEDCT code, identified by the coding system table 0396 value "SNM" in component 3 of the CWE problem code field
			//There must be a disease def setup with the SNOMEDCT code in the problem list or we will ignore this problem
			if(seg.GetFieldComponent(probCodeOrder,2).ToLower()!="snm" || probDefNum==0) {
				EventLog.WriteEntry("OpenDentHL7","The PRB segment was not processed.  "
					+"The code is not attached to an existing problem definition or is not a SNOMEDCT code.",EventLogEntryType.Information);
				return;
			}
			string probIdExternal=seg.GetFieldComponent(probUniqueIdOrder,0);
			string probRootExternal=seg.GetFieldComponent(probUniqueIdOrder,2);
			if(probIdExternal=="" || probRootExternal=="") {
				EventLog.WriteEntry("OpenDentHL7","The PRB segment was not processed. "
					+" The problem does not have a unique ID with assigning authority root.",EventLogEntryType.Information);
				return;
			}
			//If problem external ID and root is in the database, but is used to identify an object other than a problem, do not process the segment
			OIDExternal probOidExt=OIDExternals.GetByRootAndExtension(probRootExternal,probIdExternal);
			if(probOidExt!=null && probOidExt.IDType!=IdentifierType.Problem) {
				EventLog.WriteEntry("OpenDentHL7","The PRB segment was not processed.  "
					+"The problem has a unique ID with assigning authority root that has already been used to identify an object of type "
					+probOidExt.IDType.ToString()+".",EventLogEntryType.Information);
				return;
			}
			long diseaseNum=0;
			if(probOidExt!=null) {//exists in oidexternal table and is of type Problem, so IDInternal is a DiseaseNum
				diseaseNum=probOidExt.IDInternal;					
			}
			Disease probCur=new Disease();
			probCur.DiseaseNum=diseaseNum;//probNum could be 0 if new
			//The problem referenced by the external root and ID is already linked in the oidexternal table, get the problem to update
			//Also make sure the problem linked by oidexternal table is for the patient identified in the PID segment
			if(diseaseNum!=0) {
				probCur=Diseases.GetOne(diseaseNum);
				if(probCur==null || probCur.PatNum!=pat.PatNum) {//should never be null if in the oidexternal table
					EventLog.WriteEntry("OpenDentHL7","The PRB segment was not processed.  "
						+"The problem referenced and the patient in the PID segment do not match.",EventLogEntryType.Information);
					return;
				}
			}
			DateTime dateProbStart=DateTime.MinValue;
			if(probStartDateOrder>-1) {
				dateProbStart=FieldParser.DateTimeParse(seg.GetFieldComponent(probStartDateOrder));
			}
			DateTime dateProbStop=DateTime.MinValue;
			if(probStopDateOrder>-1) {
				dateProbStop=FieldParser.DateTimeParse(seg.GetFieldComponent(probStopDateOrder));
			}
			//The patient may already have an active problem with this DiseaseDefNum, but it is not referenced by this problem GUID
			//Mark the existing problem inactive and add a new one with StartDate of today
			//Add an entry in the oidexternal table that will point the problem GUID to this new problem.
			List<Disease> listProbsForPat=Diseases.GetDiseasesForPatient(pat.PatNum,probDefNum,true);
			int markedInactiveCount=0;
			for(int p=0;p<listProbsForPat.Count;p++) {
				if(listProbsForPat[p].DiseaseNum==diseaseNum) {//probNum may be 0 if there was not an existing problem referenced by the GUID in the message
					continue;
				}
				listProbsForPat[p].ProbStatus=ProblemStatus.Inactive;
				Diseases.Update(listProbsForPat[p]);
				markedInactiveCount++;
			}
			if(_isVerboseLogging && markedInactiveCount>0) {
				EventLog.WriteEntry("OpenDentHL7","Updated "+markedInactiveCount.ToString()+" problems to a status of inactive due to an incoming PRB segment.",EventLogEntryType.Information);
			}
			Disease probOld=probCur.Copy();
			probCur.PatNum=pat.PatNum;
			probCur.DiseaseDefNum=probDefNum;
			probCur.ProbStatus=ProblemStatus.Active;
			probCur.DateStart=dateProbStart;//could be '0001-01-01' if not present or not the correct format, handled by FieldParser.DateTimeParse
			probCur.DateStop=dateProbStop;//could be '0001-01-01' if not present or not the correct format, handled by FieldParser.DateTimeParse
			if(probCur.DiseaseNum==0) {//new problem
				//insert new problem
				probCur.DiseaseNum=Diseases.Insert(probCur);
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Inserted a new problem for patient "+pat.GetNameFLnoPref()+" due to an incoming PRB segment.",EventLogEntryType.Information);
				}
				//using DiseaseNum from newly inserted problem, link to the external GUID and root in the oidexternals table
				probOidExt=new OIDExternal();
				probOidExt.IDType=IdentifierType.Problem;
				probOidExt.IDInternal=probCur.DiseaseNum;
				probOidExt.IDExternal=probIdExternal;
				probOidExt.rootExternal=probRootExternal;
				OIDExternals.Insert(probOidExt);
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Added an external problem ID to the oidexternals table due to an incoming PRB segment.\r\nDiseaesNum: "
						+probCur.DiseaseNum.ToString()+", External problem ID: "+probOidExt.IDExternal+", External root: "+probOidExt.rootExternal+".",EventLogEntryType.Information);
				}
			}
			else {//the segment is for an existing problem, update fields if necessary
				Diseases.Update(probCur,probOld);
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Updated an existing problem for patient "+pat.GetNameFLnoPref()+" due to an incoming PRB segment.",EventLogEntryType.Information);
				}
			}
			return;
		}
Exemple #15
0
		///<summary>Returns AptNum of the incoming appointment.  apt was found using the apt.AptNum field of the SCH segment, but can be null if it's a new appointment.  Used for eCW and other interfaces where OD is not the filler application.  When OD is not the filler application, we allow appointments to be created by the interfaced software and communicated to OD with an SIU message.</summary>
		public static long ProcessSCH(Patient pat,Appointment apt,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			if(pat.FName=="" || pat.LName=="") {
				throw new Exception("Appointment not processed due to missing patient first or last name. PatNum:"+pat.PatNum.ToString());
			}
			char escapeChar='\\';
			if(msg.Delimiters.Length>2) {//it is possible they did not send all 4 of the delimiter chars, in which case we will use the default \
				escapeChar=msg.Delimiters[2];
			}
			string strAptNote="";
			double aptLength=0;
			long aptNum=0;
			DateTime aptStart=DateTime.MinValue;
			DateTime aptStop=DateTime.MinValue;
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "apt.AptNum":
						try {
							aptNum=PIn.Long(seg.GetFieldComponent(itemOrder));
						}
						catch(Exception ex) {
							//do nothing, aptNum will remain 0
						}
						if(apt!=null && apt.AptNum!=aptNum) {
							//an appointment was located from the inbound message, but the AptNum on the appointment is not the same as the AptNum in this SCH segment (should never happen)
							throw new Exception("Invalid appointment number.");
						}
						continue;
					case "apt.lengthStartEnd":
						aptLength=FieldParser.SecondsToMinutes(seg.GetFieldComponent(itemOrder,2));
						aptStart=FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder,3));
						aptStop=FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder,4));
						continue;
					case "apt.Note":
						strAptNote=FieldParser.StringNewLineParse(seg.GetFieldComponent(itemOrder),escapeChar);
						continue;
					default:
						continue;
				}
			}
			Appointment aptOld=null;
			bool isNewApt=(apt==null);
			if(isNewApt) {
				apt=new Appointment();
				apt.AptNum=aptNum;
				apt.PatNum=pat.PatNum;
				apt.AptStatus=ApptStatus.Scheduled;
				apt.Note="";
			}
			else {
				aptOld=apt.Clone();
			}
			if(apt.PatNum!=pat.PatNum) {//we can't process this message because wrong patnum.
				throw new Exception("Appointment does not match patient "+pat.GetNameFLnoPref()+", apt.PatNum: "+apt.PatNum.ToString()+", pat.PatNum: "+pat.PatNum.ToString());
			}
			//if the existing note contains the exact text of the note in the SCH segment, don't append it again
			//replace the \r's and then \n's with a blank string before comparing to eliminate inconsistencies in new line characters
			if(!apt.Note.Replace("\r","").Replace("\n","").Contains(strAptNote.Replace("\r","").Replace("\n",""))) {
				if(apt.Note.Length>0) {//if the existing note already contains some text, add a new line before appending the note from the SCH segment
					apt.Note+="\r\n";
				}
				apt.Note+=strAptNote;
			}
			string pattern;
			//If aptStop is MinValue we know that stop time was not sent or was not in the correct format so try to use the duration field.
			if(aptStop==DateTime.MinValue && aptLength!=0) {//Stop time is optional.  If not included we will use the duration field to calculate pattern.
				pattern=FieldParser.ProcessPattern(aptStart,aptStart.AddMinutes(aptLength));
			}
			else {//We received a good stop time or stop time is MinValue but we don't have a good aptLength so ProcessPattern will return the apt length or the default 5 minutes
				pattern=FieldParser.ProcessPattern(aptStart,aptStop);
			}
			apt.AptDateTime=aptStart;
			apt.Pattern=pattern;
			apt.ProvNum=pat.PriProv;//Set apt.ProvNum to the patient's primary provider.  This may change after processing the AIG or PV1 segments, but set here in case those segs are missing.
			if(isNewApt) {
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Inserted appointment for "+pat.GetNameFLnoPref()+" due to an incoming SCH segment.",EventLogEntryType.Information);
				}
				Appointments.InsertIncludeAptNum(apt,true);
			}
			else {
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Updated appointment for "+pat.GetNameFLnoPref()+" due to an incoming SCH segment.",EventLogEntryType.Information);
				}
				Appointments.Update(apt,aptOld);
			}
			_hl7MsgCur.AptNum=apt.AptNum;
			HL7Msgs.Update(_hl7MsgCur);
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated hl7msg to include AptNum for "+pat.GetNameFLnoPref()+" due to an incoming SCH segment.",EventLogEntryType.Information);
			}
			_aptProcessed=apt;
			return aptNum;
		}
Exemple #16
0
		///<summary></summary>
		public static void ProcessORC(HL7DefSegment segDef,SegmentHL7 orcSeg) {
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				HL7DefField fieldDefCur=segDef.hl7DefFields[i];
				switch(fieldDefCur.FieldName) {
					case "orderingProv":
						FieldHL7 fieldCur=orcSeg.GetField(fieldDefCur.OrdinalPos);//fieldCur can be null
						if(fieldCur==null) {
							continue;
						}
						_medLabCur.OrderingProvNPI=FieldParserMedLab.OrderingProvIDParse(fieldCur,"N");
						_medLabCur.OrderingProvLocalID=FieldParserMedLab.OrderingProvIDParse(fieldCur,"L");
						_medLabCur.OrderingProvLName=fieldCur.GetComponentVal(1).Trim();
						_medLabCur.OrderingProvFName=fieldCur.GetComponentVal(2).Trim();
						int j=0;
						while(_medLabCur.OrderingProvLName=="" && j<fieldCur.ListRepeatFields.Count) {//if LName is not present in first repetition, check others
							_medLabCur.OrderingProvLName=fieldCur.ListRepeatFields[j].GetComponentVal(1).Trim();
							j++;
						}
						j=0;
						while(_medLabCur.OrderingProvFName=="" && j<fieldCur.ListRepeatFields.Count) {//if FName is not present in first repetition, check others
							_medLabCur.OrderingProvLName=fieldCur.ListRepeatFields[j].GetComponentVal(2).Trim();
							j++;
						}
						#region Locate Provider
						_medicaidIdCur=FieldParserMedLab.OrderingProvIDParse(fieldCur,"P");
						List<Provider> listProvs=Providers.GetProvsByNpiOrMedicaidId(_medLabCur.OrderingProvNPI,_medicaidIdCur);
						listProvs.Sort(SortByNpiMedicaidIdMatch);
						if(listProvs.Count>0) {//if a provider with either a matching NPI or Medicaid ID is found, use the first matching prov
							_medLabCur.ProvNum=listProvs[0].ProvNum;
							continue;
						}
						//no provider match based on NPI or MedicaidID
						listProvs=Providers.GetProvsByFLName(_medLabCur.OrderingProvLName,_medLabCur.OrderingProvFName);//must have both LName and FName
						if(listProvs.Count>0) {//use the first provider found with matching LName and FName
							_medLabCur.ProvNum=listProvs[0].ProvNum;
						}
						#endregion Locate Provider
						continue;
					case "specimenID":
						if(_medLabCur.SpecimenID!=null && _medLabCur.SpecimenID!="") {//could be filled in by value in OBR
							continue;
						}
						_medLabCur.SpecimenID=orcSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "specimenIDFiller":
						if(_medLabCur.SpecimenIDFiller!=null && _medLabCur.SpecimenIDFiller!="") {//could be filled in by value in OBR
							continue;
						}
						_medLabCur.SpecimenIDFiller=orcSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					default:
						continue;
				}
			}
			return;
		}
Exemple #17
0
		//public static void ProcessPD1() {
		//	return;
		//}

		public static void ProcessPID(Patient pat,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			Patient patOld=pat.Copy();
			char escapeChar='\\';
			if(msg.Delimiters.Length>2) {//it is possible they did not send all 4 of the delimiter chars, in which case we will use the default \
				escapeChar=msg.Delimiters[2];
			}
			char subcompChar='&';
			if(msg.Delimiters.Length>3) {//it is possible they did not send all 4 of the delimiter chars, in which case we will use the default &
				subcompChar=msg.Delimiters[3];
			}
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "pat.addressCityStateZip":
						pat.Address=seg.GetFieldComponent(itemOrder,0);
						pat.Address2=seg.GetFieldComponent(itemOrder,1);
						pat.City=seg.GetFieldComponent(itemOrder,2);
						pat.State=seg.GetFieldComponent(itemOrder,3);
						pat.Zip=seg.GetFieldComponent(itemOrder,4);
						string strAddrNote=FieldParser.StringNewLineParse(seg.GetFieldComponent(itemOrder,19),escapeChar);
						if(strAddrNote!="") {
							pat.AddrNote=strAddrNote;
						}						
						continue;
					case "pat.birthdateTime":
						pat.Birthdate=FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.ChartNumber":
						pat.ChartNumber=seg.GetFieldComponent(itemOrder);
						continue;
					case "pat.FeeSched":
						if(Programs.IsEnabled(ProgramName.eClinicalWorks) && ProgramProperties.GetPropVal(ProgramName.eClinicalWorks,"FeeSchedulesSetManually")=="1") {
							//if using eCW and FeeSchedulesSetManually
							continue;//do not process fee sched field, manually set by user
						}
						else {
							pat.FeeSched=FieldParser.FeeScheduleParse(seg.GetFieldComponent(itemOrder));
						}
						continue;
					case "pat.Gender":
						pat.Gender=FieldParser.GenderParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.HmPhone":
						if(seg.GetFieldComponent(itemOrder,2)=="" && seg.GetField(itemOrder).ListRepeatFields.Count==0) {//must be eCW, process the old way
							//either no component 2 or left blank, and there are no repetitions, process the old way
							//the first repetition is considered the primary number, but if the primary number is not sent then it will be blank followed by the list of other numbers
							pat.HmPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
						}
						else {
							//XTN data type, repeatable.
							//Component 2 values: PH-Phone, FX-Fax, MD-Modem, CP-Cell Phone, Internet-Internet Address, X.400-X.400 email address, TDD-Tel Device for the Deaf, TTY-Teletypewriter.
							//We will support PH for pat.HmPhone, CP for pat.WirelessPhone, and Internet for pat.Email
							//Component 5 is area code, 6 is number
							//Component 3 will be Email if the type is Internet
							//Example: ^PRN^PH^^^503^3635432~^PRN^Internet^[email protected]
							FieldHL7 phField=seg.GetField(itemOrder);
							if(phField==null) {
								continue;
							}
							string strPhType=seg.GetFieldComponent(itemOrder,2);
							string strPh=seg.GetFieldComponent(itemOrder,5)+seg.GetFieldComponent(itemOrder,6);
							string strEmail=seg.GetFieldComponent(itemOrder,3);
							for(int p=-1;p<phField.ListRepeatFields.Count;p++) {
								if(p>=0) {
									strPhType=phField.ListRepeatFields[p].GetComponentVal(2);
									strPh=phField.ListRepeatFields[p].GetComponentVal(5)+phField.ListRepeatFields[p].GetComponentVal(6);
									strEmail=phField.ListRepeatFields[p].GetComponentVal(3);
								}
								switch(strPhType) {
									case "PH":
										pat.HmPhone=FieldParser.PhoneParse(strPh);
										continue;
									case "CP":
										pat.WirelessPhone=FieldParser.PhoneParse(strPh);
										continue;
									case "Internet":
										pat.Email=strEmail;
										continue;
									default:
										continue;
								}
							}
						}
						continue;
					case "pat.nameLFM":
						pat.LName=seg.GetFieldComponent(itemOrder,0);
						pat.FName=seg.GetFieldComponent(itemOrder,1);
						pat.MiddleI=seg.GetFieldComponent(itemOrder,2);
						pat.Title=seg.GetFieldComponent(itemOrder,4);
						continue;
					case "pat.PatNum":
						//pat.PatNum guaranteed to not be 0, a new patient will be inserted if the field component for PatNum is not an int, is 0, or is blank
						//if(pat.PatNum!=0 && pat.PatNum!=PIn.Long(seg.GetFieldComponent(intItemOrder))) {
						//if field component is a valid number and the patient located is not the same as the patient with the PatNum in the segment, then throw the exception, message will fail.
						long patNumFromPid=0;
						try {
							patNumFromPid=PIn.Long(seg.GetFieldComponent(itemOrder));
						}
						catch(Exception ex) {
							//do nothing, patNumFromPID will remain 0
						}
						if(patNumFromPid!=0 && pat.PatNum!=patNumFromPid) {
							throw new Exception("Invalid PatNum");
						}
						continue;
					case "pat.Position":
						pat.Position=FieldParser.MaritalStatusParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.Race":
						//PID.10 is a CWE data type, with 9 defined components.  The first three are CodeValue^CodeDescription^CodeSystem
						//This field can repeat, so we will need to add an entry in the patientrace table for each repetition
						//The race code system is going to be CDCREC and the values match our enum.
						//The code description is not saved, we only require CodeValue and CodeSystem=CDCREC.  Descriptions come from the CDCREC table for display in OD.
						//Example race component: 
						string strRaceCode=seg.GetFieldComponent(itemOrder,0);
						string strRaceCodeSystem=seg.GetFieldComponent(itemOrder,2);
						//if there aren't 3 components to the race field or if the code system is not CDCREC, then parse the old way by matching to string name, i.e. white=PatientRaceOld.White
						if(strRaceCodeSystem!="CDCREC") {//must be eCW, process the old way
							PatientRaceOld patientRaceOld=FieldParser.RaceParseOld(strRaceCode);
							//Converts deprecated PatientRaceOld enum to list of PatRaces, and adds them to the PatientRaces table for the patient.
							PatientRaces.Reconcile(pat.PatNum,PatientRaces.GetPatRacesFromPatientRaceOld(patientRaceOld));
						}
						else {
							FieldHL7 fieldRace=seg.GetField(itemOrder);
							if(fieldRace==null) {
								continue;
							}
							List<PatRace> listPatRaces=new List<PatRace>();
							listPatRaces.Add(FieldParser.RaceParse(strRaceCode));
							for(int r=0;r<fieldRace.ListRepeatFields.Count;r++) {
								strRaceCode=fieldRace.ListRepeatFields[r].GetComponentVal(0);
								strRaceCodeSystem=fieldRace.ListRepeatFields[r].GetComponentVal(2);
								if(strRaceCodeSystem=="CDCREC") {
									listPatRaces.Add(FieldParser.RaceParse(strRaceCode));
								}
							}
							PatientRaces.Reconcile(pat.PatNum,listPatRaces);
						}
						continue;
					case "pat.SSN":
						pat.SSN=seg.GetFieldComponent(itemOrder);
						continue;
					case "pat.WkPhone":
						if(seg.GetFieldComponent(itemOrder,2)=="PH") {
							//Component 2 value: PH-Phone
							//Component 5 is area code, 6 is number
							//Example: ^WPN^PH^^^503^3635432
							pat.WkPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder,5)+seg.GetFieldComponent(itemOrder,6));
							continue;
						}
						//either no component 2 or left blank, process the old way
						pat.WkPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));//must be eCW
						continue;
					case "patientIds"://Not used by eCW
						//We will store the ID's from other software in the oidexternal table.  These ID's will be sent in outbound msgs and used to locate a patient for subsequent inbound msgs.
						//Example: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.2&HL7^PI~7684^8^M11^&Other.Software.OID&OIDType^PI|
						//field component values will be the first repetition, repeats will be in field.ListRepeatFields
						//1234=PatNum, 3=check digit, M11=using check digit scheme, the assigning authority universal ID is the offices oidinternal.IDRoot for IDType Patient,
						//HL7=ID type, PI=identifier type code for: Patient internal identifier (a number that is unique to a patient within an assigning authority).
						FieldHL7 fieldCur=seg.GetField(itemOrder);
						//get the id with the assigning authority equal to the internal OID root stored in their database for a patient object
						string strPatOIDRoot=OIDInternals.GetForType(IdentifierType.Patient).IDRoot;
						if(strPatOIDRoot=="") {
							//if they have not set their internal OID root, we cannot identify which repetition in this field contains the OD PatNum
							EventLog.WriteEntry("OpenDentHL7","Could not process the patientIdList field due to the internal OID for the patient object missing.",EventLogEntryType.Information);
							continue;
						}
						string strPatIdCur="";
						string strPatIdRootCur="";
						string[] arrayPatIdSubComps=fieldCur.GetComponentVal(3).Split(new char[] { subcompChar },StringSplitOptions.None);
						if(arrayPatIdSubComps.Length>1 //so the next line doesn't throw an exception
							&& arrayPatIdSubComps[1].ToLower()!=strPatOIDRoot.ToLower()//not our PatNum
							&& fieldCur.GetComponentVal(4).ToLower()=="pi")//PI=patient internal identifier; a number that is unique to a patient within an assigning authority
						{
							int intCheckDigit=-1;
							try {
								intCheckDigit=PIn.Int(fieldCur.GetComponentVal(1));
							}
							catch(Exception ex) {
								//checkDigit will remain -1
							}
							//if using the M10 or M11 check digit algorithm and it passes the respective test, or not using either algorithm, then use the ID
							if((fieldCur.GetComponentVal(2).ToLower()=="m10"
									&& intCheckDigit!=-1
									&& M10CheckDigit(fieldCur.GetComponentVal(0))==intCheckDigit)//using M10 scheme and the check digit is valid and matches calc
								|| (fieldCur.GetComponentVal(2).ToLower()=="m11"
									&& intCheckDigit!=-1
									&& M11CheckDigit(fieldCur.GetComponentVal(0))==intCheckDigit)//using M11 scheme and the check digit is valid and matches calc
								|| (fieldCur.GetComponentVal(2).ToLower()!="m10"
									&& fieldCur.GetComponentVal(2).ToLower()!="m11"))//not using either check digit scheme
							{
								//Either passed the check digit test or not using the M10 or M11 check digit scheme, so trust the ID to be valid
								strPatIdCur=fieldCur.GetComponentVal(0);
								strPatIdRootCur=arrayPatIdSubComps[1];
							}
						}
						OIDExternal oidExtCur=new OIDExternal();
						string verboseMsg="";
						if(strPatIdCur!="" && strPatIdRootCur!="" && OIDExternals.GetByRootAndExtension(strPatIdRootCur,strPatIdCur)==null) {
							oidExtCur.IDType=IdentifierType.Patient;
							oidExtCur.IDInternal=pat.PatNum;
							oidExtCur.IDExternal=strPatIdCur;
							oidExtCur.rootExternal=strPatIdRootCur;
							OIDExternals.Insert(oidExtCur);
							verboseMsg+="\r\nExternal patient ID: "+oidExtCur.IDExternal+", External root: "+oidExtCur.rootExternal;
						}
						for(int r=0;r<fieldCur.ListRepeatFields.Count;r++) {
							arrayPatIdSubComps=fieldCur.ListRepeatFields[r].GetComponentVal(3).Split(new char[] { subcompChar },StringSplitOptions.None);
							if(arrayPatIdSubComps.Length<2) {//there must be at least 2 sub-components in the assigning authority component so we can identify whose ID this is
								continue;
							}
							if(arrayPatIdSubComps[1].ToLower()==strPatOIDRoot.ToLower() //if this is the OD patient OID root
								|| fieldCur.ListRepeatFields[r].GetComponentVal(4).ToLower()!="pi")//or not a patient identifier, then skip this repetition
							{
								continue;
							}
							int intCheckDigit=-1;
							try {
								intCheckDigit=PIn.Int(fieldCur.ListRepeatFields[r].GetComponentVal(1));
							}
							catch(Exception ex) {
								//checkDigit will remain -1
							}
							if(fieldCur.ListRepeatFields[r].GetComponentVal(2).ToLower()=="m10"
								&& (intCheckDigit==-1 || M10CheckDigit(fieldCur.ListRepeatFields[r].GetComponentVal(0))!=intCheckDigit))//using M11 scheme and either an invalid check digit was received or it doesn't match our calc
							{
								continue;
							}
							if(fieldCur.ListRepeatFields[r].GetComponentVal(2).ToLower()=="m11"
								&& (intCheckDigit==-1 || M11CheckDigit(fieldCur.ListRepeatFields[r].GetComponentVal(0))!=intCheckDigit))//using M11 scheme and either an invalid check digit was received or it doesn't match our calc
							{
								continue;
							}
							//if not using the M10 or M11 check digit scheme or if the check digit is good, trust the ID in component 0 to be valid and store as IDExternal
							strPatIdCur=fieldCur.ListRepeatFields[r].GetComponentVal(0);
							strPatIdRootCur=arrayPatIdSubComps[1];
							if(strPatIdCur!="" && strPatIdRootCur!="" && OIDExternals.GetByRootAndExtension(strPatIdRootCur,strPatIdCur)==null) {
								oidExtCur=new OIDExternal();
								oidExtCur.IDType=IdentifierType.Patient;
								oidExtCur.IDInternal=pat.PatNum;
								oidExtCur.IDExternal=strPatIdCur;
								oidExtCur.rootExternal=strPatIdRootCur;
								OIDExternals.Insert(oidExtCur);
								verboseMsg+="\r\nExternal patient ID: "+oidExtCur.IDExternal+", External root: "+oidExtCur.rootExternal;
							}
						}
						if(_isVerboseLogging && verboseMsg.Length>0) {
							EventLog.WriteEntry("OpenDentHL7","Added the following external patient ID(s) to the oidexternals table due to an incoming PID segment for PatNum: "
								+pat.PatNum+"."+verboseMsg+".",EventLogEntryType.Information);
						}
						continue;
					default:
						continue;
				}
			}
			Patients.Update(pat,patOld);
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated patient "+pat.GetNameFLnoPref()+" due to an incoming PID segment.",EventLogEntryType.Information);
			}
			return;
		}
Exemple #18
0
        //public static void ProcessPD1() {
        //	return;
        //}

        public static void ProcessPID(Patient pat, HL7DefSegment segDef, SegmentHL7 seg)
        {
            for (int i = 0; i < segDef.hl7DefFields.Count; i++)
            {
                int itemOrder = segDef.hl7DefFields[i].OrdinalPos;
                switch (segDef.hl7DefFields[i].FieldName)
                {
                case "pat.addressCityStateZip":
                    pat.Address  = seg.GetFieldComponent(itemOrder, 0);
                    pat.Address2 = seg.GetFieldComponent(itemOrder, 1);
                    pat.City     = seg.GetFieldComponent(itemOrder, 2);
                    pat.State    = seg.GetFieldComponent(itemOrder, 3);
                    pat.Zip      = seg.GetFieldComponent(itemOrder, 4);
                    continue;

                case "pat.birthdateTime":
                    pat.Birthdate = FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder));
                    continue;

                case "pat.ChartNumber":
                    pat.ChartNumber = seg.GetFieldComponent(itemOrder);
                    continue;

                case "pat.Gender":
                    pat.Gender = FieldParser.GenderParse(seg.GetFieldComponent(itemOrder));
                    continue;

                case "pat.HmPhone":
                    pat.HmPhone = FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
                    continue;

                case "pat.nameLFM":
                    pat.LName   = seg.GetFieldComponent(itemOrder, 0);
                    pat.FName   = seg.GetFieldComponent(itemOrder, 1);
                    pat.MiddleI = seg.GetFieldComponent(itemOrder, 2);
                    continue;

                case "pat.PatNum":
                    if (pat.PatNum != 0 && pat.PatNum != PIn.Long(seg.GetFieldComponent(itemOrder)))
                    {
                        throw new Exception("Invalid PatNum");
                    }
                    continue;

                case "pat.Position":
                    pat.Position = FieldParser.MaritalStatusParse(seg.GetFieldComponent(itemOrder));
                    continue;

                case "pat.Race":
                    PatientRaceOld patientRaceOld = FieldParser.RaceParse(seg.GetFieldComponent(itemOrder));
                    //Converts deprecated PatientRaceOld enum to list of PatRaces, and adds them to the PatientRaces table for the patient.
                    PatientRaces.Reconcile(pat.PatNum, PatientRaces.GetPatRacesFromPatientRaceOld(patientRaceOld));
                    continue;

                case "pat.SSN":
                    pat.SSN = seg.GetFieldComponent(itemOrder);
                    continue;

                case "pat.WkPhone":
                    pat.WkPhone = FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
                    continue;

                case "pat.FeeSched":
                    if (Programs.IsEnabled(ProgramName.eClinicalWorks) && ProgramProperties.GetPropVal(ProgramName.eClinicalWorks, "FeeSchedulesSetManually") == "1")
                    {
                        //if using eCW and FeeSchedulesSetManually
                        continue;                                //do not process fee sched field, manually set by user
                    }
                    else
                    {
                        pat.FeeSched = FieldParser.FeeScheduleParse(seg.GetFieldComponent(itemOrder));
                    }
                    continue;

                default:
                    continue;
                }
            }
            return;
        }
Exemple #19
0
        ///<summary>Returns AptNum of the incoming appointment.</summary>
        public static long ProcessSCH(Patient pat, HL7DefSegment segDef, SegmentHL7 seg)
        {
            string   aptNote   = "";
            double   aptLength = 0;
            long     aptNum    = 0;
            DateTime aptStart  = DateTime.MinValue;
            DateTime aptStop   = DateTime.MinValue;

            for (int i = 0; i < segDef.hl7DefFields.Count; i++)
            {
                int ordinalPos = segDef.hl7DefFields[i].OrdinalPos;
                switch (segDef.hl7DefFields[i].FieldName)
                {
                case "apt.AptNum":
                    aptNum = PIn.Long(seg.GetFieldComponent(ordinalPos));
                    continue;

                case "apt.lengthStartEnd":
                    aptLength = FieldParser.SecondsToMinutes(seg.GetFieldComponent(ordinalPos, 2));
                    aptStart  = FieldParser.DateTimeParse(seg.GetFieldComponent(ordinalPos, 3));
                    aptStop   = FieldParser.DateTimeParse(seg.GetFieldComponent(ordinalPos, 4));
                    continue;

                case "apt.Note":
                    aptNote = seg.GetFieldComponent(ordinalPos);
                    continue;

                default:
                    continue;
                }
            }
            Appointment apt      = Appointments.GetOneApt(aptNum);
            Appointment aptOld   = null;
            bool        isNewApt = apt == null;

            if (isNewApt)
            {
                apt           = new Appointment();
                apt.AptNum    = aptNum;
                apt.PatNum    = pat.PatNum;
                apt.AptStatus = ApptStatus.Scheduled;
            }
            else
            {
                aptOld = apt.Clone();
            }
            if (apt.PatNum != pat.PatNum)           //we can't process this message because wrong patnum.
            {
                throw new Exception("Appointment does not match patient: " + pat.FName + " " + pat.LName + ", apt.PatNum: " + apt.PatNum.ToString() + ", pat.PatNum: " + pat.PatNum.ToString());
            }
            apt.Note = aptNote;
            string pattern;

            //If aptStop is MinValue we know that stop time was not sent or was not in the correct format so try to use the duration field.
            if (aptStop == DateTime.MinValue && aptLength != 0)         //Stop time is optional.  If not included we will use the duration field to calculate pattern.
            {
                pattern = FieldParser.ProcessPattern(aptStart, aptStart.AddMinutes(aptLength));
            }
            else              //We received a good stop time or stop time is MinValue but we don't have a good aptLength so ProcessPattern will return the apt length or the default 5 minutes
            {
                pattern = FieldParser.ProcessPattern(aptStart, aptStop);
            }
            apt.AptDateTime = aptStart;
            apt.Pattern     = pattern;
            apt.ProvNum     = pat.PriProv;      //Set apt.ProvNum to the patient's primary provider.  This may change after processing the AIG or PV1 segments, but set here in case those segs are missing.
            if (pat.FName == "" || pat.LName == "")
            {
                throw new Exception("Appointment not processed due to missing patient first or last name. PatNum:" + pat.PatNum.ToString());
            }
            if (isNewApt)
            {
                if (IsVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Inserted appointment for: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Appointments.InsertIncludeAptNum(apt, true);
            }
            else
            {
                if (IsVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Updated appointment for: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Appointments.Update(apt, aptOld);
            }
            HL7MsgCur.AptNum = apt.AptNum;
            HL7Msgs.Update(HL7MsgCur);
            return(aptNum);
        }
Exemple #20
0
        ///<summary>If relationship is self, this method does nothing.  A new pat will later change guarantor to be same as patnum. </summary>
        public static void ProcessGT1(Patient pat, HL7DefSegment segDef, SegmentHL7 seg)
        {
            //Find the position of the guarNum, guarChartNum, guarName, and guarBirthdate in this HL7 segment based on the definition of a GT1
            int guarPatNumOrdinal    = -1;
            int guarChartNumOrdinal  = -1;
            int guarNameOrdinal      = -1;
            int guarBirthdateOrdinal = -1;

            for (int i = 0; i < segDef.hl7DefFields.Count; i++)
            {
                if (segDef.hl7DefFields[i].FieldName == "guar.PatNum")
                {
                    guarPatNumOrdinal = segDef.hl7DefFields[i].OrdinalPos;
                }
                if (segDef.hl7DefFields[i].FieldName == "guar.ChartNumber")
                {
                    guarChartNumOrdinal = segDef.hl7DefFields[i].OrdinalPos;
                }
                if (segDef.hl7DefFields[i].FieldName == "guar.nameLFM")
                {
                    guarNameOrdinal = segDef.hl7DefFields[i].OrdinalPos;
                }
                if (segDef.hl7DefFields[i].FieldName == "guar.birthdateTime")
                {
                    guarBirthdateOrdinal = segDef.hl7DefFields[i].OrdinalPos;
                }
            }
            //If neither guar.PatNum nor guar.ChartNumber are included in this GT1 definition log a message in the event log and return
            if (guarPatNumOrdinal == -1 && guarChartNumOrdinal == -1)
            {
                HL7MsgCur.Note = "Guarantor not processed.  guar.PatNum or guar.ChartNumber must be included in the GT1 definition.  PatNum of patient:" + pat.PatNum.ToString();
                HL7Msgs.Update(HL7MsgCur);
                EventLog.WriteEntry("OpenDentHL7", "Guarantor not processed.  guar.PatNum or guar.ChartNumber must be included in the GT1 definition.  PatNum of patient:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                return;
            }
            //If guar.nameLFM is not included in this GT1 definition log a message in the event log and return
            if (guarNameOrdinal == -1)
            {
                HL7MsgCur.Note = "Guarantor not processed due to guar.nameLFM not included in the GT1 definition.  Patnum of patient:" + pat.PatNum.ToString();
                HL7Msgs.Update(HL7MsgCur);
                EventLog.WriteEntry("OpenDentHL7", "Guarantor not processed due to guar.nameLFM not included in the GT1 definition.  Patnum of patient:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                return;
            }
            //If the first or last name are not included in this GT1 segment, log a message in the event log and return
            if (seg.GetFieldComponent(guarNameOrdinal, 0) == "" || seg.GetFieldComponent(guarNameOrdinal, 1) == "")
            {
                HL7MsgCur.Note = "Guarantor not processed due to missing first or last name.  PatNum of patient:" + pat.PatNum.ToString();
                HL7Msgs.Update(HL7MsgCur);
                EventLog.WriteEntry("OpenDentHL7", "Guarantor not processed due to missing first or last name.  PatNum of patient:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                return;
            }
            //Only process GT1 if either guar.PatNum or guar.ChartNumber is included and both guar.LName and guar.FName are included
            long   guarPatNum   = 0;
            string guarChartNum = "";

            if (guarPatNumOrdinal != -1)
            {
                guarPatNum = PIn.Long(seg.GetFieldFullText(guarPatNumOrdinal));
            }
            if (guarChartNumOrdinal != -1)
            {
                guarChartNum = seg.GetFieldComponent(guarChartNumOrdinal);
            }
            if (guarPatNum == 0 && guarChartNum == "")         //because we have an example where they sent us this (position 2 (guarPatNumOrder or guarChartNumOrder for eCW) is empty): GT1|1||^^||^^^^||||||||
            {
                HL7MsgCur.Note = "Guarantor not processed due to missing both guar.PatNum and guar.ChartNumber.  One of those numbers must be included.  PatNum of patient:" + pat.PatNum.ToString();
                HL7Msgs.Update(HL7MsgCur);
                EventLog.WriteEntry("OpenDentHL7", "Guarantor not processed due to missing both guar.PatNum and guar.ChartNumber.  One of those numbers must be included.  PatNum of patient:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                return;
            }
            if (guarPatNum == pat.PatNum || guarChartNum == pat.ChartNumber)         //if relationship is self
            {
                return;
            }
            //Guar must be someone else
            Patient guar    = null;
            Patient guarOld = null;

            //Find guarantor by guar.PatNum if defined and in this segment
            if (guarPatNum != 0)
            {
                guar = Patients.GetPat(guarPatNum);
            }
            else              //guarPatNum was 0 so try to get guar by guar.ChartNumber or name and birthdate
                              //try to find guarantor using chartNumber
            {
                guar = Patients.GetPatByChartNumber(guarChartNum);
                if (guar == null)
                {
                    //try to find the guarantor by using name and birthdate
                    string   guarLName     = seg.GetFieldComponent(guarNameOrdinal, 0);
                    string   guarFName     = seg.GetFieldComponent(guarNameOrdinal, 1);
                    DateTime guarBirthdate = FieldParser.DateTimeParse(seg.GetFieldFullText(guarBirthdateOrdinal));
                    long     guarNumByName = Patients.GetPatNumByNameAndBirthday(guarLName, guarFName, guarBirthdate);
                    if (guarNumByName == 0)                   //guarantor does not exist in OD
                    //so guar will still be null, triggering creation of new guarantor further down.
                    {
                    }
                    else
                    {
                        guar             = Patients.GetPat(guarNumByName);
                        guarOld          = guar.Copy();
                        guar.ChartNumber = guarChartNum;                      //from now on, we will be able to find guar by chartNumber
                        Patients.Update(guar, guarOld);
                    }
                }
            }
            //At this point we have a guarantor located in OD or guar=null so guar is new patient
            bool isNewGuar = guar == null;

            if (isNewGuar)             //then we need to add guarantor to db
            {
                guar = new Patient();
                if (guarPatNum != 0)
                {
                    guar.PatNum = guarPatNum;
                }
                else
                {
                    guar.ChartNumber = guarChartNum;
                }
                guar.PriProv     = PrefC.GetLong(PrefName.PracticeDefaultProv);
                guar.BillingType = PrefC.GetLong(PrefName.PracticeDefaultBillType);
            }
            else
            {
                guarOld = guar.Copy();
            }
            //Now that we have our guarantor, process the GT1 segment
            for (int i = 0; i < segDef.hl7DefFields.Count; i++)
            {
                int itemOrder = segDef.hl7DefFields[i].OrdinalPos;
                switch (segDef.hl7DefFields[i].FieldName)
                {
                case "guar.addressCityStateZip":
                    guar.Address  = seg.GetFieldComponent(itemOrder, 0);
                    guar.Address2 = seg.GetFieldComponent(itemOrder, 1);
                    guar.City     = seg.GetFieldComponent(itemOrder, 2);
                    guar.State    = seg.GetFieldComponent(itemOrder, 3);
                    guar.Zip      = seg.GetFieldComponent(itemOrder, 4);
                    continue;

                case "guar.birthdateTime":
                    guar.Birthdate = FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder));
                    continue;

                case "guar.ChartNumber":
                    guar.ChartNumber = seg.GetFieldComponent(itemOrder);
                    continue;

                case "guar.Gender":
                    guar.Gender = FieldParser.GenderParse(seg.GetFieldComponent(itemOrder));
                    continue;

                case "guar.HmPhone":
                    guar.HmPhone = FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
                    continue;

                case "guar.nameLFM":
                    guar.LName   = seg.GetFieldComponent(itemOrder, 0);
                    guar.FName   = seg.GetFieldComponent(itemOrder, 1);
                    guar.MiddleI = seg.GetFieldComponent(itemOrder, 2);
                    continue;

                //case "guar.PatNum": Maybe do nothing??
                case "guar.SSN":
                    guar.SSN = seg.GetFieldComponent(itemOrder);
                    continue;

                case "guar.WkPhone":
                    guar.WkPhone = FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
                    continue;

                default:
                    continue;
                }
            }
            if (isNewGuar)
            {
                guarOld = guar.Copy();
                if (guar.PatNum == 0)
                {
                    guar.PatNum = Patients.Insert(guar, false);
                }
                else
                {
                    guar.PatNum = Patients.Insert(guar, true);
                }
                guar.Guarantor = guar.PatNum;
                Patients.Update(guar, guarOld);
            }
            else
            {
                Patients.Update(guar, guarOld);
            }
            pat.Guarantor = guar.PatNum;
            return;
        }
		///<summary>Returns AptNum of the incoming appointment.</summary>
		public static long ProcessSCH(Patient pat,HL7DefSegment segDef,SegmentHL7 seg) {
			string aptNote="";
			double aptLength=0;
			long aptNum=0;
			DateTime aptStart=DateTime.MinValue;
			DateTime aptStop=DateTime.MinValue;
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int ordinalPos=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "apt.AptNum":
						aptNum=PIn.Long(seg.GetFieldComponent(ordinalPos));
						continue;
					case "apt.lengthStartEnd":
						aptLength=FieldParser.SecondsToMinutes(seg.GetFieldComponent(ordinalPos,2));
						aptStart=FieldParser.DateTimeParse(seg.GetFieldComponent(ordinalPos,3));
						aptStop=FieldParser.DateTimeParse(seg.GetFieldComponent(ordinalPos,4));
						continue;
					case "apt.Note":
						aptNote=seg.GetFieldComponent(ordinalPos);
						continue;
					default:
						continue;
				}
			}
			Appointment apt=Appointments.GetOneApt(aptNum);
			Appointment aptOld=null;
			bool isNewApt=apt==null;
			if(isNewApt) {
				apt=new Appointment();
				apt.AptNum=aptNum;
				apt.PatNum=pat.PatNum;
				apt.AptStatus=ApptStatus.Scheduled;
			}
			else {
				aptOld=apt.Clone();
			}
			if(apt.PatNum!=pat.PatNum) {//we can't process this message because wrong patnum.
				throw new Exception("Appointment does not match patient: "+pat.FName+" "+pat.LName+", apt.PatNum: "+apt.PatNum.ToString()+", pat.PatNum: "+pat.PatNum.ToString());
			}
			apt.Note=aptNote;
			string pattern;
			//If aptStop is MinValue we know that stop time was not sent or was not in the correct format so try to use the duration field.
			if(aptStop==DateTime.MinValue && aptLength!=0) {//Stop time is optional.  If not included we will use the duration field to calculate pattern.
				pattern=FieldParser.ProcessPattern(aptStart,aptStart.AddMinutes(aptLength));
			}
			else {//We received a good stop time or stop time is MinValue but we don't have a good aptLength so ProcessPattern will return the apt length or the default 5 minutes
				pattern=FieldParser.ProcessPattern(aptStart,aptStop);
			}
			apt.AptDateTime=aptStart;
			apt.Pattern=pattern;
			apt.ProvNum=pat.PriProv;//Set apt.ProvNum to the patient's primary provider.  This may change after processing the AIG or PV1 segments, but set here in case those segs are missing.
			if(pat.FName=="" || pat.LName=="") {
				throw new Exception("Appointment not processed due to missing patient first or last name. PatNum:"+pat.PatNum.ToString());
			}
			if(isNewApt) {
				if(IsVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Inserted appointment for: "+pat.FName+" "+pat.LName,EventLogEntryType.Information);
				}
				Appointments.InsertIncludeAptNum(apt,true);
			}
			else {
				if(IsVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Updated appointment for: "+pat.FName+" "+pat.LName,EventLogEntryType.Information);
				}
				Appointments.Update(apt,aptOld);
			}
			HL7MsgCur.AptNum=apt.AptNum;
			HL7Msgs.Update(HL7MsgCur);
			return aptNum;
		}
		//public static void ProcessPD1() {
		//	return;
		//}

		public static void ProcessPID(Patient pat,HL7DefSegment segDef,SegmentHL7 seg) {
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "pat.addressCityStateZip":
						pat.Address=seg.GetFieldComponent(itemOrder,0);
						pat.Address2=seg.GetFieldComponent(itemOrder,1);
						pat.City=seg.GetFieldComponent(itemOrder,2);
						pat.State=seg.GetFieldComponent(itemOrder,3);
						pat.Zip=seg.GetFieldComponent(itemOrder,4);
						continue;
					case "pat.birthdateTime":
						pat.Birthdate=FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.ChartNumber":
						pat.ChartNumber=seg.GetFieldComponent(itemOrder);
						continue;
					case "pat.Gender":
						pat.Gender=FieldParser.GenderParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.HmPhone":
						pat.HmPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.nameLFM":
						pat.LName=seg.GetFieldComponent(itemOrder,0);
						pat.FName=seg.GetFieldComponent(itemOrder,1);
						pat.MiddleI=seg.GetFieldComponent(itemOrder,2);
						continue;
					case "pat.PatNum":
						if(pat.PatNum!=0 && pat.PatNum!=PIn.Long(seg.GetFieldComponent(itemOrder))) {
							throw new Exception("Invalid PatNum");
						}
						continue;
					case "pat.Position":
						pat.Position=FieldParser.MaritalStatusParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.Race":
						PatientRaceOld patientRaceOld=FieldParser.RaceParse(seg.GetFieldComponent(itemOrder));
						//Converts deprecated PatientRaceOld enum to list of PatRaces, and adds them to the PatientRaces table for the patient.
						PatientRaces.Reconcile(pat.PatNum,PatientRaces.GetPatRacesFromPatientRaceOld(patientRaceOld));
						continue;
					case "pat.SSN":
						pat.SSN=seg.GetFieldComponent(itemOrder);
						continue;
					case "pat.WkPhone":
						pat.WkPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.FeeSched":
						if(Programs.IsEnabled(ProgramName.eClinicalWorks) && ProgramProperties.GetPropVal(ProgramName.eClinicalWorks,"FeeSchedulesSetManually")=="1") {
							//if using eCW and FeeSchedulesSetManually
							continue;//do not process fee sched field, manually set by user
						}
						else {
							pat.FeeSched=FieldParser.FeeScheduleParse(seg.GetFieldComponent(itemOrder));
						}
						continue;
					default:
						continue;
				}
			}
			return;
		}
Exemple #23
0
 ///<summary>If relationship is self, this loop does nothing.  A new pat will later change guarantor to be same as patnum. </summary>
 public static void ProcessGT1(Patient pat,SegmentHL7 seg,bool useChartNumber)
 {
     long guarNum=PIn.Long(seg.GetFieldFullText(2));
     if(guarNum==0) {//because we have an example where they sent us this (position 2 is empty): GT1|1||^^||^^^^||||||||
         return;
     }
     if(seg.GetFieldFullText(11)=="1") {//if relationship is self (according to some of their documentation)
         return;
     }
     Patient guar=null;
     Patient guarOld=null;
     //So guarantor is someone else
     if(useChartNumber) {
         //try to find guarantor by using chartNumber
         guar=Patients.GetPatByChartNumber(guarNum.ToString());
         if(guar==null) {
             //try to find the guarantor by using name and birthdate
             string lName=seg.GetFieldComponent(3,0);
             string fName=seg.GetFieldComponent(3,1);
             DateTime birthdate=SegmentPID.DateParse(seg.GetFieldFullText(8));
             long guarNumByName=Patients.GetPatNumByNameAndBirthday(lName,fName,birthdate);
             if(guarNumByName==0) {//guarantor does not exist in OD
                 //so guar will still be null, triggering creation of new guarantor further down.
             }
             else {
                 guar=Patients.GetPat(guarNumByName);
                 guar.ChartNumber=guarNum.ToString();//from now on, we will be able to find guar by chartNumber
             }
         }
     }
     else {
         guar=Patients.GetPat(guarNum);
     }
     //we can't necessarily set pat.Guarantor yet, because in Standalone mode, we might not know it yet.
     bool isNewGuar= guar==null;
     if(isNewGuar) {//then we need to add guarantor to db
         guar=new Patient();
         if(useChartNumber) {
             guar.ChartNumber=guarNum.ToString();
         }
         else {
             guar.PatNum=guarNum;
         }
         guar.PriProv=PrefC.GetLong(PrefName.PracticeDefaultProv);
         guar.BillingType=PrefC.GetLong(PrefName.PracticeDefaultBillType);
     }
     else {
         guarOld=guar.Copy();
     }
     //guar.Guarantor=guarNum;
     guar.LName=seg.GetFieldComponent(3,0);
     guar.FName=seg.GetFieldComponent(3,1);
     guar.MiddleI=seg.GetFieldComponent(3,2);
     guar.Address=seg.GetFieldComponent(5,0);
     guar.Address2=seg.GetFieldComponent(5,1);
     guar.City=seg.GetFieldComponent(5,2);
     guar.State=seg.GetFieldComponent(5,3);
     guar.Zip=seg.GetFieldComponent(5,4);
     guar.HmPhone=PhoneParse(seg.GetFieldFullText(6));
     guar.WkPhone=PhoneParse(seg.GetFieldFullText(7));
     guar.Birthdate=DateParse(seg.GetFieldFullText(8));
     guar.Gender=GenderParse(seg.GetFieldFullText(9));
     //11. Guarantor relationship to patient.  We can't really do anything with this value
     guar.SSN=seg.GetFieldFullText(12);
     if(isNewGuar) {
         Patients.Insert(guar,true);
         guarOld=guar.Copy();
         guar.Guarantor=guar.PatNum;
         Patients.Update(guar,guarOld);
     }
     else {
         Patients.Update(guar,guarOld);
     }
     pat.Guarantor=guar.PatNum;
 }
Exemple #24
0
        public static void ProcessMessage(MessageHL7 message, bool isStandalone, bool isVerboseLogging)
        {
            /*string triggerevent=message.Segments[0].GetFieldComponent(8,1);
             * switch(triggerevent) {
             *      case "A01"://Admit/Visit Information
             *
             *              break;
             *      case "A04"://New Patient Information
             *              ProcessNewPatient(message);
             *              break;
             *      case "A08"://Update Patient Information
             *
             *              break;
             *      case "A28"://Add Patient Information
             *
             *              break;
             *      case "A31"://Update Patient Information
             *
             *              break;
             * }*/
            //MSH-Ignore
            //EVN-Ignore
            //PID-------------------------------------
            SegmentHL7 seg    = message.GetSegment(SegmentNameHL7.PID, true);
            long       patNum = PIn.Long(seg.GetFieldFullText(2));
            Patient    pat    = null;

            if (isStandalone)
            {
                pat = Patients.GetPatByChartNumber(patNum.ToString());
                if (pat == null)
                {
                    //try to find the patient in question by using name and birthdate
                    string   lName        = seg.GetFieldComponent(5, 0);
                    string   fName        = seg.GetFieldComponent(5, 1);
                    DateTime birthdate    = EcwSegmentPID.DateParse(seg.GetFieldFullText(7));
                    long     patNumByName = Patients.GetPatNumByNameAndBirthday(lName, fName, birthdate);
                    if (patNumByName == 0)                   //patient does not exist in OD
                    //so pat will still be null, triggering creation of new patient further down.
                    {
                    }
                    else
                    {
                        pat             = Patients.GetPat(patNumByName);
                        pat.ChartNumber = patNum.ToString();                      //from now on, we will be able to find pat by chartNumber
                    }
                }
            }
            else
            {
                pat = Patients.GetPat(patNum);
            }
            Patient patOld   = null;
            bool    isNewPat = pat == null;

            if (isNewPat)
            {
                pat = new Patient();
                if (isStandalone)
                {
                    pat.ChartNumber = patNum.ToString();
                    //this line does not work if isStandalone, so moved to end
                    //pat.Guarantor=patNum;
                }
                else
                {
                    pat.PatNum    = patNum;
                    pat.Guarantor = patNum;
                }
                pat.PriProv     = PrefC.GetLong(PrefName.PracticeDefaultProv);
                pat.BillingType = PrefC.GetLong(PrefName.PracticeDefaultBillType);
            }
            else
            {
                patOld = pat.Copy();
            }
            EcwSegmentPID.ProcessPID(pat, seg, isStandalone);
            //PV1-patient visit---------------------------
            //seg=message.GetSegment(SegmentName.PV1,false);
            //if(seg!=null) {//this seg is optional
            //	SegmentPID.ProcessPV1(pat,seg);
            //}
            //PD1-additional patient demographics------------
            //seg=message.GetSegment(SegmentName.PD1,false);
            //if(seg!=null) {//this seg is optional
            //	ProcessPD1(pat,seg);
            //}
            //GT1-Guarantor-------------------------------------
            seg = message.GetSegment(SegmentNameHL7.GT1, true);
            EcwSegmentPID.ProcessGT1(pat, seg, isStandalone);
            //IN1-Insurance-------------------------------------
            //List<SegmentHL7> segments=message.GetSegments(SegmentName.IN1);
            //for(int i=0;i<segments.Count;i++) {
            //	ProcessIN1(pat,seg);
            //}
            if (pat.FName == "" || pat.LName == "")
            {
                EventLog.WriteEntry("OpenDentHL7", "Patient demographics not processed due to missing first or last name. PatNum:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                return;
            }
            if (isNewPat)
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Inserted patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Patients.Insert(pat, true);
                if (pat.Guarantor == 0)
                {
                    patOld        = pat.Copy();
                    pat.Guarantor = pat.PatNum;
                    Patients.Update(pat, patOld);
                }
            }
            else
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Updated patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Patients.Update(pat, patOld);
            }
        }
		///<summary>If relationship is self, this method does nothing.  A new pat will later change guarantor to be same as patnum. </summary>
		public static void ProcessGT1(Patient pat,HL7DefSegment segDef,SegmentHL7 seg) {
			//Find the position of the guarNum, guarChartNum, guarName, and guarBirthdate in this HL7 segment based on the definition of a GT1
			int guarPatNumOrdinal=-1;
			int guarChartNumOrdinal=-1;
			int guarNameOrdinal=-1;
			int guarBirthdateOrdinal=-1;
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				if(segDef.hl7DefFields[i].FieldName=="guar.PatNum") {
					guarPatNumOrdinal=segDef.hl7DefFields[i].OrdinalPos;
				}
				if(segDef.hl7DefFields[i].FieldName=="guar.ChartNumber") {
					guarChartNumOrdinal=segDef.hl7DefFields[i].OrdinalPos;
				}
				if(segDef.hl7DefFields[i].FieldName=="guar.nameLFM") {
					guarNameOrdinal=segDef.hl7DefFields[i].OrdinalPos;
				}
				if(segDef.hl7DefFields[i].FieldName=="guar.birthdateTime") {
					guarBirthdateOrdinal=segDef.hl7DefFields[i].OrdinalPos;
				}
			}
			//If neither guar.PatNum nor guar.ChartNumber are included in this GT1 definition log a message in the event log and return
			if(guarPatNumOrdinal==-1 && guarChartNumOrdinal==-1) {
				HL7MsgCur.Note="Guarantor not processed.  guar.PatNum or guar.ChartNumber must be included in the GT1 definition.  PatNum of patient:"+pat.PatNum.ToString();
				HL7Msgs.Update(HL7MsgCur);
				EventLog.WriteEntry("OpenDentHL7","Guarantor not processed.  guar.PatNum or guar.ChartNumber must be included in the GT1 definition.  PatNum of patient:"+pat.PatNum.ToString()
					,EventLogEntryType.Information);
				return;
			}
			//If guar.nameLFM is not included in this GT1 definition log a message in the event log and return
			if(guarNameOrdinal==-1) {
				HL7MsgCur.Note="Guarantor not processed due to guar.nameLFM not included in the GT1 definition.  Patnum of patient:"+pat.PatNum.ToString();
				HL7Msgs.Update(HL7MsgCur);
				EventLog.WriteEntry("OpenDentHL7","Guarantor not processed due to guar.nameLFM not included in the GT1 definition.  Patnum of patient:"+pat.PatNum.ToString()
					,EventLogEntryType.Information);
				return;
			}
			//If the first or last name are not included in this GT1 segment, log a message in the event log and return
			if(seg.GetFieldComponent(guarNameOrdinal,0)=="" || seg.GetFieldComponent(guarNameOrdinal,1)=="") {
				HL7MsgCur.Note="Guarantor not processed due to missing first or last name.  PatNum of patient:"+pat.PatNum.ToString();
				HL7Msgs.Update(HL7MsgCur);
				EventLog.WriteEntry("OpenDentHL7","Guarantor not processed due to missing first or last name.  PatNum of patient:"+pat.PatNum.ToString()
					,EventLogEntryType.Information);
				return;
			}
			//Only process GT1 if either guar.PatNum or guar.ChartNumber is included and both guar.LName and guar.FName are included
			long guarPatNum=0;
			string guarChartNum="";
			if(guarPatNumOrdinal!=-1) {
				guarPatNum=PIn.Long(seg.GetFieldFullText(guarPatNumOrdinal));
			}
			if(guarChartNumOrdinal!=-1) {
				guarChartNum=seg.GetFieldComponent(guarChartNumOrdinal);
			}
			if(guarPatNum==0 && guarChartNum=="") {//because we have an example where they sent us this (position 2 (guarPatNumOrder or guarChartNumOrder for eCW) is empty): GT1|1||^^||^^^^||||||||
				HL7MsgCur.Note="Guarantor not processed due to missing both guar.PatNum and guar.ChartNumber.  One of those numbers must be included.  PatNum of patient:"+pat.PatNum.ToString();
				HL7Msgs.Update(HL7MsgCur);
				EventLog.WriteEntry("OpenDentHL7","Guarantor not processed due to missing both guar.PatNum and guar.ChartNumber.  One of those numbers must be included.  PatNum of patient:"+pat.PatNum.ToString()
					,EventLogEntryType.Information);
				return;
			}
			if(guarPatNum==pat.PatNum || guarChartNum==pat.ChartNumber) {//if relationship is self
				return;
			}
			//Guar must be someone else
			Patient guar=null;
			Patient guarOld=null;
			//Find guarantor by guar.PatNum if defined and in this segment
			if(guarPatNum!=0) {
				guar=Patients.GetPat(guarPatNum);
			}
			else {//guarPatNum was 0 so try to get guar by guar.ChartNumber or name and birthdate
				//try to find guarantor using chartNumber
				guar=Patients.GetPatByChartNumber(guarChartNum);
				if(guar==null) {
					//try to find the guarantor by using name and birthdate
					string guarLName=seg.GetFieldComponent(guarNameOrdinal,0);
					string guarFName=seg.GetFieldComponent(guarNameOrdinal,1);
					DateTime guarBirthdate=FieldParser.DateTimeParse(seg.GetFieldFullText(guarBirthdateOrdinal));
					long guarNumByName=Patients.GetPatNumByNameAndBirthday(guarLName,guarFName,guarBirthdate);
					if(guarNumByName==0) {//guarantor does not exist in OD
						//so guar will still be null, triggering creation of new guarantor further down.
					}
					else {
						guar=Patients.GetPat(guarNumByName);
						guarOld=guar.Copy();
						guar.ChartNumber=guarChartNum;//from now on, we will be able to find guar by chartNumber
						Patients.Update(guar,guarOld);
					}
				}
			}
			//At this point we have a guarantor located in OD or guar=null so guar is new patient
			bool isNewGuar=guar==null;
			if(isNewGuar) {//then we need to add guarantor to db
				guar=new Patient();
				if(guarPatNum!=0) {
					guar.PatNum=guarPatNum;
				}
				else {
					guar.ChartNumber=guarChartNum;
				}
				guar.PriProv=PrefC.GetLong(PrefName.PracticeDefaultProv);
				guar.BillingType=PrefC.GetLong(PrefName.PracticeDefaultBillType);
			}
			else {
				guarOld=guar.Copy();
			}
			//Now that we have our guarantor, process the GT1 segment
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "guar.addressCityStateZip":
						guar.Address=seg.GetFieldComponent(itemOrder,0);
						guar.Address2=seg.GetFieldComponent(itemOrder,1);
						guar.City=seg.GetFieldComponent(itemOrder,2);
						guar.State=seg.GetFieldComponent(itemOrder,3);
						guar.Zip=seg.GetFieldComponent(itemOrder,4);
						continue;
					case "guar.birthdateTime":
						guar.Birthdate=FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "guar.ChartNumber":
						guar.ChartNumber=seg.GetFieldComponent(itemOrder);
						continue;
					case "guar.Gender":
						guar.Gender=FieldParser.GenderParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "guar.HmPhone":
						guar.HmPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "guar.nameLFM":
						guar.LName=seg.GetFieldComponent(itemOrder,0);
						guar.FName=seg.GetFieldComponent(itemOrder,1);
						guar.MiddleI=seg.GetFieldComponent(itemOrder,2);
						continue;
					//case "guar.PatNum": Maybe do nothing??
					case "guar.SSN":
						guar.SSN=seg.GetFieldComponent(itemOrder);
						continue;
					case "guar.WkPhone":
						guar.WkPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
						continue;
					default:
						continue;
				}
			}
			if(isNewGuar) {
				guarOld=guar.Copy();
				if(guar.PatNum==0) {
					guar.PatNum=Patients.Insert(guar,false);
				}
				else {
					guar.PatNum=Patients.Insert(guar,true);
				}
				guar.Guarantor=guar.PatNum;
				Patients.Update(guar,guarOld);
			}
			else {
				Patients.Update(guar,guarOld);
			}
			pat.Guarantor=guar.PatNum;
			return;
		}
Exemple #26
0
        public MessageHL7(string msgtext)
        {
            AckCode         = "";
            ControlId       = "";
            AckEvent        = "";
            originalMsgText = msgtext;
            Segments        = new List <SegmentHL7>();
            string[] rows = msgtext.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
            //We need to get the separator characters in order to create the field objects.
            //The separators are part of the MSH segment and we force users to leave them in position 1 for incoming messages.
            Delimiters = new char[] { '^', '~', '\\', '&' };       //this is the default, but we will get them from the MSH segment of the incoming message in case they are using something unique.
            //if def is enabled, set delimiters to user defined values
            HL7Def enabledDef = HL7Defs.GetOneDeepEnabled();

            if (enabledDef != null)
            {
                for (int i = 0; i < rows.Length; i++)
                {
                    //we're going to assume that the user has not inserted an escaped '|' before the second field of the message and just split by '|'s without
                    //checking for escaped '|'s.  Technically '\|' would be a literal pipe and should not indicate a new field, but we only want to retrieve the
                    //delimiters from MSH.1 and we require field 0 to be MSH and field 1 should be ^~\&.
                    string[] fields = rows[i].Split(new string[] { "|" }, StringSplitOptions.None);
                    if (fields.Length > 1 && fields[0] == "MSH" && fields[1].Length == 4)
                    {
                        //Encoding characters are in the following order:  component separator, repetition separator, escape character, subcomponent separator
                        Delimiters = fields[1].ToCharArray();                      //we force users to leave the delimiters in position 1 of the MSH segment
                        break;
                    }
                }
            }
            SegmentHL7 segment;

            for (int i = 0; i < rows.Length; i++)
            {
                segment = new SegmentHL7(rows[i], Delimiters);             //this creates the field objects.
                Segments.Add(segment);
                if (i == 0 && segment.Name == SegmentNameHL7.MSH)
                {
//js 7/3/12 Make this more intelligent because we also now need the suffix
                    string msgtype      = segment.GetFieldComponent(8, 0);            //We force the user to leave the 'messageType' field in this position, position 8 of the MSH segment
                    string evnttype     = segment.GetFieldComponent(8, 1);
                    string msgStructure = segment.GetFieldComponent(8, 2);
                    AckEvent = evnttype;                  //We will use this when constructing the acknowledgment to echo back to sender the same event type sent to us
                    //If message type or event type are not in this list, they will default to the not supported type and will not be processed
                    try {
                        MsgType = (MessageTypeHL7)Enum.Parse(typeof(MessageTypeHL7), msgtype, true);
                    }
                    catch (Exception ex) {
                        ex.DoNothing();
                        MsgType = MessageTypeHL7.NotDefined;
                    }
                    try {
                        EventType = (EventTypeHL7)Enum.Parse(typeof(EventTypeHL7), evnttype, true);
                    }
                    catch (Exception ex) {
                        ex.DoNothing();
                        EventType = EventTypeHL7.NotDefined;
                    }
                    try {
                        MsgStructure = (MessageStructureHL7)Enum.Parse(typeof(MessageStructureHL7), msgStructure, true);
                    }
                    catch (Exception ex) {
                        ex.DoNothing();
                        MsgStructure = MessageStructureHL7.NotDefined;
                    }
                }
            }
        }
Exemple #27
0
		public static void ProcessPR1(Patient pat,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			string strToothNum="";//could contain the tooth range in comma-delimited list
			string strSurf="";//used for surf/quad/sext/arch
			string strOidExt="";
			string strOidExtRoot="";
			ProcedureCode procCode=null;
			DateTime dateProc=DateTime.MinValue;
			Hashtable hashProcedureCodes=ProcedureCodeC.GetHList();
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "proccode.ProcCode":
						//ProcCode^descript (ignored)^CD2^^^^2014^^Layman Term (ignored)
						//Example: D1351^^CD2^^^^2014
						//must be CDT code (CD2 is code system abbr according to HL7 documentation) and must be version 2014
						if(seg.GetFieldComponent(itemOrder,2).ToLower()!="cd2" || seg.GetFieldComponent(itemOrder,6)!="2014") {
							EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()
								+".  Only CDT codes from code system version 2014 are currently allowed in the PR1 segment.  The code system name provided was "
								+seg.GetFieldComponent(itemOrder,2)+" and the code system version provided was "+seg.GetFieldComponent(itemOrder,6)+".",EventLogEntryType.Information);
							return;
						}
						string strProcCode=seg.GetFieldComponent(itemOrder,0);
						if(!hashProcedureCodes.ContainsKey(strProcCode)) {//code does not exist in proc code list, write entry in event log an return
							EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()
								+".  The code supplied in the PR1 segment does not exist in the database.  The code provided was "+strProcCode+".",EventLogEntryType.Information);
							return;
						}
						procCode=(ProcedureCode)hashProcedureCodes[strProcCode];
						continue;
					case "proc.procDateTime":
						dateProc=FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "proc.toothSurfRange":
						char subcompSeparator='&';
						if(msg.Delimiters.Length>3) {
							subcompSeparator=msg.Delimiters[3];
						}
						string[] listSubComponents=seg.GetFieldComponent(itemOrder).Split(new char[] { subcompSeparator },StringSplitOptions.None);
						if(listSubComponents.Length>0) {
							strToothNum=listSubComponents[0];
						}
						if(listSubComponents.Length>1) {
							strSurf=listSubComponents[1];
						}
						continue;
					case "proc.uniqueId":
						//Id^^UniversalId
						strOidExt=seg.GetFieldComponent(itemOrder,0);
						strOidExtRoot=seg.GetFieldComponent(itemOrder,2);
						if(strOidExt!="" && strOidExtRoot!="" && OIDExternals.GetByRootAndExtension(strOidExtRoot,strOidExt)!=null) {
							//the universal ID and root are already in the oidexternals table, do not insert another procedure, must be a duplicate
							EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()
								+".  The universal ID and root supplied in the PR1 segment refers to an existing procedure."
								+"  Inserting another would result in a duplicate procedure.  The ID provided was "
								+strOidExt+", the root was "+strOidExtRoot+".",EventLogEntryType.Information);
							return;
						}
						continue;
					default:
						continue;
				}
			}
			if(procCode==null) {
				EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()
					+".  No procedure code was defined for a PR1 segment or was missing.",EventLogEntryType.Information);
				return;
			}
			Procedure procCur=new Procedure();
			#region Validate/Convert/Set Treatment Area
			switch(procCode.TreatArea) {
				case TreatmentArea.Arch:
					if(strSurf!="L" && strSurf!="U") {
						EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "
							+procCode.ProcCode+" is arch but the arch of "+strSurf+" is invalid.",EventLogEntryType.Information);
						return;
					}
					procCur.Surf=strSurf;
					break;
				case TreatmentArea.Quad:
					if(strSurf!="UL" && strSurf!="UR" && strSurf!="LL" && strSurf!="LR") {
						EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "
							+procCode.ProcCode+" is quadrant but the quadrant of "+strSurf+" is invalid.",EventLogEntryType.Information);
						return;
					}
					procCur.Surf=strSurf;
					break;
				case TreatmentArea.Sextant:
					bool isValidSextant=false;
					if(strSurf=="1" || strSurf=="2" || strSurf=="3" || strSurf=="4" || strSurf=="5" || strSurf=="6") {
						isValidSextant=true;
					}
					if(CultureInfo.CurrentCulture.Name.EndsWith("CA")) {//Canadian. en-CA or fr-CA
						if(strSurf=="03" || strSurf=="04" || strSurf=="05" || strSurf=="06" || strSurf=="07" || strSurf=="08") {
							isValidSextant=true;
						}
					}
					if(!isValidSextant) {
						EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "
							+procCode.ProcCode+" is sextant but the sextant of "+strSurf+" is invalid.",EventLogEntryType.Information);
						return;
					}
					procCur.Surf=strSurf;
					break;
				case TreatmentArea.Surf:
					if(!Tooth.IsValidEntry(strToothNum)) {
						EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "
							+procCode.ProcCode+" is surface but the tooth number of "+strToothNum+" is invalid.",EventLogEntryType.Information);
					}
					procCur.ToothNum=Tooth.FromInternat(strToothNum);
					string strSurfTidy=Tooth.SurfTidyFromDisplayToDb(strSurf,procCur.ToothNum);
					if(strSurfTidy=="" || strSurf=="") {
						EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "
							+procCode.ProcCode+" is surface but the surface of "+strSurf+" is invalid.",EventLogEntryType.Information);
						return;
					}
					procCur.Surf=strSurfTidy;
					break;
				case TreatmentArea.Tooth:
					if(!Tooth.IsValidEntry(strToothNum)) {
						EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "
							+procCode.ProcCode+" is tooth but the tooth number of "+strToothNum+" is invalid.",EventLogEntryType.Information);
						return;
					}
					procCur.ToothNum=Tooth.FromInternat(strToothNum);
					break;
				case TreatmentArea.ToothRange:
					//break up the list of tooth numbers supplied and validate and convert them into universal tooth numbers for inserting into the db
					string[] listToothNums=strToothNum.Split(new char[] { ',' },StringSplitOptions.RemoveEmptyEntries);
					for(int i=0;i<listToothNums.Length;i++) {
						if(!Tooth.IsValidEntry(listToothNums[i])) {
							EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "
								+procCode.ProcCode+" is tooth range but the tooth number of "+listToothNums[i]+" is invalid.",EventLogEntryType.Information);
							return;
						}
						if(Tooth.IsPrimary(Tooth.FromInternat(listToothNums[i]))) {
							EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "+procCode.ProcCode
								+" is tooth range but the tooth number of "+listToothNums[i]+" is a primary tooth number and therefore not allowed.",EventLogEntryType.Information);
						}
						listToothNums[i]=Tooth.FromInternat(listToothNums[i]);
					}
					procCur.ToothNum=string.Join(",",listToothNums);
					break;
				//We won't validate or use the tooth number or surface fields if the treatment are of the proccode is mouth or none
				case TreatmentArea.None:
				case TreatmentArea.Mouth:
				default:
					break;
			}
			#endregion Validate/Convert/Set Treatment Area
			Procedures.SetDateFirstVisit(dateProc,1,pat);//wait until after validating, might not insert the proc, don't return after this point
			procCur.PatNum=pat.PatNum;
			procCur.CodeNum=procCode.CodeNum;
			procCur.ProcDate=dateProc;
			procCur.DateTP=dateProc;
			procCur.ProcStatus=ProcStat.TP;
			procCur.ProvNum=pat.PriProv;
			if(procCode.ProvNumDefault!=0) {
				procCur.ProvNum=procCode.ProvNumDefault;
			}
			else if(procCode.IsHygiene && pat.SecProv!=0) {
				procCur.ProvNum=pat.SecProv;
			}
			procCur.Note="";
			procCur.ClinicNum=pat.ClinicNum;
			procCur.BaseUnits=procCode.BaseUnits;
			procCur.SiteNum=pat.SiteNum;
			procCur.RevCode=procCode.RevenueCodeDefault;
			procCur.DiagnosticCode=PrefC.GetString(PrefName.ICD9DefaultForNewProcs);
			List<PatPlan> listPatPlan=PatPlans.Refresh(pat.PatNum);
			List<Benefit> listBen=Benefits.Refresh(listPatPlan,new List<InsSub>());
			#region Set ProcFee From Fee Schedule
			//check if it's a medical procedure
			bool isMed=false;
			procCur.MedicalCode=procCode.MedicalCode;
			if(procCur.MedicalCode!=null && procCur.MedicalCode!="") {
				isMed=true;
			}
			//Get fee schedule for medical or dental
			long feeSch;
			if(isMed) {
				feeSch=Fees.GetMedFeeSched(pat,new List<InsPlan>(),listPatPlan,new List<InsSub>());
			}
			else {
				feeSch=Fees.GetFeeSched(pat,new List<InsPlan>(),listPatPlan,new List<InsSub>());
			}
			//Get the fee amount for medical or dental
			double insfee;
			if(PrefC.GetBool(PrefName.MedicalFeeUsedForNewProcs) && isMed) {
				insfee=Fees.GetAmount0(ProcedureCodes.GetCodeNum(procCur.MedicalCode),feeSch);
			}
			else {
				insfee=Fees.GetAmount0(procCode.CodeNum,feeSch);
			}
			InsPlan priplan=null;
			if(listPatPlan.Count>0) {
				priplan=InsPlans.GetPlan(InsSubs.GetSub(listPatPlan[0].InsSubNum,new List<InsSub>()).PlanNum,new List<InsPlan>());
			}
			if(priplan!=null && priplan.PlanType=="p" && !isMed) {//PPO
				Provider patProv=Providers.GetProv(pat.PriProv);
				if(patProv==null) {
					patProv=Providers.GetProv(PrefC.GetLong(PrefName.PracticeDefaultProv));
				}
				double standardFee=Fees.GetAmount0(procCode.CodeNum,patProv.FeeSched);
				if(standardFee>insfee) {
					procCur.ProcFee=standardFee;
				}
				else {
					procCur.ProcFee=insfee;
				}
			}
			else {
				procCur.ProcFee=insfee;
			}
			#endregion Set ProcFee From Fee Schedule
			procCur.ProcNum=Procedures.Insert(procCur);
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Inserted a new procedure for patient "+pat.GetNameFLnoPref()+" due to an incoming PR1 segment.",EventLogEntryType.Information);
			}
			if(strOidExt!="" && strOidExtRoot!="") {
				OIDExternal procOidExt=new OIDExternal();
				procOidExt.IDType=IdentifierType.Procedure;
				procOidExt.IDInternal=procCur.ProcNum;
				procOidExt.IDExternal=strOidExt;
				procOidExt.rootExternal=strOidExtRoot;
				OIDExternals.Insert(procOidExt);
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Added an external procedure ID to the oidexternals table due to an incoming PR1 segment.\r\nProcNum: "
						+procCur.ProcNum.ToString()+", External problem ID: "+procOidExt.IDExternal+", External root: "+procOidExt.rootExternal+".",EventLogEntryType.Information);
				}
			}
			Procedures.ComputeEstimates(procCur,pat.PatNum,new List<ClaimProc>(),true,new List<InsPlan>(),listPatPlan,listBen,pat.Age,new List<InsSub>());
			return;
		}
Exemple #28
0
        public static void ProcessMessage(MessageHL7 message, bool isStandalone, bool isVerboseLogging)
        {
            /*string triggerevent=message.Segments[0].GetFieldComponent(8,1);
             * switch(triggerevent) {
             *      case "A01"://Admit/Visit Information
             *
             *              break;
             *      case "A04"://New Patient Information
             *              ProcessNewPatient(message);
             *              break;
             *      case "A08"://Update Patient Information
             *
             *              break;
             *      case "A28"://Add Patient Information
             *
             *              break;
             *      case "A31"://Update Patient Information
             *
             *              break;
             * }*/
            //MSH-Ignore
            //EVN-Ignore
            //PID-------------------------------------
            SegmentHL7 seg    = message.GetSegment(SegmentNameHL7.PID, true);
            long       patNum = PIn.Long(seg.GetFieldFullText(2));
            Patient    pat    = null;

            if (isStandalone)
            {
                pat = Patients.GetPatByChartNumber(patNum.ToString());
                if (pat == null)
                {
                    //try to find the patient in question by using name and birthdate
                    string   lName        = seg.GetFieldComponent(5, 0);
                    string   fName        = seg.GetFieldComponent(5, 1);
                    DateTime birthdate    = EcwSegmentPID.DateParse(seg.GetFieldFullText(7));
                    long     patNumByName = Patients.GetPatNumByNameAndBirthday(lName, fName, birthdate);
                    if (patNumByName == 0)                   //patient does not exist in OD
                    //so pat will still be null, triggering creation of new patient further down.
                    {
                    }
                    else
                    {
                        pat             = Patients.GetPat(patNumByName);
                        pat.ChartNumber = patNum.ToString();                      //from now on, we will be able to find pat by chartNumber
                    }
                }
            }
            else
            {
                pat = Patients.GetPat(patNum);
            }
            Patient patOld   = null;
            bool    isNewPat = pat == null;

            if (isNewPat)
            {
                pat = new Patient();
                if (isStandalone)
                {
                    pat.ChartNumber = patNum.ToString();
                    //this line does not work if isStandalone, so moved to end
                    //pat.Guarantor=patNum;
                }
                else
                {
                    pat.PatNum    = patNum;
                    pat.Guarantor = patNum;
                }
                pat.PriProv     = PrefC.GetLong(PrefName.PracticeDefaultProv);
                pat.BillingType = PrefC.GetLong(PrefName.PracticeDefaultBillType);
            }
            else
            {
                patOld = pat.Copy();
            }
            List <PatientRace> listPatRaces = new List <PatientRace>();
            bool hasNoRaceInStandalone      = (isStandalone && (pat == null || pat.PatNum == 0));

            EcwSegmentPID.ProcessPID(pat, seg, isStandalone, listPatRaces);
            //PV1-patient visit---------------------------
            //seg=message.GetSegment(SegmentName.PV1,false);
            //if(seg!=null) {//this seg is optional
            //	SegmentPID.ProcessPV1(pat,seg);
            //}
            //PD1-additional patient demographics------------
            //seg=message.GetSegment(SegmentName.PD1,false);
            //if(seg!=null) {//this seg is optional
            //	ProcessPD1(pat,seg);
            //}
            //GT1-Guarantor-------------------------------------
            seg = message.GetSegment(SegmentNameHL7.GT1, true);
            EcwSegmentPID.ProcessGT1(pat, seg, isStandalone);
            //IN1-Insurance-------------------------------------
            //List<SegmentHL7> segments=message.GetSegments(SegmentName.IN1);
            //for(int i=0;i<segments.Count;i++) {
            //	ProcessIN1(pat,seg);
            //}
            if (pat.FName == "" || pat.LName == "")
            {
                EventLog.WriteEntry("OpenDentHL7", "Patient demographics not processed due to missing first or last name. PatNum:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                return;
            }
            if (isNewPat)
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Inserted patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                pat.PatNum = Patients.Insert(pat, !isStandalone);             //use existing PK if not standalone, standalone will have PatNum=0, so set PatNum here
                SecurityLogs.MakeLogEntry(Permissions.PatientCreate, pat.PatNum, "Created from HL7 for eCW.", LogSources.HL7);
                if (hasNoRaceInStandalone)
                {
                    Patient patientRaceTemp = pat.Copy();                  //Make a deep copy so that we do not accidentally override something.
                    seg = message.GetSegment(SegmentNameHL7.PID, true);
                    //We have to process the PID again in order to correct the patient race.  Patient race(s) will automatically get inserted if needed.
                    EcwSegmentPID.ProcessPID(patientRaceTemp, seg, isStandalone, listPatRaces);
                }
                if (pat.Guarantor == 0)
                {
                    patOld        = pat.Copy();
                    pat.Guarantor = pat.PatNum;
                    Patients.Update(pat, patOld);
                }
            }
            else
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Updated patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Patients.Update(pat, patOld);
            }
            //had to move this reconcile here since we might not have a PatNum for new patients until after the insert
            PatientRaces.Reconcile(pat.PatNum, listPatRaces);
        }
Exemple #29
0
		///<summary>apt could be null if the PV1 segment is from a message that does not refer to an appointment like an ADT or PPR message or if it is from an SIU message and is for a new appointment.  If apt is null, do not update any of the apt fields, like clinic or provider.</summary>
		public static void ProcessPV1(Patient pat,Appointment apt,HL7DefSegment segDef,SegmentHL7 seg) {
			Appointment aptOld=null;
			if(apt!=null) {
				aptOld=apt.Clone();
			}
			Patient patOld=pat.Copy();
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "pat.GradeLevel":
						int intGradeLevel=0;
						try {
							intGradeLevel=PIn.Int(seg.GetFieldComponent(itemOrder));
						}
						catch(Exception ex) {
							//if parsing field to int fails, do nothing
							continue;
						}
						if(intGradeLevel<Enum.GetNames(typeof(PatientGrade)).Length) {//if parsed value is outside the range of enum, do nothing with the data
							pat.GradeLevel=(PatientGrade)intGradeLevel;//0=Unknown,1-12=first-twelfth, 13=PrenatalWIC, 14=PreK, 15=Kindergarten, 16=Other
						}
						continue;
					case "pat.location":
						//Example: ClinicDescript^OpName^^PracticeTitle^^c  (c for clinic)
						if(seg.GetFieldComponent(itemOrder,5).ToLower()!="c") {//LocationType is 'c' for clinic
							continue;
						}
						long clinicNum=Clinics.GetByDesc(seg.GetFieldComponent(itemOrder,0));//0 if field is blank or description doesn't match clinic description in the db
						if(clinicNum==0) {
							continue;//do nothing, either no clinic description in the message or no matching clinic found
						}
						pat.ClinicNum=clinicNum;
						if(apt!=null) {
							apt.ClinicNum=clinicNum;//the apt.ClinicNum may be set based on a different segment, like the AIL segment
						}
						continue;
					case "prov.provIdName":
					case "prov.provIdNameLFM":
						long provNum=0;
						if(_isEcwHL7Def) {//uses prov.EcwID
							provNum=FieldParser.ProvProcessEcw(seg.GetField(itemOrder));
						}
						else {
							provNum=FieldParser.ProvParse(seg.GetField(itemOrder),SegmentNameHL7.PV1,_isVerboseLogging);
						}
						if(provNum==0) {//This segment didn't have valid provider information in it, so do nothing
							continue;
						}
						if(apt!=null) {//We will set the appt.ProvNum (dentist) to the provider located in the PV1 segment, but this may be changed if the AIG or AIP segments are included
							apt.ProvNum=provNum;
						}
						pat.PriProv=provNum;
						continue;
					case "pat.site":
						//Example: |West Salem Elementary^^^^^s| ('s' for site)
						if(seg.GetFieldComponent(itemOrder,5).ToLower()!="s") {//LocationType is 's' for site
							continue;//not a site description, do nothing
						}
						long siteNum=Sites.FindMatchSiteNum(seg.GetFieldComponent(itemOrder,0));//0 if component is blank, -1 if no matching site description in the db
						if(siteNum>0) {
							pat.SiteNum=siteNum;
						}
						continue;
					case "pat.Urgency":
						int intPatUrgency=-1;
						try {
							intPatUrgency=PIn.Int(seg.GetFieldComponent(itemOrder));//if field is empty, PIn.Int will return 0 which will be the Unknown default urgency
						}
						catch(Exception ex) {
							//do nothing, patUrgency will remain -1
						}
						if(intPatUrgency>-1 && intPatUrgency<4) {//only cast to enum if 0-3
							pat.Urgency=(TreatmentUrgency)intPatUrgency;
						}
						continue;
					default:
						continue;
				}
			}
			Patients.Update(pat,patOld);
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated patient "+pat.GetNameFLnoPref()+" due to an incoming PV1 segment.",EventLogEntryType.Information);
			}
			if(apt!=null) {
				Appointments.Update(apt,aptOld);
				_aptProcessed=apt;
			}
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated appointment for patient "+pat.GetNameFLnoPref()+" due to an incoming PV1 segment.",EventLogEntryType.Information);
			}
			return;
		}
Exemple #30
0
		///<summary>This will insert a new MedLabResult object and set _medLabResultCur.</summary>
		public static void ProcessOBX(HL7DefSegment segDef,SegmentHL7 obxSeg) {
			if(_medLabResultCur!=null) {
				//if _medLabResultCur already exists and we're about to start another OBX, save the changes to _medLabResultCur before instantiating a new one
				MedLabResults.Update(_medLabResultCur);
			}
			_medLabResultCur=new MedLabResult();
			_medLabResultCur.MedLabNum=_medLabCur.MedLabNum;
			_isObsValueNte=false;
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				HL7DefField fieldDefCur=segDef.hl7DefFields[i];
				switch(fieldDefCur.FieldName) {
					case "obsID":
						_medLabResultCur.ObsID=obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						_medLabResultCur.ObsText=obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos,1);
						_medLabResultCur.ObsLoinc=obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos,3);
						_medLabResultCur.ObsLoincText=obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos,4);
						continue;
					case "obsIDSub":
						_medLabResultCur.ObsIDSub=obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "obsValue":
						_medLabResultCur.ObsValue=obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						if(_medLabResultCur.ObsValue.ToLower()=="tnp") {
							_medLabResultCur.ObsValue="Test Not Performed";
						}
						DataSubtype dataSubType;
						try {
							dataSubType=(DataSubtype)Enum.Parse(typeof(DataSubtype),obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos,2),true);
						}
						catch(Exception ex){
							dataSubType=DataSubtype.Unknown;
						}
						_medLabResultCur.ObsSubType=dataSubType;
						continue;
					case "obsValueType":
						if(obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos).ToLower()=="tx") {//if value type is text (TX) the value will be in attached NTEs
							_isObsValueNte=true;
						}
						continue;
					case "obsUnits":
						if(_medLabResultCur.ObsValue.ToLower()=="test not performed") {//if TNP then we won't bother saving the units
							continue;
						}
						_medLabResultCur.ObsUnits=obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						if(obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos,1).Length>0) {
							if(_medLabResultCur.Note!=null && _medLabResultCur.Note.Length>0) {
								_medLabResultCur.Note+="\r\n";
							}
							_medLabResultCur.Note+="Units full text: "+obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos,1);
						}
						continue;
					case "obsRefRange":
						_medLabResultCur.ReferenceRange=obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "obsAbnormalFlag":
						_medLabResultCur.AbnormalFlag=FieldParserMedLab.AbnormalFlagParse(obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						continue;
					case "resultStatus":
						_medLabResultCur.ResultStatus=FieldParserMedLab.ResultStatusParse(obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						continue;
					case "dateTimeObs":
						_medLabResultCur.DateTimeObs=FieldParserMedLab.DateTimeParse(obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						continue;
					case "facilityID":
						_medLabResultCur.FacilityID=obxSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					default:
						continue;
				}
			}
			_medLabResultCur.MedLabResultNum=MedLabResults.Insert(_medLabResultCur);
			if(_medLabResultCur.FacilityID=="") {//no facility ID in the OBX segment, can't link to facilities in the ZPS segments
				return;
			}
			if(!_dictFacilityCodeNum.ContainsKey(_medLabResultCur.FacilityID)) {//no facility in the ZPS segments with this facility ID
				return;
			}
			List<long> facNumList=_dictFacilityCodeNum[_medLabResultCur.FacilityID];//should only be one facility in the ZPS segments with this ID
			for(int i=0;i<facNumList.Count;i++) {
				MedLabFacAttach medLabAttachCur=new MedLabFacAttach();
				medLabAttachCur.MedLabFacilityNum=facNumList[i];
				medLabAttachCur.MedLabResultNum=_medLabResultCur.MedLabResultNum;
				MedLabFacAttaches.Insert(medLabAttachCur);
			}
		}
Exemple #31
0
		///<summary>This is used to set the provider (either dentist or hygienist depending on provType) and the confirmation status of the appointment.  If the apt is null, does nothing.  If this is an AIG, the provider field will be in the format ProvNum^LName, FName^^Abbr.  AIP and PV1 have the provider field in the format ProvNum^LName^FName^^^Abbr.  segDef.SegmentName will be used to determine how to parse the field.</summary>
		public static void ProcessAIGorAIP(Patient pat,Appointment apt,HL7DefSegment segDef,SegmentHL7 seg) {
			if(apt==null) {//We have to have an appt to process the AIG or AIP segment
				return;
			}
			Appointment aptOld=apt.Clone();
			long provNum=0;
			string strProvType="";
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				if(itemOrder<1) {
					continue;
				}
				switch(segDef.hl7DefFields[i].FieldName) {
					case "prov.provIdNameLFM":
					case "prov.provIdName":
						if(_isEcwHL7Def) {
							//for eCW interfaces, we allow inserting a new provider from the AIG or AIP segment and store the provider ID they supply in the prov.EcwId column
							provNum=FieldParser.ProvProcessEcw(seg.GetField(itemOrder));
						}
						else {
							//for all other interfaces, we will only accept provider ID's that match the OD ProvNum
							//if not found by ProvNum, we will attempt to match LName, FName, and Abbr
							//if still not found, we will not set the provider on the appt
							provNum=FieldParser.ProvParse(seg.GetField(itemOrder),segDef.SegmentName,_isVerboseLogging);
						}
						//provNum may still be 0
						continue;
					case "prov.provType":
						strProvType=seg.GetFieldComponent(itemOrder);
						//provType could still be an empty string, which is treated the same as 'd' or 'D' for dentist
						continue;
					case "apt.confirmStatus":
						long aptConfirmDefNum=0;
						Def[] listConfirmStats=DefC.GetList(DefCat.ApptConfirmed);
						for(int j=0;j<listConfirmStats.Length;j++) {
							if(seg.GetFieldComponent(itemOrder,1).ToLower()==listConfirmStats[j].ItemName.ToLower()//ItemName is the confirmation name
								|| (listConfirmStats[j].ItemValue!="" && seg.GetFieldComponent(itemOrder,1).ToLower()==listConfirmStats[j].ItemValue.ToLower()))//ItemValue is the confirmation abbreviation, which may be blank
							{
								aptConfirmDefNum=listConfirmStats[j].DefNum;
								break;
							}
						}
						if(aptConfirmDefNum>0) {
							apt.Confirmed=aptConfirmDefNum;
						}
						continue;
					default:
						continue;
				}
			}
			if(provNum>0) {
				if(strProvType.ToLower()=="h") {//only set ProvHyg if they specifically send 'h' or 'H' as the provType
					apt.ProvHyg=provNum;
				}
				else {//if 'd' or 'D' or not specified or invalid provType, default to setting the ProvNum
					apt.ProvNum=provNum;
				}
				if(_isEcwHL7Def) {
					pat.PriProv=provNum;
				}
			}
			Appointments.Update(apt,aptOld);
			_aptProcessed=apt;
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated appointment for patient "+pat.GetNameFLnoPref()+" due to an incoming AIG or AIP segment.",EventLogEntryType.Information);
			}
			return;
		}
Exemple #32
0
		///<summary>Finds a patient from the information in the PID segment, using the PID segment definition in the enabled HL7 def.
		///Will return null if a patient cannot be found using the information in the PID segment.  If an alternate patient ID is
		///provided and the name and birthdate in the PID segment match the name and birthdate of the patient located,
		///it will be stored in the oidexternal table linked to the patient's PatNum.</summary>
		public static Patient GetPatFromPID(HL7DefSegment pidSegDef,SegmentHL7 pidSeg) {
			//PID.2 should contain the OpenDental PatNum.
			//If there is no patient with PatNum=PID.2, we will attempt to find the value in PID.4 in the oidexternals table IDExternal column
			//with root MedLabv2_3.Patient and type IdentifierType.Patient.
			//The PatNum found in the oidexternals table will only be trusted if the name and birthdate of the pat match the name and birthdate in the msg.
			//If there is no entry in the oidexternals table, we will attempt to match by name and birthdate alone.
			//If a patient is found, an entry will be made in the oidexternals table with IDExternal=PID.4, rootExternal=MedLabv2_3.Patient,
			//IDType=IdentifierType.Patient, and IDInternal=PatNum if one does not already exist.
			long patNum=0;
			long patNumFromAlt=0;
			string altPatID="";
			string patLName="";
			string patFName="";
			DateTime birthdate=DateTime.MinValue;
			//Go through fields of PID segment and get patnum, altPatNum, patient name, and birthdate to locate patient
			for(int i=0;i<pidSegDef.hl7DefFields.Count;i++) {
				HL7DefField fieldDefCur=pidSegDef.hl7DefFields[i];
				OIDExternal oidCur=null;
				switch(fieldDefCur.FieldName) {
					case "altPatID":
						altPatID=pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						if(altPatID=="") {
							continue;
						}
						oidCur=OIDExternals.GetByRootAndExtension(HL7InternalType.MedLabv2_3.ToString()+".Patient",altPatID);
						if(oidCur==null || oidCur.IDType!=IdentifierType.Patient) {
							//not in the oidexternals table or the oidexternal located is not for a patient object, patNumFromAlt will remain 0
							continue;
						}
						patNumFromAlt=oidCur.IDInternal;
						continue;
					case "patBirthdateAge":
						//LabCorp sends the birthdate and age in years, months, and days like yyyyMMdd^YYY^MM^DD
						birthdate=FieldParser.DateTimeParse(pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						continue;
					default:
						continue;
					case "pat.nameLFM":
						patLName=pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos,0);
						patFName=pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos,1);
						continue;
					case "pat.PatNum":
						try {
							patNum=PIn.Long(pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						}
						catch(Exception ex) {
							//do nothing, patNum will remain 0
						}
						continue;
				}
			}
			//We now have patNum, patNumFromAlt, patLName, patFName, and birthdate so locate pat
			Patient patCur=Patients.GetPat(patNum);//will be null if not found or patNum=0
			#region Upsert the oidexternals Table
			//insert/update the altPatID and labPatID in the oidexternals table if a patient was found and the patient's name and birthdate match the message
			if(patCur!=null && IsMatchNameBirthdate(patCur,patLName,patFName,birthdate)) {
				//the altPatID field was populated in the PID segment (usually PID.4) and the altPatID isn't stored in the oidexternals table as IDExternal
				if(altPatID!="") {
					if(patNumFromAlt==0) { //if the altPatID isn't stored in the oidexternals table as IDExternal, insert
						OIDExternal oidCur=new OIDExternal();
						oidCur.IDType=IdentifierType.Patient;
						oidCur.IDInternal=patCur.PatNum;
						oidCur.rootExternal=HL7InternalType.MedLabv2_3.ToString()+".Patient";
						oidCur.IDExternal=altPatID;
						OIDExternals.Insert(oidCur);
					}
					else if(patCur.PatNum!=patNumFromAlt) { //else if patCur.PatNum is different than the IDInternal stored in the oidexternals table, update
						OIDExternal oidCur=OIDExternals.GetByRootAndExtension(HL7InternalType.MedLabv2_3.ToString()+".Patient",altPatID);
						oidCur.IDInternal=patCur.PatNum;
						OIDExternals.Update(oidCur);
					}
				}
			}
			#endregion Upsert the oidexternals Table
			//patCur is null so try to find a patient from the altPatID (PID.4)
			if(patCur==null && patNumFromAlt>0) {
				patCur=Patients.GetPat(patNumFromAlt);
				//We will only trust the altPatID if the name and birthdate of the patient match the name and birthdate in the message.
				if(!IsMatchNameBirthdate(patCur,patLName,patFName,birthdate)) {
					patCur=null;
				}
			}
			//if we haven't located a patient yet, attempt with name and birthdate
			if(patCur==null && patLName!="" && patFName!="" && birthdate>DateTime.MinValue) {
				long patNumByName=Patients.GetPatNumByNameAndBirthday(patLName,patFName,birthdate);
				if(patNumByName>0) {
					patCur=Patients.GetPat(patNumByName);
				}
			}
			return patCur;
		}
Exemple #33
0
		public static void ProcessAL1(Patient pat,HL7DefSegment segDef,SegmentHL7 seg) {
			//If there is an allergydef with SnomedType 2 or 3 (DrugAllergy or DrugIntolerance) with attached medication with RxCui=rxnorm supplied
			//And if there is not already an active allergy with that AllergyDefNum for the patient
			//Then insert an allergy with that AllergyDefNum for this patient
			long rxnorm=0;
			string strAllergenType="";
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int intItemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "allergenType":
						strAllergenType=seg.GetFieldComponent(intItemOrder).ToLower();
						continue;
					case "allergenRxNorm":
						if(seg.GetFieldComponent(intItemOrder,2).ToLower()!="rxnorm") {
							//if not an RXNORM code, do nothing.  Only RXNORM codes are currently supported
							EventLog.WriteEntry("OpenDentHL7","A drug allergy was not added for patient "+pat.GetNameFLnoPref()
								+".  Only RxNorm codes are currently allowed in the AL1 segment.  The code system name provided was "
								+seg.GetFieldComponent(intItemOrder,2)+".",EventLogEntryType.Information);
							return;
						}
						try {
							rxnorm=PIn.Long(seg.GetFieldComponent(intItemOrder,0));
						}
						catch(Exception ex) {//PIn.Long throws an exception if converting to an Int64 fails
							//do nothing, rxnorm will remain 0
						}
						continue;
					default:
						continue;
				}
			}
			if(rxnorm==0 || strAllergenType!="da") {
				EventLog.WriteEntry("OpenDentHL7","A drug allergy was not added for patient "+pat.GetNameFLnoPref()
					+".  Only drug allergies, identified by type 'DA', are currently allowed in the AL1 segment.  The allergen type received was '"
					+strAllergenType+"'.",EventLogEntryType.Information);
				return;//not able to assign drug allergy if not given a valid rxnorm or allergen type is not a drug allergy
			}
			AllergyDef allergyDefCur=AllergyDefs.GetAllergyDefFromRxnorm(rxnorm);
			if(allergyDefCur==null) {
				EventLog.WriteEntry("OpenDentHL7","A drug allergy was not added for patient "+pat.GetNameFLnoPref()+
					".  There is not a drug allergy in the database with an RxNorm code of "+rxnorm.ToString()+".",EventLogEntryType.Information);
				return;//no allergydef for this rxnorm exists
			}
			//see if there is already an active allergy with this AllergyDefNum for this patient
			List<Allergy> listAllergForPat=Allergies.GetAll(pat.PatNum,false);
			for(int i=0;i<listAllergForPat.Count;i++) {
				if(listAllergForPat[i].AllergyDefNum==allergyDefCur.AllergyDefNum) {
					return;//already an active allergy with this AllergyDefNum
				}
			}
			Allergy allergyCur=new Allergy();
			allergyCur.AllergyDefNum=allergyDefCur.AllergyDefNum;
			allergyCur.PatNum=pat.PatNum;
			allergyCur.StatusIsActive=true;
			Allergies.Insert(allergyCur);
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Inserted a new allergy for patient "+pat.GetNameFLnoPref()+" due to an incoming AL1 segment.",EventLogEntryType.Information);
			}
			return;
		}
Exemple #34
0
		//public static void ProcessIN1() {
		//	return;
		//}

		public static void ProcessMSA(HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			int ackCodeOrder=0;
			int msgControlIdOrder=0;
			//find position of AckCode in segDef for MSA seg
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				if(segDef.hl7DefFields[i].FieldName=="ackCode") {
					ackCodeOrder=segDef.hl7DefFields[i].OrdinalPos;
				}
				if(segDef.hl7DefFields[i].FieldName=="messageControlId") {
					msgControlIdOrder=segDef.hl7DefFields[i].OrdinalPos;
				}
			}
			if(ackCodeOrder==0) {//no ackCode defined for this def of MSA, do nothing with it?
				return;
			}
			if(msgControlIdOrder==0) {//no messageControlId defined for this def of MSA, do nothing with it?
				return;
			}
			//set msg.AckCode to value in position located in def of ackcode in seg
			msg.AckCode=seg.GetFieldComponent(ackCodeOrder).ToString();
			msg.ControlId=seg.GetFieldComponent(msgControlIdOrder).ToString();
		}
Exemple #35
0
		///<summary>If relationship is self, this method does nothing.  A new pat will later change guarantor to be same as patnum. </summary>
		public static void ProcessGT1(Patient pat,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			char escapeChar='\\';
			if(msg.Delimiters.Length>2) {//it is possible they did not send all 4 of the delimiter chars, in which case we will use the default \
				escapeChar=msg.Delimiters[2];
			}
			char subcompChar='&';
			if(msg.Delimiters.Length>3) {
				subcompChar=msg.Delimiters[3];
			}
			#region Get And Validate Definition Field Ordinals
			//Find the position of the guarNum, guarChartNum, guarName, and guarBirthdate in this HL7 segment based on the definition of a GT1
			int guarPatNumOrdinal=-1;
			int guarChartNumOrdinal=-1;
			int guarNameOrdinal=-1;
			int guarBirthdateOrdinal=-1;
			int guarIdsOrdinal=-1;
			string patOidRoot="";
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				switch(segDef.hl7DefFields[i].FieldName) {
					case "guar.PatNum":
						guarPatNumOrdinal=segDef.hl7DefFields[i].OrdinalPos;
						continue;
					case "guar.ChartNumber":
						guarChartNumOrdinal=segDef.hl7DefFields[i].OrdinalPos;
						continue;
					case "guar.nameLFM":
						guarNameOrdinal=segDef.hl7DefFields[i].OrdinalPos;
						continue;
					case "guar.birthdateTime":
						guarBirthdateOrdinal=segDef.hl7DefFields[i].OrdinalPos;
						continue;
					case "guarIdList":
						//get the id with the assigning authority equal to the internal OID root stored in their database for a patient object
						patOidRoot=OIDInternals.GetForType(IdentifierType.Patient).IDRoot;
						if(patOidRoot=="") {
							//if they have not set their internal OID root, we cannot identify which repetition in this field contains the OD PatNum, guarIdListOrdinal will remain -1
							continue;
						}
						guarIdsOrdinal=segDef.hl7DefFields[i].OrdinalPos;
						continue;
					default://not supported
						continue;
				}
			}
			//If neither guar.PatNum nor guar.ChartNumber are included in this GT1 definition log a message in the event log and return
			if(guarPatNumOrdinal==-1 && guarChartNumOrdinal==-1 && guarIdsOrdinal==-1) {
				_hl7MsgCur.Note="Guarantor not processed.  guar.PatNum, guar.ChartNumber, or guarIdList must be included in the GT1 definition.  PatNum of patient: "+pat.PatNum.ToString();
				HL7Msgs.Update(_hl7MsgCur);
				EventLog.WriteEntry("OpenDentHL7","Guarantor not processed.  guar.PatNum, guar.ChartNumber, or guarIdList must be included in the GT1 definition.  "
					+"PatNum of patient: "+pat.PatNum.ToString(),EventLogEntryType.Information);
				return;
			}
			//If guar.nameLFM is not included in this GT1 definition log a message in the event log and return
			if(guarNameOrdinal==-1) {
				_hl7MsgCur.Note="Guarantor not processed due to guar.nameLFM not included in the GT1 definition.  Patnum of patient: "+pat.PatNum.ToString();
				HL7Msgs.Update(_hl7MsgCur);
				EventLog.WriteEntry("OpenDentHL7","Guarantor not processed due to guar.nameLFM not included in the GT1 definition.  Patnum of patient: "
					+pat.PatNum.ToString(),EventLogEntryType.Information);
				return;
			}
			//If the first or last name are not included in this GT1 segment, log a message in the event log and return
			if(seg.GetFieldComponent(guarNameOrdinal,0)=="" || seg.GetFieldComponent(guarNameOrdinal,1)=="") {
				_hl7MsgCur.Note="Guarantor not processed due to missing first or last name.  PatNum of patient: "+pat.PatNum.ToString();
				HL7Msgs.Update(_hl7MsgCur);
				EventLog.WriteEntry("OpenDentHL7","Guarantor not processed due to missing first or last name.  PatNum of patient: "
					+pat.PatNum.ToString(),EventLogEntryType.Information);
				return;
			}
			#endregion Get And Validate Definition Field Ordinals
			#region Get guar.PatNum, guar.ChartNumber, and guarIdList IDs
			//Only process GT1 if guar.PatNum, guar.ChartNumber, or guarIdList is included and both guar.LName and guar.FName are included
			long guarPatNum=0;
			string guarChartNum="";
			long guarPatNumFromIds=0;
			List<OIDExternal> listOids=new List<OIDExternal>();
			if(guarPatNumOrdinal!=-1) {
				try {
					guarPatNum=PIn.Long(seg.GetFieldFullText(guarPatNumOrdinal));
				}
				catch(Exception ex) {
					//do nothing, guarPatNum will remain 0
				}
			}
			if(guarChartNumOrdinal!=-1) {
				guarChartNum=seg.GetFieldComponent(guarChartNumOrdinal);
			}
			if(guarIdsOrdinal!=-1) {//if OIDInternal root for a patient object is not defined, guarIdListOrdinal will be -1
				FieldHL7 fieldGuarIds=seg.GetField(guarIdsOrdinal);
				//Example field: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.2&HL7^PI~7684^8^M11^&Other.Software.OID&OIDType^PI|
				//field component values will be the first repetition, repeats will be in field.ListRepeatFields
				string[] arrayGuarIdSubComps=fieldGuarIds.GetComponentVal(3).Split(new char[] { subcompChar },StringSplitOptions.None);
				if(arrayGuarIdSubComps.Length>1 //must be at least two subcomponents in the assigning authority component so we can identify whose ID this is
					&& fieldGuarIds.GetComponentVal(4).ToLower()=="pi") //PI=patient internal identifier; a number that is unique to a patient within an assigning authority
				{
					int intCheckDigit=-1;
					try {
						intCheckDigit=PIn.Int(fieldGuarIds.GetComponentVal(1));
					}
					catch(Exception ex) {
						//checkDigit will remain -1
					}
					//if using the M10 or M11 check digit algorithm and it passes the respective test, or not using either algorithm
					//and only if there's at least 2 components in field 3 for the assigning authority so we can identify whose ID we are dealing with, then use the ID
					if((fieldGuarIds.GetComponentVal(2).ToLower()=="m10"
							&& intCheckDigit!=-1
							&& M10CheckDigit(fieldGuarIds.GetComponentVal(0))==intCheckDigit)//using M10 scheme and the check digit is valid and matches calc
						|| (fieldGuarIds.GetComponentVal(2).ToLower()=="m11"
							&& intCheckDigit!=-1
							&& M11CheckDigit(fieldGuarIds.GetComponentVal(0))==intCheckDigit)//using M11 scheme and the check digit is valid and matches calc
						|| (fieldGuarIds.GetComponentVal(2).ToLower()!="m10"
							&& fieldGuarIds.GetComponentVal(2).ToLower()!="m11"))//not using either check digit scheme
					{
						if(arrayGuarIdSubComps[1].ToLower()==patOidRoot.ToLower()) {
							try {
								guarPatNumFromIds=PIn.Long(fieldGuarIds.GetComponentVal(0));
							}
							catch(Exception ex) {
								//do nothing, guarPatNumFromList will remain 0
							}
						}
						else {
							OIDExternal oidCur=new OIDExternal();
							oidCur.IDType=IdentifierType.Patient;
							oidCur.IDExternal=fieldGuarIds.GetComponentVal(0);
							oidCur.rootExternal=arrayGuarIdSubComps[1];
							listOids.Add(oidCur);
						}
					}
				}
				for(int r=0;r<fieldGuarIds.ListRepeatFields.Count;r++) {
					arrayGuarIdSubComps=fieldGuarIds.ListRepeatFields[r].GetComponentVal(3).Split(new char[] { subcompChar },StringSplitOptions.None);
					if(arrayGuarIdSubComps.Length<2) {//must be at least two sub-components to the assigning authority component so we can identify whose ID this is
						continue;
					}
					if(fieldGuarIds.ListRepeatFields[r].GetComponentVal(4).ToLower()!="pi")
					{
						continue;
					}
					int intCheckDigit=-1;
					try {
						intCheckDigit=PIn.Int(fieldGuarIds.ListRepeatFields[r].GetComponentVal(1));
					}
					catch(Exception ex) {
						//checkDigit will remain -1
					}
					if(fieldGuarIds.ListRepeatFields[r].GetComponentVal(2).ToLower()=="m10"
						&& (intCheckDigit==-1 || M10CheckDigit(fieldGuarIds.ListRepeatFields[r].GetComponentVal(0))!=intCheckDigit))//using M10 scheme and either invalid check digit or doesn't match calc
					{
						continue;
					}
					if(fieldGuarIds.ListRepeatFields[r].GetComponentVal(2).ToLower()=="m11"
						&& (intCheckDigit==-1 || M11CheckDigit(fieldGuarIds.ListRepeatFields[r].GetComponentVal(0))!=intCheckDigit))//using M11 scheme and either invalid check digit or doesn't match calc
					{
						continue;
					}
					//if not using the M10 or M11 check digit scheme or if the check digit is good, trust the ID in component 0 to be valid and attempt to use
					if(arrayGuarIdSubComps[1].ToLower()==patOidRoot.ToLower()) {
						try {
							guarPatNumFromIds=PIn.Long(fieldGuarIds.ListRepeatFields[r].GetComponentVal(0));
						}
						catch(Exception ex) {
							//do nothing, guarPatNumFromList will remain 0
						}
					}
					else {
						OIDExternal oidCur=new OIDExternal();
						oidCur.IDType=IdentifierType.Patient;
						oidCur.IDExternal=fieldGuarIds.ListRepeatFields[r].GetComponentVal(0);
						oidCur.rootExternal=arrayGuarIdSubComps[1];
						listOids.Add(oidCur);
					}
				}
			}
			if(guarPatNum==0 && guarChartNum=="" && guarPatNumFromIds==0 && listOids.Count==0) {//because we have an example where they sent us this (position 2 (guarPatNumOrder or guarChartNumOrder for eCW) is empty): GT1|1||^^||^^^^||||||||
				_hl7MsgCur.Note="Guarantor not processed due to missing guar.PatNum, guar.ChartNumber, and guarIdList.  One of those numbers must be included.  "
					+"PatNum of patient: "+pat.PatNum.ToString();
				HL7Msgs.Update(_hl7MsgCur);
				EventLog.WriteEntry("OpenDentHL7","Guarantor not processed due to missing guar.PatNum, guar.ChartNumber, and guarIdList.  "
					+"One of those numbers must be included.  PatNum of patient: "+pat.PatNum.ToString(),EventLogEntryType.Information);
				return;
			}
			#endregion Get guar.PatNum, guar.ChartNumber, and guarIdList IDs
			if(guarPatNum==pat.PatNum
				|| (guarChartNum!="" && guarChartNum==pat.ChartNumber)
				|| guarPatNumFromIds==pat.PatNum)
			{//if relationship is self
				return;
			}
			#region Get Patient from Ids
			//Guar must be someone else
			Patient guar=null;
			Patient guarOld=null;
			//Find guarantor by guar.PatNum if defined and in this segment
			if(guarPatNum!=0) {
				guar=Patients.GetPat(guarPatNum);
			}
			else if(guarPatNumFromIds!=0) {
				guar=Patients.GetPat(guarPatNumFromIds);
			}
			else if(guarChartNum!="") {//guarPatNum and guarPatNumFromList was 0 so try to get guar by guar.ChartNumber or name and birthdate
				//try to find guarantor using chartNumber
				guar=Patients.GetPatByChartNumber(guarChartNum);
				if(guar==null) {
					//try to find the guarantor by using name and birthdate
					string strGuarLName=seg.GetFieldComponent(guarNameOrdinal,0);
					string strGuarFName=seg.GetFieldComponent(guarNameOrdinal,1);
					DateTime guarBirthdate=FieldParser.DateTimeParse(seg.GetFieldFullText(guarBirthdateOrdinal));
					long guarNamePatNum=Patients.GetPatNumByNameAndBirthday(strGuarLName,strGuarFName,guarBirthdate);
					if(guarNamePatNum==0) {//guarantor does not exist in OD
						//so guar will still be null, triggering creation of new guarantor further down.
					}
					else {
						guar=Patients.GetPat(guarNamePatNum);
						guarOld=guar.Copy();
						guar.ChartNumber=guarChartNum;//from now on, we will be able to find guar by chartNumber
						Patients.Update(guar,guarOld);
					}
				}
			}
			long guarExtPatNum=0;
			if(guar==null) {//As a last resort, use the external IDs for this patient in the oidexternal to find the guar
				//Use the external OIDs stored in the oidexternal table to find the patient
				//Only trust the external IDs if all OIDs refer to the same patient
				for(int i=0;i<listOids.Count;i++) {
					OIDExternal oidExternalCur=OIDExternals.GetByRootAndExtension(listOids[i].rootExternal,listOids[i].IDExternal);
					if(oidExternalCur==null || oidExternalCur.IDInternal==0 || oidExternalCur.IDType!=IdentifierType.Patient) {//must have an IDType of Patient
						continue;
					}
					if(guarExtPatNum==0) {
						guarExtPatNum=oidExternalCur.IDInternal;
					}
					else if(guarExtPatNum!=oidExternalCur.IDInternal) {//the current ID refers to a different patient than a previously found ID, don't trust the external IDs
						guarExtPatNum=0;
						break;
					}
				}
				if(guarExtPatNum>0) {//will be 0 if not in the OIDExternal table or no external IDs supplied or more than one supplied and they point to different pats (ambiguous)
					guar=Patients.GetPat(guarExtPatNum);
				}
			}
			//At this point we have a guarantor located in OD or guar=null so guar is new patient
			bool isNewGuar=(guar==null);
			if(isNewGuar) {//then we need to add guarantor to db
				guar=new Patient();
				if(guarChartNum!="") {
					guar.ChartNumber=guarChartNum;
				}
				if(guarPatNum!=0) {
					guar.PatNum=guarPatNum;
					guar.Guarantor=guarPatNum;
				}
				else if(guarPatNumFromIds!=0) {
					guar.PatNum=guarPatNumFromIds;
					guar.Guarantor=guarPatNumFromIds;
				}
				else if(guarExtPatNum!=0) {
					guar.PatNum=guarExtPatNum;
					guar.Guarantor=guarExtPatNum;
				}
				guar.PriProv=PrefC.GetLong(PrefName.PracticeDefaultProv);
				guar.BillingType=PrefC.GetLong(PrefName.PracticeDefaultBillType);
			}
			else {
				guarOld=guar.Copy();
			}
			#endregion Get Patient from Ids
			#region Update Guarantor Data
			//Now that we have our guarantor, process the GT1 segment
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "guar.addressCityStateZip":
						guar.Address=seg.GetFieldComponent(itemOrder,0);
						guar.Address2=seg.GetFieldComponent(itemOrder,1);
						guar.City=seg.GetFieldComponent(itemOrder,2);
						guar.State=seg.GetFieldComponent(itemOrder,3);
						guar.Zip=seg.GetFieldComponent(itemOrder,4);
						guar.AddrNote=FieldParser.StringNewLineParse(seg.GetFieldComponent(itemOrder,19),escapeChar);
						continue;
					case "guar.birthdateTime":
						guar.Birthdate=FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "guar.ChartNumber":
						guar.ChartNumber=seg.GetFieldComponent(itemOrder);
						continue;
					case "guar.Gender":
						guar.Gender=FieldParser.GenderParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "guar.HmPhone":
						if(seg.GetFieldComponent(itemOrder,2)=="" && seg.GetField(itemOrder).ListRepeatFields.Count==0) {
							//either no component 2 or left blank, and there are no repetitions, process the old way
							//the first repetition is considered the primary number, but if the primary number is not sent then it will be blank followed by the list of other numbers
							guar.HmPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
						}
						else {
							//XTN data type, repeatable.
							//Component 2 values: PH-Phone, FX-Fax, MD-Modem, CP-Cell Phone, Internet-Internet Address, X.400-X.400 email address, TDD-Tel Device for the Deaf, TTY-Teletypewriter.
							//We will support PH for pat.HmPhone, CP for pat.WirelessPhone, and Internet for pat.Email
							//Component 5 is area code, 6 is number
							//Component 3 will be Email if the type is Internet
							//Example: ^PRN^PH^^^503^3635432~^PRN^Internet^[email protected]
							FieldHL7 fieldPh=seg.GetField(itemOrder);
							if(fieldPh==null) {
								continue;
							}
							string strPhType=seg.GetFieldComponent(itemOrder,2);
							string strPh=seg.GetFieldComponent(itemOrder,5)+seg.GetFieldComponent(itemOrder,6);
							string strEmail=seg.GetFieldComponent(itemOrder,3);
							for(int p=-1;p<fieldPh.ListRepeatFields.Count;p++) {
								if(p>=0) {
									strPhType=fieldPh.ListRepeatFields[p].GetComponentVal(2);
									strPh=fieldPh.ListRepeatFields[p].GetComponentVal(5)+fieldPh.ListRepeatFields[p].GetComponentVal(6);
									strEmail=fieldPh.ListRepeatFields[p].GetComponentVal(3);
								}
								switch(strPhType) {
									case "PH":
										guar.HmPhone=FieldParser.PhoneParse(strPh);
										continue;
									case "CP":
										guar.WirelessPhone=FieldParser.PhoneParse(strPh);
										continue;
									case "Internet":
										guar.Email=strEmail;
										continue;
									default:
										continue;
								}
							}
						}
						continue;
					case "guar.nameLFM":
						guar.LName=seg.GetFieldComponent(itemOrder,0);
						guar.FName=seg.GetFieldComponent(itemOrder,1);
						guar.MiddleI=seg.GetFieldComponent(itemOrder,2);
						guar.Title=seg.GetFieldComponent(itemOrder,4);
						continue;
					//case "guar.PatNum": Maybe do nothing??
					case "guar.SSN":
						guar.SSN=seg.GetFieldComponent(itemOrder);
						continue;
					case "guar.WkPhone":
						if(seg.GetFieldComponent(itemOrder,2)=="PH") {
							//Component 2 value: PH-Phone
							//Component 5 is area code, 6 is number
							//Example: ^WPN^PH^^^503^3635432
							guar.WkPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder,5)+seg.GetFieldComponent(itemOrder,6));
							continue;
						}
						//either no component 2 or left blank, process the old way
						guar.WkPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
						continue;
					default:
						continue;
				}
			}
			if(isNewGuar) {
				if(guar.PatNum==0) {
					guarOld=guar.Copy();
					guar.PatNum=Patients.Insert(guar,false);
					guar.Guarantor=guar.PatNum;
					Patients.Update(guar,guarOld);
				}
				else {
					guar.PatNum=Patients.Insert(guar,true);
				}
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Inserted patient "+guar.GetNameFLnoPref()+" when processing a GT1 segment.",EventLogEntryType.Information);
				}
			}
			else {
				Patients.Update(guar,guarOld);
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Updated patient "+guar.GetNameFLnoPref()+" when processing a GT1 segment.",EventLogEntryType.Information);
				}
			}
			#endregion Update Guarantor Data
			pat.Guarantor=guar.PatNum;
			//store external IDs in the oidexternal table if they do not already exist in the table
			string strVerboseMsg="";
			for(int i=0;i<listOids.Count;i++) {
				if(listOids[i].IDExternal==""//not a good external ID OR
					|| listOids[i].rootExternal==""//not a good external root OR
					|| OIDExternals.GetByRootAndExtension(listOids[i].rootExternal,listOids[i].IDExternal)!=null)//already exists in the oidexternal table
				{
					continue;
				}
				listOids[i].IDInternal=guar.PatNum;
				OIDExternals.Insert(listOids[i]);
				strVerboseMsg+="\r\nExternal patient ID: "+listOids[i].IDExternal+", External root: "+listOids[i].rootExternal;
			}
			if(_isVerboseLogging && strVerboseMsg.Length>0) {
				EventLog.WriteEntry("OpenDentHL7","Added the following external patient ID(s) to the oidexternals table due to an incoming GT1 segment for PatNum: "+guar.PatNum+"."
					+strVerboseMsg+".",EventLogEntryType.Information);
			}
			return;
		}
Exemple #36
0
		public static void ProcessMSH(HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			int msgControlIdOrder=0;
			//find position of messageControlId in segDef for MSH seg
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				if(segDef.hl7DefFields[i].FieldName=="messageControlId") {
					msgControlIdOrder=segDef.hl7DefFields[i].OrdinalPos;
					continue;
				}
			}
			if(msgControlIdOrder==0) {
				return;
			}
			msg.ControlId=seg.GetFieldComponent(msgControlIdOrder).ToString();
		}
Exemple #37
0
        ///<summary>If relationship is self, this loop does nothing.  A new pat will later change guarantor to be same as patnum. </summary>
        public static void ProcessGT1(Patient pat, SegmentHL7 seg, bool useChartNumber)
        {
            long guarNum = PIn.Long(seg.GetFieldFullText(2));

            if (guarNum == 0)           //because we have an example where they sent us this (position 2 is empty): GT1|1||^^||^^^^||||||||
            {
                return;
            }
            if (seg.GetFieldFullText(11) == "1")           //if relationship is self (according to some of their documentation)
            {
                return;
            }
            if (seg.GetFieldComponent(3, 0) == "" ||     //lname
                seg.GetFieldComponent(3, 1) == "")                //fname
            {
                EventLog.WriteEntry("OpenDentHL7", "Guarantor not processed due to missing first or last name. PatNum of patient:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                return;
            }
            Patient guar    = null;
            Patient guarOld = null;

            //So guarantor is someone else
            if (useChartNumber)
            {
                //try to find guarantor by using chartNumber
                guar = Patients.GetPatByChartNumber(guarNum.ToString());
                if (guar == null)
                {
                    //try to find the guarantor by using name and birthdate
                    string   lName         = seg.GetFieldComponent(3, 0);
                    string   fName         = seg.GetFieldComponent(3, 1);
                    DateTime birthdate     = EcwSegmentPID.DateParse(seg.GetFieldFullText(8));
                    long     guarNumByName = Patients.GetPatNumByNameAndBirthday(lName, fName, birthdate);
                    if (guarNumByName == 0)                   //guarantor does not exist in OD
                    //so guar will still be null, triggering creation of new guarantor further down.
                    {
                    }
                    else
                    {
                        guar             = Patients.GetPat(guarNumByName);
                        guar.ChartNumber = guarNum.ToString();                      //from now on, we will be able to find guar by chartNumber
                    }
                }
            }
            else
            {
                guar = Patients.GetPat(guarNum);
            }
            //we can't necessarily set pat.Guarantor yet, because in Standalone mode, we might not know it yet.
            bool isNewGuar = guar == null;

            if (isNewGuar)             //then we need to add guarantor to db
            {
                guar = new Patient();
                if (useChartNumber)
                {
                    guar.ChartNumber = guarNum.ToString();
                }
                else
                {
                    guar.PatNum = guarNum;
                }
                guar.PriProv     = PrefC.GetLong(PrefName.PracticeDefaultProv);
                guar.BillingType = PrefC.GetLong(PrefName.PracticeDefaultBillType);
            }
            else
            {
                guarOld = guar.Copy();
            }
            //guar.Guarantor=guarNum;
            guar.LName     = seg.GetFieldComponent(3, 0);
            guar.FName     = seg.GetFieldComponent(3, 1);
            guar.MiddleI   = seg.GetFieldComponent(3, 2);
            guar.Address   = seg.GetFieldComponent(5, 0);
            guar.Address2  = seg.GetFieldComponent(5, 1);
            guar.City      = seg.GetFieldComponent(5, 2);
            guar.State     = seg.GetFieldComponent(5, 3);
            guar.Zip       = seg.GetFieldComponent(5, 4);
            guar.HmPhone   = PhoneParse(seg.GetFieldFullText(6));
            guar.WkPhone   = PhoneParse(seg.GetFieldFullText(7));
            guar.Birthdate = DateParse(seg.GetFieldFullText(8));
            guar.Gender    = GenderParse(seg.GetFieldFullText(9));
            //11. Guarantor relationship to patient.  We can't really do anything with this value
            guar.SSN = seg.GetFieldFullText(12);
            if (isNewGuar)
            {
                Patients.Insert(guar, !useChartNumber);               //if using chartnumber (standalone mode), then can't insert using existing PK
                guarOld        = guar.Copy();
                guar.Guarantor = guar.PatNum;
                Patients.Update(guar, guarOld);
            }
            else
            {
                Patients.Update(guar, guarOld);
            }
            pat.Guarantor = guar.PatNum;
        }
Exemple #38
0
		///<summary>So far this is only used in SRM messages and saves data to the appointment note field.  If apt is null this does nothing.  The note in the NTE segment will be appended to the existing appointment note unless the existing note already contains the exact note we are attempting to append.</summary>
		public static void ProcessNTE(Patient pat,Appointment apt,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			char escapeChar='\\';
			if(msg.Delimiters.Length>2) {//it is possible they did not send all 4 of the delimiter chars, in which case we will use the default \
				escapeChar=msg.Delimiters[2];
			}
			if(apt==null) {
				return;
			}
			if(apt.PatNum!=pat.PatNum) {
				throw new Exception("Appointment does not match patient "+pat.GetNameFLnoPref()+", apt.PatNum: "+apt.PatNum.ToString()+", pat.PatNum: "+pat.PatNum.ToString());
			}
			string strAptNote="";
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int intItemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "apt.Note":
						strAptNote=FieldParser.StringNewLineParse(seg.GetFieldComponent(intItemOrder),escapeChar);
						continue;
					default:
						continue;
				}
			}
			//if the existing note contains the exact text of the note in the NTE segment, don't append it again
			//replace the \r's and then \n's with a blank string before comparing to eliminate inconsistencies in new line characters
			if(apt.Note==null) {//just in case a new appointment gets here and has not been inserted yet, should never happen
				apt.Note="";
			}
			if(apt.Note.Replace("\r\n","\n").Replace("\r","\n").Contains(strAptNote.Replace("\r\n","\n").Replace("\r","\n"))) {
				return;
			}
			Appointment aptOld=apt.Clone();
			if(apt.Note.Length>0) {//if the existing note already contains some text, add a new line before appending the note from the NTE segment
				apt.Note+="\r\n";
			}
			apt.Note+=strAptNote;
			Appointments.Update(apt,aptOld);
			_aptProcessed=apt;
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated appointment for patient "+pat.GetNameFLnoPref()+" due to an incoming NTE segment.",EventLogEntryType.Information);
			}
			return;
		}
Exemple #39
0
 ///<summary>PatNum will not be altered here.  The pat passed in must either have PatNum=0, or must have a PatNum matching the segment.  The reason that isStandalone is passed in is because if using tight integration mode (isStandalone=false), then we need to store the "alternate patient id" aka Account No. that comes in on PID.4 in the ChartNumber field so we can pass it back in PID.2 of the DFT charge message.  However, if not using tight integration (isStandalone=true), the ChartNumber field is already occupied by the eCW patient ID, and we do not want to overwrite it.</summary>
 public static void ProcessPID(Patient pat,SegmentHL7 seg,bool isStandalone)
 {
     long patNum=PIn.Long(seg.GetFieldFullText(2));
     //if(pat.PatNum==0) {
     //	pat.PatNum=patNum;
     //}
     //else
     if(pat.PatNum!=0 && pat.PatNum != patNum) {
         throw new ApplicationException("Invalid patNum");
     }
     if(!isStandalone) {//when in tight integration mode
         pat.ChartNumber=seg.GetFieldFullText(4);
     }
     pat.LName=seg.GetFieldComponent(5,0);
     pat.FName=seg.GetFieldComponent(5,1);
     pat.MiddleI=seg.GetFieldComponent(5,2);
     pat.Birthdate=DateParse(seg.GetFieldFullText(7));
     pat.Gender=GenderParse(seg.GetFieldFullText(8));
     pat.Race=RaceParse(seg.GetFieldFullText(10));
     pat.Address=seg.GetFieldComponent(11,0);
     pat.Address2=seg.GetFieldComponent(11,1);
     pat.City=seg.GetFieldComponent(11,2);
     pat.State=seg.GetFieldComponent(11,3);
     pat.Zip=seg.GetFieldComponent(11,4);
     pat.HmPhone=PhoneParse(seg.GetFieldFullText(13));
     pat.WkPhone=PhoneParse(seg.GetFieldFullText(14));
     pat.Position=MaritalStatusParse(seg.GetFieldFullText(16));
     //pat.ChartNumber=seg.GetFieldFullText(18);//this is wrong.  Would also break standalone mode
     pat.SSN=seg.GetFieldFullText(19);
     pat.FeeSched=FeeScheduleParse(seg.GetFieldFullText(22));
 }
Exemple #40
0
		public static void ProcessOBX(Patient pat,HL7DefSegment segDef,SegmentHL7 seg) {
			long rxnorm=0;
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int intItemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "medicationRxNorm":
						if(seg.GetFieldComponent(intItemOrder,2).ToLower()!="rxnorm") {
							//if not an RXNORM code, do nothing.  Only RXNORM codes are currently supported
							EventLog.WriteEntry("OpenDentHL7","A medication was not added for patient "+pat.GetNameFLnoPref()
								+".  Only RxNorm codes are currently allowed in the OBX segment.  The code system name provided was "
								+seg.GetFieldComponent(intItemOrder,2)+".",EventLogEntryType.Information);
							return;
						}
						try {
							rxnorm=PIn.Long(seg.GetFieldComponent(intItemOrder,0));
						}
						catch(Exception ex) {//PIn.Long throws an exception if converting to an Int64 fails
							//do nothing, rxnorm will remain 0
						}
						continue;
					default:
						continue;
				}
			}
			if(rxnorm==0) {
				EventLog.WriteEntry("OpenDentHL7","A medication was not added for patient "
					+pat.GetNameFLnoPref()+".  The RxNorm code supplied in the OBX segment was invalid.",EventLogEntryType.Information);
				return;//not able to enter this medication if not given a valid rxnorm
			}
			Medication medCur=Medications.GetMedicationFromDbByRxCui(rxnorm);//an RxNorm could be attached to multiple medications, we will just add the first one we come to
			if(medCur==null) {
				EventLog.WriteEntry("OpenDentHL7","A medication was not added for patient "+pat.GetNameFLnoPref()
					+".  There is not a medication in the database with the RxNorm code of "+rxnorm.ToString()+".",EventLogEntryType.Information);
				return;
			}
			List<MedicationPat> listMedPatsCur=MedicationPats.Refresh(pat.PatNum,false);
			for(int i=0;i<listMedPatsCur.Count;i++) {
				if(listMedPatsCur[i].MedicationNum==medCur.MedicationNum) {
					return;//this patient already has this medication recorded and active
				}
			}
			MedicationPat medpatCur=new MedicationPat();
			medpatCur.PatNum=pat.PatNum;
			medpatCur.MedicationNum=medCur.MedicationNum;
			medpatCur.ProvNum=pat.PriProv;
			medpatCur.RxCui=medCur.RxCui;
			MedicationPats.Insert(medpatCur);
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Inserted a new medication for patient "+pat.GetNameFLnoPref()+" due to an incoming OBX segment.",EventLogEntryType.Information);
			}
			return;
		}
Exemple #41
0
        public static void ProcessMessage(MessageHL7 message, bool isVerboseLogging)
        {
            SegmentHL7 seg      = message.GetSegment(SegmentNameHL7.PID, true);
            long       patNum   = PIn.Long(seg.GetFieldFullText(2));
            Patient    pat      = Patients.GetPat(patNum);
            Patient    patOld   = null;
            bool       isNewPat = pat == null;

            if (isNewPat)
            {
                pat             = new Patient();
                pat.PatNum      = patNum;
                pat.Guarantor   = patNum;
                pat.PriProv     = PrefC.GetLong(PrefName.PracticeDefaultProv);
                pat.BillingType = PrefC.GetLong(PrefName.PracticeDefaultBillType);
            }
            else
            {
                patOld = pat.Copy();
            }
            List <PatientRace> listPatRaces = new List <PatientRace>();

            EcwSegmentPID.ProcessPID(pat, seg, false, listPatRaces);         //IsStandalone=false because should never make it this far.
            //PV1-patient visit---------------------------
            //seg=message.GetSegment(SegmentName.PV1,false);
            //if(seg!=null) {
            //	SegmentPID.ProcessPV1(pat,seg);
            //}
            //SCH- Schedule Activity Information
            seg = message.GetSegment(SegmentNameHL7.SCH, true);
            //The documentation is wrong.  SCH.01 is not the appointment ID, but is instead a sequence# (always 1)
            long        aptNum   = PIn.Long(seg.GetFieldFullText(2));
            Appointment apt      = Appointments.GetOneApt(aptNum);
            Appointment aptOld   = null;
            bool        isNewApt = apt == null;

            if (isNewApt)
            {
                apt           = new Appointment();
                apt.AptNum    = aptNum;
                apt.PatNum    = pat.PatNum;
                apt.AptStatus = ApptStatus.Scheduled;
            }
            else
            {
                aptOld = apt.Copy();
            }
            if (apt.PatNum != pat.PatNum)
            {
                EventLog.WriteEntry("OpenDentHL7", "Appointment does not match patient: " + pat.FName + " " + pat.LName
                                    + ", apt.PatNum:" + apt.PatNum.ToString() + ", pat.PatNum:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Error);
                return;                //we can't process this message because wrong patnum.
            }
            apt.Note = seg.GetFieldFullText(7);
            //apt.Pattern=ProcessDuration(seg.GetFieldFullText(9));
            //9 and 10 are not actually available, in spite of the documentation.
            //11-We need start time and stop time
            apt.AptDateTime = DateTimeParse(seg.GetFieldComponent(11, 3));
            DateTime stopTime = DateTimeParse(seg.GetFieldComponent(11, 4));

            apt.Pattern = ProcessPattern(apt.AptDateTime, stopTime);
            apt.ProvNum = pat.PriProv;          //just in case there's not AIG segment.
            //AIG is optional, but looks like the only way to get provider for the appt-----------
            //PV1 seems to frequently be sent instead of AIG.
            SegmentHL7 segAIG = message.GetSegment(SegmentNameHL7.AIG, false);
            SegmentHL7 segPV  = message.GetSegment(SegmentNameHL7.PV1, false);

            if (segAIG != null)
            {
                long provNum = EcwSegmentPID.ProvProcess(segAIG.GetField(3));
                if (provNum != 0)
                {
                    apt.ProvNum = provNum;
                    pat.PriProv = provNum;
                }
            }
            else if (segPV != null)
            {
                long provNum = EcwSegmentPID.ProvProcess(segPV.GetField(7));
                if (provNum != 0)
                {
                    apt.ProvNum = provNum;
                    pat.PriProv = provNum;
                }
            }
            //AIL,AIP seem to be optional, and I'm going to ignore them for now.
            if (pat.FName == "" || pat.LName == "")
            {
                EventLog.WriteEntry("OpenDentHL7", "Appointment not processed due to missing patient first or last name. PatNum:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                return;                //this will also skip the appt insert.
            }
            if (isNewPat)
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Inserted patient: " + pat.FName + " " + pat.LName + ", PatNum:" + pat.PatNum.ToString()
                                        , EventLogEntryType.Information);
                }
                Patients.Insert(pat, true);
                SecurityLogs.MakeLogEntry(Permissions.PatientCreate, pat.PatNum, "Created from HL7 for eCW.", LogSources.HL7);
            }
            else
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Updated patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Patients.Update(pat, patOld);
            }
            //had to move this reconcile here since we might not have a PatNum for new patients until after the insert
            PatientRaces.Reconcile(pat.PatNum, listPatRaces);
            if (isNewApt)
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Inserted appointment for: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Appointments.InsertIncludeAptNum(apt, true);
            }
            else
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Updated appointment for: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Appointments.Update(apt, aptOld);
            }
        }
Exemple #42
0
		///<summary>Sets values on _medLabCur based on the PID segment fields.  Also sets medlab.OriginalPIDSegment to the full PID segment.</summary>
		public static void ProcessPID(HL7DefSegment segDef,SegmentHL7 pidSeg) {
			_medLabCur.OriginalPIDSegment=pidSeg.ToString();
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				HL7DefField fieldDefCur=segDef.hl7DefFields[i];
				switch(fieldDefCur.FieldName) {
					case "accountNum":
						_medLabCur.PatAccountNum=pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						string fastingStr=pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos,6);
						//if the component is blank or has a value other than "Y" or "N", the PatFasting field will be 0 - Unknown
						if(fastingStr.Length>0) {
							fastingStr=fastingStr.ToLower().Substring(0,1);
							if(fastingStr=="y") {
								_medLabCur.PatFasting=YN.Yes;
							}
							else if(fastingStr=="n") {
								_medLabCur.PatFasting=YN.No;
							}
						}
						continue;
					case "altPatID":
						_medLabCur.PatIDAlt=pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "labPatID":
						_medLabCur.PatIDLab=pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "pat.nameLFM":
						//not currently using this to update any db fields, only used to validate the correct patient was selected
						continue;
					case "pat.PatNum":
						if(_patCur!=null) {
							//If a patient was not located, the MedLab object will have a 0 for PatNum.
							//We will be able to generate a list of all 'unattached' MedLab objects so the user can manually select the correct patient.
							_medLabCur.PatNum=_patCur.PatNum;
						}
						continue;
					case "patBirthdateAge":
						//the birthday field for MedLab is birthdate^age in years^age months^age days.
						//The year component is left padded with 0's to three digits, the month and day components are left padded with 0's to two digits.
						//If the year, age, or month components don't exist or are blank, the default will be to 
						//Example: 19811213^033^02^19
						FieldHL7 fieldCur=pidSeg.GetField(fieldDefCur.OrdinalPos);
						if(fieldCur==null || fieldCur.Components.Count<4) {//if there aren't even 4 components (3 ^'s) in the field, don't set the age
							continue;
						}
						_medLabCur.PatAge=pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos,1).PadLeft(3,'0')+"/"
							+pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos,2).PadLeft(2,'0')+"/"
							+pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos,3).PadLeft(2,'0');
						continue;
					default:
						continue;
				}
			}
			return;
		}