Example #1
0
 private void EcwOldTimerCallbackSendFunction(Object stateInfo)
 {
     //does not happen for standalone
     if (_ecwOldIsSending)             //if there is a thread that is still sending, return
     {
         return;
     }
     try {
         _ecwOldIsSending = true;
         if (IsVerboseLogging)
         {
             EventLog.WriteEntry("GetOnePending Start");
         }
         List <HL7Msg> list = HL7Msgs.GetOnePending();
         if (IsVerboseLogging)
         {
             EventLog.WriteEntry("GetOnePending Finished");
         }
         string filename;
         for (int i = 0; i < list.Count; i++)           //Right now, there will only be 0 or 1 item in the list.
         {
             if (list[i].AptNum == 0)
             {
                 filename = ODFileUtils.CreateRandomFile(ecwOldHl7FolderIn, ".txt");
             }
             else
             {
                 filename = Path.Combine(ecwOldHl7FolderIn, list[i].AptNum.ToString() + ".txt");
             }
             //EventLog.WriteEntry("Attempting to create file: "+filename);
             File.WriteAllText(filename, list[i].MsgText);
             list[i].HL7Status = HL7MessageStatus.OutSent;
             HL7Msgs.Update(list[i]);                    //set the status to sent.
         }
         if (_ecwOldDateTimeOldMsgsDeleted.Date < DateTime.Now.Date)
         {
             if (IsVerboseLogging)
             {
                 EventLog.WriteEntry("DeleteOldMsgText Starting");
             }
             _ecwOldDateTimeOldMsgsDeleted = DateTime.Now;
             HL7Msgs.DeleteOldMsgText();                    //this function deletes if DateTStamp is less than CURDATE-INTERVAL 4 MONTH.  That means it will delete message text only once a day, not time based.
             if (IsVerboseLogging)
             {
                 EventLog.WriteEntry("DeleteOldMsgText Finished");
             }
         }
     }
     catch (Exception ex) {
         EventLog.WriteEntry("OpenDentHL7 error when sending HL7 message: " + ex.Message, EventLogEntryType.Warning);             //Warning because the service will spawn a new thread in 1.8 seconds
     }
     finally {
         _ecwOldIsSending = false;
     }
 }
Example #2
0
        private void TimerCallbackSendFiles(Object stateInfo)
        {
            List <HL7Msg> list = HL7Msgs.GetOnePending();
            string        filename;

            for (int i = 0; i < list.Count; i++)       //Right now, there will only be 0 or 1 item in the list.
            {
                filename = ODFileUtils.CreateRandomFile(hl7FolderOut, ".txt");
                File.WriteAllText(filename, list[i].MsgText);
                list[i].HL7Status = HL7MessageStatus.OutSent;
                HL7Msgs.Update(list[i]);                //set the status to sent.
                HL7Msgs.DeleteOldMsgText();             //This is inside the loop so that it happens less frequently.  To clean up incoming messages, we may move this someday.
            }
        }
Example #3
0
        private void TimerCallbackSendFunction(Object stateInfo)
        {
            //does not happen for standalone
            List <HL7Msg> list = HL7Msgs.GetOnePending();
            string        filename;

            for (int i = 0; i < list.Count; i++)
            {
                if (list[i].AptNum == 0)
                {
                    filename = ODFileUtils.CreateRandomFile(hl7FolderIn, ".txt");
                }
                else
                {
                    filename = Path.Combine(hl7FolderIn, list[i].AptNum.ToString() + ".txt");
                }
                //EventLog.WriteEntry("Attempting to create file: "+filename);
                File.WriteAllText(filename, list[i].MsgText);
                list[i].HL7Status = HL7MessageStatus.OutSent;
                HL7Msgs.Update(list[i]);                //set the status to sent.
            }
        }
Example #4
0
        private void EcwOldTimerCallbackSendFunction(Object stateInfo)
        {
            //does not happen for standalone
            List <HL7Msg> list = HL7Msgs.GetOnePending();
            string        filename;

            for (int i = 0; i < list.Count; i++)       //Right now, there will only be 0 or 1 item in the list.
            {
                if (list[i].AptNum == 0)
                {
                    filename = ODFileUtils.CreateRandomFile(ecwOldHl7FolderIn, ".txt");
                }
                else
                {
                    filename = Path.Combine(ecwOldHl7FolderIn, list[i].AptNum.ToString() + ".txt");
                }
                //EventLog.WriteEntry("Attempting to create file: "+filename);
                File.WriteAllText(filename, list[i].MsgText);
                list[i].HL7Status = HL7MessageStatus.OutSent;
                HL7Msgs.Update(list[i]);                //set the status to sent.
                HL7Msgs.DeleteOldMsgText();             //This is inside the loop so that it happens less frequently.  To clean up incoming messages, we may move this someday.
            }
        }
Example #5
0
 private void butOK_Click(object sender, EventArgs e)
 {
     MsgCur.Note = textNote.Text;
     HL7Msgs.Update(MsgCur);
     DialogResult = DialogResult.OK;
 }
Example #6
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);
        }
Example #7
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;
        }
Example #8
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 #9
0
        private void TimerCallbackSendTCP(Object stateInfo)
        {
            List <HL7Msg> list = HL7Msgs.GetOnePending();

            for (int i = 0; i < list.Count; i++)                                       //Right now, there will only be 0 or 1 item in the list.
            {
                string     sendMsgControlId = HL7Msgs.GetControlId(list[i]);           //could be empty string
                Socket     socket           = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                string[]   strIpPort        = HL7DefEnabled.OutgoingIpPort.Split(':'); //this was already validated in the HL7DefEdit window.
                IPAddress  ipaddress        = IPAddress.Parse(strIpPort[0]);           //already validated
                int        port             = int.Parse(strIpPort[1]);                 //already validated
                IPEndPoint endpoint         = new IPEndPoint(ipaddress, port);
                try {
                    socket.Connect(endpoint);
                    if (!IsSendTCPConnected)                     //Previous run failed to connect. This time connected so make log entry that connection was successful
                    {
                        EventLog.WriteEntry("OpenDentHL7", "The HL7 send TCP/IP socket connection failed to connect previously and was successful this time.", EventLogEntryType.Information);
                        IsSendTCPConnected = true;
                    }
                }
                catch (SocketException ex) {
                    if (IsSendTCPConnected)                     //Previous run connected fine, make log entry and set bool to false
                    {
                        EventLog.WriteEntry("OpenDentHL7", "The HL7 send TCP/IP socket connection failed to connect.\r\nException: " + ex.Message, EventLogEntryType.Warning);
                        IsSendTCPConnected = false;
                    }
                    return;
                }
                string data = MLLP_START_CHAR + list[i].MsgText + MLLP_END_CHAR + MLLP_ENDMSG_CHAR;
                try {
                    byte[] byteData = Encoding.ASCII.GetBytes(data);
                    socket.Send(byteData);                                //this is a blocking call
                    //For MLLP V2, do a blocking Receive here, along with a timeout.
                    byte[] ackBuffer = new byte[256];                     //plenty big enough to receive the entire ack/nack response
                    socket.ReceiveTimeout = 5000;                         //5 second timeout. Database is polled every 6 seconds for a new message to send, 5 second wait for acknowledgment
                    int    byteCountReceived = socket.Receive(ackBuffer); //blocking Receive
                    char[] chars             = new char[byteCountReceived];
                    Encoding.UTF8.GetDecoder().GetChars(ackBuffer, 0, byteCountReceived, chars, 0);
                    StringBuilder strbAckMsg = new StringBuilder();
                    strbAckMsg.Append(chars);
                    if (strbAckMsg.Length > 0 && strbAckMsg[0] != MLLP_START_CHAR)
                    {
                        list[i].Note = list[i].Note + "Malformed acknowledgment.\r\n";
                        HL7Msgs.Update(list[i]);
                        throw new Exception("Malformed acknowledgment.");
                    }
                    else if (strbAckMsg.Length >= 3 &&
                             strbAckMsg[strbAckMsg.Length - 1] == MLLP_ENDMSG_CHAR &&               //last char is the endmsg char.
                             strbAckMsg[strbAckMsg.Length - 2] == MLLP_END_CHAR)                  //the second-to-the-last char is the end char.
                    {
                        //we have a complete message
                        strbAckMsg.Remove(0, 1);                       //strip off the start char
                        strbAckMsg.Remove(strbAckMsg.Length - 2, 2);   //strip off the end chars
                    }
                    else if (strbAckMsg.Length >= 2 &&              //so that the next line won't crash
                             strbAckMsg[strbAckMsg.Length - 1] == MLLP_END_CHAR)                  //the last char is the end char.
                    {
                        //we will treat this as a complete message, because the endmsg char is optional.
                        strbAckMsg.Remove(0, 1);                       //strip off the start char
                        strbAckMsg.Remove(strbFullMsg.Length - 1, 1);  //strip off the end char
                    }
                    else
                    {
                        list[i].Note = list[i].Note + "Malformed acknowledgment.\r\n";
                        HL7Msgs.Update(list[i]);
                        throw new Exception("Malformed acknowledgment.");
                    }
                    MessageHL7 ackMsg = new MessageHL7(strbAckMsg.ToString());
                    try {
                        MessageParser.ProcessAck(ackMsg, IsVerboseLogging);
                    }
                    catch (Exception ex) {
                        list[i].Note = list[i].Note + ackMsg.ToString() + "\r\nError processing acknowledgment.\r\n";
                        HL7Msgs.Update(list[i]);
                        throw new Exception("Error processing acknowledgment.\r\n" + ex.Message);
                    }
                    if (ackMsg.AckCode == "" || ackMsg.ControlId == "")
                    {
                        list[i].Note = list[i].Note + ackMsg.ToString() + "\r\nInvalid ACK message.  Attempt to resend.\r\n";
                        HL7Msgs.Update(list[i]);
                        throw new Exception("Invalid ACK message received.");
                    }
                    if (ackMsg.ControlId == sendMsgControlId && ackMsg.AckCode == "AA")                 //acknowledged received (Application acknowledgment: Accept)
                    {
                        list[i].Note = list[i].Note + ackMsg.ToString() + "\r\nMessage ACK (acknowledgment) received.\r\n";
                    }
                    else if (ackMsg.ControlId == sendMsgControlId && ackMsg.AckCode != "AA") //ACK received for this message, but ack code was not acknowledgment accepted
                    {
                        if (list[i].Note.Contains("NACK4"))                                  //this is the 5th negative acknowledgment, don't try again
                        {
                            list[i].Note      = list[i].Note + "Ack code: " + ackMsg.AckCode + "\r\nThis is NACK5, the message status has been changed to OutFailed. We will not attempt to send again.\r\n";
                            list[i].HL7Status = HL7MessageStatus.OutFailed;
                        }
                        else if (list[i].Note.Contains("NACK"))                         //failed sending at least once already
                        {
                            list[i].Note = list[i].Note + "Ack code: " + ackMsg.AckCode + "\r\nNACK" + list[i].Note.Split(new string[] { "NACK" }, StringSplitOptions.None).Length + "\r\n";
                        }
                        else
                        {
                            list[i].Note = list[i].Note + "Ack code: " + ackMsg.AckCode + "\r\nMessage NACK (negative acknowlegment) received. We will try to send again.\r\n";
                        }
                        HL7Msgs.Update(list[i]); //Add NACK note to hl7msg table entry
                        return;                  //socket closed in finally
                    }
                    else                         //ack received for control ID that does not match the control ID of message just sent
                    {
                        list[i].Note = list[i].Note + "Sent message control ID: " + sendMsgControlId + "\r\nAck message control ID: " + ackMsg.ControlId
                                       + "\r\nAck received for message other than message just sent.  We will try to send again.\r\n";
                        HL7Msgs.Update(list[i]);
                        return;
                    }
                }
                catch (SocketException ex) {
                    EventLog.WriteEntry("OpenDentHL7", "The HL7 send TCP/IP socket encountered an error when sending message or receiving acknowledgment.\r\nSocket Exception: " + ex.Message, EventLogEntryType.Warning);
                    return;                    //Try again in 3 seconds. socket closed in finally
                }
                catch (Exception ex) {
                    EventLog.WriteEntry("OpenDentHL7", "The HL7 send TCP/IP encountered an error when sending message or receiving acknowledgment.\r\nException: " + ex.Message, EventLogEntryType.Warning);
                    return;                    //socket closed in finally
                }
                finally {
                    if (socket != null)
                    {
                        socket.Shutdown(SocketShutdown.Both);
                        socket.Close();
                    }
                }
                list[i].HL7Status = HL7MessageStatus.OutSent;
                HL7Msgs.Update(list[i]);                //set the status to sent and save ack message in Note field.
                HL7Msgs.DeleteOldMsgText();             //This is inside the loop so that it happens less frequently.  To clean up incoming messages, we may move this someday.
            }
        }