//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); }