private void textHL7Raw_TextChanged(object sender,EventArgs e) {
			textPatName.Text="";
			textPatIDNum.Text="";
			textPatAccountNum.Text="";
			textDateTimeTest.Text="";
			textServiceID.Text="";
			textServiceName.Text="";
			try {
				//ORU-R01
				MessageHL7 msg=new MessageHL7(textHL7Raw.Text);
				SegmentHL7 segPID=msg.GetSegment(SegmentNameHL7.PID,false);
				patNum=0;
				if(segPID!=null) {
					fName=segPID.GetFieldComponent(5,1);
					lName=segPID.GetFieldComponent(5,0);
					//F M L ?
					textPatName.Text=segPID.GetFieldComponent(5,1)+" "+segPID.GetFieldComponent(5,2)+" "+segPID.GetFieldComponent(5,0);
					textPatIDNum.Text=segPID.GetFieldFullText(2);
					patNum=Patients.GetPatNumByName(lName,fName);//could be 0
					//patNum=PIn.Long(segPID.GetFieldFullText(2));
					textPatAccountNum.Text=segPID.GetFieldFullText(18);
				}
				SegmentHL7 segOBR=msg.GetSegment(SegmentNameHL7.OBR,false);
				if(segOBR!=null) {
					textServiceID.Text=segOBR.GetFieldComponent(4,0);
					textServiceName.Text=segOBR.GetFieldComponent(4,1);
				}
				SegmentHL7 segOBX=msg.GetSegment(SegmentNameHL7.OBX,false);
				if(segOBX!=null) {
					DateTime dt=segOBX.GetDateTime(14);
					if(dt.Year>1880) {
						textDateTimeTest.Text=dt.ToShortDateString();// +" "+dt.ToShortTimeString();
					}
				}
				FillPatAndGrid();
			}
			catch {
				patNum=0;
				FillPatAndGrid();
				MessageBox.Show("Error parsing HL7.");
			}
		}
Example #2
0
        public static void ProcessAck(MessageHL7 msg, bool isVerboseLogging)
        {
            IsVerboseLogging = isVerboseLogging;
            HL7Def def = HL7Defs.GetOneDeepEnabled();

            if (def == null)
            {
                throw new Exception("Could not process ACK.  No HL7 definition is enabled.");
            }
            HL7DefMessage hl7defmsg = null;

            for (int i = 0; i < def.hl7DefMessages.Count; i++)
            {
                if (def.hl7DefMessages[i].MessageType == MessageTypeHL7.ACK && def.hl7DefMessages[i].InOrOut == InOutHL7.Incoming)
                {
                    hl7defmsg = def.hl7DefMessages[i];
                    break;
                }
            }
            if (hl7defmsg == null)           //No incoming ACK defined, do nothing with it
            {
                throw new Exception("Could not process HL7 ACK message.  No definition for this type of message in the enabled HL7Def.");
            }
            for (int i = 0; i < hl7defmsg.hl7DefSegments.Count; i++)
            {
                try {
                    SegmentHL7 seg = msg.GetSegment(hl7defmsg.hl7DefSegments[i].SegmentName, !hl7defmsg.hl7DefSegments[i].IsOptional);
                    if (seg != null)                   //null if segment was not found but is optional
                    {
                        ProcessSeg(null, 0, hl7defmsg.hl7DefSegments[i], seg, msg);
                    }
                }
                catch (ApplicationException ex) {               //Required segment was missing, or other error.
                    throw new Exception("Could not process HL7 message.  " + ex);
                }
            }
        }
Example #3
0
File: EcwSIU.cs Project: mnisl/OD
		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<PatRace> listPatRaces=new List<PatRace>();
			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.Clone();
			}
			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);
			}
			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);
			}
		}
Example #4
0
		public static void ProcessAck(MessageHL7 msg,bool isVerboseLogging) {
			_isVerboseLogging=isVerboseLogging;
			HL7Def hl7Def=HL7Defs.GetOneDeepEnabled();
			if(hl7Def==null) {
				throw new Exception("Could not process ACK.  No HL7 definition is enabled.");
			}
			HL7DefMessage hl7DefMsg=null;
			for(int i=0;i<hl7Def.hl7DefMessages.Count;i++) {
				if(hl7Def.hl7DefMessages[i].MessageType==MessageTypeHL7.ACK && hl7Def.hl7DefMessages[i].InOrOut==InOutHL7.Incoming) {
					hl7DefMsg=hl7Def.hl7DefMessages[i];
					break;
				}
			}
			if(hl7DefMsg==null) {//No incoming ACK defined, do nothing with it
				throw new Exception("Could not process HL7 ACK message.  No definition for this type of message in the enabled HL7Def.");
			}
			for(int i=0;i<hl7DefMsg.hl7DefSegments.Count;i++) {
				try {
					SegmentHL7 seg=msg.GetSegment(hl7DefMsg.hl7DefSegments[i].SegmentName,!hl7DefMsg.hl7DefSegments[i].IsOptional);
					if(seg!=null) {//null if segment was not found but is optional
						ProcessSeg(null,null,hl7DefMsg.hl7DefSegments[i],seg,msg);
					}
				}
				catch(ApplicationException ex) {//Required segment was missing, or other error.
					throw new Exception("Could not process HL7 message.  "+ex);
				}
			}
		}
Example #5
0
		private static Appointment _aptProcessed;//return value for ProcessSeg if an appointment was processed
		//Open \\SERVERFILES\storage\OPEN DENTAL\Programmers Documents\Standards (X12, ADA, etc)\HL7\Version2.6\V26_CH02_Control_M4_JAN2007.doc
		//At the top of page 33, there are rules for the recipient.
		//Basically, they state that parsing should not fail just because there are extra unexpected items.
		//And parsing should also not fail if expected items are missing.

		public static void Process(MessageHL7 msg,bool isVerboseLogging) {
			_hl7MsgCur=new HL7Msg();
			_hl7MsgCur.HL7Status=HL7MessageStatus.InFailed;//it will be marked InProcessed once data is inserted.
			_hl7MsgCur.MsgText=msg.ToString();
			_hl7MsgCur.PatNum=0;
			_hl7MsgCur.AptNum=0;
			List<HL7Msg> listHL7Existing=HL7Msgs.GetOneExisting(_hl7MsgCur);
			if(listHL7Existing.Count>0) {//This message is already in the db
				_hl7MsgCur.HL7MsgNum=listHL7Existing[0].HL7MsgNum;
				HL7Msgs.UpdateDateTStamp(_hl7MsgCur);
				msg.ControlId=HL7Msgs.GetControlId(_hl7MsgCur);
				return;
			}
			else {
				//Insert as InFailed until processing is complete.  Update once complete, PatNum will have correct value, AptNum will have correct value if SIU message or 0 if ADT, and status changed to InProcessed
				HL7Msgs.Insert(_hl7MsgCur);
			}
			_isVerboseLogging=isVerboseLogging;
			_isNewPat=false;
			HL7Def def=HL7Defs.GetOneDeepEnabled();
			if(def==null) {
				_hl7MsgCur.Note="Could not process HL7 message.  No HL7 definition is enabled.";
				HL7Msgs.Update(_hl7MsgCur);
				throw new Exception("Could not process HL7 message.  No HL7 definition is enabled.");
			}
			if(def.InternalType==HL7InternalType.eCWFull
				|| def.InternalType==HL7InternalType.eCWTight
				|| def.InternalType==HL7InternalType.eCWStandalone)
			{
				_isEcwHL7Def=true;
			}
			HL7DefMessage hl7defmsg=null;
			for(int i=0;i<def.hl7DefMessages.Count;i++) {
				if(def.hl7DefMessages[i].MessageType==msg.MsgType && def.hl7DefMessages[i].InOrOut==InOutHL7.Incoming) {//Ignoring event type for now, we will treat all ADT's and SIU's the same
					hl7defmsg=def.hl7DefMessages[i];
					break;
				}
			}
			if(hl7defmsg==null) {//No message definition matches this message's MessageType and is Incoming
				_hl7MsgCur.Note="Could not process HL7 message.  No definition for this type of message in the enabled HL7Def.";
				HL7Msgs.Update(_hl7MsgCur);
				throw new Exception("Could not process HL7 message.  No definition for this type of message in the enabled HL7Def.");
			}
			string chartNum=null;
			long patNum=0;
			long patNumFromIds=0;
			//if we cannot locate the patient by the supplied patnum, either from the PatNum field or the list of IDs in PID.3, then we will use the external IDs to attempt to locate the pat
			//we will only trust these external IDs to return the correct patient if they all refer to a single patient
			//we may want to do some other checking to ensure that the patient referred to is the right patient?
			List<OIDExternal> listOids=new List<OIDExternal>();
			DateTime birthdate=DateTime.MinValue;
			string patLName=null;
			string patFName=null;
			#region GetPatientIDs
			#region PID segmentsLoop
			//Identify the location of the PID segment based on the message definition
			//Get patient in question, incoming messages must have a PID segment so use that to find the pat in question
			int pidOrder=-1;
			int pidDefOrder=-1;
			//get the def's PID segment order and the defined intItemOrder of the PID segment in the message
			for(int i=0;i<hl7defmsg.hl7DefSegments.Count;i++) {
				if(hl7defmsg.hl7DefSegments[i].SegmentName!=SegmentNameHL7.PID) {
					continue;
				}
				pidDefOrder=i;
				pidOrder=hl7defmsg.hl7DefSegments[i].ItemOrder;
				//we found the PID segment in the def, make sure it exists in the msg
				if(msg.Segments.Count<=pidOrder //If the number of segments in the message is less than the item order of the PID segment
					|| msg.Segments[pidOrder].GetField(0).ToString()!="PID") //Or if the segment we expect to be the PID segment is not the PID segment
				{
					_hl7MsgCur.Note="Could not process the HL7 message due to missing PID segment.";
					HL7Msgs.Update(_hl7MsgCur);
					throw new Exception("Could not process HL7 message.  Could not process the HL7 message due to missing PID segment.");
				}
				//if we get here, we've located the PID segment location within the message based on the def and it exists in the message
				break;
			}
			#endregion PID segmentsLoop
			#region PID fieldsLoop
			//Using the identified location of the PID segment, loop through the fields and find each identifier defined
			for(int f=0;f<hl7defmsg.hl7DefSegments[pidDefOrder].hl7DefFields.Count;f++) {//Go through fields of PID segment and get patnum, chartnum, patient name, and/or birthdate to locate patient
				if(hl7defmsg.hl7DefSegments[pidDefOrder].hl7DefFields[f].FieldName=="pat.ChartNumber") {
					int chartNumOrdinal=hl7defmsg.hl7DefSegments[pidDefOrder].hl7DefFields[f].OrdinalPos;
					chartNum=msg.Segments[pidOrder].GetField(chartNumOrdinal).ToString();
				}
				else if(hl7defmsg.hl7DefSegments[pidDefOrder].hl7DefFields[f].FieldName=="pat.PatNum") {
					int patNumOrdinal=hl7defmsg.hl7DefSegments[pidDefOrder].hl7DefFields[f].OrdinalPos;
					try {
						patNum=PIn.Long(msg.Segments[pidOrder].GetField(patNumOrdinal).ToString());
					}
					catch(Exception ex) {
						//do nothing, patNum will remain 0
					}
				}
				else if(hl7defmsg.hl7DefSegments[pidDefOrder].hl7DefFields[f].FieldName=="pat.birthdateTime") {
					int patBdayOrdinal=hl7defmsg.hl7DefSegments[pidDefOrder].hl7DefFields[f].OrdinalPos;
					birthdate=FieldParser.DateTimeParse(msg.Segments[pidOrder].GetField(patBdayOrdinal).ToString());
				}
				else if(hl7defmsg.hl7DefSegments[pidDefOrder].hl7DefFields[f].FieldName=="pat.nameLFM") {
					int patNameOrdinal=hl7defmsg.hl7DefSegments[pidDefOrder].hl7DefFields[f].OrdinalPos;
					patLName=msg.Segments[pidOrder].GetFieldComponent(patNameOrdinal,0);
					patFName=msg.Segments[pidOrder].GetFieldComponent(patNameOrdinal,1);
				}
				#region patientIdList
				else if(hl7defmsg.hl7DefSegments[pidDefOrder].hl7DefFields[f].FieldName=="patientIds") {
					//get the id with the assigning authority equal to the internal OID root stored in their database for a patient object
					string 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
						continue;
					}
					int patIdListOrdinal=hl7defmsg.hl7DefSegments[pidDefOrder].hl7DefFields[f].OrdinalPos;
					FieldHL7 fieldPatIds=msg.Segments[pidOrder].GetField(patIdListOrdinal);
					//Example: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.2&HL7^PI~7684^8^M11^&Other.Software.OID&OIDType^MR|
					//field component values will be the first repetition, repeats will be in field.ListRepeatFields
					//field 4 is an HD data type, which is composed of 3 subcomponents separated by the "&".
					//subcomponent 1 is the universal ID for the assigning authority
					//subcomponent 2 is the universal ID type for the assigning authority
					char subcompSeparator='&';
					if(msg.Delimiters.Length>3) {
						subcompSeparator=msg.Delimiters[3];
					}
					string[] arrayPatIdSubComps=fieldPatIds.GetComponentVal(3).Split(new char[] { subcompSeparator },StringSplitOptions.None);
					if(arrayPatIdSubComps.Length>1//there must be at least 2 sub-components in the assigning authority component so we can identify whose ID this is
						&& fieldPatIds.GetComponentVal(4).ToLower()=="pi")//PI=patient internal identifier; a number that is unique to a patient within an assigning authority
					{
						int checkDigit=-1;
						try {
							checkDigit=PIn.Int(fieldPatIds.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((fieldPatIds.GetComponentVal(2).ToLower()=="m10"
								&& checkDigit!=-1
								&& M10CheckDigit(fieldPatIds.GetComponentVal(0))==checkDigit)//using M10 scheme and the check digit is valid and matches calc
							|| (fieldPatIds.GetComponentVal(2).ToLower()=="m11"
								&& checkDigit!=-1
								&& M11CheckDigit(fieldPatIds.GetComponentVal(0))==checkDigit)//using M11 scheme and the check digit is valid and matches calc
							|| (fieldPatIds.GetComponentVal(2).ToLower()!="m10"
								&& fieldPatIds.GetComponentVal(2).ToLower()!="m11"))//not using either check digit scheme
						{
							if(arrayPatIdSubComps[1].ToLower()==patOIDRoot.ToLower()) {
								try {
									patNumFromIds=PIn.Long(fieldPatIds.GetComponentVal(0));
								}
								catch(Exception ex) {
									//do nothing, patNumFromList will remain 0
								}
							}
							else {
								OIDExternal oidCur=new OIDExternal();
								oidCur.IDType=IdentifierType.Patient;
								oidCur.IDExternal=fieldPatIds.GetComponentVal(0);
								oidCur.rootExternal=arrayPatIdSubComps[1];
								listOids.Add(oidCur);
							}
						}
					}
					//patNumFromList will be 0 if the first repetition is not the OD patient id or if the check digit is incorrect based on the specified algorithm
					if(patNumFromIds!=0) {
						continue;
					}
					for(int r=0;r<fieldPatIds.ListRepeatFields.Count;r++) {
						arrayPatIdSubComps=fieldPatIds.ListRepeatFields[r].GetComponentVal(3).ToLower().Split(new char[] { subcompSeparator },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(fieldPatIds.ListRepeatFields[r].GetComponentVal(4).ToLower()!="pi")
						{
							continue;
						}
						int checkDigit=-1;
						try {
							checkDigit=PIn.Int(fieldPatIds.ListRepeatFields[r].GetComponentVal(1));
						}
						catch(Exception ex) {
							//checkDigit will remain -1
						}
						if(fieldPatIds.ListRepeatFields[r].GetComponentVal(2).ToLower()=="m10"
						&& (checkDigit==-1 || M10CheckDigit(fieldPatIds.ListRepeatFields[r].GetComponentVal(0))!=checkDigit))//using M10 scheme and either invalid check digit or doesn't match calc
						{
							continue;
						}
						if(fieldPatIds.ListRepeatFields[r].GetComponentVal(2).ToLower()=="m11"
						&& (checkDigit==-1 || M11CheckDigit(fieldPatIds.ListRepeatFields[r].GetComponentVal(0))!=checkDigit))//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(arrayPatIdSubComps[1]==patOIDRoot.ToLower()) {
							if(patNumFromIds==0) {
								try {
									patNumFromIds=PIn.Long(fieldPatIds.ListRepeatFields[r].GetComponentVal(0));
								}
								catch(Exception ex) {
									//do nothing, patNumFromList will remain 0
								}
							}
						}
						else {
							OIDExternal oidCur=new OIDExternal();
							oidCur.IDType=IdentifierType.Patient;
							oidCur.IDExternal=fieldPatIds.ListRepeatFields[r].GetComponentVal(0);
							oidCur.rootExternal=arrayPatIdSubComps[1];
							listOids.Add(oidCur);
						}
					}
				}
				#endregion patientIdList
			}
			if(_isEcwHL7Def &&  (patLName=="" || patFName=="")) {
				EventLog.WriteEntry("OpenDentHL7","Message not processed due to missing first or last name. PatNum:"+patNum.ToString()
					,EventLogEntryType.Information);
				_hl7MsgCur.Note="Message not processed due to missing first or last name. PatNum:"+patNum.ToString();
				HL7Msgs.Update(_hl7MsgCur);
				return;
			}
			#endregion PID fieldsLoop
			#endregion GetPatientIDs
			//We now have patnum, chartnum, patname, and/or birthdate so locate pat
			Patient pat=null;
			Patient patOld=null;
			//pat will be null if patNum==0
			pat=Patients.GetPat(patNum);
			if(pat==null && patNumFromIds>0) {
				pat=Patients.GetPat(patNumFromIds);
			}
			//If ChartNumber is a field in their defined PID segment, and they are not using eCWTight or Full internal type
			//Use the ChartNumber followed by Name and Birthdate to try to locate the patient for this message if chartNum is not null
			if(def.InternalType!=HL7InternalType.eCWFull && def.InternalType!=HL7InternalType.eCWTight && pat==null && chartNum!=null) {
				pat=Patients.GetPatByChartNumber(chartNum);
				//If not using eCWTight or Full integration, if pat is still null we need to try to locate patient by name and birthdate
				if(pat==null) {
					long patNumByName=Patients.GetPatNumByNameAndBirthday(patLName,patFName,birthdate);
					if(patNumByName>0) {
						pat=Patients.GetPat(patNumByName);
					}
				}
				if(pat!=null) {
					patOld=pat.Copy();
					pat.ChartNumber=chartNum;//from now on, we will be able to find pat by chartNumber
					Patients.Update(pat,patOld);
					if(_isVerboseLogging) {
						EventLog.WriteEntry("OpenDentHL7","Updated patient "+pat.GetNameFLnoPref()+" to include ChartNumber.",EventLogEntryType.Information);
					}
				}
			}
			//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
			long patNumFromExtIds=0;
			if(pat==null) {
				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(patNumFromExtIds==0) {
						patNumFromExtIds=oidExternalCur.IDInternal;
					}
					else if(patNumFromExtIds!=oidExternalCur.IDInternal) {//the current ID refers to a different patient than a previously found ID, don't trust the external IDs
						patNumFromExtIds=0;
						break;
					}
				}
				if(patNumFromExtIds>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)
					pat=Patients.GetPat(patNumFromExtIds);
				}
			}
			_isNewPat=pat==null;
			if(!_isEcwHL7Def && msg.MsgType==MessageTypeHL7.SRM && _isNewPat) {//SRM messages must refer to existing appointments, so there must be an existing patient as well
				MessageHL7 hl7SRR=MessageConstructor.GenerateSRR(pat,null,msg.EventType,msg.ControlId,false,msg.AckEvent);//use false to indicate AE - Application Error in SRR.MSA segment
				HL7Msg hl7Msg=new HL7Msg();
				hl7Msg.HL7Status=HL7MessageStatus.OutPending;//it will be marked outSent by the HL7 service.
				hl7Msg.MsgText=hl7SRR.ToString();
				hl7Msg.Note="Could not process HL7 SRM message due to an invalid or missing patient ID in the PID segment.";
				HL7Msgs.Insert(hl7Msg);
				throw new Exception("Could not process HL7 SRM message due to an invalid or missing patient ID in the PID segment.");
			}
			if(_isNewPat) {
				pat=new Patient();
				if(chartNum!=null) {
					pat.ChartNumber=chartNum;
				}
				if(patNum!=0) {
					pat.PatNum=patNum;
					pat.Guarantor=patNum;
				}
				else if(patNumFromIds!=0) {
					pat.PatNum=patNumFromIds;
					pat.Guarantor=patNumFromIds;
				}
				else if(patNumFromExtIds!=0) {
					pat.PatNum=patNumFromExtIds;
					pat.Guarantor=patNumFromExtIds;
				}
				pat.PriProv=PrefC.GetLong(PrefName.PracticeDefaultProv);
				pat.BillingType=PrefC.GetLong(PrefName.PracticeDefaultBillType);
			}
			else {
				patOld=pat.Copy();
			}
			long aptNum=0;
			//If this is a message that contains an ARQ or SCH segment, loop through the fields to find the AptNum.  Pass it to other segment parsing methods that require it.
			//If this is an SRM message, and an AptNum is not included or no appointment with this AptNum is in the OD db, do not process the message.
			//We only accept SRM messages for appointments that already exist in the OD db.
			for(int i=0;i<hl7defmsg.hl7DefSegments.Count;i++) {
				if(hl7defmsg.hl7DefSegments[i].SegmentName!=SegmentNameHL7.SCH//SIU messages will have the SCH segment, used for eCW or other interfaces where OD is an auxiliary application
					&& hl7defmsg.hl7DefSegments[i].SegmentName!=SegmentNameHL7.ARQ)//SRM messages will have the ARQ segment, used for interfaces where OD is the filler application
				{
					continue;
				}
				//we found the SCH or ARQ segment
				int segOrder=hl7defmsg.hl7DefSegments[i].ItemOrder;
				for(int j=0;j<hl7defmsg.hl7DefSegments[i].hl7DefFields.Count;j++) {//Go through fields of SCH or ARQ segment and get AptNum
					if(hl7defmsg.hl7DefSegments[i].hl7DefFields[j].FieldName=="apt.AptNum") {
						int aptNumOrdinal=hl7defmsg.hl7DefSegments[i].hl7DefFields[j].OrdinalPos;
						try {
							aptNum=PIn.Long(msg.Segments[segOrder].GetFieldComponent(aptNumOrdinal,0).ToString());
						}
						catch(Exception ex) {//PIn.Long will throw an exception if a value is not able to be parsed into a long
							//do nothing, aptNum will remain 0
						}
						break;
					}
				}
				if(aptNum>0) {
					break;
				}
			}
			Appointment aptCur=Appointments.GetOneApt(aptNum);//if aptNum=0, aptCur will be null
			//SRM messages are only for interfaces where OD is considered the 'filler' application
			//Not valid for eCW where OD is considered an 'auxiliary' application and we receive SIU messages instead.
			if(!_isEcwHL7Def && msg.MsgType==MessageTypeHL7.SRM) {
				MessageHL7 hl7Srr=null;
				HL7Msg hl7Msg=null;
				if(aptCur==null) {
					hl7Srr=MessageConstructor.GenerateSRR(pat,aptCur,msg.EventType,msg.ControlId,false,msg.AckEvent);//use false to indicate AE - Application Error in SRR.MSA segment
					hl7Msg=new HL7Msg();
					hl7Msg.HL7Status=HL7MessageStatus.OutPending;//it will be marked outSent by the HL7 service.
					hl7Msg.MsgText=hl7Srr.ToString();
					hl7Msg.PatNum=pat.PatNum;
					hl7Msg.Note="Could not process HL7 SRM message due to an invalid or missing appointment ID in the ARQ segment.  Appointment ID attempted: "+aptNum.ToString();
					HL7Msgs.Insert(hl7Msg);
					throw new Exception("Could not process HL7 SRM message due to an invalid or missing appointment ID in the ARQ segment.  Appointment ID attempted: "+aptNum.ToString());
				}
				if(pat.PatNum!=aptCur.PatNum) {//an SRM must refer to a valid appt, therefore the patient cannot be new and must have a PatNum
					hl7Srr=MessageConstructor.GenerateSRR(pat,aptCur,msg.EventType,msg.ControlId,false,msg.AckEvent);//use false to indicate AE - Application Error in SRR.MSA segment
					hl7Msg=new HL7Msg();
					hl7Msg.AptNum=aptCur.AptNum;
					hl7Msg.HL7Status=HL7MessageStatus.OutPending;//it will be marked outSent by the HL7 service.
					hl7Msg.MsgText=hl7Srr.ToString();
					hl7Msg.PatNum=pat.PatNum;
					hl7Msg.Note="Could not process HL7 SRM message.\r\n"
						+"The patient identified in the PID segment is not the same as the patient on the appointment identified in the ARQ segment.\r\n"
						+"Appointment PatNum: "+aptCur.PatNum.ToString()+".  PID segment PatNum: "+pat.PatNum.ToString()+".";
					HL7Msgs.Insert(hl7Msg);
					throw new Exception("Could not process HL7 SRM message.\r\n"
						+"The patient identified in the PID segment is not the same as the patient on the appointment identified in the ARQ segment.\r\n"
						+"Appointment PatNum: "+aptCur.PatNum.ToString()+".  PID segment PatNum: "+pat.PatNum.ToString()+".");
				}
			}
			//We now have a patient object , either loaded from the db or new, and an appointment (could be null) so process this message for this patient
			//We need to insert the pat to get a patnum so we can compare to guar patnum to see if relationship to guar is self
			if(_isNewPat) {
				if(pat.PatNum==0) {//Only eCWTight or eCWFull internal types will allow the HL7 message to dictate our PatNums.
					pat.PatNum=Patients.Insert(pat,false);
				}
				else {
					pat.PatNum=Patients.Insert(pat,true);
				}
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Inserted patient "+pat.GetNameFLnoPref(),EventLogEntryType.Information);
				}
				patOld=pat.Copy();
			}
			//Update hl7msg table with correct PatNum for this message
			_hl7MsgCur.PatNum=pat.PatNum;
			HL7Msgs.Update(_hl7MsgCur);
			if(aptCur!=null && pat.PatNum!=aptCur.PatNum) {
				throw new Exception("Appointment does not match patient "+pat.GetNameFLnoPref()+", apt.PatNum: "+aptCur.PatNum.ToString()+", pat.PatNum: "+pat.PatNum.ToString());
			}
			for(int i=0;i<hl7defmsg.hl7DefSegments.Count;i++) {
				try {
					List<SegmentHL7> listSegments=new List<SegmentHL7>();
					if(hl7defmsg.hl7DefSegments[i].CanRepeat) {
						listSegments=msg.GetSegments(hl7defmsg.hl7DefSegments[i].SegmentName,!hl7defmsg.hl7DefSegments[i].IsOptional);
					}
					else {
						SegmentHL7 seg=msg.GetSegment(hl7defmsg.hl7DefSegments[i].SegmentName,!hl7defmsg.hl7DefSegments[i].IsOptional);
						if(seg==null) {//null if segment was not found but is optional
							continue;
						}
						listSegments.Add(seg);
					}
					for(int j=0;j<listSegments.Count;j++) {//normally only 1 or 0 in the list, but if it is a repeatable segment the list may contain multiple segments to process
						if(_isVerboseLogging) {
							EventLog.WriteEntry("OpenDentHL7","Process segment "+hl7defmsg.hl7DefSegments[i].SegmentName.ToString(),EventLogEntryType.Information);
						}
						ProcessSeg(pat,aptCur,hl7defmsg.hl7DefSegments[i],listSegments[j],msg);
						if(hl7defmsg.hl7DefSegments[i].SegmentName==SegmentNameHL7.SCH) {
							aptCur=_aptProcessed;
						}
					}
				}
				catch(ApplicationException ex) {//Required segment was missing, or other error.
					_hl7MsgCur.Note="Could not process this HL7 message.  "+ex;
					HL7Msgs.Update(_hl7MsgCur);
					if(!_isEcwHL7Def && msg.MsgType==MessageTypeHL7.SRM) {//SRM messages require sending an SRR response, this will be with Ack Code AE - Application Error
						MessageHL7 hl7Srr=MessageConstructor.GenerateSRR(pat,aptCur,msg.EventType,msg.ControlId,false,msg.AckEvent);//use false to indicate AE - Application Error in SRR.MSA segment
						HL7Msg hl7Msg=new HL7Msg();
						hl7Msg.AptNum=aptCur.AptNum;
						hl7Msg.HL7Status=HL7MessageStatus.OutPending;//it will be marked outSent by the HL7 service.
						hl7Msg.MsgText=hl7Srr.ToString();
						hl7Msg.Note="Could not process an HL7 SRM message.  Send SRR for the request.  "+ex;
						hl7Msg.PatNum=pat.PatNum;
						HL7Msgs.Insert(hl7Msg);
					}
					throw new Exception("Could not process an HL7 message.  "+ex);
				}
			}
			//We have processed the message so now update the patient
			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);
				_hl7MsgCur.Note="Patient demographics not processed due to missing first or last name. PatNum:"+pat.PatNum.ToString();
				HL7Msgs.Update(_hl7MsgCur);
			}
			else {
				if(_isNewPat && pat.Guarantor==0) {
					pat.Guarantor=pat.PatNum;
				}
				Patients.Update(pat,patOld);
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Updated patient "+pat.GetNameFLnoPref(),EventLogEntryType.Information);
				}
				_hl7MsgCur.HL7Status=HL7MessageStatus.InProcessed;
				HL7Msgs.Update(_hl7MsgCur);
			}
			//Schedule Request Messages require a Schedule Request Response if the data requested to be changed was successful
			//We only allow changing the appt note, setting the dentist and hygienist, updating the confirmation status, and changing the ClinicNum.
			//We also allow setting the appt status to broken if the EventType is S04 - Request Appointment Cancellation.
			//We will generate the SRR if we get here, since we will have processed the message properly.
			//The SRM will be ACK'd after returning from this Process method in ServiceHL7.
			//Our SRR will also be ACK'd by the receiving software.
			if(!_isEcwHL7Def && msg.MsgType==MessageTypeHL7.SRM) {
				if(msg.AckEvent=="S04") {
					Appointment aptOld=aptCur.Clone();
					aptCur.AptStatus=ApptStatus.Broken;
					Appointments.Update(aptCur,aptOld);
					if(_isVerboseLogging) {
						EventLog.WriteEntry("OpenDentHL7","Appointment broken due to inbound SRM message with event type S04 for patient "+pat.GetNameFLnoPref(),EventLogEntryType.Information);
					}
				}
				MessageHL7 hl7Srr=MessageConstructor.GenerateSRR(pat,aptCur,msg.EventType,msg.ControlId,true,msg.AckEvent);
				HL7Msg hl7Msg=new HL7Msg();
				hl7Msg.AptNum=aptCur.AptNum;
				hl7Msg.HL7Status=HL7MessageStatus.OutPending;//it will be marked outSent by the HL7 service.
				hl7Msg.MsgText=hl7Srr.ToString();
				hl7Msg.PatNum=pat.PatNum;
				HL7Msgs.Insert(hl7Msg);
			}
		}
Example #6
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);
            }
        }
Example #7
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);
        }
Example #8
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);
			}				
		}
Example #9
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);
            }
        }
Example #10
0
        //Open \\SERVERFILES\storage\OPEN DENTAL\Programmers Documents\Standards (X12, ADA, etc)\HL7\Version2.6\V26_CH02_Control_M4_JAN2007.doc
        //At the top of page 33, there are rules for the recipient.
        //Basically, they state that parsing should not fail just because there are extra unexpected items.
        //And parsing should also not fail if expected items are missing.

        public static void Process(MessageHL7 msg, bool isVerboseLogging)
        {
            HL7MsgCur           = new HL7Msg();
            HL7MsgCur.HL7Status = HL7MessageStatus.InFailed;          //it will be marked InProcessed once data is inserted.
            HL7MsgCur.MsgText   = msg.ToString();
            HL7MsgCur.PatNum    = 0;
            HL7MsgCur.AptNum    = 0;
            List <HL7Msg> hl7Existing = HL7Msgs.GetOneExisting(HL7MsgCur);

            if (hl7Existing.Count > 0)           //This message is already in the db
            {
                HL7MsgCur.HL7MsgNum = hl7Existing[0].HL7MsgNum;
                HL7Msgs.UpdateDateTStamp(HL7MsgCur);
                msg.ControlId = HL7Msgs.GetControlId(HL7MsgCur);
                return;
            }
            else
            {
                //Insert as InFailed until processing is complete.  Update once complete, PatNum will have correct value, AptNum will have correct value if SIU message or 0 if ADT, and status changed to InProcessed
                HL7Msgs.Insert(HL7MsgCur);
            }
            IsVerboseLogging = isVerboseLogging;
            IsNewPat         = false;
            HL7Def def = HL7Defs.GetOneDeepEnabled();

            if (def == null)
            {
                HL7MsgCur.Note = "Could not process HL7 message.  No HL7 definition is enabled.";
                HL7Msgs.Update(HL7MsgCur);
                throw new Exception("Could not process HL7 message.  No HL7 definition is enabled.");
            }
            HL7DefMessage hl7defmsg = null;

            for (int i = 0; i < def.hl7DefMessages.Count; i++)
            {
                if (def.hl7DefMessages[i].MessageType == msg.MsgType)               //&& def.hl7DefMessages[i].EventType==msg.EventType) { //Ignoring event type for now, we will treat all ADT's and SIU's the same
                {
                    hl7defmsg = def.hl7DefMessages[i];
                }
            }
            if (hl7defmsg == null)           //No message definition matches this message's MessageType and EventType
            {
                HL7MsgCur.Note = "Could not process HL7 message.  No definition for this type of message in the enabled HL7Def.";
                HL7Msgs.Update(HL7MsgCur);
                throw new Exception("Could not process HL7 message.  No definition for this type of message in the enabled HL7Def.");
            }
            string   chartNum      = null;
            long     patNum        = 0;
            DateTime birthdate     = DateTime.MinValue;
            string   patLName      = null;
            string   patFName      = null;
            bool     isExistingPID = false;      //Needed to add note to hl7msg table if there isn't a PID segment in the message.

            //Get patient in question, incoming messages must have a PID segment so use that to find the pat in question
            for (int s = 0; s < hl7defmsg.hl7DefSegments.Count; s++)
            {
                if (hl7defmsg.hl7DefSegments[s].SegmentName != SegmentNameHL7.PID)
                {
                    continue;
                }
                int pidOrder = hl7defmsg.hl7DefSegments[s].ItemOrder;
                //we found the PID segment in the def, make sure it exists in the msg
                if (msg.Segments.Count <= pidOrder ||           //If the number of segments in the message is less than the item order of the PID segment
                    msg.Segments[pidOrder].GetField(0).ToString() != "PID"                      //Or if the segment we expect to be the PID segment is not the PID segment
                    )
                {
                    break;
                }
                isExistingPID = true;
                for (int f = 0; f < hl7defmsg.hl7DefSegments[s].hl7DefFields.Count; f++)           //Go through fields of PID segment and get patnum, chartnum, patient name, and/or birthdate to locate patient
                {
                    if (hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName == "pat.ChartNumber")
                    {
                        int chartNumOrdinal = hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
                        chartNum = msg.Segments[pidOrder].Fields[chartNumOrdinal].ToString();
                    }
                    else if (hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName == "pat.PatNum")
                    {
                        int patNumOrdinal = hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
                        patNum = PIn.Long(msg.Segments[pidOrder].Fields[patNumOrdinal].ToString());
                    }
                    else if (hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName == "pat.birthdateTime")
                    {
                        int patBdayOrdinal = hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
                        birthdate = FieldParser.DateTimeParse(msg.Segments[pidOrder].Fields[patBdayOrdinal].ToString());
                    }
                    else if (hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName == "pat.nameLFM")
                    {
                        int patNameOrdinal = hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
                        patLName = msg.Segments[pidOrder].GetFieldComponent(patNameOrdinal, 0);
                        patFName = msg.Segments[pidOrder].GetFieldComponent(patNameOrdinal, 1);
                    }
                }
            }
            if (!isExistingPID)
            {
                HL7MsgCur.Note = "Could not process the HL7 message due to missing PID segment.";
                HL7Msgs.Update(HL7MsgCur);
                throw new Exception("Could not process HL7 message.  Could not process the HL7 message due to missing PID segment.");
            }
            //We now have patnum, chartnum, patname, and/or birthdate so locate pat
            Patient pat    = null;
            Patient patOld = null;

            if (patNum != 0)
            {
                pat = Patients.GetPat(patNum);
            }
            if (def.InternalType != "eCWStandalone" && pat == null)
            {
                IsNewPat = true;
            }
            //In eCWstandalone integration, if we couldn't locate patient by patNum or patNum was 0 then pat will still be null so try to locate by chartNum if chartNum is not null
            if (def.InternalType == "eCWStandalone" && chartNum != null)
            {
                pat = Patients.GetPatByChartNumber(chartNum);
            }
            //In eCWstandalone integration, if pat is still null we need to try to locate patient by name and birthdate
            if (def.InternalType == "eCWStandalone" && pat == null)
            {
                long patNumByName = Patients.GetPatNumByNameAndBirthday(patLName, patFName, birthdate);
                //If patNumByName is 0 we couldn't locate by patNum, chartNum or name and birthdate so this message must be for a new patient
                if (patNumByName == 0)
                {
                    IsNewPat = true;
                }
                else
                {
                    pat             = Patients.GetPat(patNumByName);
                    patOld          = pat.Copy();
                    pat.ChartNumber = chartNum;                  //from now on, we will be able to find pat by chartNumber
                    Patients.Update(pat, patOld);
                }
            }
            if (IsNewPat)
            {
                pat = new Patient();
                if (chartNum != null)
                {
                    pat.ChartNumber = chartNum;
                }
                if (patNum != 0)
                {
                    pat.PatNum    = patNum;
                    pat.Guarantor = patNum;
                }
                pat.PriProv     = PrefC.GetLong(PrefName.PracticeDefaultProv);
                pat.BillingType = PrefC.GetLong(PrefName.PracticeDefaultBillType);
            }
            else
            {
                patOld = pat.Copy();
            }
            //Update hl7msg table with correct PatNum for this message
            HL7MsgCur.PatNum = pat.PatNum;
            HL7Msgs.Update(HL7MsgCur);
            //If this is a message that contains an SCH segment, loop through to find the AptNum.  Pass it to the other segments that will need it.
            long aptNum = 0;

            for (int s = 0; s < hl7defmsg.hl7DefSegments.Count; s++)
            {
                if (hl7defmsg.hl7DefSegments[s].SegmentName != SegmentNameHL7.SCH)
                {
                    continue;
                }
                //we found the SCH segment
                int schOrder = hl7defmsg.hl7DefSegments[s].ItemOrder;
                for (int f = 0; f < hl7defmsg.hl7DefSegments[s].hl7DefFields.Count; f++)           //Go through fields of SCH segment and get AptNum
                {
                    if (hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName == "apt.AptNum")
                    {
                        int aptNumOrdinal = hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
                        aptNum = PIn.Long(msg.Segments[schOrder].Fields[aptNumOrdinal].ToString());
                    }
                }
            }
            //We now have a patient object , either loaded from the db or new, and aptNum so process this message for this patient
            //We need to insert the pat to get a patnum so we can compare to guar patnum to see if relationship to guar is self
            if (IsNewPat)
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Inserted patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                if (pat.PatNum == 0)
                {
                    pat.PatNum = Patients.Insert(pat, false);
                }
                else
                {
                    pat.PatNum = Patients.Insert(pat, true);
                }
                patOld = pat.Copy();
            }
            for (int i = 0; i < hl7defmsg.hl7DefSegments.Count; i++)
            {
                try {
                    SegmentHL7 seg = msg.GetSegment(hl7defmsg.hl7DefSegments[i].SegmentName, !hl7defmsg.hl7DefSegments[i].IsOptional);
                    if (seg != null)                   //null if segment was not found but is optional
                    {
                        ProcessSeg(pat, aptNum, hl7defmsg.hl7DefSegments[i], seg, msg);
                    }
                }
                catch (ApplicationException ex) {               //Required segment was missing, or other error.
                    HL7MsgCur.Note = "Could not process this HL7 message.  " + ex;
                    HL7Msgs.Update(HL7MsgCur);
                    throw new Exception("Could not process HL7 message.  " + ex);
                }
            }
            //We have processed the message so now update or insert the patient
            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);
                HL7MsgCur.Note = "Patient demographics not processed due to missing first or last name. PatNum:" + pat.PatNum.ToString();
                HL7Msgs.Update(HL7MsgCur);
                return;
            }
            if (IsNewPat)
            {
                if (pat.Guarantor == 0)
                {
                    pat.Guarantor = pat.PatNum;
                    Patients.Update(pat, patOld);
                }
                else
                {
                    Patients.Update(pat, patOld);
                }
            }
            else
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Updated patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Patients.Update(pat, patOld);
            }
            HL7MsgCur.HL7Status = HL7MessageStatus.InProcessed;
            HL7Msgs.Update(HL7MsgCur);
        }
Example #11
0
		//Open \\SERVERFILES\storage\OPEN DENTAL\Programmers Documents\Standards (X12, ADA, etc)\HL7\Version2.6\V26_CH02_Control_M4_JAN2007.doc
		//At the top of page 33, there are rules for the recipient.
		//Basically, they state that parsing should not fail just because there are extra unexpected items.
		//And parsing should also not fail if expected items are missing.

		public static void Process(MessageHL7 msg,bool isVerboseLogging) {
			HL7MsgCur=new HL7Msg();
			HL7MsgCur.HL7Status=HL7MessageStatus.InFailed;//it will be marked InProcessed once data is inserted.
			HL7MsgCur.MsgText=msg.ToString();
			HL7MsgCur.PatNum=0;
			HL7MsgCur.AptNum=0;
			List<HL7Msg> hl7Existing=HL7Msgs.GetOneExisting(HL7MsgCur);
			if(hl7Existing.Count>0) {//This message is already in the db
				HL7MsgCur.HL7MsgNum=hl7Existing[0].HL7MsgNum;
				HL7Msgs.UpdateDateTStamp(HL7MsgCur);
				msg.ControlId=HL7Msgs.GetControlId(HL7MsgCur);
				return;
			}
			else {
				//Insert as InFailed until processing is complete.  Update once complete, PatNum will have correct value, AptNum will have correct value if SIU message or 0 if ADT, and status changed to InProcessed
				HL7Msgs.Insert(HL7MsgCur);
			}
			IsVerboseLogging=isVerboseLogging;
			IsNewPat=false;
			HL7Def def=HL7Defs.GetOneDeepEnabled();
			if(def==null) {
				HL7MsgCur.Note="Could not process HL7 message.  No HL7 definition is enabled.";
				HL7Msgs.Update(HL7MsgCur);
				throw new Exception("Could not process HL7 message.  No HL7 definition is enabled.");
			}
			HL7DefMessage hl7defmsg=null;
			for(int i=0;i<def.hl7DefMessages.Count;i++) {
				if(def.hl7DefMessages[i].MessageType==msg.MsgType) {//&& def.hl7DefMessages[i].EventType==msg.EventType) { //Ignoring event type for now, we will treat all ADT's and SIU's the same
					hl7defmsg=def.hl7DefMessages[i];
				}
			}
			if(hl7defmsg==null) {//No message definition matches this message's MessageType and EventType
				HL7MsgCur.Note="Could not process HL7 message.  No definition for this type of message in the enabled HL7Def.";
				HL7Msgs.Update(HL7MsgCur);
				throw new Exception("Could not process HL7 message.  No definition for this type of message in the enabled HL7Def.");
			}
			string chartNum=null;
			long patNum=0;
			DateTime birthdate=DateTime.MinValue;
			string patLName=null;
			string patFName=null;
			bool isExistingPID=false;//Needed to add note to hl7msg table if there isn't a PID segment in the message.
			//Get patient in question, incoming messages must have a PID segment so use that to find the pat in question
			for(int s=0;s<hl7defmsg.hl7DefSegments.Count;s++) {
				if(hl7defmsg.hl7DefSegments[s].SegmentName!=SegmentNameHL7.PID) {
					continue;
				}
				int pidOrder=hl7defmsg.hl7DefSegments[s].ItemOrder;
				//we found the PID segment in the def, make sure it exists in the msg
				if(msg.Segments.Count<=pidOrder //If the number of segments in the message is less than the item order of the PID segment
					|| msg.Segments[pidOrder].GetField(0).ToString()!="PID" //Or if the segment we expect to be the PID segment is not the PID segment
				) {
					break;
				}
				isExistingPID=true;
				for(int f=0;f<hl7defmsg.hl7DefSegments[s].hl7DefFields.Count;f++) {//Go through fields of PID segment and get patnum, chartnum, patient name, and/or birthdate to locate patient
					if(hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName=="pat.ChartNumber") {
						int chartNumOrdinal=hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
						chartNum=msg.Segments[pidOrder].Fields[chartNumOrdinal].ToString();
					}
					else if(hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName=="pat.PatNum") {
						int patNumOrdinal=hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
						patNum=PIn.Long(msg.Segments[pidOrder].Fields[patNumOrdinal].ToString());
					}
					else if(hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName=="pat.birthdateTime") {
						int patBdayOrdinal=hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
						birthdate=FieldParser.DateTimeParse(msg.Segments[pidOrder].Fields[patBdayOrdinal].ToString());
					}
					else if(hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName=="pat.nameLFM") {
						int patNameOrdinal=hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
						patLName=msg.Segments[pidOrder].GetFieldComponent(patNameOrdinal,0);
						patFName=msg.Segments[pidOrder].GetFieldComponent(patNameOrdinal,1);
					}
				}
			}
			if(!isExistingPID) {
				HL7MsgCur.Note="Could not process the HL7 message due to missing PID segment.";
				HL7Msgs.Update(HL7MsgCur);
				throw new Exception("Could not process HL7 message.  Could not process the HL7 message due to missing PID segment.");
			}
			//We now have patnum, chartnum, patname, and/or birthdate so locate pat
			Patient pat=null;
			Patient patOld=null;
			if(patNum!=0) {
				pat=Patients.GetPat(patNum);
			}
			if(def.InternalType!="eCWStandalone" && pat==null) {
				IsNewPat=true;
			}
			//In eCWstandalone integration, if we couldn't locate patient by patNum or patNum was 0 then pat will still be null so try to locate by chartNum if chartNum is not null
			if(def.InternalType=="eCWStandalone" && chartNum!=null) {
				pat=Patients.GetPatByChartNumber(chartNum);
			}
			//In eCWstandalone integration, if pat is still null we need to try to locate patient by name and birthdate
			if(def.InternalType=="eCWStandalone" && pat==null) {
				long patNumByName=Patients.GetPatNumByNameAndBirthday(patLName,patFName,birthdate);
				//If patNumByName is 0 we couldn't locate by patNum, chartNum or name and birthdate so this message must be for a new patient
				if(patNumByName==0) {
					IsNewPat=true;
				}
				else {
					pat=Patients.GetPat(patNumByName);
					patOld=pat.Copy();
					pat.ChartNumber=chartNum;//from now on, we will be able to find pat by chartNumber
					Patients.Update(pat,patOld);
				}
			}
			if(IsNewPat) {
				pat=new Patient();
				if(chartNum!=null) {
					pat.ChartNumber=chartNum;
				}
				if(patNum!=0) {
					pat.PatNum=patNum;
					pat.Guarantor=patNum;
				}
				pat.PriProv=PrefC.GetLong(PrefName.PracticeDefaultProv);
				pat.BillingType=PrefC.GetLong(PrefName.PracticeDefaultBillType);
			}
			else {
				patOld=pat.Copy();
			}
			//Update hl7msg table with correct PatNum for this message
			HL7MsgCur.PatNum=pat.PatNum;
			HL7Msgs.Update(HL7MsgCur);
			//If this is a message that contains an SCH segment, loop through to find the AptNum.  Pass it to the other segments that will need it.
			long aptNum=0;
			for(int s=0;s<hl7defmsg.hl7DefSegments.Count;s++) {
				if(hl7defmsg.hl7DefSegments[s].SegmentName!=SegmentNameHL7.SCH) {
					continue;
				}
				//we found the SCH segment
				int schOrder=hl7defmsg.hl7DefSegments[s].ItemOrder;
				for(int f=0;f<hl7defmsg.hl7DefSegments[s].hl7DefFields.Count;f++) {//Go through fields of SCH segment and get AptNum
					if(hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName=="apt.AptNum") {
						int aptNumOrdinal=hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
						aptNum=PIn.Long(msg.Segments[schOrder].Fields[aptNumOrdinal].ToString());
					}
				}
			}
			//We now have a patient object , either loaded from the db or new, and aptNum so process this message for this patient
			//We need to insert the pat to get a patnum so we can compare to guar patnum to see if relationship to guar is self
			if(IsNewPat) {
				if(isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Inserted patient: "+pat.FName+" "+pat.LName,EventLogEntryType.Information);
				}
				if(pat.PatNum==0) {
					pat.PatNum=Patients.Insert(pat,false);
				}
				else {
					pat.PatNum=Patients.Insert(pat,true);
				}
				patOld=pat.Copy();
			}
			for(int i=0;i<hl7defmsg.hl7DefSegments.Count;i++) {
				try {
					SegmentHL7 seg=msg.GetSegment(hl7defmsg.hl7DefSegments[i].SegmentName,!hl7defmsg.hl7DefSegments[i].IsOptional);
					if(seg!=null) {//null if segment was not found but is optional
						ProcessSeg(pat,aptNum,hl7defmsg.hl7DefSegments[i],seg,msg);
					}
				}
				catch(ApplicationException ex) {//Required segment was missing, or other error.
					HL7MsgCur.Note="Could not process this HL7 message.  "+ex;
					HL7Msgs.Update(HL7MsgCur);
					throw new Exception("Could not process HL7 message.  "+ex);
				}
			}
			//We have processed the message so now update or insert the patient
			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);
				HL7MsgCur.Note="Patient demographics not processed due to missing first or last name. PatNum:"+pat.PatNum.ToString();
				HL7Msgs.Update(HL7MsgCur);
				return;
			}
			if(IsNewPat) {
				if(pat.Guarantor==0) {
					pat.Guarantor=pat.PatNum;
					Patients.Update(pat,patOld);
				}
				else {
					Patients.Update(pat,patOld);
				}
			}
			else {
				if(isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Updated patient: "+pat.FName+" "+pat.LName,EventLogEntryType.Information);
				}
				Patients.Update(pat,patOld);
			}
			HL7MsgCur.HL7Status=HL7MessageStatus.InProcessed;
			HL7Msgs.Update(HL7MsgCur);
		}