Exemple #1
0
        ///<summary>Gets the message control ID of the message we are attempting to send, for TCP/IP acknowledgment.</summary>
        public static string GetControlId(HL7Msg msg)
        {
            string retval = "";

            if (msg == null)
            {
                return(retval);
            }
            int        controlIdOrder = 0;
            MessageHL7 msgHl7         = new MessageHL7(msg.MsgText);  //creates the segments
            HL7Def     def            = HL7Defs.GetOneDeepEnabled();

            if (def == null)
            {
                return(retval);
            }
            HL7DefMessage hl7defmsg = null;

            for (int i = 0; i < def.hl7DefMessages.Count; i++)
            {
                if (def.hl7DefMessages[i].MessageType == msgHl7.MsgType)
                {
                    hl7defmsg = def.hl7DefMessages[i];
                    break;
                }
            }
            if (hl7defmsg == null)           //No message definition for this type of message in the enabled def
            {
                return(retval);
            }
            for (int s = 0; s < hl7defmsg.hl7DefSegments.Count; s++)       //get MSH segment
            {
                if (hl7defmsg.hl7DefSegments[s].SegmentName == SegmentNameHL7.MSH)
                {
                    for (int f = 0; f < hl7defmsg.hl7DefSegments[s].hl7DefFields.Count; f++)               //find messageControlId field in MSH segment def
                    {
                        if (hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName == "messageControlId")
                        {
                            controlIdOrder = hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
                            break;
                        }
                    }
                    break;
                }
            }
            if (controlIdOrder == 0)           //No messageControlId defined for this MSH segment
            {
                return(retval);
            }
            for (int i = 0; i < msgHl7.Segments.Count; i++)       //get control ID from message located in MSH segment with field determined above
            {
                if (msgHl7.Segments[i].Name == SegmentNameHL7.MSH)
                {
                    retval = msgHl7.Segments[i].Fields[controlIdOrder].ToString();
                    break;
                }
            }
            return(retval);
        }
Exemple #2
0
        private void EcwOldProcessMessage(string fullPath)
        {
            string msgtext = "";
            int    i       = 0;

            while (i < 5)
            {
                try {
                    msgtext = File.ReadAllText(fullPath);
                    break;
                }
                catch {
                }
                Thread.Sleep(200);
                i++;
                if (i == 5)
                {
                    EventLog.WriteEntry("Could not read text from file due to file locking issues.", EventLogEntryType.Error);
                    return;
                }
            }
            try {
                MessageHL7 msg = new MessageHL7(msgtext);              //this creates an entire heirarchy of objects.
                if (msg.MsgType == MessageTypeHL7.ADT)
                {
                    if (IsVerboseLogging)
                    {
                        EventLog.WriteEntry("OpenDentHL7", "Processed ADT message", EventLogEntryType.Information);
                    }
                    EcwADT.ProcessMessage(msg, ecwOldIsStandalone, IsVerboseLogging);
                }
                else if (msg.MsgType == MessageTypeHL7.SIU && !ecwOldIsStandalone)               //appointments don't get imported if standalone mode.
                {
                    if (IsVerboseLogging)
                    {
                        EventLog.WriteEntry("OpenDentHL7", "Processed SUI message", EventLogEntryType.Information);
                    }
                    EcwSIU.ProcessMessage(msg, IsVerboseLogging);
                }
            }
            catch (Exception ex) {
                EventLog.WriteEntry(ex.Message + "\r\n" + ex.StackTrace, EventLogEntryType.Error);
                return;
            }
            //we won't be processing DFT messages.
            //else if(msg.MsgType==MessageType.DFT) {
            //ADT.ProcessMessage(msg);
            //}
            try {
                File.Delete(fullPath);
            }
            catch (Exception ex) {
                EventLog.WriteEntry("Delete failed for " + fullPath + "\r\n" + ex.Message, EventLogEntryType.Error);
            }
        }
Exemple #3
0
        /// <summary>Helper method to send given appt to the unscheduled list.
        /// Creates SecurityLogs and considers HL7.</summary>
        public static void SetApptUnschedHelper(Appointment appt, Patient pat = null, bool doFireApptEvent = true)
        {
            DateTime datePrevious = appt.DateTStamp;

            Appointments.SetAptStatus(appt, ApptStatus.UnschedList); //Appointments S-Class handles Signalods
            #region SecurityLogs
            if (appt.AptStatus != ApptStatus.Complete)               //seperate log entry for editing completed appts.
            {
                SecurityLogs.MakeLogEntry(Permissions.AppointmentMove, appt.PatNum,
                                          appt.ProcDescript + ", " + appt.AptDateTime.ToString() + ", Sent to Unscheduled List",
                                          appt.AptNum, datePrevious);
            }
            else
            {
                SecurityLogs.MakeLogEntry(Permissions.AppointmentCompleteEdit, appt.PatNum,
                                          appt.ProcDescript + ", " + appt.AptDateTime.ToString() + ", Sent to Unscheduled List",
                                          appt.AptNum, datePrevious);
            }
            #endregion
            #region HL7
            //If there is an existing HL7 def enabled, send a SIU message if there is an outbound SIU message defined
            if (HL7Defs.IsExistingHL7Enabled())
            {
                if (pat == null)
                {
                    pat = Patients.GetPat(appt.PatNum);
                }
                //S15 - Appt Cancellation event
                MessageHL7 messageHL7 = MessageConstructor.GenerateSIU(pat, Patients.GetPat(pat.Guarantor), EventTypeHL7.S15, appt);
                //Will be null if there is no outbound SIU message defined, so do nothing
                if (messageHL7 != null)
                {
                    HL7Msg hl7Msg = new HL7Msg();
                    hl7Msg.AptNum    = appt.AptNum;
                    hl7Msg.HL7Status = HL7MessageStatus.OutPending;                  //it will be marked outSent by the HL7 service.
                    hl7Msg.MsgText   = messageHL7.ToString();
                    hl7Msg.PatNum    = pat.PatNum;
                    HL7Msgs.Insert(hl7Msg);
#if DEBUG
                    MessageBox.Show("Appointments", messageHL7.ToString());
#endif
                }
            }
            #endregion
            if (doFireApptEvent)
            {
                AppointmentEvent.Fire(ODEventType.AppointmentEdited, appt);
            }
            Recalls.SynchScheduledApptFull(appt.PatNum);
        }
Exemple #4
0
        ///<summary>Reprocess the original HL7 msgs for any MedLabs with PatNum 0, creates the embedded PDF files from the base64 text in the ZEF segments
        ///<para>The old method used when parsing MedLab HL7 msgs was to wait to extract these files until the msg was manually associated with a patient.
        ///Associating the MedLabs to a patient and reprocessing the HL7 messages using middle tier was very slow.</para>
        ///<para>The new method is to create the PDF files and save them in the image folder in a subdirectory called "MedLabEmbeddedFiles" if a patient
        ///isn't located from the details in the PID segment of the message.  Associating the MedLabs to a pat is now just a matter of moving the files to
        ///the pat's image folder and updating the PatNum columns.  All files are now extracted and stored, either in a pat's folder or in the
        ///"MedLabEmbeddedFiles" folder, by the HL7 service.</para>
        ///<para>This will reprocess all HL7 messages for MedLabs with PatNum=0 and replace the MedLab, MedLabResult, MedLabSpecimen, and MedLabFacAttach
        ///rows as well as create any embedded files and insert document table rows.  The document table rows will have PatNum=0, just like the MedLabs,
        ///if a pat is still not located with the details in the PID segment.  Once the user manually attaches the MedLab to a patient, all rows will be
        ///updated with the correct PatNum and the embedded PDFs will be moved to the pat's image folder.  The document.FileName column will contain the
        ///name of the file, regardless of where it is located.  The file name will be updated to a relevant name for the folder in which it is located.
        ///i.e. in the MedLabEmbeddedFiles directory it may be named 3YG8Z420150909100527.pdf, but once moved to a pat's folder it will be renamed to
        ///something like PatientAustin375.pdf and the document.FileName column will be the current name.</para>
        ///<para>If storing images in the db, the document table rows will contain the base64 text version of the PDFs with PatNum=0 and will be updated
        ///with the correct PatNum once associated.  The FileName will be just the extension ".pdf" until it is associated with a patient at which time it
        ///will be updated to something like PatientAustin375.pdf.</para></summary>
        public static int Reconcile()
        {
            if (RemotingClient.RemotingRole == RemotingRole.ClientWeb)
            {
                return(Meth.GetInt(MethodBase.GetCurrentMethod()));
            }
            string        command     = "SELECT * FROM medlab WHERE PatNum=0";
            List <MedLab> listMedLabs = Crud.MedLabCrud.SelectMany(command);

            if (listMedLabs.Count < 1)
            {
                return(0);
            }
            List <long> listMedLabNumsNew = new List <long>();        //used to delete old MedLab objects after creating these new ones from the HL7 message text
            int         failedCount       = 0;

            foreach (string relativePath in listMedLabs.Select(x => x.FileName).Distinct().ToList())
            {
                string fileTextCur = "";
                try {
                    if (PrefC.AtoZfolderUsed != DataStorageType.InDatabase)
                    {
                        fileTextCur = FileAtoZ.ReadAllText(FileAtoZ.CombinePaths(ImageStore.GetPreferredAtoZpath(), relativePath));
                    }
                }
                catch (Exception ex) {
                    ex.DoNothing();                    //To avoid a warning message.  The ex is needed to ensure all exceptions are caught.
                    failedCount++;
                    continue;
                }
                MessageHL7  msg = new MessageHL7(fileTextCur);
                List <long> listMedLabNumsCur = MessageParserMedLab.Process(msg, relativePath, false);           //re-creates the documents from the ZEF segments
                if (listMedLabNumsCur == null || listMedLabNumsCur.Count < 1)
                {
                    failedCount++;
                    continue;                    //not sure what to do, just move on?
                }
                listMedLabNumsNew.AddRange(listMedLabNumsCur);
                MedLabs.UpdateFileNames(listMedLabNumsCur, relativePath);
            }
            //Delete all MedLabs, MedLabResults, MedLabSpecimens, and MedLabFacAttaches except the ones just created
            //Don't delete until we successfully process the messages and have valid new MedLab objects
            foreach (MedLab medLab in listMedLabs)
            {
                failedCount += DeleteLabsAndResults(medLab, listMedLabNumsNew);
            }
            return(failedCount);
        }
 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.");
     }
 }
        private void CreateLabPanel()
        {
            MedicalOrder order = listLabOrders[gridMain.GetSelectedIndex()];
            MessageHL7   msg   = new MessageHL7(textHL7Raw.Text);
            //SegmentHL7 segOBR=null;
            //SegmentHL7 segOBX=null;
            //int idxPanel=0;
            //int idxResult=0;
            LabPanel  panel  = null;
            LabResult result = null;

            //loop through all message segments.
            for (int i = 0; i < msg.Segments.Count; i++)
            {
                if (msg.Segments[i].Name == SegmentNameHL7.OBR)              //if this is the start of a new panel
                {
                    panel                   = new LabPanel();
                    panel.PatNum            = order.PatNum;
                    panel.MedicalOrderNum   = order.MedicalOrderNum;
                    panel.RawMessage        = textHL7Raw.Text;
                    panel.LabNameAddress    = msg.Segments[i].GetFieldFullText(20);
                    panel.SpecimenSource    = msg.Segments[i].GetFieldFullText(15);
                    panel.SpecimenCondition = msg.Segments[i].GetFieldFullText(13);
                    panel.ServiceId         = msg.Segments[i].GetFieldComponent(4, 0);
                    panel.ServiceName       = msg.Segments[i].GetFieldComponent(4, 1);
                    LabPanels.Insert(panel);
                }
                if (msg.Segments[i].Name == SegmentNameHL7.OBX)              //if this is a result within a panel
                {
                    result              = new LabResult();
                    result.LabPanelNum  = panel.LabPanelNum;
                    result.DateTimeTest = msg.Segments[i].GetDateTime(14);
                    result.TestID       = msg.Segments[i].GetFieldComponent(3, 0);
                    result.TestName     = msg.Segments[i].GetFieldComponent(3, 1);
                    result.ObsValue     = msg.Segments[i].GetFieldFullText(5);
                    result.ObsUnits     = msg.Segments[i].GetFieldFullText(6);
                    result.ObsRange     = msg.Segments[i].GetFieldFullText(7);
                    LabResults.Insert(result);
                }
                //any other kind of segment, continue.
            }
            //order.IsLabPending=false;
            //MedicalOrders.Update(order);
            //return true;//I guess it's always true?
        }
Exemple #7
0
        private void ProcessMessageFile(string fullPath)
        {
            string msgtext = "";
            int    i       = 0;

            while (i < 5)
            {
                try {
                    msgtext = File.ReadAllText(fullPath);
                    break;
                }
                catch {
                }
                Thread.Sleep(200);
                i++;
                if (i == 5)
                {
                    EventLog.WriteEntry("Could not read text from file due to file locking issues.", EventLogEntryType.Error);
                    return;
                }
            }
            try {
                MessageHL7 msg = new MessageHL7(msgtext);              //this creates an entire heirarchy of objects.
                MessageParser.Process(msg, IsVerboseLogging);
                if (IsVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Processed message " + msg.MsgType.ToString(), EventLogEntryType.Information);
                }
            }
            catch (Exception ex) {
                EventLog.WriteEntry(ex.Message + "\r\n" + ex.StackTrace, EventLogEntryType.Error);
                return;
            }
            try {
                File.Delete(fullPath);
            }
            catch (Exception ex) {
                EventLog.WriteEntry("Delete failed for " + fullPath + "\r\n" + ex.Message, EventLogEntryType.Error);
            }
        }
Exemple #8
0
        ///<summary>Creates a single recall appointment. If it's from a double click, then it will end up on that spot in the Appts module.  If not, it will end up on the pinboard with StringDateJumpTo as due date to jump to.  ListAptNumsSelected will contain the AptNum of the new appointment.</summary>
        public void MakeRecallAppointment()
        {
            List <InsSub>  listInsSubs  = InsSubs.RefreshForFam(_famCur);
            List <InsPlan> listInsPlans = InsPlans.RefreshForSubList(listInsSubs);
            Appointment    apt          = null;
            DateTime       dateTimeApt  = DateTime.MinValue;

            if (this.IsInitialDoubleClick)
            {
                dateTimeApt = DateTimeClicked;
            }
            try{
                apt = AppointmentL.CreateRecallApt(_patCur, listInsPlans, -1, listInsSubs, dateTimeApt);
            }
            catch (Exception ex) {
                MessageBox.Show(ex.Message);
                return;
            }
            DateTime datePrevious = apt.DateTStamp;

            ListAptNumsSelected.Add(apt.AptNum);
            if (IsInitialDoubleClick)
            {
                Appointment oldApt = apt.Copy();
                if (_patCur.AskToArriveEarly > 0)
                {
                    apt.DateTimeAskedToArrive = apt.AptDateTime.AddMinutes(-_patCur.AskToArriveEarly);
                    MessageBox.Show(Lan.g(this, "Ask patient to arrive") + " " + _patCur.AskToArriveEarly
                                    + " " + Lan.g(this, "minutes early at") + " " + apt.DateTimeAskedToArrive.ToShortTimeString() + ".");
                }
                apt.AptStatus = ApptStatus.Scheduled;
                apt.ClinicNum = _patCur.ClinicNum;
                apt.Op        = OpNumClicked;
                apt           = Appointments.AssignFieldsForOperatory(apt);
                //Use apt.ClinicNum because it was just set based on Op.ClinicNum in AssignFieldsForOperatory().
                if (!AppointmentL.IsSpecialtyMismatchAllowed(_patCur.PatNum, apt.ClinicNum))
                {
                    return;
                }
                Appointments.Update(apt, oldApt);
                _otherResult = OtherResult.CreateNew;
                SecurityLogs.MakeLogEntry(Permissions.AppointmentCreate, apt.PatNum, apt.AptDateTime.ToString(), apt.AptNum, datePrevious);
                //If there is an existing HL7 def enabled, send a SIU message if there is an outbound SIU message defined
                if (HL7Defs.IsExistingHL7Enabled())
                {
                    //S12 - New Appt Booking event
                    MessageHL7 messageHL7 = MessageConstructor.GenerateSIU(_patCur, _famCur.GetPatient(_patCur.Guarantor), EventTypeHL7.S12, apt);
                    //Will be null if there is no outbound SIU message defined, so do nothing
                    if (messageHL7 != null)
                    {
                        HL7Msg hl7Msg = new HL7Msg();
                        hl7Msg.AptNum    = apt.AptNum;
                        hl7Msg.HL7Status = HL7MessageStatus.OutPending;                      //it will be marked outSent by the HL7 service.
                        hl7Msg.MsgText   = messageHL7.ToString();
                        hl7Msg.PatNum    = _patCur.PatNum;
                        HL7Msgs.Insert(hl7Msg);
#if DEBUG
                        MessageBox.Show(this, messageHL7.ToString());
#endif
                    }
                }
                DialogResult = DialogResult.OK;
                return;
            }
            //not initialClick
            _otherResult = OtherResult.PinboardAndSearch;
            Recall recall = Recalls.GetRecallProphyOrPerio(_patCur.PatNum);          //shouldn't return null.
            if (recall.DateDue < DateTime.Today)
            {
                StringDateJumpTo = DateTime.Today.ToShortDateString();              //they are overdue
            }
            else
            {
                StringDateJumpTo = recall.DateDue.ToShortDateString();
            }
            //no securitylog entry needed here.  That will happen when it's dragged off pinboard.
            DialogResult = DialogResult.OK;
        }
Exemple #9
0
        ///<summary>Sets given appt.AptStatus to broken.
        ///Provide procCode that should be charted, can be null but will not chart a broken procedure.
        ///Also considers various broken procedure based prefs.
        ///Makes its own securitylog entries.</summary>
        public static void BreakApptHelper(Appointment appt, Patient pat, ProcedureCode procCode)
        {
            //suppressHistory is true due to below logic creating a log with a specific HistAppointmentAction instead of the generic changed.
            DateTime datePrevious    = appt.DateTStamp;
            bool     suppressHistory = false;

            if (procCode != null)
            {
                suppressHistory = (procCode.ProcCode.In("D9986", "D9987"));
            }
            Appointments.SetAptStatus(appt, ApptStatus.Broken, suppressHistory); //Appointments S-Class handles Signalods
            if (appt.AptStatus != ApptStatus.Complete)                           //seperate log entry for completed appointments.
            {
                SecurityLogs.MakeLogEntry(Permissions.AppointmentEdit, pat.PatNum,
                                          appt.ProcDescript + ", " + appt.AptDateTime.ToString()
                                          + ", Broken from the Appts module.", appt.AptNum, datePrevious);
            }
            else
            {
                SecurityLogs.MakeLogEntry(Permissions.AppointmentCompleteEdit, pat.PatNum,
                                          appt.ProcDescript + ", " + appt.AptDateTime.ToString()
                                          + ", Broken from the Appts module.", appt.AptNum, datePrevious);
            }
            #region HL7
            //If there is an existing HL7 def enabled, send a SIU message if there is an outbound SIU message defined
            if (HL7Defs.IsExistingHL7Enabled())
            {
                //S15 - Appt Cancellation event
                MessageHL7 messageHL7 = MessageConstructor.GenerateSIU(pat, Patients.GetPat(pat.Guarantor), EventTypeHL7.S15, appt);
                //Will be null if there is no outbound SIU message defined, so do nothing
                if (messageHL7 != null)
                {
                    HL7Msg hl7Msg = new HL7Msg();
                    hl7Msg.AptNum    = appt.AptNum;
                    hl7Msg.HL7Status = HL7MessageStatus.OutPending;                  //it will be marked outSent by the HL7 service.
                    hl7Msg.MsgText   = messageHL7.ToString();
                    hl7Msg.PatNum    = pat.PatNum;
                    HL7Msgs.Insert(hl7Msg);
#if DEBUG
                    MessageBox.Show("Appointments", messageHL7.ToString());
#endif
                }
            }
            #endregion
            #region Charting the proc
            if (procCode != null)
            {
                switch (procCode.ProcCode)
                {
                case "D9986":                        //Missed
                    HistAppointments.CreateHistoryEntry(appt.AptNum, HistAppointmentAction.Missed);
                    break;

                case "D9987":                        //Cancelled
                    HistAppointments.CreateHistoryEntry(appt.AptNum, HistAppointmentAction.Cancelled);
                    break;
                }
                Procedure procedureCur = new Procedure();
                procedureCur.PatNum       = pat.PatNum;
                procedureCur.ProvNum      = (procCode.ProvNumDefault > 0 ? procCode.ProvNumDefault : appt.ProvNum);
                procedureCur.CodeNum      = procCode.CodeNum;
                procedureCur.ProcDate     = DateTime.Today;
                procedureCur.DateEntryC   = DateTime.Now;
                procedureCur.ProcStatus   = ProcStat.C;
                procedureCur.ClinicNum    = appt.ClinicNum;
                procedureCur.UserNum      = Security.CurUser.UserNum;
                procedureCur.Note         = Lans.g("AppointmentEdit", "Appt BROKEN for") + " " + appt.ProcDescript + "  " + appt.AptDateTime.ToString();
                procedureCur.PlaceService = (PlaceOfService)PrefC.GetInt(PrefName.DefaultProcedurePlaceService);              //Default proc place of service for the Practice is used.
                List <InsSub>  listInsSubs    = InsSubs.RefreshForFam(Patients.GetFamily(pat.PatNum));
                List <InsPlan> listInsPlans   = InsPlans.RefreshForSubList(listInsSubs);
                List <PatPlan> listPatPlans   = PatPlans.Refresh(pat.PatNum);
                InsPlan        insPlanPrimary = null;
                InsSub         insSubPrimary  = null;
                if (listPatPlans.Count > 0)
                {
                    insSubPrimary  = InsSubs.GetSub(listPatPlans[0].InsSubNum, listInsSubs);
                    insPlanPrimary = InsPlans.GetPlan(insSubPrimary.PlanNum, listInsPlans);
                }
                double procFee;
                long   feeSch;
                if (insPlanPrimary == null || procCode.NoBillIns)
                {
                    feeSch = FeeScheds.GetFeeSched(0, pat.FeeSched, procedureCur.ProvNum);
                }
                else                  //Only take into account the patient's insurance fee schedule if the D9986 procedure is not marked as NoBillIns
                {
                    feeSch = FeeScheds.GetFeeSched(insPlanPrimary.FeeSched, pat.FeeSched, procedureCur.ProvNum);
                }
                procFee = Fees.GetAmount0(procedureCur.CodeNum, feeSch, procedureCur.ClinicNum, procedureCur.ProvNum);
                if (insPlanPrimary != null && insPlanPrimary.PlanType == "p" && !insPlanPrimary.IsMedical)         //PPO
                {
                    double provFee = Fees.GetAmount0(procedureCur.CodeNum, Providers.GetProv(procedureCur.ProvNum).FeeSched, procedureCur.ClinicNum,
                                                     procedureCur.ProvNum);
                    procedureCur.ProcFee = Math.Max(provFee, procFee);
                }
                else
                {
                    procedureCur.ProcFee = procFee;
                }
                if (!PrefC.GetBool(PrefName.EasyHidePublicHealth))
                {
                    procedureCur.SiteNum = pat.SiteNum;
                }
                Procedures.Insert(procedureCur);
                //Now make a claimproc if the patient has insurance.  We do this now for consistency because a claimproc could get created in the future.
                List <Benefit>   listBenefits          = Benefits.Refresh(listPatPlans, listInsSubs);
                List <ClaimProc> listClaimProcsForProc = ClaimProcs.RefreshForProc(procedureCur.ProcNum);
                Procedures.ComputeEstimates(procedureCur, pat.PatNum, listClaimProcsForProc, false, listInsPlans, listPatPlans, listBenefits, pat.Age, listInsSubs);
                FormProcBroken FormPB = new FormProcBroken(procedureCur);
                FormPB.IsNew = true;
                FormPB.ShowDialog();
            }
            #endregion
            #region BrokenApptAdjustment
            if (PrefC.GetBool(PrefName.BrokenApptAdjustment))
            {
                Adjustment AdjustmentCur = new Adjustment();
                AdjustmentCur.DateEntry = DateTime.Today;
                AdjustmentCur.AdjDate   = DateTime.Today;
                AdjustmentCur.ProcDate  = DateTime.Today;
                AdjustmentCur.ProvNum   = appt.ProvNum;
                AdjustmentCur.PatNum    = pat.PatNum;
                AdjustmentCur.AdjType   = PrefC.GetLong(PrefName.BrokenAppointmentAdjustmentType);
                AdjustmentCur.ClinicNum = appt.ClinicNum;
                FormAdjust FormA = new FormAdjust(pat, AdjustmentCur);
                FormA.IsNew = true;
                FormA.ShowDialog();
            }
            #endregion
            #region BrokenApptCommLog
            if (PrefC.GetBool(PrefName.BrokenApptCommLog))
            {
                Commlog CommlogCur = new Commlog();
                CommlogCur.PatNum       = pat.PatNum;
                CommlogCur.CommDateTime = DateTime.Now;
                CommlogCur.CommType     = Commlogs.GetTypeAuto(CommItemTypeAuto.APPT);
                CommlogCur.Note         = Lan.g("Appointment", "Appt BROKEN for") + " " + appt.ProcDescript + "  " + appt.AptDateTime.ToString();
                CommlogCur.Mode_        = CommItemMode.None;
                CommlogCur.UserNum      = Security.CurUser.UserNum;
                FormCommItem FormCI = new FormCommItem();
                FormCI.ShowDialog(new CommItemModel()
                {
                    CommlogCur = CommlogCur
                }, new CommItemController(FormCI)
                {
                    IsNew = true
                });
            }
            #endregion
            AutomationL.Trigger(AutomationTrigger.BreakAppointment, null, pat.PatNum);
            Recalls.SynchScheduledApptFull(appt.PatNum);
        }
Exemple #10
0
        ///<summary>Sets given appt.AptStatus to broken.
        ///Provide procCode that should be charted, can be null but will not chart a broken procedure.
        ///Also considers various broken procedure based prefs.
        ///Makes its own securitylog entries.</summary>
        public static void BreakApptHelper(Appointment appt, Patient pat, ProcedureCode procCode)
        {
            //suppressHistory is true due to below logic creating a log with a specific HistAppointmentAction instead of the generic changed.
            DateTime datePrevious    = appt.DateTStamp;
            bool     suppressHistory = false;

            if (procCode != null)
            {
                suppressHistory = (procCode.ProcCode.In("D9986", "D9987"));
            }
            Appointments.SetAptStatus(appt, ApptStatus.Broken, suppressHistory); //Appointments S-Class handles Signalods
            if (appt.AptStatus != ApptStatus.Complete)                           //seperate log entry for completed appointments.
            {
                SecurityLogs.MakeLogEntry(Permissions.AppointmentEdit, pat.PatNum,
                                          appt.ProcDescript + ", " + appt.AptDateTime.ToString()
                                          + ", Broken from the Appts module.", appt.AptNum, datePrevious);
            }
            else
            {
                SecurityLogs.MakeLogEntry(Permissions.AppointmentCompleteEdit, pat.PatNum,
                                          appt.ProcDescript + ", " + appt.AptDateTime.ToString()
                                          + ", Broken from the Appts module.", appt.AptNum, datePrevious);
            }
            #region HL7
            //If there is an existing HL7 def enabled, send a SIU message if there is an outbound SIU message defined
            if (HL7Defs.IsExistingHL7Enabled())
            {
                //S15 - Appt Cancellation event
                MessageHL7 messageHL7 = MessageConstructor.GenerateSIU(pat, Patients.GetPat(pat.Guarantor), EventTypeHL7.S15, appt);
                //Will be null if there is no outbound SIU message defined, so do nothing
                if (messageHL7 != null)
                {
                    HL7Msg hl7Msg = new HL7Msg();
                    hl7Msg.AptNum    = appt.AptNum;
                    hl7Msg.HL7Status = HL7MessageStatus.OutPending;                  //it will be marked outSent by the HL7 service.
                    hl7Msg.MsgText   = messageHL7.ToString();
                    hl7Msg.PatNum    = pat.PatNum;
                    HL7Msgs.Insert(hl7Msg);
#if DEBUG
                    MessageBox.Show("Appointments", messageHL7.ToString());
#endif
                }
            }
            #endregion
            List <Procedure> listProcedures = new List <Procedure>();
            //splits should only exist on procs if they are using tp pre-payments
            List <PaySplit> listSplitsForApptProcs = new List <PaySplit>();
            bool            isNonRefundable        = false;
            double          brokenProcAmount       = 0;
            Procedure       brokenProcedure        = new Procedure();
            bool            wasBrokenProcDeleted   = false;
            if (PrefC.GetYN(PrefName.PrePayAllowedForTpProcs))
            {
                listProcedures = Procedures.GetProcsForSingle(appt.AptNum, false);
                if (listProcedures.Count > 0)
                {
                    listSplitsForApptProcs = PaySplits.GetPaySplitsFromProcs(listProcedures.Select(x => x.ProcNum).ToList());
                }
            }
            #region Charting the proc
            if (procCode != null)
            {
                switch (procCode.ProcCode)
                {
                case "D9986":                        //Missed
                    HistAppointments.CreateHistoryEntry(appt.AptNum, HistAppointmentAction.Missed);
                    break;

                case "D9987":                        //Cancelled
                    HistAppointments.CreateHistoryEntry(appt.AptNum, HistAppointmentAction.Cancelled);
                    break;
                }
                brokenProcedure.PatNum       = pat.PatNum;
                brokenProcedure.ProvNum      = (procCode.ProvNumDefault > 0 ? procCode.ProvNumDefault : appt.ProvNum);
                brokenProcedure.CodeNum      = procCode.CodeNum;
                brokenProcedure.ProcDate     = DateTime.Today;
                brokenProcedure.DateEntryC   = DateTime.Now;
                brokenProcedure.ProcStatus   = ProcStat.C;
                brokenProcedure.ClinicNum    = appt.ClinicNum;
                brokenProcedure.UserNum      = Security.CurUser.UserNum;
                brokenProcedure.Note         = Lans.g("AppointmentEdit", "Appt BROKEN for") + " " + appt.ProcDescript + "  " + appt.AptDateTime.ToString();
                brokenProcedure.PlaceService = (PlaceOfService)PrefC.GetInt(PrefName.DefaultProcedurePlaceService);              //Default proc place of service for the Practice is used.
                List <InsSub>  listInsSubs    = InsSubs.RefreshForFam(Patients.GetFamily(pat.PatNum));
                List <InsPlan> listInsPlans   = InsPlans.RefreshForSubList(listInsSubs);
                List <PatPlan> listPatPlans   = PatPlans.Refresh(pat.PatNum);
                InsPlan        insPlanPrimary = null;
                InsSub         insSubPrimary  = null;
                if (listPatPlans.Count > 0)
                {
                    insSubPrimary  = InsSubs.GetSub(listPatPlans[0].InsSubNum, listInsSubs);
                    insPlanPrimary = InsPlans.GetPlan(insSubPrimary.PlanNum, listInsPlans);
                }
                double procFee;
                long   feeSch;
                if (insPlanPrimary == null || procCode.NoBillIns)
                {
                    feeSch = FeeScheds.GetFeeSched(0, pat.FeeSched, brokenProcedure.ProvNum);
                }
                else                  //Only take into account the patient's insurance fee schedule if the D9986 procedure is not marked as NoBillIns
                {
                    feeSch = FeeScheds.GetFeeSched(insPlanPrimary.FeeSched, pat.FeeSched, brokenProcedure.ProvNum);
                }
                procFee = Fees.GetAmount0(brokenProcedure.CodeNum, feeSch, brokenProcedure.ClinicNum, brokenProcedure.ProvNum);
                if (insPlanPrimary != null && insPlanPrimary.PlanType == "p" && !insPlanPrimary.IsMedical)         //PPO
                {
                    double provFee = Fees.GetAmount0(brokenProcedure.CodeNum, Providers.GetProv(brokenProcedure.ProvNum).FeeSched, brokenProcedure.ClinicNum,
                                                     brokenProcedure.ProvNum);
                    brokenProcedure.ProcFee = Math.Max(provFee, procFee);
                }
                else if (listSplitsForApptProcs.Count > 0 && PrefC.GetBool(PrefName.TpPrePayIsNonRefundable) && procCode.ProcCode == "D9986")
                {
                    //if there are pre-payments, non-refundable pre-payments is turned on, and the broken appointment is a missed code then auto-fill
                    //the window with the sum of the procs for the appointment. Transfer money below after broken procedure is confirmed by the user.
                    brokenProcedure.ProcFee = listSplitsForApptProcs.Sum(x => x.SplitAmt);
                    isNonRefundable         = true;
                }
                else
                {
                    brokenProcedure.ProcFee = procFee;
                }
                if (!PrefC.GetBool(PrefName.EasyHidePublicHealth))
                {
                    brokenProcedure.SiteNum = pat.SiteNum;
                }
                Procedures.Insert(brokenProcedure);
                //Now make a claimproc if the patient has insurance.  We do this now for consistency because a claimproc could get created in the future.
                List <Benefit>   listBenefits          = Benefits.Refresh(listPatPlans, listInsSubs);
                List <ClaimProc> listClaimProcsForProc = ClaimProcs.RefreshForProc(brokenProcedure.ProcNum);
                Procedures.ComputeEstimates(brokenProcedure, pat.PatNum, listClaimProcsForProc, false, listInsPlans, listPatPlans, listBenefits, pat.Age, listInsSubs);
                FormProcBroken FormPB = new FormProcBroken(brokenProcedure, isNonRefundable);
                FormPB.IsNew = true;
                FormPB.ShowDialog();
                brokenProcAmount     = FormPB.AmountTotal;
                wasBrokenProcDeleted = FormPB.IsProcDeleted;
            }
            #endregion
            #region BrokenApptAdjustment
            if (PrefC.GetBool(PrefName.BrokenApptAdjustment))
            {
                Adjustment AdjustmentCur = new Adjustment();
                AdjustmentCur.DateEntry = DateTime.Today;
                AdjustmentCur.AdjDate   = DateTime.Today;
                AdjustmentCur.ProcDate  = DateTime.Today;
                AdjustmentCur.ProvNum   = appt.ProvNum;
                AdjustmentCur.PatNum    = pat.PatNum;
                AdjustmentCur.AdjType   = PrefC.GetLong(PrefName.BrokenAppointmentAdjustmentType);
                AdjustmentCur.ClinicNum = appt.ClinicNum;
                FormAdjust FormA = new FormAdjust(pat, AdjustmentCur);
                FormA.IsNew = true;
                FormA.ShowDialog();
            }
            #endregion
            #region BrokenApptCommLog
            if (PrefC.GetBool(PrefName.BrokenApptCommLog))
            {
                Commlog commlogCur = new Commlog();
                commlogCur.PatNum       = pat.PatNum;
                commlogCur.CommDateTime = DateTime.Now;
                commlogCur.CommType     = Commlogs.GetTypeAuto(CommItemTypeAuto.APPT);
                commlogCur.Note         = Lan.g("Appointment", "Appt BROKEN for") + " " + appt.ProcDescript + "  " + appt.AptDateTime.ToString();
                commlogCur.Mode_        = CommItemMode.None;
                commlogCur.UserNum      = Security.CurUser.UserNum;
                commlogCur.IsNew        = true;
                FormCommItem FormCI = new FormCommItem(commlogCur);
                FormCI.ShowDialog();
            }
            #endregion
            #region Transfer money from TP Procedures if necessary
            //Note this MUST come after FormProcBroken since clicking cancel in that window will delete the procedure.
            if (isNonRefundable && !wasBrokenProcDeleted && listSplitsForApptProcs.Count > 0)
            {
                //transfer what the user specified in the broken appointment window.
                //transfer up to the amount specified by the user
                foreach (Procedure proc in listProcedures)
                {
                    if (brokenProcAmount == 0)
                    {
                        break;
                    }
                    List <PaySplit> listSplitsForAppointmentProcedure = listSplitsForApptProcs.FindAll(x => x.ProcNum == proc.ProcNum);
                    foreach (PaySplit split in listSplitsForAppointmentProcedure)
                    {
                        if (brokenProcAmount == 0)
                        {
                            break;
                        }
                        double amt = Math.Min(brokenProcAmount, split.SplitAmt);
                        Payments.CreateTransferForTpProcs(proc, new List <PaySplit> {
                            split
                        }, brokenProcedure, amt);
                        double amtPaidOnApt = listSplitsForApptProcs.Sum(x => x.SplitAmt);
                        if (amtPaidOnApt > amt)
                        {
                            //If the original prepayment amount is greater than the amt being specified for the appointment break, transfer
                            //the difference to an Unallocated Unearned Paysplit on the account.
                            double remainingAmt = amtPaidOnApt - amt;
                            //We have to create a new transfer payment here to correlate to the split.
                            Payment txfrPayment = new Payment();
                            txfrPayment.PayAmt    = 0;
                            txfrPayment.PayDate   = DateTime.Today;
                            txfrPayment.ClinicNum = split.ClinicNum;
                            txfrPayment.PayNote   = "Automatic transfer from treatment planned procedure prepayment.";
                            txfrPayment.PatNum    = split.PatNum;                       //ultimately where the payment ends up.
                            txfrPayment.PayType   = 0;
                            Payments.Insert(txfrPayment);
                            PaymentEdit.IncomeTransferData transferData = PaymentEdit.IncomeTransferData.CreateTransfer(split, txfrPayment.PayNum, true, remainingAmt);
                            PaySplit offset         = transferData.ListSplitsCur.FirstOrDefault(x => x.FSplitNum != 0);
                            long     offsetSplitNum = PaySplits.Insert(offset);                      //Get the FSplitNum from the offset
                            PaySplit allocation     = transferData.ListSplitsCur.FirstOrDefault(x => x.FSplitNum == 0);
                            allocation.FSplitNum = offsetSplitNum;
                            PaySplits.Insert(allocation);                            //Insert so the split is now up to date
                            SecurityLogs.MakeLogEntry(Permissions.PaymentCreate, txfrPayment.PatNum, "Automatic transfer of funds for treatment plan procedure pre-payments.");
                        }
                        brokenProcAmount -= amt;
                    }
                }
            }
            //if broken appointment procedure was deleted (user cancelled out of the window) just keep money on the original procedure.
            #endregion
            AppointmentEvent.Fire(ODEventType.AppointmentEdited, appt);
            AutomationL.Trigger(AutomationTrigger.BreakAppointment, null, pat.PatNum);
            Recalls.SynchScheduledApptFull(appt.PatNum);
        }
Exemple #11
0
        /// <summary>
        /// </summary>
        private Patient CreatePatient(String LastName, String FirstName, DateTime birthDate, WebSheets.SheetAndSheetField sAnds)
        {
            Patient newPat = new Patient();

            newPat.LName     = LastName;
            newPat.FName     = FirstName;
            newPat.Birthdate = birthDate;
            newPat.ClinicNum = sAnds.web_sheet.ClinicNum;
            if (PrefC.GetBool(PrefName.EasyNoClinics))
            {
                //Set the patients primary provider to the practice default provider.
                newPat.PriProv = Providers.GetDefaultProvider().ProvNum;
            }
            else              //Using clinics.
                              //Set the patients primary provider to the clinic default provider.
            {
                newPat.PriProv = Providers.GetDefaultProvider(Clinics.ClinicNum).ProvNum;
            }
            Type t = newPat.GetType();

            FieldInfo[] fi = t.GetFields();
            foreach (FieldInfo field in fi)
            {
                // find match for fields in Patients in the web_sheetfieldlist
                var WebSheetFieldList = sAnds.web_sheetfieldlist.Where(sf => sf.FieldName.ToLower() == field.Name.ToLower());
                if (WebSheetFieldList.Count() > 0)
                {
                    // this loop is used to fill a field that may generate mutiple values for a single field in the patient.
                    //for example the field gender has 2 eqivalent sheet fields in the web_sheetfieldlist
                    for (int i = 0; i < WebSheetFieldList.Count(); i++)
                    {
                        WebSheets.webforms_sheetfield sf = WebSheetFieldList.ElementAt(i);
                        String SheetWebFieldValue        = sf.FieldValue;
                        String RadioButtonValue          = sf.RadioButtonValue;
                        FillPatientFields(newPat, field, SheetWebFieldValue, RadioButtonValue);
                    }
                }
            }
            try{
                Patients.Insert(newPat, false);
                SecurityLogs.MakeLogEntry(Permissions.PatientCreate, newPat.PatNum, "Created from Web Forms.");
                //set Guarantor field the same as PatNum
                Patient patOld = newPat.Copy();
                newPat.Guarantor = newPat.PatNum;
                Patients.Update(newPat, patOld);
                //If there is an existing HL7 def enabled, send an ADT message if there is an outbound ADT message defined
                if (HL7Defs.IsExistingHL7Enabled())
                {
                    MessageHL7 messageHL7 = MessageConstructor.GenerateADT(newPat, newPat, EventTypeHL7.A04);                //patient is guarantor
                    //Will be null if there is no outbound ADT message defined, so do nothing
                    if (messageHL7 != null)
                    {
                        HL7Msg hl7Msg = new HL7Msg();
                        hl7Msg.AptNum    = 0;
                        hl7Msg.HL7Status = HL7MessageStatus.OutPending;                      //it will be marked outSent by the HL7 service.
                        hl7Msg.MsgText   = messageHL7.ToString();
                        hl7Msg.PatNum    = newPat.PatNum;
                        HL7Msgs.Insert(hl7Msg);
#if DEBUG
                        MessageBox.Show(this, messageHL7.ToString());
#endif
                    }
                }
            }
            catch (Exception e) {
                gridMain.EndUpdate();
                MessageBox.Show(e.Message);
            }
            return(newPat);
        }
Exemple #12
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.
            }
        }
Exemple #13
0
        ///<summary>Runs in a separate thread</summary>
        private void OnDataReceived(IAsyncResult asyncResult)
        {
            int byteCountReceived = socketIncomingWorker.EndReceive(asyncResult);          //blocks until data is recieved.

            char[]  chars   = new char[byteCountReceived];
            Decoder decoder = Encoding.UTF8.GetDecoder();

            decoder.GetChars(dataBufferIncoming, 0, byteCountReceived, chars, 0); //doesn't necessarily get all bytes from the buffer because buffer could be half full.
            strbFullMsg.Append(chars);                                            //strbFullMsg might already have partial data
            //I think we are guaranteed to have received at least one char.
            bool isFullMsg   = false;
            bool isMalformed = false;

            if (strbFullMsg.Length == 1 && strbFullMsg[0] == MLLP_ENDMSG_CHAR) //the only char in the message is the end char
            {
                strbFullMsg.Clear();                                           //this must be the very end of a previously processed message.  Discard.
                isFullMsg = false;
            }
            //else if(strbFullMsg[0]!=MLLP_START_CHAR) {
            else if (strbFullMsg.Length > 0 && strbFullMsg[0] != MLLP_START_CHAR)
            {
                //Malformed message.
                isFullMsg   = true;            //we're going to do this so that the error gets saved in the database further down.
                isMalformed = true;
            }
            else if (strbFullMsg.Length >= 3 &&      //so that the next two lines won't crash
                     strbFullMsg[strbFullMsg.Length - 1] == MLLP_ENDMSG_CHAR &&       //last char is the endmsg char.
                     strbFullMsg[strbFullMsg.Length - 2] == MLLP_END_CHAR)          //the second-to-the-last char is the end char.
            {
                //we have a complete message
                strbFullMsg.Remove(0, 1);                      //strip off the start char
                strbFullMsg.Remove(strbFullMsg.Length - 2, 2); //strip off the end chars
                isFullMsg = true;
            }
            else if (strbFullMsg.Length >= 2 &&      //so that the next line won't crash
                     strbFullMsg[strbFullMsg.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.
                //if the endmsg char gets sent in a subsequent block, the code above will discard it.
                strbFullMsg.Remove(0, 1);                      //strip off the start char
                strbFullMsg.Remove(strbFullMsg.Length - 1, 1); //strip off the end char
                isFullMsg = true;
            }
            else
            {
                isFullMsg = false;              //this is an incomplete message.  Continue to receive more blocks.
            }
            //end of big if statement-------------------------------------------------
            if (!isFullMsg)
            {
                dataBufferIncoming = new byte[8]; //clear the buffer
                socketIncomingWorker.BeginReceive(dataBufferIncoming, 0, dataBufferIncoming.Length, SocketFlags.None, new AsyncCallback(OnDataReceived), null);
                return;                           //get another block
            }
            //Prepare to save message to database if malformed and not processed
            HL7Msg hl7Msg = new HL7Msg();

            hl7Msg.MsgText = strbFullMsg.ToString();
            strbFullMsg.Clear();            //ready for the next message
            bool   isProcessed      = true;
            string messageControlId = "";
            string ackEvent         = "";

            if (isMalformed)
            {
                hl7Msg.HL7Status = HL7MessageStatus.InFailed;
                hl7Msg.Note      = "This message is malformed so it was not processed.";
                HL7Msgs.Insert(hl7Msg);
                isProcessed = false;
            }
            else
            {
                MessageHL7 messageHl7Object = new MessageHL7(hl7Msg.MsgText);              //this creates an entire heirarchy of objects.
                try {
                    MessageParser.Process(messageHl7Object, IsVerboseLogging);             //also saves the message to the db
                    messageControlId = messageHl7Object.ControlId;
                    ackEvent         = messageHl7Object.AckEvent;
                }
                catch (Exception ex) {
                    EventLog.WriteEntry("OpenDentHL7", "Error in OnDataRecieved when processing message:\r\n" + ex.Message + "\r\n" + ex.StackTrace, EventLogEntryType.Error);
                    isProcessed = false;
                }
            }
            MessageHL7 hl7Ack = MessageConstructor.GenerateACK(messageControlId, isProcessed, ackEvent);

            if (hl7Ack == null)
            {
                EventLog.WriteEntry("OpenDentHL7", "No ACK defined for the enabled HL7 definition or no HL7 definition enabled.", EventLogEntryType.Information);
                return;
            }
            byte[] ackByteOutgoing = Encoding.ASCII.GetBytes(MLLP_START_CHAR + hl7Ack.ToString() + MLLP_END_CHAR + MLLP_ENDMSG_CHAR);
            if (IsVerboseLogging)
            {
                EventLog.WriteEntry("OpenDentHL7", "Beginning to send ACK.\r\n" + MLLP_START_CHAR + hl7Ack.ToString() + MLLP_END_CHAR + MLLP_ENDMSG_CHAR, EventLogEntryType.Information);
            }
            socketIncomingWorker.Send(ackByteOutgoing);            //this is a locking call
            //eCW uses the same worker socket to send the next message. Without this call to BeginReceive, they would attempt to send again
            //and the send would fail since we were no longer listening in this thread. eCW would timeout after 30 seconds of waiting for their
            //acknowledgement, then they would close their end and create a new socket for the next message. With this call, we can accept message
            //after message without waiting for a new connection.
            dataBufferIncoming = new byte[8];          //clear the buffer
            socketIncomingWorker.BeginReceive(dataBufferIncoming, 0, dataBufferIncoming.Length, SocketFlags.None, new AsyncCallback(OnDataReceived), null);
        }
Exemple #14
0
        /// <summary>
        private static Patient CreatePatient(String LastName, String FirstName, DateTime birthDate, WebForms_Sheet webFormSheet, Sheet sheet, string cultureName)
        {
            bool    isWebForm = webFormSheet != null;
            Patient newPat    = new Patient();

            newPat.LName     = LastName;
            newPat.FName     = FirstName;
            newPat.Birthdate = birthDate;
            if (isWebForm)
            {
                newPat.ClinicNum = webFormSheet.ClinicNum;
            }
            else
            {
                newPat.ClinicNum = sheet.ClinicNum;
            }
            if (!PrefC.HasClinicsEnabled)
            {
                //Set the patients primary provider to the practice default provider.
                newPat.PriProv = Providers.GetDefaultProvider().ProvNum;
            }
            else              //Using clinics.
            //Set the patients primary provider to the clinic default provider.
            {
                newPat.PriProv = Providers.GetDefaultProvider(Clinics.ClinicNum).ProvNum;
            }
            Type t = newPat.GetType();

            FieldInfo[] fi = t.GetFields();
            foreach (FieldInfo field in fi)
            {
                // find match for fields in Patients in the SheetFields
                if (isWebForm)
                {
                    List <WebForms_SheetField> listWebFormsSheetFields = webFormSheet.SheetFields.FindAll(x => x.FieldName.ToLower() == field.Name.ToLower());
                    if (listWebFormsSheetFields.Count() > 0)
                    {
                        // this loop is used to fill a field that may generate mutiple values for a single field in the patient.
                        //for example the field gender has 2 eqivalent sheet fields in the SheetFields
                        foreach (WebForms_SheetField webFormsSheetField in listWebFormsSheetFields)
                        {
                            FillPatientFields(newPat, field, webFormsSheetField.FieldValue, webFormsSheetField.RadioButtonValue, cultureName, isWebForm, false);
                        }
                    }
                }
                else
                {
                    List <SheetField> listSheetFields = sheet.SheetFields.FindAll(x => x.FieldName.ToLower() == field.Name.ToLower());
                    if (listSheetFields.Count() > 0)
                    {
                        // this loop is used to fill a field that may generate mutiple values for a single field in the patient.
                        //for example the field gender has 2 eqivalent sheet fields in the SheetFields
                        foreach (SheetField sheetField in listSheetFields)
                        {
                            FillPatientFields(newPat, field, sheetField.FieldValue, sheetField.RadioButtonValue, "", isWebForm, sheet.IsCemtTransfer);
                        }
                    }
                }
            }
            try {
                Patients.Insert(newPat, false);
                SecurityLogs.MakeLogEntry(Permissions.PatientCreate, newPat.PatNum, isWebForm ? "Created from Web Forms." : "Created from CEMT transfer.");
                //set Guarantor field the same as PatNum
                Patient patOld = newPat.Copy();
                newPat.Guarantor = newPat.PatNum;
                Patients.Update(newPat, patOld);
                //If there is an existing HL7 def enabled, send an ADT message if there is an outbound ADT message defined
                if (HL7Defs.IsExistingHL7Enabled())
                {
                    MessageHL7 messageHL7 = MessageConstructor.GenerateADT(newPat, newPat, EventTypeHL7.A04);                //patient is guarantor
                    //Will be null if there is no outbound ADT message defined, so do nothing
                    if (messageHL7 != null)
                    {
                        HL7Msg hl7Msg = new HL7Msg();
                        hl7Msg.AptNum    = 0;
                        hl7Msg.HL7Status = HL7MessageStatus.OutPending;                      //it will be marked outSent by the HL7 service.
                        hl7Msg.MsgText   = messageHL7.ToString();
                        hl7Msg.PatNum    = newPat.PatNum;
                        HL7Msgs.Insert(hl7Msg);
#if DEBUG
                        MessageBox.Show("FormWebForms", messageHL7.ToString());
#endif
                    }
                }
            }
            catch (Exception e) {
                MessageBox.Show(e.Message);
            }
            return(newPat);
        }