Esempio n. 1
0
        //public static void ProcessIN1() {
        //	return;
        //}

        public static void ProcessMSA(HL7DefSegment segDef, SegmentHL7 seg, MessageHL7 msg)
        {
            int ackCodeOrder      = 0;
            int msgControlIdOrder = 0;

            //find position of AckCode in segDef for MSA seg
            for (int i = 0; i < segDef.hl7DefFields.Count; i++)
            {
                if (segDef.hl7DefFields[i].FieldName == "ackCode")
                {
                    ackCodeOrder = segDef.hl7DefFields[i].OrdinalPos;
                }
                if (segDef.hl7DefFields[i].FieldName == "messageControlId")
                {
                    msgControlIdOrder = segDef.hl7DefFields[i].OrdinalPos;
                }
            }
            if (ackCodeOrder == 0)           //no ackCode defined for this def of MSA, do nothing with it?
            {
                return;
            }
            if (msgControlIdOrder == 0)           //no messageControlId defined for this def of MSA, do nothing with it?
            {
                return;
            }
            //set msg.AckCode to value in position located in def of ackcode in seg
            msg.AckCode   = seg.Fields[ackCodeOrder].ToString();
            msg.ControlId = seg.Fields[msgControlIdOrder].ToString();
        }
Esempio n. 2
0
 ///<summary>Returns true if Update(HL7DefSegment,HL7DefSegment) would make changes to the database.
 ///Does not make any changes to the database and can be called before remoting role is checked.</summary>
 public static bool UpdateComparison(HL7DefSegment hL7DefSegment, HL7DefSegment oldHL7DefSegment)
 {
     if (hL7DefSegment.HL7DefMessageNum != oldHL7DefSegment.HL7DefMessageNum)
     {
         return(true);
     }
     if (hL7DefSegment.ItemOrder != oldHL7DefSegment.ItemOrder)
     {
         return(true);
     }
     if (hL7DefSegment.CanRepeat != oldHL7DefSegment.CanRepeat)
     {
         return(true);
     }
     if (hL7DefSegment.IsOptional != oldHL7DefSegment.IsOptional)
     {
         return(true);
     }
     if (hL7DefSegment.SegmentName != oldHL7DefSegment.SegmentName)
     {
         return(true);
     }
     if (hL7DefSegment.Note != oldHL7DefSegment.Note)
     {
         return(true);
     }
     return(false);
 }
Esempio n. 3
0
		///<summary>Inserts one HL7DefSegment into the database.  Provides option to use the existing priKey.  Doesn't use the cache.</summary>
		public static long InsertNoCache(HL7DefSegment hL7DefSegment,bool useExistingPK){
			bool isRandomKeys=Prefs.GetBoolNoCache(PrefName.RandomPrimaryKeys);
			string command="INSERT INTO hl7defsegment (";
			if(!useExistingPK && isRandomKeys) {
				hL7DefSegment.HL7DefSegmentNum=ReplicationServers.GetKeyNoCache("hl7defsegment","HL7DefSegmentNum");
			}
			if(isRandomKeys || useExistingPK) {
				command+="HL7DefSegmentNum,";
			}
			command+="HL7DefMessageNum,ItemOrder,CanRepeat,IsOptional,SegmentName,Note) VALUES(";
			if(isRandomKeys || useExistingPK) {
				command+=POut.Long(hL7DefSegment.HL7DefSegmentNum)+",";
			}
			command+=
				     POut.Long  (hL7DefSegment.HL7DefMessageNum)+","
				+    POut.Int   (hL7DefSegment.ItemOrder)+","
				+    POut.Bool  (hL7DefSegment.CanRepeat)+","
				+    POut.Bool  (hL7DefSegment.IsOptional)+","
				+"'"+POut.String(hL7DefSegment.SegmentName.ToString())+"',"
				+    DbHelper.ParamChar+"paramNote)";
			if(hL7DefSegment.Note==null) {
				hL7DefSegment.Note="";
			}
			OdSqlParameter paramNote=new OdSqlParameter("paramNote",OdDbType.Text,POut.StringParam(hL7DefSegment.Note));
			if(useExistingPK || isRandomKeys) {
				Db.NonQ(command,paramNote);
			}
			else {
				hL7DefSegment.HL7DefSegmentNum=Db.NonQ(command,true,"HL7DefSegmentNum","hL7DefSegment",paramNote);
			}
			return hL7DefSegment.HL7DefSegmentNum;
		}
Esempio n. 4
0
        ///<summary>Converts a DataTable to a list of objects.</summary>
        public static List <HL7DefSegment> TableToList(DataTable table)
        {
            List <HL7DefSegment> retVal = new List <HL7DefSegment>();
            HL7DefSegment        hL7DefSegment;

            for (int i = 0; i < table.Rows.Count; i++)
            {
                hL7DefSegment = new HL7DefSegment();
                hL7DefSegment.HL7DefSegmentNum = PIn.Long(table.Rows[i]["HL7DefSegmentNum"].ToString());
                hL7DefSegment.HL7DefMessageNum = PIn.Long(table.Rows[i]["HL7DefMessageNum"].ToString());
                hL7DefSegment.ItemOrder        = PIn.Int(table.Rows[i]["ItemOrder"].ToString());
                hL7DefSegment.CanRepeat        = PIn.Bool(table.Rows[i]["CanRepeat"].ToString());
                hL7DefSegment.IsOptional       = PIn.Bool(table.Rows[i]["IsOptional"].ToString());
                string segmentName = table.Rows[i]["SegmentName"].ToString();
                if (segmentName == "")
                {
                    hL7DefSegment.SegmentName = (SegmentNameHL7)0;
                }
                else
                {
                    try{
                        hL7DefSegment.SegmentName = (SegmentNameHL7)Enum.Parse(typeof(SegmentNameHL7), segmentName);
                    }
                    catch {
                        hL7DefSegment.SegmentName = (SegmentNameHL7)0;
                    }
                }
                hL7DefSegment.Note = PIn.String(table.Rows[i]["Note"].ToString());
                retVal.Add(hL7DefSegment);
            }
            return(retVal);
        }
Esempio n. 5
0
 ///<summary>Inserts one HL7DefSegment into the database.  Returns the new priKey.</summary>
 public static long Insert(HL7DefSegment hL7DefSegment)
 {
     if (DataConnection.DBtype == DatabaseType.Oracle)
     {
         hL7DefSegment.HL7DefSegmentNum = DbHelper.GetNextOracleKey("hl7defsegment", "HL7DefSegmentNum");
         int loopcount = 0;
         while (loopcount < 100)
         {
             try {
                 return(Insert(hL7DefSegment, true));
             }
             catch (Oracle.DataAccess.Client.OracleException ex) {
                 if (ex.Number == 1 && ex.Message.ToLower().Contains("unique constraint") && ex.Message.ToLower().Contains("violated"))
                 {
                     hL7DefSegment.HL7DefSegmentNum++;
                     loopcount++;
                 }
                 else
                 {
                     throw ex;
                 }
             }
         }
         throw new ApplicationException("Insert failed.  Could not generate primary key.");
     }
     else
     {
         return(Insert(hL7DefSegment, false));
     }
 }
Esempio n. 6
0
        ///<summary>Converts a DataTable to a list of objects.</summary>
        public static List <HL7DefSegment> TableToList(DataTable table)
        {
            List <HL7DefSegment> retVal = new List <HL7DefSegment>();
            HL7DefSegment        hL7DefSegment;

            foreach (DataRow row in table.Rows)
            {
                hL7DefSegment = new HL7DefSegment();
                hL7DefSegment.HL7DefSegmentNum = PIn.Long(row["HL7DefSegmentNum"].ToString());
                hL7DefSegment.HL7DefMessageNum = PIn.Long(row["HL7DefMessageNum"].ToString());
                hL7DefSegment.ItemOrder        = PIn.Int(row["ItemOrder"].ToString());
                hL7DefSegment.CanRepeat        = PIn.Bool(row["CanRepeat"].ToString());
                hL7DefSegment.IsOptional       = PIn.Bool(row["IsOptional"].ToString());
                string segmentName = row["SegmentName"].ToString();
                if (segmentName == "")
                {
                    hL7DefSegment.SegmentName = (OpenDentBusiness.SegmentNameHL7) 0;
                }
                else
                {
                    try{
                        hL7DefSegment.SegmentName = (OpenDentBusiness.SegmentNameHL7)Enum.Parse(typeof(OpenDentBusiness.SegmentNameHL7), segmentName);
                    }
                    catch {
                        hL7DefSegment.SegmentName = (OpenDentBusiness.SegmentNameHL7) 0;
                    }
                }
                hL7DefSegment.Note = PIn.String(row["Note"].ToString());
                retVal.Add(hL7DefSegment);
            }
            return(retVal);
        }
		///<summary>Converts a DataTable to a list of objects.</summary>
		public static List<HL7DefSegment> TableToList(DataTable table){
			List<HL7DefSegment> retVal=new List<HL7DefSegment>();
			HL7DefSegment hL7DefSegment;
			for(int i=0;i<table.Rows.Count;i++) {
				hL7DefSegment=new HL7DefSegment();
				hL7DefSegment.HL7DefSegmentNum= PIn.Long  (table.Rows[i]["HL7DefSegmentNum"].ToString());
				hL7DefSegment.HL7DefMessageNum= PIn.Long  (table.Rows[i]["HL7DefMessageNum"].ToString());
				hL7DefSegment.ItemOrder       = PIn.Int   (table.Rows[i]["ItemOrder"].ToString());
				hL7DefSegment.CanRepeat       = PIn.Bool  (table.Rows[i]["CanRepeat"].ToString());
				hL7DefSegment.IsOptional      = PIn.Bool  (table.Rows[i]["IsOptional"].ToString());
				string segmentName=table.Rows[i]["SegmentName"].ToString();
				if(segmentName==""){
					hL7DefSegment.SegmentName   =(SegmentNameHL7)0;
				}
				else try{
					hL7DefSegment.SegmentName   =(SegmentNameHL7)Enum.Parse(typeof(SegmentNameHL7),segmentName);
				}
				catch{
					hL7DefSegment.SegmentName   =(SegmentNameHL7)0;
				}
				hL7DefSegment.Note            = PIn.String(table.Rows[i]["Note"].ToString());
				retVal.Add(hL7DefSegment);
			}
			return retVal;
		}
Esempio n. 8
0
		///<summary>Inserts one HL7DefSegment into the database.  Returns the new priKey.  Doesn't use the cache.</summary>
		public static long InsertNoCache(HL7DefSegment hL7DefSegment){
			if(DataConnection.DBtype==DatabaseType.MySql) {
				return InsertNoCache(hL7DefSegment,false);
			}
			else {
				if(DataConnection.DBtype==DatabaseType.Oracle) {
					hL7DefSegment.HL7DefSegmentNum=DbHelper.GetNextOracleKey("hl7defsegment","HL7DefSegmentNum"); //Cacheless method
				}
				return InsertNoCache(hL7DefSegment,true);
			}
		}
Esempio n. 9
0
		///<summary>Updates one HL7DefSegment in the database.</summary>
		public static void Update(HL7DefSegment hL7DefSegment){
			string command="UPDATE hl7defsegment SET "
				+"HL7DefMessageNum=  "+POut.Long  (hL7DefSegment.HL7DefMessageNum)+", "
				+"ItemOrder       =  "+POut.Int   (hL7DefSegment.ItemOrder)+", "
				+"CanRepeat       =  "+POut.Bool  (hL7DefSegment.CanRepeat)+", "
				+"IsOptional      =  "+POut.Bool  (hL7DefSegment.IsOptional)+", "
				+"SegmentName     = '"+POut.String(hL7DefSegment.SegmentName.ToString())+"', "
				+"Note            =  "+DbHelper.ParamChar+"paramNote "
				+"WHERE HL7DefSegmentNum = "+POut.Long(hL7DefSegment.HL7DefSegmentNum);
			if(hL7DefSegment.Note==null) {
				hL7DefSegment.Note="";
			}
			OdSqlParameter paramNote=new OdSqlParameter("paramNote",OdDbType.Text,POut.StringParam(hL7DefSegment.Note));
			Db.NonQ(command,paramNote);
		}
Esempio n. 10
0
        public static void ProcessSeg(Patient pat, long aptNum, HL7DefSegment segDef, SegmentHL7 seg, MessageHL7 msg)
        {
            switch (segDef.SegmentName)
            {
            case SegmentNameHL7.AIG:
                ProcessAIG(pat, aptNum, segDef, seg);
                return;

            case SegmentNameHL7.GT1:
                ProcessGT1(pat, segDef, seg);
                return;

            case SegmentNameHL7.IN1:
                //ProcessIN1();
                return;

            case SegmentNameHL7.MSA:
                ProcessMSA(segDef, seg, msg);
                return;

            case SegmentNameHL7.MSH:
                ProcessMSH(segDef, seg, msg);
                return;

            case SegmentNameHL7.PD1:
                //ProcessPD1();
                return;

            case SegmentNameHL7.PID:
                ProcessPID(pat, segDef, seg);
                return;

            case SegmentNameHL7.PV1:
                ProcessPV1(pat, aptNum, segDef, seg);
                return;

            case SegmentNameHL7.SCH:
                ProcessSCH(pat, segDef, seg);
                return;

            default:
                return;
            }
        }
Esempio n. 11
0
        public static void ProcessMSH(HL7DefSegment segDef, SegmentHL7 seg, MessageHL7 msg)
        {
            int msgControlIdOrder = 0;

            //find position of messageControlId in segDef for MSH seg
            for (int i = 0; i < segDef.hl7DefFields.Count; i++)
            {
                if (segDef.hl7DefFields[i].FieldName == "messageControlId")
                {
                    msgControlIdOrder = segDef.hl7DefFields[i].OrdinalPos;
                    break;
                }
            }
            if (msgControlIdOrder == 0)
            {
                return;
            }
            msg.ControlId = seg.Fields[msgControlIdOrder].ToString();
        }
Esempio n. 12
0
		///<summary>Updates one HL7DefSegment in the database.  Uses an old object to compare to, and only alters changed fields.  This prevents collisions and concurrency problems in heavily used tables.  Returns true if an update occurred.</summary>
		public static bool Update(HL7DefSegment hL7DefSegment,HL7DefSegment oldHL7DefSegment){
			string command="";
			if(hL7DefSegment.HL7DefMessageNum != oldHL7DefSegment.HL7DefMessageNum) {
				if(command!=""){ command+=",";}
				command+="HL7DefMessageNum = "+POut.Long(hL7DefSegment.HL7DefMessageNum)+"";
			}
			if(hL7DefSegment.ItemOrder != oldHL7DefSegment.ItemOrder) {
				if(command!=""){ command+=",";}
				command+="ItemOrder = "+POut.Int(hL7DefSegment.ItemOrder)+"";
			}
			if(hL7DefSegment.CanRepeat != oldHL7DefSegment.CanRepeat) {
				if(command!=""){ command+=",";}
				command+="CanRepeat = "+POut.Bool(hL7DefSegment.CanRepeat)+"";
			}
			if(hL7DefSegment.IsOptional != oldHL7DefSegment.IsOptional) {
				if(command!=""){ command+=",";}
				command+="IsOptional = "+POut.Bool(hL7DefSegment.IsOptional)+"";
			}
			if(hL7DefSegment.SegmentName != oldHL7DefSegment.SegmentName) {
				if(command!=""){ command+=",";}
				command+="SegmentName = '"+POut.String(hL7DefSegment.SegmentName.ToString())+"'";
			}
			if(hL7DefSegment.Note != oldHL7DefSegment.Note) {
				if(command!=""){ command+=",";}
				command+="Note = "+DbHelper.ParamChar+"paramNote";
			}
			if(command==""){
				return false;
			}
			if(hL7DefSegment.Note==null) {
				hL7DefSegment.Note="";
			}
			OdSqlParameter paramNote=new OdSqlParameter("paramNote",OdDbType.Text,POut.StringParam(hL7DefSegment.Note));
			command="UPDATE hl7defsegment SET "+command
				+" WHERE HL7DefSegmentNum = "+POut.Long(hL7DefSegment.HL7DefSegmentNum);
			Db.NonQ(command,paramNote);
			return true;
		}
Esempio n. 13
0
        public static void ProcessPV1(Patient pat, long aptNum, HL7DefSegment segDef, SegmentHL7 seg)
        {
            long provNum;
            int  provNumOrder = 0;

            for (int i = 0; i < segDef.hl7DefFields.Count; i++)
            {
                if (segDef.hl7DefFields[i].FieldName == "prov.provIdName" || segDef.hl7DefFields[i].FieldName == "prov.provIdNameLFM")
                {
                    provNumOrder = segDef.hl7DefFields[i].OrdinalPos;
                    break;
                }
            }
            if (provNumOrder == 0)           //No provIdName or provIdNameLFM field in this segment definition so do nothing with it
            {
                return;
            }
            provNum = FieldParser.ProvProcess(seg.Fields[provNumOrder]);
            if (provNum == 0)           //This segment didn't have a valid provider id in it to locate the provider (must have been blank) so do nothing
            {
                return;
            }
            Appointment apt = Appointments.GetOneApt(aptNum); //SCH segment was found and aptNum was retrieved, if no SCH segment for this message then 0

            if (apt == null)                                  //Just in case we can't find an apt with the aptNum from SCH segment
            {
                return;
            }
            Appointment aptOld = apt.Clone();
            Patient     patOld = pat.Copy();

            apt.ProvNum = provNum;
            pat.PriProv = provNum;
            Appointments.Update(apt, aptOld);
            Patients.Update(pat, patOld);
            return;
        }
		///<summary>Inserts one HL7DefSegment into the database.  Returns the new priKey.</summary>
		public static long Insert(HL7DefSegment hL7DefSegment){
			if(DataConnection.DBtype==DatabaseType.Oracle) {
				hL7DefSegment.HL7DefSegmentNum=DbHelper.GetNextOracleKey("hl7defsegment","HL7DefSegmentNum");
				int loopcount=0;
				while(loopcount<100){
					try {
						return Insert(hL7DefSegment,true);
					}
					catch(Oracle.DataAccess.Client.OracleException ex){
						if(ex.Number==1 && ex.Message.ToLower().Contains("unique constraint") && ex.Message.ToLower().Contains("violated")){
							hL7DefSegment.HL7DefSegmentNum++;
							loopcount++;
						}
						else{
							throw ex;
						}
					}
				}
				throw new ApplicationException("Insert failed.  Could not generate primary key.");
			}
			else {
				return Insert(hL7DefSegment,false);
			}
		}
Esempio n. 15
0
		///<summary>Appointment request segment.  Included in inbound SRM, Schedule Request Messages.  When OD is the filler application, this will identify the appointment that the placer or auxiliary aplication is trying to update.  We only support event S03 - Appt Modification requests or event S04 - Appt Cancellation requests for now.</summary>
		public static void ProcessARQ(Patient pat,Appointment apt,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			long aptNum=0;
			string externAptId="";
			string externRoot="";
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int intItemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "apt.externalAptID":
						externAptId=seg.GetFieldComponent(intItemOrder,0);
						externRoot=seg.GetFieldComponent(intItemOrder,2);
						continue;
					case "apt.AptNum":
						try {
							aptNum=PIn.Long(seg.GetFieldComponent(intItemOrder,0));
						}
						catch(Exception ex) {
							//do nothing, aptNum will remain 0
						}
						if(apt!=null && apt.AptNum!=aptNum) {
							//an appointment was located from the inbound message, but the AptNum on the appointment is not the same as the AptNum in this ARQ segment (should never happen)
							throw new Exception("Invalid appointment number.");
						}
						continue;
					default:
						continue;
				}
			}
			if(externAptId!="" && externRoot!="" && OIDExternals.GetByRootAndExtension(externRoot,externAptId)==null) {
				OIDExternal oidExtCur=new OIDExternal();
				oidExtCur.IDType=IdentifierType.Appointment;
				oidExtCur.IDInternal=apt.AptNum;
				oidExtCur.IDExternal=externAptId;
				oidExtCur.rootExternal=externRoot;
				OIDExternals.Insert(oidExtCur);
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Added an external appointment ID to the oidexternals table due to an incoming ARQ segment.\r\n"
						+"AptNum: "+apt.AptNum.ToString()+", External AptID: "+externAptId+", External root: "+externRoot+".",EventLogEntryType.Information);
				}
			}
			_hl7MsgCur.AptNum=apt.AptNum;
			HL7Msgs.Update(_hl7MsgCur);
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated hl7msg to include AptNum for "+pat.GetNameFLnoPref()+" due to an incoming SCH segment.",EventLogEntryType.Information);
			}
			_aptProcessed=apt;
			return;
		}
Esempio n. 16
0
        public static HL7Def GetDeepInternal(HL7Def def)
        {
            //ok to pass in null
            if (def == null)           //wasn't in the database
            {
                def                       = new HL7Def();
                def.IsNew                 = true;
                def.Description           = "MedLab HL7 v2.3";
                def.ModeTx                = ModeTxHL7.Sftp;
                def.IncomingFolder        = "";
                def.OutgoingFolder        = "";
                def.IncomingPort          = "";
                def.OutgoingIpPort        = "";
                def.SftpInSocket          = "";
                def.SftpUsername          = "";
                def.SftpPassword          = "";
                def.FieldSeparator        = "|";
                def.ComponentSeparator    = "^";
                def.SubcomponentSeparator = "&";
                def.RepetitionSeparator   = "~";
                def.EscapeCharacter       = @"\";
                def.IsInternal            = true;
                def.InternalType          = HL7InternalType.MedLabv2_3;
                def.InternalTypeVersion   = Assembly.GetAssembly(typeof(Db)).GetName().Version.ToString();
                def.IsEnabled             = false;
                def.Note                  = "";
                def.ShowDemographics      = HL7ShowDemographics.ChangeAndAdd;         //these last four properties will not be editable for a lab interface type
                def.ShowAccount           = true;
                def.ShowAppts             = true;
                def.IsQuadAsToothNum      = false;
            }
            def.hl7DefMessages = new List <HL7DefMessage>();
            HL7DefMessage msg = new HL7DefMessage();
            HL7DefSegment seg = new HL7DefSegment();

            #region Inbound Messages
            #region ORU - Unsolicited Observation Message
            def.AddMessage(msg, MessageTypeHL7.ORU, MessageStructureHL7.ORU_R01, InOutHL7.Incoming, 0);
            #region MSH - Message Header
            msg.AddSegment(seg, 0, SegmentNameHL7.MSH);
            //Fields-------------------------------------------------------------------------------------------------------------
            //MSH.2, Sending Application.  To identify the LabCorp Lab System sending the results.
            //Possible values for LabCorp (as of their v10.7 specs): '1100' - LabCorp Lab System, 'DIANON' - DIANON Systems,
            //'ADL' - Acupath Diagnostic Laboratories, 'EGL' - Esoterix Genetic Laboratories.
            //For backward compatibility only: 'CMBP', 'LITHOLINK', 'USLABS'
            seg.AddField(2, "sendingApp");
            //MSH.3, Sending Facility.  Identifies the LabCorp laboratory responsible for the client.
            //It could be a LabCorp assigned 'Responsible Lab Code' representing the responsible laboratory or it could be a CLIA number.
            seg.AddField(3, "sendingFacility");
            //MSH.8, Message Type
            seg.AddField(8, "messageType");
            //MSH.9, Message Control ID
            seg.AddField(9, "messageControlId");
            #endregion MSH - Message Header
            #region PID - Patient Identification
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 1, SegmentNameHL7.PID);
            //Fields-------------------------------------------------------------------------------------------------------------
            //PID.2, External Patient ID.  LabCorp defines this as 'client' assigned patient id, just like they do PID.4.
            //This should be the Open Dental patient number, sent in outbound PID.4 and returned in PID.2.
            seg.AddField(2, "pat.PatNum");
            //PID.3, Lab Assigned Patient ID.  LabCorp assigned specimen number.
            seg.AddField(3, "labPatID");
            //PID.4, Alternate Patient ID.  LabCorp defines this as a 'client' assigned patient id, just like they do PID.2.
            //This will be in outbound PID.2, returned in PID.4.
            seg.AddField(4, "altPatID");
            //PID.5, Patient Name
            //This will contain the last, first, and middle names as well as the title
            //Example:  LName^FName^MiddleI
            seg.AddField(5, "pat.nameLFM");
            //PID.7, Date/Time of Birth with Age
            //LabCorp uses this for the birthdate as well as the age in years, months, and days of the patient in the format bday^years^months^days.
            //All age components are left padded with 0's, the years is padded to 3 chars, the months and days are padded to 2 chars
            //Example: 19811213^033^02^19
            seg.AddField(7, "patBirthdateAge");
            //PID.8, Patient Gender
            //We use this field to assist the user in selecting a patient if one is not found when importing the message, but we don't store it
            seg.AddField(8, "pat.Gender");
            //PID.18.1, Patient Account Number.  LabCorp assigned account number.  This field is also used to send the Fasting flag in component 7.
            //Fasting flag values are 'Y', 'N', or blank
            //Example: AccountNum^^^BillCode^ABNFlag^SpecimenStatus^FastingFlag
            seg.AddField(18, "accountNum");
            //PID.19, Patient SSN Number
            //We use this field to assist the user in selecting a patient if one is not found when importing the message, but we don't store it
            seg.AddField(19, "pat.SSN");
            #endregion PID - Patient Identification
            #region NK1 - Next of Kin
            //This segment is for future use only, nothing is currently imported from this segment
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 2, false, true, SegmentNameHL7.NK1);
            //Fields-------------------------------------------------------------------------------------------------------------
            //NK1.2, Next of Kin Name
            //Example: LName^FName^Middle
            //seg.AddField(2,"nextOfKinName");
            //NK1.4, Next of Kin Address
            //Example: Address^Address2^City^State^Zip
            //seg.AddField(4,"nextOfKinAddress");
            //NK1.5, Next of Kin Phone
            //seg.AddField(5,"nextOfKinPhone");
            seg.hl7DefFields = new List <HL7DefField>();
            #endregion NK1 - Next of Kin
            #region NTE - Notes and Comments
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 3, true, true, SegmentNameHL7.NTE);
            //Fields-------------------------------------------------------------------------------------------------------------
            //NTE.2, Comment Source, ID data type
            //LabCorp supported values: 'L' - Laboratory is the source of comment, 'AC' - Accession Comment,
            //'RC' - Result comment, 'RI' - Normal Comment, 'UK' - Undefined comment type
            //We might pull out the source and prepend it to the note, but we won't explicitly add it to the definition or store it separately
            //NTE.3, Comment Text, FT data type (formatted text)
            //Stored in the medlab.NotePat field
            seg.AddField(3, "patNote");
            #endregion NTE - Notes and Comments
            #region ORC - Common Order
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 4, true, false, SegmentNameHL7.ORC);
            //Fields-------------------------------------------------------------------------------------------------------------
            //ORC.2, Unique Foreign Accession or Specimen ID
            //Must match the value in OBR.2 and is the ID value sent on the specimen container and is unique per patient order, not test order.
            //ORC.2.2 is the constant value 'LAB'
            //Example: L2435^LAB
            seg.AddField(2, "specimenID");
            //ORC.3, Filler Accession ID.  The LabCorp assigned specimen number.  These are reused on a yearly basis, but used with the client
            //specific specimen ID in ORC.2, these two numbers should uniquely identify a specimen/order.  ORC.3.2 is the constant value 'LAB'.
            //This should match OBR.3.
            //Example: 08599499950^LAB
            seg.AddField(3, "specimenIDFiller");
            //ORC.12, Ordering Provider, XCN Data Type
            //ProvID^ProvLName^ProvFName^ProvMiddleI^^^^SourceTable
            //This field repeats for every ID available for the provider with the SourceTable component identifying the type of ID in each repetition.
            //SourceTable possible values: 'U' - UPIN, 'P' - Provider Number (Medicaid or Commercial Insurance Provider ID),
            //'N' - NPI Number (Required for Third Party Billing), 'L' - Local (Physician ID)
            //Example: A12345^LNAME^FNAME^M^^^^U~23462^LNAME^FNAME^M^^^^L~0123456789^LNAME^FNAME^M^^^^N~1234567890^LNAME^FNAME^M^^^^P
            seg.AddField(12, "orderingProv");
            #endregion ORC - Common Order
            #region OBR - Observation Request
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 5, true, false, SegmentNameHL7.OBR);
            //Fields-------------------------------------------------------------------------------------------------------------
            //OBR.2, Unique Foreign Accession or Specimen ID
            //Must match the value in ORC.2 and is the ID value sent on the specimen container and is unique per patient order, not test order.
            //OBR.2.2 is the constant value 'LAB'.
            //Example: L2435^LAB
            seg.AddField(2, "specimenID");
            //OBR.3, Internal Accession ID.  The LabCorp assigned specimen number.  These are reused on a yearly basis, but used with the client
            //specific specimen ID in OBR.2, these two numbers should uniquely identify a specimen/order.  OBR.3.2 is the constant value 'LAB'.
            //This should match ORC.3.
            //Example: 08599499950^LAB
            seg.AddField(3, "specimenIDFiller");
            //OBR.4, Universal Service Identifier, CWE data type
            //This identifies the observation.  This will be the ID and text description of the test, as well as the LOINC code and description.
            //Example: 006072^RPR^L^20507-0^Reagin Ab^LN
            seg.AddField(4, "obsTestID");
            //OBR.7, Observation/Specimen Collection Date/Time
            //Format for LabCorp: yyyyMMddHHmm
            seg.AddField(7, "dateTimeCollected");
            //OBR.9, Collection/Urine Volume
            seg.AddField(9, "totalVolume");
            //OBR.11, Action Code
            //Used to identify the type of result being returned.  'A' - Add on, 'G' - Reflex, Blank for standard results
            seg.AddField(11, "specimenAction");
            //OBR.13, Relevant Clinical Information.  Used for informational purposes.
            seg.AddField(13, "clinicalInfo");
            //OBR.14, Date/Time of Specimen Receipt in Lab.
            //LabCorp format: yyyMMddHHmm
            seg.AddField(14, "dateTimeEntered");
            //OBR.16, Ordering Provider.
            //ProvID^ProvLName^ProvFName^ProvMiddleI^^^^SourceTable
            //This field repeats for every ID available for the provider with the SourceTable component identifying the type of ID in each repetition.
            //SourceTable possible values: 'U' - UPIN, 'P' - Provider Number (Medicaid or Commercial Insurance Provider ID),
            //'N' - NPI Number (Required for Third Party Billing), 'L' - Local (Physician ID)
            //Example: A12345^LNAME^FNAME^M^^^^U~23462^LNAME^FNAME^M^^^^L~0123456789^LNAME^FNAME^M^^^^N~1234567890^LNAME^FNAME^M^^^^P
            seg.AddField(16, "orderingProv");
            //OBR.18, Alternate Specimen ID.
            seg.AddField(18, "specimenIDAlt");
            //OBR.22, Date/Time Observation Reported.
            //LabCorp format: yyyyMMddHHmm
            seg.AddField(22, "dateTimeReported");
            //OBR.24, Producer's Section ID, used by LabCorp to identify the facility responsible for performing the testing.
            //This will be the footnote ID of the ZPS segment and will be used to attach a MedLab object to a MedLabFacility object.
            seg.AddField(24, "facilityID");
            //OBR.25, Order Result Status.
            //LabCorp values: 'F' - Final, 'P' - Preliminary, 'X' - Cancelled, 'C' - Corrected
            seg.AddField(25, "resultStatus");
            //OBR.26, Link to Parent Result.
            //If this is a reflex result, the value from the OBX.3.1 field of the parent result will be here.
            seg.AddField(26, "parentObsID");
            //OBR.29, Link to Parent Order.
            //If this is a reflex test, the value from the OBR.4.1 field of the parent test will be here.
            seg.AddField(29, "parentObsTestID");
            #endregion OBR - Observation Request
            #region NTE - Notes and Comments
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 6, true, true, SegmentNameHL7.NTE);
            //Fields-------------------------------------------------------------------------------------------------------------
            //NTE.2, Comment Source, ID data type
            //LabCorp supported values: 'L' - Laboratory is the source of comment, 'AC' - Accession Comment,
            //'RC' - Result comment, 'RI' - Normal Comment, 'UK' - Undefined comment type
            //We might pull out the source and prepend it to the note, but we won't explicitly add it to the definition or store it separately
            //NTE.3, Comment Text, FT data type (formatted text)
            //Stored in the medlab.NoteLab field
            seg.AddField(3, "labNote");
            #endregion NTE - Notes and Comments
            #region OBX - Observation/Result
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 7, true, false, SegmentNameHL7.OBX);
            //Fields-------------------------------------------------------------------------------------------------------------
            //OBX.2, Value Type.  This field is not stored explicitly, but it is used to determine the value type of the observation.
            //If this field is 'TX' for text, the value will be >21 chars and will be sent in the attached NTEs.
            seg.AddField(2, "obsValueType");
            //OBX.3, Observation ID.  This field has the same structure as the OBR.4.
            //ID^Text^CodeSystem^AltID^AltIDText^AltIDCodeSystem, the AltID is the LOINC code so the AltIDCodeSystem will be 'LN'
            //Example: 006072^RPR^L^20507-0^Reagin Ab^LN
            seg.AddField(3, "obsID");
            //OBX.4, Observation Sub ID.  This field is used to aid in the identification of results with the same observation ID (OBX.3) within a
            //given OBR.  If OBX.5.3 is 'ORM' (organism) this field will link a result to an organism, whether this is for organism #1, organism #2,
            //or organism #3.
            seg.AddField(4, "obsIDSub");
            //OBX.5, Observation Value.  ObsValue^TypeOfData^DataSubtype^Encoding^Data.  LabCorp report will display OBX.5.1 as the result.
            //For value >21 chars in length: OBX.2 will be 'TX' for text, OBX.5 will be NULL (empty field), and the value will be in attached NTEs.
            //"TNP" will be reported for Test Not Performed.
            seg.AddField(5, "obsValue");
            //OBX.6, Units.
            //Identifier^Text^CodeSystem.  Id is units of measure abbreviation, text is full text version of units, coding system is 'L' (local id).
            seg.AddField(6, "obsUnits");
            //OBX.7, Reference Range.
            seg.AddField(7, "obsRefRange");
            //OBX.8, Abnormal Flags.  For values see enum OpenDentBusiness.AbnormalFlag
            seg.AddField(8, "obsAbnormalFlag");
            //OBX.11, Observation Result Status.
            //LabCorp values: 'F' - Final, 'P' - Preliminary, 'X' - Cancelled, 'C' - Corrected, 'I' - Incomplete
            seg.AddField(11, "resultStatus");
            //OBX.14, Date/Time of Observation.
            //LabCorp format yyyyMMddHHmm
            seg.AddField(14, "dateTimeObs");
            //OBX.15, Producer's ID.
            //For LabCorp this is used to report the facility responsible for performing the testing.  This will hold the lab ID that will reference
            //a ZPS segment with the lab name, address, and director details.  Used to link a MedLabResult object to a MedLabFacility object.
            seg.AddField(15, "facilityID");
            #endregion OBX - Observation/Result
            #region ZEF - Encapsulated Data Format
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 8, true, true, SegmentNameHL7.ZEF);
            //Fields-------------------------------------------------------------------------------------------------------------
            //ZEF.1, Sequence Number, 1 through 9999
            seg.AddField(1, "sequenceNum");
            //ZEF.2, Embedded File.
            //Base64 embedded file, sent in 50k blocks and will be concatenated together to and converted back into
            seg.AddField(2, "base64File");
            #endregion ZEF - Encapsulated Data Format
            #region NTE - Notes and Comments
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 9, true, true, SegmentNameHL7.NTE);
            //Fields-------------------------------------------------------------------------------------------------------------
            //NTE.2, Comment Source, ID data type
            //LabCorp supported values: 'L' - Laboratory is the source of comment, 'AC' - Accession Comment,
            //'RC' - Result comment, 'RI' - Normal Comment, 'UK' - Undefined comment type
            //We might pull out the source and prepend it to the note, but we won't explicitly add it to the definition or store it separately
            //NTE.3, Comment Text, FT data type (formatted text)
            //Stored in the medlabresult.Note field
            seg.AddField(3, "obsNote");
            #endregion NTE - Notes and Comments
            #region SPM - Specimen
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 10, true, true, SegmentNameHL7.SPM);
            //Fields-------------------------------------------------------------------------------------------------------------
            //SPM.2, Specimen ID.
            //Unique ID of the specimen as sent on the specimen container.  Same as the value in ORC.2.
            seg.AddField(2, "specimenID");
            //SPM.4, Specimen Type
            //SPM.8, Specimen Source Site
            //SPM.4, Specimen Source Site Modifier
            //SPM.14, Specimen Description.  Text field used to send additional information about the specimen
            seg.AddField(14, "specimenDescript");
            //SPM.17, Date/Time Specimen Collected
            seg.AddField(17, "dateTimeSpecimen");
            #endregion SPM - Specimen
            #region ZPS - Place of Service
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 11, true, false, SegmentNameHL7.ZPS);
            //Fields-------------------------------------------------------------------------------------------------------------
            //ZPS.2, Facility Mnemonic.  Footnote ID for the lab facility used to reference this segment from OBX.15.
            seg.AddField(2, "facilityID");
            //ZPS.3, Facility Name.
            seg.AddField(3, "facilityName");
            //ZPS.4, Facility Address.
            //Address^^City^State^Zip
            seg.AddField(4, "facilityAddress");
            //ZPS.5, Facility Phone.  (LabCorp document says numberic characters only, so we can assume no dashes or parentheses.)
            seg.AddField(5, "facilityPhone");
            //ZPS.7, Facility Director.
            //Title^LName^FName^MiddleI
            seg.AddField(7, "facilityDirector");
            #endregion ZPS - Place of Service
            #endregion ORU - Unsolicited Observation Message
            #endregion Inbound Messages
            #region Outbound Messages
            //Results only interface for now, so no outbound messages yet
            //In the future, we will implement the orders portion of the interface and have outbound ORM messages
            #endregion Outbound Messages
            return(def);
        }
Esempio n. 17
0
		public static void ProcessSeg(Patient pat,Appointment apt,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			switch(segDef.SegmentName) {
				case SegmentNameHL7.AIG:
				case SegmentNameHL7.AIP:
					ProcessAIGorAIP(pat,apt,segDef,seg);//segDef.SegmentName will be used by this function to parse the provider as ProvNum^LName^Fname^MI^^Abbr or ProvNum^LName, FName^^Abbr
					return;
				case SegmentNameHL7.AIL:
					ProcessAIL(pat,apt,segDef,seg);
					return;
				case SegmentNameHL7.AL1:
					ProcessAL1(pat,segDef,seg);
					return;
				case SegmentNameHL7.ARQ:
					ProcessARQ(pat,apt,segDef,seg,msg);
					return;
				case SegmentNameHL7.GT1:
					ProcessGT1(pat,segDef,seg,msg);
					return;
				case SegmentNameHL7.IN1:
					//ProcessIN1();
					return;
				case SegmentNameHL7.MSA:
					ProcessMSA(segDef,seg,msg);
					return;
				case SegmentNameHL7.MSH:
					ProcessMSH(segDef,seg,msg);
					return;
				case SegmentNameHL7.NTE:
					ProcessNTE(pat,apt,segDef,seg,msg);
					return;
				case SegmentNameHL7.OBX:
					ProcessOBX(pat,segDef,seg);
					return;
				case SegmentNameHL7.PD1:
					//ProcessPD1();
					return;
				case SegmentNameHL7.PID:
					ProcessPID(pat,segDef,seg,msg);
					return;
				case SegmentNameHL7.PR1:
					ProcessPR1(pat,segDef,seg,msg);
					return;
				case SegmentNameHL7.PRB:
					ProcessPRB(pat,segDef,seg,msg);
					return;
				case SegmentNameHL7.PV1:
					ProcessPV1(pat,apt,segDef,seg);
					return;
				case SegmentNameHL7.SCH:
					ProcessSCH(pat,apt,segDef,seg,msg);
					return;
				default:
					return;
			}
		}
Esempio n. 18
0
		///<summary>This will be used to set the clinic and confirmation status of the appointment.  If apt is null, does nothing.</summary>
		public static void ProcessAIL(Patient pat,Appointment apt,HL7DefSegment segDef,SegmentHL7 seg) {
			if(apt==null) {//We have to have an appt to process the AIL segment
				return;
			}
			Appointment aptOld=apt.Clone();	
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int intItemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "apt.confirmStatus":
						long aptConfirmDefNum=0;
						Def[] listConfirmStats=DefC.GetList(DefCat.ApptConfirmed);
						for(int j=0;j<listConfirmStats.Length;j++) {
							if(seg.GetFieldComponent(intItemOrder,1).ToLower()==listConfirmStats[j].ItemName.ToLower()//ItemName is the confirmation name
								|| (listConfirmStats[j].ItemValue!="" && seg.GetFieldComponent(intItemOrder,1).ToLower()==listConfirmStats[j].ItemValue.ToLower()))//ItemValue is the confirmation abbreviation, which may be blank
							{
								aptConfirmDefNum=listConfirmStats[j].DefNum;
								break;
							}
						}
						if(aptConfirmDefNum>0) {
							apt.Confirmed=aptConfirmDefNum;
						}
						continue;
					case "apt.location":
						if(seg.GetFieldComponent(intItemOrder,5).ToLower()!="c") {
							continue;
						}
						long clinicNum=Clinics.GetByDesc(seg.GetFieldComponent(intItemOrder,0));//0 if field is blank or description doesn't match clinic description in the db
						if(clinicNum>0) {
							apt.ClinicNum=clinicNum;//the pat.ClinicNum may be set based on a different segment, like the PV1 segment
						}
						continue;
					default:
						continue;
				}
			}
			Appointments.Update(apt,aptOld);
			_aptProcessed=apt;
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated appointment for patient "+pat.GetNameFLnoPref()+" due to an incoming AIL segment.",EventLogEntryType.Information);
			}
			return;
		}
Esempio n. 19
0
		public static void ProcessPR1(Patient pat,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			string strToothNum="";//could contain the tooth range in comma-delimited list
			string strSurf="";//used for surf/quad/sext/arch
			string strOidExt="";
			string strOidExtRoot="";
			ProcedureCode procCode=null;
			DateTime dateProc=DateTime.MinValue;
			Hashtable hashProcedureCodes=ProcedureCodeC.GetHList();
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "proccode.ProcCode":
						//ProcCode^descript (ignored)^CD2^^^^2014^^Layman Term (ignored)
						//Example: D1351^^CD2^^^^2014
						//must be CDT code (CD2 is code system abbr according to HL7 documentation) and must be version 2014
						if(seg.GetFieldComponent(itemOrder,2).ToLower()!="cd2" || seg.GetFieldComponent(itemOrder,6)!="2014") {
							EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()
								+".  Only CDT codes from code system version 2014 are currently allowed in the PR1 segment.  The code system name provided was "
								+seg.GetFieldComponent(itemOrder,2)+" and the code system version provided was "+seg.GetFieldComponent(itemOrder,6)+".",EventLogEntryType.Information);
							return;
						}
						string strProcCode=seg.GetFieldComponent(itemOrder,0);
						if(!hashProcedureCodes.ContainsKey(strProcCode)) {//code does not exist in proc code list, write entry in event log an return
							EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()
								+".  The code supplied in the PR1 segment does not exist in the database.  The code provided was "+strProcCode+".",EventLogEntryType.Information);
							return;
						}
						procCode=(ProcedureCode)hashProcedureCodes[strProcCode];
						continue;
					case "proc.procDateTime":
						dateProc=FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "proc.toothSurfRange":
						char subcompSeparator='&';
						if(msg.Delimiters.Length>3) {
							subcompSeparator=msg.Delimiters[3];
						}
						string[] listSubComponents=seg.GetFieldComponent(itemOrder).Split(new char[] { subcompSeparator },StringSplitOptions.None);
						if(listSubComponents.Length>0) {
							strToothNum=listSubComponents[0];
						}
						if(listSubComponents.Length>1) {
							strSurf=listSubComponents[1];
						}
						continue;
					case "proc.uniqueId":
						//Id^^UniversalId
						strOidExt=seg.GetFieldComponent(itemOrder,0);
						strOidExtRoot=seg.GetFieldComponent(itemOrder,2);
						if(strOidExt!="" && strOidExtRoot!="" && OIDExternals.GetByRootAndExtension(strOidExtRoot,strOidExt)!=null) {
							//the universal ID and root are already in the oidexternals table, do not insert another procedure, must be a duplicate
							EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()
								+".  The universal ID and root supplied in the PR1 segment refers to an existing procedure."
								+"  Inserting another would result in a duplicate procedure.  The ID provided was "
								+strOidExt+", the root was "+strOidExtRoot+".",EventLogEntryType.Information);
							return;
						}
						continue;
					default:
						continue;
				}
			}
			if(procCode==null) {
				EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()
					+".  No procedure code was defined for a PR1 segment or was missing.",EventLogEntryType.Information);
				return;
			}
			Procedure procCur=new Procedure();
			#region Validate/Convert/Set Treatment Area
			switch(procCode.TreatArea) {
				case TreatmentArea.Arch:
					if(strSurf!="L" && strSurf!="U") {
						EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "
							+procCode.ProcCode+" is arch but the arch of "+strSurf+" is invalid.",EventLogEntryType.Information);
						return;
					}
					procCur.Surf=strSurf;
					break;
				case TreatmentArea.Quad:
					if(strSurf!="UL" && strSurf!="UR" && strSurf!="LL" && strSurf!="LR") {
						EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "
							+procCode.ProcCode+" is quadrant but the quadrant of "+strSurf+" is invalid.",EventLogEntryType.Information);
						return;
					}
					procCur.Surf=strSurf;
					break;
				case TreatmentArea.Sextant:
					bool isValidSextant=false;
					if(strSurf=="1" || strSurf=="2" || strSurf=="3" || strSurf=="4" || strSurf=="5" || strSurf=="6") {
						isValidSextant=true;
					}
					if(CultureInfo.CurrentCulture.Name.EndsWith("CA")) {//Canadian. en-CA or fr-CA
						if(strSurf=="03" || strSurf=="04" || strSurf=="05" || strSurf=="06" || strSurf=="07" || strSurf=="08") {
							isValidSextant=true;
						}
					}
					if(!isValidSextant) {
						EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "
							+procCode.ProcCode+" is sextant but the sextant of "+strSurf+" is invalid.",EventLogEntryType.Information);
						return;
					}
					procCur.Surf=strSurf;
					break;
				case TreatmentArea.Surf:
					if(!Tooth.IsValidEntry(strToothNum)) {
						EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "
							+procCode.ProcCode+" is surface but the tooth number of "+strToothNum+" is invalid.",EventLogEntryType.Information);
					}
					procCur.ToothNum=Tooth.FromInternat(strToothNum);
					string strSurfTidy=Tooth.SurfTidyFromDisplayToDb(strSurf,procCur.ToothNum);
					if(strSurfTidy=="" || strSurf=="") {
						EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "
							+procCode.ProcCode+" is surface but the surface of "+strSurf+" is invalid.",EventLogEntryType.Information);
						return;
					}
					procCur.Surf=strSurfTidy;
					break;
				case TreatmentArea.Tooth:
					if(!Tooth.IsValidEntry(strToothNum)) {
						EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "
							+procCode.ProcCode+" is tooth but the tooth number of "+strToothNum+" is invalid.",EventLogEntryType.Information);
						return;
					}
					procCur.ToothNum=Tooth.FromInternat(strToothNum);
					break;
				case TreatmentArea.ToothRange:
					//break up the list of tooth numbers supplied and validate and convert them into universal tooth numbers for inserting into the db
					string[] listToothNums=strToothNum.Split(new char[] { ',' },StringSplitOptions.RemoveEmptyEntries);
					for(int i=0;i<listToothNums.Length;i++) {
						if(!Tooth.IsValidEntry(listToothNums[i])) {
							EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "
								+procCode.ProcCode+" is tooth range but the tooth number of "+listToothNums[i]+" is invalid.",EventLogEntryType.Information);
							return;
						}
						if(Tooth.IsPrimary(Tooth.FromInternat(listToothNums[i]))) {
							EventLog.WriteEntry("OpenDentHL7","A procedure was not added for patient "+pat.GetNameFLnoPref()+".  The treatment area for the code "+procCode.ProcCode
								+" is tooth range but the tooth number of "+listToothNums[i]+" is a primary tooth number and therefore not allowed.",EventLogEntryType.Information);
						}
						listToothNums[i]=Tooth.FromInternat(listToothNums[i]);
					}
					procCur.ToothNum=string.Join(",",listToothNums);
					break;
				//We won't validate or use the tooth number or surface fields if the treatment are of the proccode is mouth or none
				case TreatmentArea.None:
				case TreatmentArea.Mouth:
				default:
					break;
			}
			#endregion Validate/Convert/Set Treatment Area
			Procedures.SetDateFirstVisit(dateProc,1,pat);//wait until after validating, might not insert the proc, don't return after this point
			procCur.PatNum=pat.PatNum;
			procCur.CodeNum=procCode.CodeNum;
			procCur.ProcDate=dateProc;
			procCur.DateTP=dateProc;
			procCur.ProcStatus=ProcStat.TP;
			procCur.ProvNum=pat.PriProv;
			if(procCode.ProvNumDefault!=0) {
				procCur.ProvNum=procCode.ProvNumDefault;
			}
			else if(procCode.IsHygiene && pat.SecProv!=0) {
				procCur.ProvNum=pat.SecProv;
			}
			procCur.Note="";
			procCur.ClinicNum=pat.ClinicNum;
			procCur.BaseUnits=procCode.BaseUnits;
			procCur.SiteNum=pat.SiteNum;
			procCur.RevCode=procCode.RevenueCodeDefault;
			procCur.DiagnosticCode=PrefC.GetString(PrefName.ICD9DefaultForNewProcs);
			List<PatPlan> listPatPlan=PatPlans.Refresh(pat.PatNum);
			List<Benefit> listBen=Benefits.Refresh(listPatPlan,new List<InsSub>());
			#region Set ProcFee From Fee Schedule
			//check if it's a medical procedure
			bool isMed=false;
			procCur.MedicalCode=procCode.MedicalCode;
			if(procCur.MedicalCode!=null && procCur.MedicalCode!="") {
				isMed=true;
			}
			//Get fee schedule for medical or dental
			long feeSch;
			if(isMed) {
				feeSch=Fees.GetMedFeeSched(pat,new List<InsPlan>(),listPatPlan,new List<InsSub>());
			}
			else {
				feeSch=Fees.GetFeeSched(pat,new List<InsPlan>(),listPatPlan,new List<InsSub>());
			}
			//Get the fee amount for medical or dental
			double insfee;
			if(PrefC.GetBool(PrefName.MedicalFeeUsedForNewProcs) && isMed) {
				insfee=Fees.GetAmount0(ProcedureCodes.GetCodeNum(procCur.MedicalCode),feeSch);
			}
			else {
				insfee=Fees.GetAmount0(procCode.CodeNum,feeSch);
			}
			InsPlan priplan=null;
			if(listPatPlan.Count>0) {
				priplan=InsPlans.GetPlan(InsSubs.GetSub(listPatPlan[0].InsSubNum,new List<InsSub>()).PlanNum,new List<InsPlan>());
			}
			if(priplan!=null && priplan.PlanType=="p" && !isMed) {//PPO
				Provider patProv=Providers.GetProv(pat.PriProv);
				if(patProv==null) {
					patProv=Providers.GetProv(PrefC.GetLong(PrefName.PracticeDefaultProv));
				}
				double standardFee=Fees.GetAmount0(procCode.CodeNum,patProv.FeeSched);
				if(standardFee>insfee) {
					procCur.ProcFee=standardFee;
				}
				else {
					procCur.ProcFee=insfee;
				}
			}
			else {
				procCur.ProcFee=insfee;
			}
			#endregion Set ProcFee From Fee Schedule
			procCur.ProcNum=Procedures.Insert(procCur);
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Inserted a new procedure for patient "+pat.GetNameFLnoPref()+" due to an incoming PR1 segment.",EventLogEntryType.Information);
			}
			if(strOidExt!="" && strOidExtRoot!="") {
				OIDExternal procOidExt=new OIDExternal();
				procOidExt.IDType=IdentifierType.Procedure;
				procOidExt.IDInternal=procCur.ProcNum;
				procOidExt.IDExternal=strOidExt;
				procOidExt.rootExternal=strOidExtRoot;
				OIDExternals.Insert(procOidExt);
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Added an external procedure ID to the oidexternals table due to an incoming PR1 segment.\r\nProcNum: "
						+procCur.ProcNum.ToString()+", External problem ID: "+procOidExt.IDExternal+", External root: "+procOidExt.rootExternal+".",EventLogEntryType.Information);
				}
			}
			Procedures.ComputeEstimates(procCur,pat.PatNum,new List<ClaimProc>(),true,new List<InsPlan>(),listPatPlan,listBen,pat.Age,new List<InsSub>());
			return;
		}
Esempio n. 20
0
		///<summary>apt could be null if the PV1 segment is from a message that does not refer to an appointment like an ADT or PPR message or if it is from an SIU message and is for a new appointment.  If apt is null, do not update any of the apt fields, like clinic or provider.</summary>
		public static void ProcessPV1(Patient pat,Appointment apt,HL7DefSegment segDef,SegmentHL7 seg) {
			Appointment aptOld=null;
			if(apt!=null) {
				aptOld=apt.Clone();
			}
			Patient patOld=pat.Copy();
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "pat.GradeLevel":
						int intGradeLevel=0;
						try {
							intGradeLevel=PIn.Int(seg.GetFieldComponent(itemOrder));
						}
						catch(Exception ex) {
							//if parsing field to int fails, do nothing
							continue;
						}
						if(intGradeLevel<Enum.GetNames(typeof(PatientGrade)).Length) {//if parsed value is outside the range of enum, do nothing with the data
							pat.GradeLevel=(PatientGrade)intGradeLevel;//0=Unknown,1-12=first-twelfth, 13=PrenatalWIC, 14=PreK, 15=Kindergarten, 16=Other
						}
						continue;
					case "pat.location":
						//Example: ClinicDescript^OpName^^PracticeTitle^^c  (c for clinic)
						if(seg.GetFieldComponent(itemOrder,5).ToLower()!="c") {//LocationType is 'c' for clinic
							continue;
						}
						long clinicNum=Clinics.GetByDesc(seg.GetFieldComponent(itemOrder,0));//0 if field is blank or description doesn't match clinic description in the db
						if(clinicNum==0) {
							continue;//do nothing, either no clinic description in the message or no matching clinic found
						}
						pat.ClinicNum=clinicNum;
						if(apt!=null) {
							apt.ClinicNum=clinicNum;//the apt.ClinicNum may be set based on a different segment, like the AIL segment
						}
						continue;
					case "prov.provIdName":
					case "prov.provIdNameLFM":
						long provNum=0;
						if(_isEcwHL7Def) {//uses prov.EcwID
							provNum=FieldParser.ProvProcessEcw(seg.GetField(itemOrder));
						}
						else {
							provNum=FieldParser.ProvParse(seg.GetField(itemOrder),SegmentNameHL7.PV1,_isVerboseLogging);
						}
						if(provNum==0) {//This segment didn't have valid provider information in it, so do nothing
							continue;
						}
						if(apt!=null) {//We will set the appt.ProvNum (dentist) to the provider located in the PV1 segment, but this may be changed if the AIG or AIP segments are included
							apt.ProvNum=provNum;
						}
						pat.PriProv=provNum;
						continue;
					case "pat.site":
						//Example: |West Salem Elementary^^^^^s| ('s' for site)
						if(seg.GetFieldComponent(itemOrder,5).ToLower()!="s") {//LocationType is 's' for site
							continue;//not a site description, do nothing
						}
						long siteNum=Sites.FindMatchSiteNum(seg.GetFieldComponent(itemOrder,0));//0 if component is blank, -1 if no matching site description in the db
						if(siteNum>0) {
							pat.SiteNum=siteNum;
						}
						continue;
					case "pat.Urgency":
						int intPatUrgency=-1;
						try {
							intPatUrgency=PIn.Int(seg.GetFieldComponent(itemOrder));//if field is empty, PIn.Int will return 0 which will be the Unknown default urgency
						}
						catch(Exception ex) {
							//do nothing, patUrgency will remain -1
						}
						if(intPatUrgency>-1 && intPatUrgency<4) {//only cast to enum if 0-3
							pat.Urgency=(TreatmentUrgency)intPatUrgency;
						}
						continue;
					default:
						continue;
				}
			}
			Patients.Update(pat,patOld);
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated patient "+pat.GetNameFLnoPref()+" due to an incoming PV1 segment.",EventLogEntryType.Information);
			}
			if(apt!=null) {
				Appointments.Update(apt,aptOld);
				_aptProcessed=apt;
			}
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated appointment for patient "+pat.GetNameFLnoPref()+" due to an incoming PV1 segment.",EventLogEntryType.Information);
			}
			return;
		}
Esempio n. 21
0
		public static void ProcessSeg(Patient pat,long aptNum,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			switch(segDef.SegmentName) {
				case SegmentNameHL7.AIG:
					ProcessAIG(pat,aptNum,segDef,seg);
					return;
				case SegmentNameHL7.GT1:
					ProcessGT1(pat,segDef,seg);
					return;
				case SegmentNameHL7.IN1:
					//ProcessIN1();
					return;
				case SegmentNameHL7.MSA:
					ProcessMSA(segDef,seg,msg);
					return;
				case SegmentNameHL7.MSH:
					ProcessMSH(segDef,seg,msg);
					return;
				case SegmentNameHL7.PD1:
					//ProcessPD1();
					return;
				case SegmentNameHL7.PID:
					ProcessPID(pat,segDef,seg);
					return;
				case SegmentNameHL7.PV1:
					ProcessPV1(pat,aptNum,segDef,seg);
					return;
				case SegmentNameHL7.SCH:
					ProcessSCH(pat,segDef,seg);
					return;
				default:
					return;
			}
		}
Esempio n. 22
0
		public static void ProcessOBX(Patient pat,HL7DefSegment segDef,SegmentHL7 seg) {
			long rxnorm=0;
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int intItemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "medicationRxNorm":
						if(seg.GetFieldComponent(intItemOrder,2).ToLower()!="rxnorm") {
							//if not an RXNORM code, do nothing.  Only RXNORM codes are currently supported
							EventLog.WriteEntry("OpenDentHL7","A medication was not added for patient "+pat.GetNameFLnoPref()
								+".  Only RxNorm codes are currently allowed in the OBX segment.  The code system name provided was "
								+seg.GetFieldComponent(intItemOrder,2)+".",EventLogEntryType.Information);
							return;
						}
						try {
							rxnorm=PIn.Long(seg.GetFieldComponent(intItemOrder,0));
						}
						catch(Exception ex) {//PIn.Long throws an exception if converting to an Int64 fails
							//do nothing, rxnorm will remain 0
						}
						continue;
					default:
						continue;
				}
			}
			if(rxnorm==0) {
				EventLog.WriteEntry("OpenDentHL7","A medication was not added for patient "
					+pat.GetNameFLnoPref()+".  The RxNorm code supplied in the OBX segment was invalid.",EventLogEntryType.Information);
				return;//not able to enter this medication if not given a valid rxnorm
			}
			Medication medCur=Medications.GetMedicationFromDbByRxCui(rxnorm);//an RxNorm could be attached to multiple medications, we will just add the first one we come to
			if(medCur==null) {
				EventLog.WriteEntry("OpenDentHL7","A medication was not added for patient "+pat.GetNameFLnoPref()
					+".  There is not a medication in the database with the RxNorm code of "+rxnorm.ToString()+".",EventLogEntryType.Information);
				return;
			}
			List<MedicationPat> listMedPatsCur=MedicationPats.Refresh(pat.PatNum,false);
			for(int i=0;i<listMedPatsCur.Count;i++) {
				if(listMedPatsCur[i].MedicationNum==medCur.MedicationNum) {
					return;//this patient already has this medication recorded and active
				}
			}
			MedicationPat medpatCur=new MedicationPat();
			medpatCur.PatNum=pat.PatNum;
			medpatCur.MedicationNum=medCur.MedicationNum;
			medpatCur.ProvNum=pat.PriProv;
			medpatCur.RxCui=medCur.RxCui;
			MedicationPats.Insert(medpatCur);
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Inserted a new medication for patient "+pat.GetNameFLnoPref()+" due to an incoming OBX segment.",EventLogEntryType.Information);
			}
			return;
		}
Esempio n. 23
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;
		}
Esempio n. 24
0
        //public static void ProcessPD1() {
        //	return;
        //}

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

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

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

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

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

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

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

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

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

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

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

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

                default:
                    continue;
                }
            }
            return;
        }
Esempio n. 25
0
		public static HL7Def GetDeepInternal(HL7Def def) {
			//ok to pass in null
			//HL7Def def=HL7Defs.GetInternalFromDb("eCWStandalone");
			if(def==null) {//wasn't in the database
				def=new HL7Def();
				def.IsNew=true;
				def.Description="eCW Standalone";
				def.ModeTx=ModeTxHL7.File;
				def.IncomingFolder="";
				def.OutgoingFolder="";
				def.IncomingPort="";
				def.OutgoingIpPort="";
				def.SftpInSocket="";
				def.SftpUsername="";
				def.SftpPassword="";
				def.FieldSeparator="|";
				def.ComponentSeparator="^";
				def.SubcomponentSeparator="&";
				def.RepetitionSeparator="~";
				def.EscapeCharacter=@"\";
				def.IsInternal=true;
				def.InternalType=HL7InternalType.eCWStandalone;
				def.InternalTypeVersion=Assembly.GetAssembly(typeof(Db)).GetName().Version.ToString();
				def.IsEnabled=false;
				def.Note="";
				def.ShowDemographics=HL7ShowDemographics.ChangeAndAdd;
				def.ShowAccount=true;
				def.ShowAppts=true;
				def.IsQuadAsToothNum=false;
			}
			def.hl7DefMessages=new List<HL7DefMessage>();//so that if this is called repeatedly, it won't pile on duplicate messages.
			//in either case, now get all child objects, which can't be in the database.
			#region Inbound Messages
				#region ADT - Patient Demographics (Admits, Discharges, and Transfers)
				//----------------------------------------------------------------------------------------------------------------------------------
				//eCW incoming patient information (ADT).
				HL7DefMessage msg=new HL7DefMessage();
				def.AddMessage(msg,MessageTypeHL7.ADT,MessageStructureHL7.ADT_A01,InOutHL7.Incoming,0);
				//MSH segment------------------------------------------------------------------
				HL7DefSegment seg=new HL7DefSegment();
				msg.AddSegment(seg,0,SegmentNameHL7.MSH);
				//MSH.8, Message Type
				seg.AddField(8,"messageType");
				//MSH.9, Message Control ID
				seg.AddField(9,"messageControlId");
				//PID segment------------------------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,2,SegmentNameHL7.PID);
				//PID.2, Patient ID
				seg.AddField(2,"pat.ChartNumber");
				//PID.4, Alternate Patient ID, PID.4 is not saved with using standalone integration
				//PID.5, Patient Name
				seg.AddField(5,"pat.nameLFM");
				//PID.7, Date/Time of Birth
				seg.AddField(7,"pat.birthdateTime");
				//PID.8, Administrative Sex
				seg.AddField(8,"pat.Gender");
				//PID.10, Race
				seg.AddField(10,"pat.Race");
				//PID.11, Patient Address
				seg.AddField(11,"pat.addressCityStateZip");
				//PID.13, Phone Number - Home
				seg.AddField(13,"pat.HmPhone");
				//PID.14, Phone Number - Business
				seg.AddField(14,"pat.WkPhone");
				//PID.16, Marital Status
				seg.AddField(16,"pat.Position");
				//PID.19, SSN - Patient
				seg.AddField(19,"pat.SSN");
				//PID.22, Fee Schedule
				seg.AddField(22,"pat.FeeSched");
				//GT1 segment------------------------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,5,SegmentNameHL7.GT1);
				//GT1.2, Guarantor Number
				seg.AddField(2,"guar.ChartNumber");
				//GT1.3, Guarantor Name
				seg.AddField(3,"guar.nameLFM");
				//GT1.5, Guarantor Address
				seg.AddField(5,"guar.addressCityStateZip");
				//GT1.6, Guarantor Phone Number - Home
				seg.AddField(6,"guar.HmPhone");
				//GT1.7, Guarantor Phone Number - Business
				seg.AddField(7,"guar.WkPhone");
				//GT1.8, Guarantor Date/Time of Birth
				seg.AddField(8,"guar.birthdateTime");
				//GT1.9, Guarantor Administrative Sex
				seg.AddField(9,"guar.Gender");
				//GT1.12, Guarantor SSN
				seg.AddField(12,"guar.SSN");
				#endregion ADT - Patient Demographics (Admits, Discharges, and Transfers)
			#endregion Inbound Messages
			return def;
		}
Esempio n. 26
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;
        }
Esempio n. 27
0
		//public static void ProcessPD1() {
		//	return;
		//}

		public static void ProcessPID(Patient pat,HL7DefSegment segDef,SegmentHL7 seg) {
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "pat.addressCityStateZip":
						pat.Address=seg.GetFieldComponent(itemOrder,0);
						pat.Address2=seg.GetFieldComponent(itemOrder,1);
						pat.City=seg.GetFieldComponent(itemOrder,2);
						pat.State=seg.GetFieldComponent(itemOrder,3);
						pat.Zip=seg.GetFieldComponent(itemOrder,4);
						continue;
					case "pat.birthdateTime":
						pat.Birthdate=FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.ChartNumber":
						pat.ChartNumber=seg.GetFieldComponent(itemOrder);
						continue;
					case "pat.Gender":
						pat.Gender=FieldParser.GenderParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.HmPhone":
						pat.HmPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.nameLFM":
						pat.LName=seg.GetFieldComponent(itemOrder,0);
						pat.FName=seg.GetFieldComponent(itemOrder,1);
						pat.MiddleI=seg.GetFieldComponent(itemOrder,2);
						continue;
					case "pat.PatNum":
						if(pat.PatNum!=0 && pat.PatNum!=PIn.Long(seg.GetFieldComponent(itemOrder))) {
							throw new Exception("Invalid PatNum");
						}
						continue;
					case "pat.Position":
						pat.Position=FieldParser.MaritalStatusParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.Race":
						PatientRaceOld patientRaceOld=FieldParser.RaceParse(seg.GetFieldComponent(itemOrder));
						//Converts deprecated PatientRaceOld enum to list of PatRaces, and adds them to the PatientRaces table for the patient.
						PatientRaces.Reconcile(pat.PatNum,PatientRaces.GetPatRacesFromPatientRaceOld(patientRaceOld));
						continue;
					case "pat.SSN":
						pat.SSN=seg.GetFieldComponent(itemOrder);
						continue;
					case "pat.WkPhone":
						pat.WkPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.FeeSched":
						if(Programs.IsEnabled(ProgramName.eClinicalWorks) && ProgramProperties.GetPropVal(ProgramName.eClinicalWorks,"FeeSchedulesSetManually")=="1") {
							//if using eCW and FeeSchedulesSetManually
							continue;//do not process fee sched field, manually set by user
						}
						else {
							pat.FeeSched=FieldParser.FeeScheduleParse(seg.GetFieldComponent(itemOrder));
						}
						continue;
					default:
						continue;
				}
			}
			return;
		}
Esempio n. 28
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;
		}
Esempio n. 29
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);
        }
Esempio n. 30
0
		///<summary>So far this is only used in SRM messages and saves data to the appointment note field.  If apt is null this does nothing.  The note in the NTE segment will be appended to the existing appointment note unless the existing note already contains the exact note we are attempting to append.</summary>
		public static void ProcessNTE(Patient pat,Appointment apt,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			char escapeChar='\\';
			if(msg.Delimiters.Length>2) {//it is possible they did not send all 4 of the delimiter chars, in which case we will use the default \
				escapeChar=msg.Delimiters[2];
			}
			if(apt==null) {
				return;
			}
			if(apt.PatNum!=pat.PatNum) {
				throw new Exception("Appointment does not match patient "+pat.GetNameFLnoPref()+", apt.PatNum: "+apt.PatNum.ToString()+", pat.PatNum: "+pat.PatNum.ToString());
			}
			string strAptNote="";
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int intItemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "apt.Note":
						strAptNote=FieldParser.StringNewLineParse(seg.GetFieldComponent(intItemOrder),escapeChar);
						continue;
					default:
						continue;
				}
			}
			//if the existing note contains the exact text of the note in the NTE segment, don't append it again
			//replace the \r's and then \n's with a blank string before comparing to eliminate inconsistencies in new line characters
			if(apt.Note==null) {//just in case a new appointment gets here and has not been inserted yet, should never happen
				apt.Note="";
			}
			if(apt.Note.Replace("\r\n","\n").Replace("\r","\n").Contains(strAptNote.Replace("\r\n","\n").Replace("\r","\n"))) {
				return;
			}
			Appointment aptOld=apt.Clone();
			if(apt.Note.Length>0) {//if the existing note already contains some text, add a new line before appending the note from the NTE segment
				apt.Note+="\r\n";
			}
			apt.Note+=strAptNote;
			Appointments.Update(apt,aptOld);
			_aptProcessed=apt;
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated appointment for patient "+pat.GetNameFLnoPref()+" due to an incoming NTE segment.",EventLogEntryType.Information);
			}
			return;
		}
		///<summary>Updates one HL7DefSegment in the database.</summary>
		public static void Update(HL7DefSegment hL7DefSegment){
			string command="UPDATE hl7defsegment SET "
				+"HL7DefMessageNum=  "+POut.Long  (hL7DefSegment.HL7DefMessageNum)+", "
				+"ItemOrder       =  "+POut.Int   (hL7DefSegment.ItemOrder)+", "
				+"CanRepeat       =  "+POut.Bool  (hL7DefSegment.CanRepeat)+", "
				+"IsOptional      =  "+POut.Bool  (hL7DefSegment.IsOptional)+", "
				+"SegmentName     = '"+POut.String(hL7DefSegment.SegmentName.ToString())+"', "
				+"Note            =  "+DbHelper.ParamChar+"paramNote "
				+"WHERE HL7DefSegmentNum = "+POut.Long(hL7DefSegment.HL7DefSegmentNum);
			if(hL7DefSegment.Note==null) {
				hL7DefSegment.Note="";
			}
			OdSqlParameter paramNote=new OdSqlParameter("paramNote",OdDbType.Text,hL7DefSegment.Note);
			Db.NonQ(command,paramNote);
		}
Esempio n. 32
0
		//public static void ProcessPD1() {
		//	return;
		//}

		public static void ProcessPID(Patient pat,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			Patient patOld=pat.Copy();
			char escapeChar='\\';
			if(msg.Delimiters.Length>2) {//it is possible they did not send all 4 of the delimiter chars, in which case we will use the default \
				escapeChar=msg.Delimiters[2];
			}
			char subcompChar='&';
			if(msg.Delimiters.Length>3) {//it is possible they did not send all 4 of the delimiter chars, in which case we will use the default &
				subcompChar=msg.Delimiters[3];
			}
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "pat.addressCityStateZip":
						pat.Address=seg.GetFieldComponent(itemOrder,0);
						pat.Address2=seg.GetFieldComponent(itemOrder,1);
						pat.City=seg.GetFieldComponent(itemOrder,2);
						pat.State=seg.GetFieldComponent(itemOrder,3);
						pat.Zip=seg.GetFieldComponent(itemOrder,4);
						string strAddrNote=FieldParser.StringNewLineParse(seg.GetFieldComponent(itemOrder,19),escapeChar);
						if(strAddrNote!="") {
							pat.AddrNote=strAddrNote;
						}						
						continue;
					case "pat.birthdateTime":
						pat.Birthdate=FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.ChartNumber":
						pat.ChartNumber=seg.GetFieldComponent(itemOrder);
						continue;
					case "pat.FeeSched":
						if(Programs.IsEnabled(ProgramName.eClinicalWorks) && ProgramProperties.GetPropVal(ProgramName.eClinicalWorks,"FeeSchedulesSetManually")=="1") {
							//if using eCW and FeeSchedulesSetManually
							continue;//do not process fee sched field, manually set by user
						}
						else {
							pat.FeeSched=FieldParser.FeeScheduleParse(seg.GetFieldComponent(itemOrder));
						}
						continue;
					case "pat.Gender":
						pat.Gender=FieldParser.GenderParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.HmPhone":
						if(seg.GetFieldComponent(itemOrder,2)=="" && seg.GetField(itemOrder).ListRepeatFields.Count==0) {//must be eCW, process the old way
							//either no component 2 or left blank, and there are no repetitions, process the old way
							//the first repetition is considered the primary number, but if the primary number is not sent then it will be blank followed by the list of other numbers
							pat.HmPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
						}
						else {
							//XTN data type, repeatable.
							//Component 2 values: PH-Phone, FX-Fax, MD-Modem, CP-Cell Phone, Internet-Internet Address, X.400-X.400 email address, TDD-Tel Device for the Deaf, TTY-Teletypewriter.
							//We will support PH for pat.HmPhone, CP for pat.WirelessPhone, and Internet for pat.Email
							//Component 5 is area code, 6 is number
							//Component 3 will be Email if the type is Internet
							//Example: ^PRN^PH^^^503^3635432~^PRN^Internet^[email protected]
							FieldHL7 phField=seg.GetField(itemOrder);
							if(phField==null) {
								continue;
							}
							string strPhType=seg.GetFieldComponent(itemOrder,2);
							string strPh=seg.GetFieldComponent(itemOrder,5)+seg.GetFieldComponent(itemOrder,6);
							string strEmail=seg.GetFieldComponent(itemOrder,3);
							for(int p=-1;p<phField.ListRepeatFields.Count;p++) {
								if(p>=0) {
									strPhType=phField.ListRepeatFields[p].GetComponentVal(2);
									strPh=phField.ListRepeatFields[p].GetComponentVal(5)+phField.ListRepeatFields[p].GetComponentVal(6);
									strEmail=phField.ListRepeatFields[p].GetComponentVal(3);
								}
								switch(strPhType) {
									case "PH":
										pat.HmPhone=FieldParser.PhoneParse(strPh);
										continue;
									case "CP":
										pat.WirelessPhone=FieldParser.PhoneParse(strPh);
										continue;
									case "Internet":
										pat.Email=strEmail;
										continue;
									default:
										continue;
								}
							}
						}
						continue;
					case "pat.nameLFM":
						pat.LName=seg.GetFieldComponent(itemOrder,0);
						pat.FName=seg.GetFieldComponent(itemOrder,1);
						pat.MiddleI=seg.GetFieldComponent(itemOrder,2);
						pat.Title=seg.GetFieldComponent(itemOrder,4);
						continue;
					case "pat.PatNum":
						//pat.PatNum guaranteed to not be 0, a new patient will be inserted if the field component for PatNum is not an int, is 0, or is blank
						//if(pat.PatNum!=0 && pat.PatNum!=PIn.Long(seg.GetFieldComponent(intItemOrder))) {
						//if field component is a valid number and the patient located is not the same as the patient with the PatNum in the segment, then throw the exception, message will fail.
						long patNumFromPid=0;
						try {
							patNumFromPid=PIn.Long(seg.GetFieldComponent(itemOrder));
						}
						catch(Exception ex) {
							//do nothing, patNumFromPID will remain 0
						}
						if(patNumFromPid!=0 && pat.PatNum!=patNumFromPid) {
							throw new Exception("Invalid PatNum");
						}
						continue;
					case "pat.Position":
						pat.Position=FieldParser.MaritalStatusParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "pat.Race":
						//PID.10 is a CWE data type, with 9 defined components.  The first three are CodeValue^CodeDescription^CodeSystem
						//This field can repeat, so we will need to add an entry in the patientrace table for each repetition
						//The race code system is going to be CDCREC and the values match our enum.
						//The code description is not saved, we only require CodeValue and CodeSystem=CDCREC.  Descriptions come from the CDCREC table for display in OD.
						//Example race component: 
						string strRaceCode=seg.GetFieldComponent(itemOrder,0);
						string strRaceCodeSystem=seg.GetFieldComponent(itemOrder,2);
						//if there aren't 3 components to the race field or if the code system is not CDCREC, then parse the old way by matching to string name, i.e. white=PatientRaceOld.White
						if(strRaceCodeSystem!="CDCREC") {//must be eCW, process the old way
							PatientRaceOld patientRaceOld=FieldParser.RaceParseOld(strRaceCode);
							//Converts deprecated PatientRaceOld enum to list of PatRaces, and adds them to the PatientRaces table for the patient.
							PatientRaces.Reconcile(pat.PatNum,PatientRaces.GetPatRacesFromPatientRaceOld(patientRaceOld));
						}
						else {
							FieldHL7 fieldRace=seg.GetField(itemOrder);
							if(fieldRace==null) {
								continue;
							}
							List<PatRace> listPatRaces=new List<PatRace>();
							listPatRaces.Add(FieldParser.RaceParse(strRaceCode));
							for(int r=0;r<fieldRace.ListRepeatFields.Count;r++) {
								strRaceCode=fieldRace.ListRepeatFields[r].GetComponentVal(0);
								strRaceCodeSystem=fieldRace.ListRepeatFields[r].GetComponentVal(2);
								if(strRaceCodeSystem=="CDCREC") {
									listPatRaces.Add(FieldParser.RaceParse(strRaceCode));
								}
							}
							PatientRaces.Reconcile(pat.PatNum,listPatRaces);
						}
						continue;
					case "pat.SSN":
						pat.SSN=seg.GetFieldComponent(itemOrder);
						continue;
					case "pat.WkPhone":
						if(seg.GetFieldComponent(itemOrder,2)=="PH") {
							//Component 2 value: PH-Phone
							//Component 5 is area code, 6 is number
							//Example: ^WPN^PH^^^503^3635432
							pat.WkPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder,5)+seg.GetFieldComponent(itemOrder,6));
							continue;
						}
						//either no component 2 or left blank, process the old way
						pat.WkPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));//must be eCW
						continue;
					case "patientIds"://Not used by eCW
						//We will store the ID's from other software in the oidexternal table.  These ID's will be sent in outbound msgs and used to locate a patient for subsequent inbound msgs.
						//Example: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.2&HL7^PI~7684^8^M11^&Other.Software.OID&OIDType^PI|
						//field component values will be the first repetition, repeats will be in field.ListRepeatFields
						//1234=PatNum, 3=check digit, M11=using check digit scheme, the assigning authority universal ID is the offices oidinternal.IDRoot for IDType Patient,
						//HL7=ID type, PI=identifier type code for: Patient internal identifier (a number that is unique to a patient within an assigning authority).
						FieldHL7 fieldCur=seg.GetField(itemOrder);
						//get the id with the assigning authority equal to the internal OID root stored in their database for a patient object
						string strPatOIDRoot=OIDInternals.GetForType(IdentifierType.Patient).IDRoot;
						if(strPatOIDRoot=="") {
							//if they have not set their internal OID root, we cannot identify which repetition in this field contains the OD PatNum
							EventLog.WriteEntry("OpenDentHL7","Could not process the patientIdList field due to the internal OID for the patient object missing.",EventLogEntryType.Information);
							continue;
						}
						string strPatIdCur="";
						string strPatIdRootCur="";
						string[] arrayPatIdSubComps=fieldCur.GetComponentVal(3).Split(new char[] { subcompChar },StringSplitOptions.None);
						if(arrayPatIdSubComps.Length>1 //so the next line doesn't throw an exception
							&& arrayPatIdSubComps[1].ToLower()!=strPatOIDRoot.ToLower()//not our PatNum
							&& fieldCur.GetComponentVal(4).ToLower()=="pi")//PI=patient internal identifier; a number that is unique to a patient within an assigning authority
						{
							int intCheckDigit=-1;
							try {
								intCheckDigit=PIn.Int(fieldCur.GetComponentVal(1));
							}
							catch(Exception ex) {
								//checkDigit will remain -1
							}
							//if using the M10 or M11 check digit algorithm and it passes the respective test, or not using either algorithm, then use the ID
							if((fieldCur.GetComponentVal(2).ToLower()=="m10"
									&& intCheckDigit!=-1
									&& M10CheckDigit(fieldCur.GetComponentVal(0))==intCheckDigit)//using M10 scheme and the check digit is valid and matches calc
								|| (fieldCur.GetComponentVal(2).ToLower()=="m11"
									&& intCheckDigit!=-1
									&& M11CheckDigit(fieldCur.GetComponentVal(0))==intCheckDigit)//using M11 scheme and the check digit is valid and matches calc
								|| (fieldCur.GetComponentVal(2).ToLower()!="m10"
									&& fieldCur.GetComponentVal(2).ToLower()!="m11"))//not using either check digit scheme
							{
								//Either passed the check digit test or not using the M10 or M11 check digit scheme, so trust the ID to be valid
								strPatIdCur=fieldCur.GetComponentVal(0);
								strPatIdRootCur=arrayPatIdSubComps[1];
							}
						}
						OIDExternal oidExtCur=new OIDExternal();
						string verboseMsg="";
						if(strPatIdCur!="" && strPatIdRootCur!="" && OIDExternals.GetByRootAndExtension(strPatIdRootCur,strPatIdCur)==null) {
							oidExtCur.IDType=IdentifierType.Patient;
							oidExtCur.IDInternal=pat.PatNum;
							oidExtCur.IDExternal=strPatIdCur;
							oidExtCur.rootExternal=strPatIdRootCur;
							OIDExternals.Insert(oidExtCur);
							verboseMsg+="\r\nExternal patient ID: "+oidExtCur.IDExternal+", External root: "+oidExtCur.rootExternal;
						}
						for(int r=0;r<fieldCur.ListRepeatFields.Count;r++) {
							arrayPatIdSubComps=fieldCur.ListRepeatFields[r].GetComponentVal(3).Split(new char[] { subcompChar },StringSplitOptions.None);
							if(arrayPatIdSubComps.Length<2) {//there must be at least 2 sub-components in the assigning authority component so we can identify whose ID this is
								continue;
							}
							if(arrayPatIdSubComps[1].ToLower()==strPatOIDRoot.ToLower() //if this is the OD patient OID root
								|| fieldCur.ListRepeatFields[r].GetComponentVal(4).ToLower()!="pi")//or not a patient identifier, then skip this repetition
							{
								continue;
							}
							int intCheckDigit=-1;
							try {
								intCheckDigit=PIn.Int(fieldCur.ListRepeatFields[r].GetComponentVal(1));
							}
							catch(Exception ex) {
								//checkDigit will remain -1
							}
							if(fieldCur.ListRepeatFields[r].GetComponentVal(2).ToLower()=="m10"
								&& (intCheckDigit==-1 || M10CheckDigit(fieldCur.ListRepeatFields[r].GetComponentVal(0))!=intCheckDigit))//using M11 scheme and either an invalid check digit was received or it doesn't match our calc
							{
								continue;
							}
							if(fieldCur.ListRepeatFields[r].GetComponentVal(2).ToLower()=="m11"
								&& (intCheckDigit==-1 || M11CheckDigit(fieldCur.ListRepeatFields[r].GetComponentVal(0))!=intCheckDigit))//using M11 scheme and either an invalid check digit was received or it doesn't match our calc
							{
								continue;
							}
							//if not using the M10 or M11 check digit scheme or if the check digit is good, trust the ID in component 0 to be valid and store as IDExternal
							strPatIdCur=fieldCur.ListRepeatFields[r].GetComponentVal(0);
							strPatIdRootCur=arrayPatIdSubComps[1];
							if(strPatIdCur!="" && strPatIdRootCur!="" && OIDExternals.GetByRootAndExtension(strPatIdRootCur,strPatIdCur)==null) {
								oidExtCur=new OIDExternal();
								oidExtCur.IDType=IdentifierType.Patient;
								oidExtCur.IDInternal=pat.PatNum;
								oidExtCur.IDExternal=strPatIdCur;
								oidExtCur.rootExternal=strPatIdRootCur;
								OIDExternals.Insert(oidExtCur);
								verboseMsg+="\r\nExternal patient ID: "+oidExtCur.IDExternal+", External root: "+oidExtCur.rootExternal;
							}
						}
						if(_isVerboseLogging && verboseMsg.Length>0) {
							EventLog.WriteEntry("OpenDentHL7","Added the following external patient ID(s) to the oidexternals table due to an incoming PID segment for PatNum: "
								+pat.PatNum+"."+verboseMsg+".",EventLogEntryType.Information);
						}
						continue;
					default:
						continue;
				}
			}
			Patients.Update(pat,patOld);
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated patient "+pat.GetNameFLnoPref()+" due to an incoming PID segment.",EventLogEntryType.Information);
			}
			return;
		}
		///<summary>Updates one HL7DefSegment in the database.  Uses an old object to compare to, and only alters changed fields.  This prevents collisions and concurrency problems in heavily used tables.</summary>
		public static void Update(HL7DefSegment hL7DefSegment,HL7DefSegment oldHL7DefSegment){
			string command="";
			if(hL7DefSegment.HL7DefMessageNum != oldHL7DefSegment.HL7DefMessageNum) {
				if(command!=""){ command+=",";}
				command+="HL7DefMessageNum = "+POut.Long(hL7DefSegment.HL7DefMessageNum)+"";
			}
			if(hL7DefSegment.ItemOrder != oldHL7DefSegment.ItemOrder) {
				if(command!=""){ command+=",";}
				command+="ItemOrder = "+POut.Int(hL7DefSegment.ItemOrder)+"";
			}
			if(hL7DefSegment.CanRepeat != oldHL7DefSegment.CanRepeat) {
				if(command!=""){ command+=",";}
				command+="CanRepeat = "+POut.Bool(hL7DefSegment.CanRepeat)+"";
			}
			if(hL7DefSegment.IsOptional != oldHL7DefSegment.IsOptional) {
				if(command!=""){ command+=",";}
				command+="IsOptional = "+POut.Bool(hL7DefSegment.IsOptional)+"";
			}
			if(hL7DefSegment.SegmentName != oldHL7DefSegment.SegmentName) {
				if(command!=""){ command+=",";}
				command+="SegmentName = '"+POut.String(hL7DefSegment.SegmentName.ToString())+"'";
			}
			if(hL7DefSegment.Note != oldHL7DefSegment.Note) {
				if(command!=""){ command+=",";}
				command+="Note = "+DbHelper.ParamChar+"paramNote";
			}
			if(command==""){
				return;
			}
			if(hL7DefSegment.Note==null) {
				hL7DefSegment.Note="";
			}
			OdSqlParameter paramNote=new OdSqlParameter("paramNote",OdDbType.Text,hL7DefSegment.Note);
			command="UPDATE hl7defsegment SET "+command
				+" WHERE HL7DefSegmentNum = "+POut.Long(hL7DefSegment.HL7DefSegmentNum);
			Db.NonQ(command,paramNote);
		}
Esempio n. 34
0
		public static void ProcessPRB(Patient pat,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			int probActionOrder=-1;
			int probCodeOrder=-1;
			int probStartDateOrder=-1;
			int probStopDateOrder=-1;
			int probUniqueIdOrder=-1;
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "problemAction":
						probActionOrder=itemOrder;
						continue;
					case "problemCode":
						probCodeOrder=itemOrder;
						continue;
					case "problemStartDate":
						probStartDateOrder=itemOrder;
						continue;
					case "problemStopDate":
						probStopDateOrder=itemOrder;
						continue;
					case "problemUniqueId":
						probUniqueIdOrder=itemOrder;
						continue;
					default:
						continue;
				}
			}
			//we need these 3 items defined in order to process the problem
			if(probActionOrder<0 || probCodeOrder<0 || probUniqueIdOrder<0) {
				EventLog.WriteEntry("OpenDentHL7","The PRB segment was not processed.  The segment must have an action, code, and unique ID defined.",EventLogEntryType.Information);
				return;
			}
			//get values from defined locations within the segment and validate info
			//We only add or update problems.  Other actions like delete or correct are not yet supported
			if(seg.GetFieldComponent(probActionOrder).ToLower()!="ad" && seg.GetFieldComponent(probActionOrder).ToLower()!="up") {
				EventLog.WriteEntry("OpenDentHL7","The PRB segment was not processed.  The action codes supported are 'AD' for add or 'UP' for update.",EventLogEntryType.Information);
				return;
			}
			long probDefNum=DiseaseDefs.GetNumFromSnomed(PIn.String(seg.GetFieldComponent(probCodeOrder,0)));
			//The problem must be a SNOMEDCT code, identified by the coding system table 0396 value "SNM" in component 3 of the CWE problem code field
			//There must be a disease def setup with the SNOMEDCT code in the problem list or we will ignore this problem
			if(seg.GetFieldComponent(probCodeOrder,2).ToLower()!="snm" || probDefNum==0) {
				EventLog.WriteEntry("OpenDentHL7","The PRB segment was not processed.  "
					+"The code is not attached to an existing problem definition or is not a SNOMEDCT code.",EventLogEntryType.Information);
				return;
			}
			string probIdExternal=seg.GetFieldComponent(probUniqueIdOrder,0);
			string probRootExternal=seg.GetFieldComponent(probUniqueIdOrder,2);
			if(probIdExternal=="" || probRootExternal=="") {
				EventLog.WriteEntry("OpenDentHL7","The PRB segment was not processed. "
					+" The problem does not have a unique ID with assigning authority root.",EventLogEntryType.Information);
				return;
			}
			//If problem external ID and root is in the database, but is used to identify an object other than a problem, do not process the segment
			OIDExternal probOidExt=OIDExternals.GetByRootAndExtension(probRootExternal,probIdExternal);
			if(probOidExt!=null && probOidExt.IDType!=IdentifierType.Problem) {
				EventLog.WriteEntry("OpenDentHL7","The PRB segment was not processed.  "
					+"The problem has a unique ID with assigning authority root that has already been used to identify an object of type "
					+probOidExt.IDType.ToString()+".",EventLogEntryType.Information);
				return;
			}
			long diseaseNum=0;
			if(probOidExt!=null) {//exists in oidexternal table and is of type Problem, so IDInternal is a DiseaseNum
				diseaseNum=probOidExt.IDInternal;					
			}
			Disease probCur=new Disease();
			probCur.DiseaseNum=diseaseNum;//probNum could be 0 if new
			//The problem referenced by the external root and ID is already linked in the oidexternal table, get the problem to update
			//Also make sure the problem linked by oidexternal table is for the patient identified in the PID segment
			if(diseaseNum!=0) {
				probCur=Diseases.GetOne(diseaseNum);
				if(probCur==null || probCur.PatNum!=pat.PatNum) {//should never be null if in the oidexternal table
					EventLog.WriteEntry("OpenDentHL7","The PRB segment was not processed.  "
						+"The problem referenced and the patient in the PID segment do not match.",EventLogEntryType.Information);
					return;
				}
			}
			DateTime dateProbStart=DateTime.MinValue;
			if(probStartDateOrder>-1) {
				dateProbStart=FieldParser.DateTimeParse(seg.GetFieldComponent(probStartDateOrder));
			}
			DateTime dateProbStop=DateTime.MinValue;
			if(probStopDateOrder>-1) {
				dateProbStop=FieldParser.DateTimeParse(seg.GetFieldComponent(probStopDateOrder));
			}
			//The patient may already have an active problem with this DiseaseDefNum, but it is not referenced by this problem GUID
			//Mark the existing problem inactive and add a new one with StartDate of today
			//Add an entry in the oidexternal table that will point the problem GUID to this new problem.
			List<Disease> listProbsForPat=Diseases.GetDiseasesForPatient(pat.PatNum,probDefNum,true);
			int markedInactiveCount=0;
			for(int p=0;p<listProbsForPat.Count;p++) {
				if(listProbsForPat[p].DiseaseNum==diseaseNum) {//probNum may be 0 if there was not an existing problem referenced by the GUID in the message
					continue;
				}
				listProbsForPat[p].ProbStatus=ProblemStatus.Inactive;
				Diseases.Update(listProbsForPat[p]);
				markedInactiveCount++;
			}
			if(_isVerboseLogging && markedInactiveCount>0) {
				EventLog.WriteEntry("OpenDentHL7","Updated "+markedInactiveCount.ToString()+" problems to a status of inactive due to an incoming PRB segment.",EventLogEntryType.Information);
			}
			Disease probOld=probCur.Copy();
			probCur.PatNum=pat.PatNum;
			probCur.DiseaseDefNum=probDefNum;
			probCur.ProbStatus=ProblemStatus.Active;
			probCur.DateStart=dateProbStart;//could be '0001-01-01' if not present or not the correct format, handled by FieldParser.DateTimeParse
			probCur.DateStop=dateProbStop;//could be '0001-01-01' if not present or not the correct format, handled by FieldParser.DateTimeParse
			if(probCur.DiseaseNum==0) {//new problem
				//insert new problem
				probCur.DiseaseNum=Diseases.Insert(probCur);
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Inserted a new problem for patient "+pat.GetNameFLnoPref()+" due to an incoming PRB segment.",EventLogEntryType.Information);
				}
				//using DiseaseNum from newly inserted problem, link to the external GUID and root in the oidexternals table
				probOidExt=new OIDExternal();
				probOidExt.IDType=IdentifierType.Problem;
				probOidExt.IDInternal=probCur.DiseaseNum;
				probOidExt.IDExternal=probIdExternal;
				probOidExt.rootExternal=probRootExternal;
				OIDExternals.Insert(probOidExt);
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Added an external problem ID to the oidexternals table due to an incoming PRB segment.\r\nDiseaesNum: "
						+probCur.DiseaseNum.ToString()+", External problem ID: "+probOidExt.IDExternal+", External root: "+probOidExt.rootExternal+".",EventLogEntryType.Information);
				}
			}
			else {//the segment is for an existing problem, update fields if necessary
				Diseases.Update(probCur,probOld);
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Updated an existing problem for patient "+pat.GetNameFLnoPref()+" due to an incoming PRB segment.",EventLogEntryType.Information);
				}
			}
			return;
		}
Esempio n. 35
0
		///<summary>Inserts any MedLabFacility objects not in the database.  Creates a dictionary linking the facilityIDs to a list of MedLabFacilityNums.
		///For each MedLab and MedLabResult in the message, OBR.24 and OBX.15, respectively, will contain the facilityID for the facility where the lab
		///was performed.  Using the facilityID, the orders and results will be attached to facilities via entries in the MedLabAttach table.</summary>
		public static void ProcessZPS(HL7DefSegment segDef,List<SegmentHL7> listSegs,MessageHL7 msg) {
			_dictFacilityCodeNum=new Dictionary<string,List<long>>();
			int facIdIndex=-1;
			int facNameIndex=-1;
			int facAddrIndex=-1;
			int facPhIndex=-1;
			int facDirIndex=-1;
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {//get indexes for fields from the segment def
				HL7DefField fieldDefCur=segDef.hl7DefFields[i];
				switch(fieldDefCur.FieldName) {
					case "facilityID":
						facIdIndex=fieldDefCur.OrdinalPos;
						continue;
					case "facilityName":
						facNameIndex=fieldDefCur.OrdinalPos;
						continue;
					case "facilityAddress":
						facAddrIndex=fieldDefCur.OrdinalPos;
						continue;
					case "facilityPhone":
						facPhIndex=fieldDefCur.OrdinalPos;
						continue;
					case "facilityDirector":
						facDirIndex=fieldDefCur.OrdinalPos;
						continue;
					default:
						continue;
				}
			}
			if(facIdIndex<0 || facNameIndex<0 || facAddrIndex<0) {
				EventLog.WriteEntry("MessageParserMedLab","The MedLab HL7 definition does not contain a field definition for facilityID, facilityName, or "
					+"facilityAddress with a valid item order.  There will not be any MedLabFacility objects created and linked to the MedLabResult objects.",
					EventLogEntryType.Warning);
				return;
			}
			for(int i=0;i<listSegs.Count;i++) {
				MedLabFacility facilityCur=new MedLabFacility();
				facilityCur.FacilityName=listSegs[i].GetFieldComponent(facNameIndex);
				if(facAddrIndex>=0) {
					facilityCur.Address=listSegs[i].GetFieldComponent(facAddrIndex,0);
					facilityCur.City=listSegs[i].GetFieldComponent(facAddrIndex,2);
					facilityCur.State=listSegs[i].GetFieldComponent(facAddrIndex,3);
					facilityCur.Zip=listSegs[i].GetFieldComponent(facAddrIndex,4);
				}
				if(facPhIndex>=0) {
					facilityCur.Phone=listSegs[i].GetFieldComponent(facPhIndex);
				}
				if(facDirIndex>=0) {
					facilityCur.DirectorTitle=listSegs[i].GetFieldComponent(facDirIndex,0);
					facilityCur.DirectorLName=listSegs[i].GetFieldComponent(facDirIndex,1);
					facilityCur.DirectorFName=listSegs[i].GetFieldComponent(facDirIndex,2);
				}
				facilityCur.MedLabFacilityNum=MedLabFacilities.InsertIfNotInDb(facilityCur);
				string segFacId=listSegs[i].GetFieldComponent(facIdIndex);
				if(!_dictFacilityCodeNum.ContainsKey(segFacId)) {//if the footnote id doesn't exist in the dictionary, add it and the MedLabFacilityNum value
					_dictFacilityCodeNum.Add(segFacId,new List<long>() { facilityCur.MedLabFacilityNum });
					continue;
				}
				if(!_dictFacilityCodeNum[segFacId].Contains(facilityCur.MedLabFacilityNum)) {//if the id is not linked to this facilitynum, add it to the list
					_dictFacilityCodeNum[segFacId].Add(facilityCur.MedLabFacilityNum);
				}
				//dictionary contains the footnote id key and the list value for that key contains this MedLabFacilityNum
			}
			return;
		}
Esempio n. 36
0
		///<summary>Returns AptNum of the incoming appointment.  apt was found using the apt.AptNum field of the SCH segment, but can be null if it's a new appointment.  Used for eCW and other interfaces where OD is not the filler application.  When OD is not the filler application, we allow appointments to be created by the interfaced software and communicated to OD with an SIU message.</summary>
		public static long ProcessSCH(Patient pat,Appointment apt,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			if(pat.FName=="" || pat.LName=="") {
				throw new Exception("Appointment not processed due to missing patient first or last name. PatNum:"+pat.PatNum.ToString());
			}
			char escapeChar='\\';
			if(msg.Delimiters.Length>2) {//it is possible they did not send all 4 of the delimiter chars, in which case we will use the default \
				escapeChar=msg.Delimiters[2];
			}
			string strAptNote="";
			double aptLength=0;
			long aptNum=0;
			DateTime aptStart=DateTime.MinValue;
			DateTime aptStop=DateTime.MinValue;
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "apt.AptNum":
						try {
							aptNum=PIn.Long(seg.GetFieldComponent(itemOrder));
						}
						catch(Exception ex) {
							//do nothing, aptNum will remain 0
						}
						if(apt!=null && apt.AptNum!=aptNum) {
							//an appointment was located from the inbound message, but the AptNum on the appointment is not the same as the AptNum in this SCH segment (should never happen)
							throw new Exception("Invalid appointment number.");
						}
						continue;
					case "apt.lengthStartEnd":
						aptLength=FieldParser.SecondsToMinutes(seg.GetFieldComponent(itemOrder,2));
						aptStart=FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder,3));
						aptStop=FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder,4));
						continue;
					case "apt.Note":
						strAptNote=FieldParser.StringNewLineParse(seg.GetFieldComponent(itemOrder),escapeChar);
						continue;
					default:
						continue;
				}
			}
			Appointment aptOld=null;
			bool isNewApt=(apt==null);
			if(isNewApt) {
				apt=new Appointment();
				apt.AptNum=aptNum;
				apt.PatNum=pat.PatNum;
				apt.AptStatus=ApptStatus.Scheduled;
				apt.Note="";
			}
			else {
				aptOld=apt.Clone();
			}
			if(apt.PatNum!=pat.PatNum) {//we can't process this message because wrong patnum.
				throw new Exception("Appointment does not match patient "+pat.GetNameFLnoPref()+", apt.PatNum: "+apt.PatNum.ToString()+", pat.PatNum: "+pat.PatNum.ToString());
			}
			//if the existing note contains the exact text of the note in the SCH segment, don't append it again
			//replace the \r's and then \n's with a blank string before comparing to eliminate inconsistencies in new line characters
			if(!apt.Note.Replace("\r","").Replace("\n","").Contains(strAptNote.Replace("\r","").Replace("\n",""))) {
				if(apt.Note.Length>0) {//if the existing note already contains some text, add a new line before appending the note from the SCH segment
					apt.Note+="\r\n";
				}
				apt.Note+=strAptNote;
			}
			string pattern;
			//If aptStop is MinValue we know that stop time was not sent or was not in the correct format so try to use the duration field.
			if(aptStop==DateTime.MinValue && aptLength!=0) {//Stop time is optional.  If not included we will use the duration field to calculate pattern.
				pattern=FieldParser.ProcessPattern(aptStart,aptStart.AddMinutes(aptLength));
			}
			else {//We received a good stop time or stop time is MinValue but we don't have a good aptLength so ProcessPattern will return the apt length or the default 5 minutes
				pattern=FieldParser.ProcessPattern(aptStart,aptStop);
			}
			apt.AptDateTime=aptStart;
			apt.Pattern=pattern;
			apt.ProvNum=pat.PriProv;//Set apt.ProvNum to the patient's primary provider.  This may change after processing the AIG or PV1 segments, but set here in case those segs are missing.
			if(isNewApt) {
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Inserted appointment for "+pat.GetNameFLnoPref()+" due to an incoming SCH segment.",EventLogEntryType.Information);
				}
				Appointments.InsertIncludeAptNum(apt,true);
			}
			else {
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Updated appointment for "+pat.GetNameFLnoPref()+" due to an incoming SCH segment.",EventLogEntryType.Information);
				}
				Appointments.Update(apt,aptOld);
			}
			_hl7MsgCur.AptNum=apt.AptNum;
			HL7Msgs.Update(_hl7MsgCur);
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated hl7msg to include AptNum for "+pat.GetNameFLnoPref()+" due to an incoming SCH segment.",EventLogEntryType.Information);
			}
			_aptProcessed=apt;
			return aptNum;
		}
Esempio n. 37
0
		public static HL7Def GetDeepInternal(HL7Def def) {
			//ok to pass in null
			if(def==null) {//wasn't in the database
				def=new HL7Def();
				def.IsNew=true;
				def.Description="HL7 version 2.6";
				def.ModeTx=ModeTxHL7.File;
				def.IncomingFolder="";
				def.OutgoingFolder="";
				def.IncomingPort="";
				def.OutgoingIpPort="";
				def.SftpInSocket="";
				def.SftpUsername="";
				def.SftpPassword="";
				def.FieldSeparator="|";
				def.ComponentSeparator="^";
				def.SubcomponentSeparator="&";
				def.RepetitionSeparator="~";
				def.EscapeCharacter=@"\";
				def.IsInternal=true;
				def.InternalType=HL7InternalType.HL7v2_6;
				def.InternalTypeVersion=Assembly.GetAssembly(typeof(Db)).GetName().Version.ToString();
				def.IsEnabled=false;
				def.Note="";
				def.ShowDemographics=HL7ShowDemographics.ChangeAndAdd;
				def.ShowAccount=true;
				def.ShowAppts=true;
				def.IsQuadAsToothNum=false;
			}
			def.hl7DefMessages=new List<HL7DefMessage>();
			HL7DefMessage msg=new HL7DefMessage();
			HL7DefSegment seg=new HL7DefSegment();
			#region Inbound Messages
				#region ACK - General Acknowledgment
				def.AddMessage(msg,MessageTypeHL7.ACK,MessageStructureHL7.ADT_A01,InOutHL7.Incoming,0);
					#region MSH - Message Header
					msg.AddSegment(seg,0,SegmentNameHL7.MSH);
						//Fields-------------------------------------------------------------------------------------------------------------
						//MSH.8, Message Type
						seg.AddField(8,"messageType");
						//MSH.9, Message Control ID
						seg.AddField(9,"messageControlId");
					#endregion MSH - Message Header
					#region MSA - Message Acknowledgment
					seg=new HL7DefSegment();
					msg.AddSegment(seg,1,SegmentNameHL7.MSA);
						//Fields-------------------------------------------------------------------------------------------------------------
						//MSA.1, Acknowledgment Code
						seg.AddField(1,"ackCode");
						//MSA.2, Message Control ID
						seg.AddField(2,"messageControlId");
					#endregion MSA - Message Acknowledgment
				#endregion ACK - General Acknowledgment
				#region ADT - Patient Demographics (Admits, Discharges, and Transfers)
				msg=new HL7DefMessage();
				def.AddMessage(msg,MessageTypeHL7.ADT,MessageStructureHL7.ADT_A01,InOutHL7.Incoming,1);
					#region MSH - Message Header
					seg=new HL7DefSegment();
					msg.AddSegment(seg,0,SegmentNameHL7.MSH);
					//HL7 documentation says field 1 is Field Separator.  "This field contains the separator between the segment ID and the first real field.  As such it serves as the separator and defines the character to be used as a separator for the rest of the message." (HL7 v2.6 documentation) The separator is usually | (pipes) and is part of field 0, which is the segment ID followed by a |.  Encoding Characters is the first real field, so it will be numbered starting with 1 in our def.
						//Fields-------------------------------------------------------------------------------------------------------------
						//MSH.8, Message Type
						seg.AddField(8,"messageType");
						//MSH.9, Message Control ID
						seg.AddField(9,"messageControlId");
					#endregion MSH - Message Header
					#region PID - Patient Identification
					seg=new HL7DefSegment();
					msg.AddSegment(seg,2,SegmentNameHL7.PID);//order 2 since the EVN segment is order 1.  We don't process anything out of the EVN segment, so only defined for outgoing messages
						//Fields-------------------------------------------------------------------------------------------------------------
						//PID.2, Patient ID (retained for backward compatibility only).  Defined as 'external' ID but we've always used it as our PatNum for eCW.
						//The standard will be to continue to use PID.2 as the PatNum for incoming messages and attempt to locate the patient if this field is populated.
						seg.AddField(2,"pat.PatNum");
						//PID.3, Patient Identifier List, contains a list of identifiers separated by the repetition character (usually ~)
						//We will use the OID root for the office, stored in the table oidinternal with IDType Patient.
						//The Patient ID data type CX contains the Assigning Authority data type HD - Heirarchic Designator.
						//Within the Assigning Authority, sub-component 2 is the Universal ID that needs to have the OID root for the office.
						//Sub-component 3 of the Assigning Authority, Universal ID Type, will be 'HL7' for our PatNums since our root is registered with HL7.
						//The Patient ID CX type will also have the Identifier Type Code of 'PI', Patient internal identifier.
						//Once located, PatNum is the first component
						//Example: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.2&HL7^PI~7684^8^M11^&Other.Software.OID&OIDType^PI|
						seg.AddField(3,"patientIds");
						//PID.4, Alternate Patient ID, (retained for backward compatibility only).
						//We've used PID.4 for ChartNumber in the past and will continue to use this as a backup method for locating a patient if the ID in PID.2 is not present
						//or if no patient can be found using that value.
						seg.AddField(4,"pat.ChartNumber");
						//PID.5, Patient Name
						//This will contain the last, first, and middle names as well as the title
						//Example:  LName^FName^MiddleI^^Title
						seg.AddField(5,"pat.nameLFM");
						//PID.7, Date/Time of Birth
						seg.AddField(7,"pat.birthdateTime");
						//PID.8, Administrative Sex
						seg.AddField(8,"pat.Gender");
						//PID.10, Race
						//The old race parsing will still work and matches to an exact string to find the race.  The string can be the only component of the field or the first of many.
						//The old parse translates the string to the PatRaceOld enum, then reconciles them into one or more of the PatRace enums, then adds/deletes entries in the patientrace table.
						//The old race strings are: "American Indian Or Alaska Native", "Asian", "Native Hawaiian or Other Pacific", "Black or African American", "White", "Hispanic", "Other Race"
						//The new race parse accepts the CWE - Coded with Exceptions data type with 9 fields.
						//The 9 fields are: Code^Description^CodeSystem^AlternateCode^AltDescript^AltCodeSystem^CodeSystemVersionID^AltCodeSystemVersionID^OriginalText
						//We will make sure CodeSystem, PID.10.2, is "CDCREC" and use Code, PID.10.0, to find the correct race from the new PatRace enum and update the patientrace table.
						//The race field can repeat, so any number of races can be sent and will add to the patientrace table.
						seg.AddField(10,"pat.Race");
						//PID.11, Patient Address
						//PID.11.20, comment, is used to populate patient.AddrNote with '\.br\' signaling a line break. (the '\' is the default escape character, may be different and parses correctly)
						//Example: ...^^Emergency Contact: Mom Test\.br\Mother\.br\(503)555-1234
						seg.AddField(11,"pat.addressCityStateZip");
						//PID.13, Phone Number - Home, XTN data type (can repeat)
						//This field will also contain the patient's email address as a repetition as well as the WirelessPhone as a repetition
						//PRN stands for Primary Residence Number, equipment type: PH is Telephone, CP is Cell Phone, Internet is Internet Address (email)
						//Example: ^PRN^PH^^^503^3635432~^PRN^Internet^[email protected]~^PRN^CP^^^503^6895555
						seg.AddField(13,"pat.HmPhone");
						//PID.14, Phone Number - Business, XTN data type (can repeat)
						//We will send just one repetition, the WkPhone, but we will adhere to the data type
						//WPN=Work Number
						//Example: ^WPN^PH^^^503^3635432
						seg.AddField(14,"pat.WkPhone");
						//PID.16, Marital Status
						seg.AddField(16,"pat.Position");
						//PID.19, SSN - Patient
						seg.AddField(19,"pat.SSN");
					#endregion PID - Patient Identification
					#region PV1 - Patient Visit
					seg=new HL7DefSegment();
					msg.AddSegment(seg,3,SegmentNameHL7.PV1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PV1.2, Patient Class, IS data type (coded value for user-defined tables)
						//If this field is populated, it will set the patient.GradeLevel if the field can be converted to an integer between 1 and 12
						seg.AddField(2,"pat.GradeLevel");
						//PV1.3, Assigned Patient Location, PL - Person Location Data Type: Point of Care^Room^^Facility^^Person Location Type
						//Facility is a HD data type, so Namespace&ID&IDType.  We will just use &PracticeTitle with no namespace or IDType.
						//Example: ClinicDescript^OpName^^&PracticeTitle^^C  (C for clinic)
						//Used to set patient.ClinicNum if the location description matches clinic.Description
						seg.AddField(3,"pat.location");
						//PV1.7, Attending/Primary Care Doctor, XCN data type, ProviderId^LastName^FirstName^MI
						//In the PV1 segment, the primary provider will be set for the patient
						//The ProviderID component will hold the office's OID for a provider+"."+ProvNum if they send us a ProviderID that we have previously sent them
						//If the first component is not the provider root, we will assume this is an external ID and store it in the oidexternals linked to our internal ProvNum
						seg.AddField(7,"prov.provIdNameLFM");
						//PV1.11, Temporary Location, PL - Person Location data type: PointOfCare^^^^^Person Location Type
						//Using the location type field to identify this field as a "Site (or Grade School)", we will attempt to match the description to a site.Description in the db
						//If exact match is found, set the patient.SiteNum=site.SiteNum
						//Example: |West Salem Elementary^^^^^S| ('S' for site)
						seg.AddField(11,"pat.site");
						//PV1.18, Patient Type, 0 - Unknown, 1 - NoProblems, 2 - NeedsCare, 3 - Urgent
						//Stored in the patient.Urgency field for treatment urgnecy, used in public health screening
						seg.AddField(18,"pat.Urgency");
					#endregion PV1 - Patient Visit
					#region GT1 - Guarantor
					seg=new HL7DefSegment();
					msg.AddSegment(seg,4,false,true,SegmentNameHL7.GT1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//GT1.2, Guarantor Number
						//This field is repeatable and will be handled the same as the patientIdList in the PID segment, so it may contain multiple CX data type identifiers that point to a patient.
						seg.AddField(2,"guarIdList");
						//GT1.3, Guarantor Name
						//This will contain the last, first, and middle names as well as the title
						//Example:  LName^FName^MiddleI^^Title
						seg.AddField(3,"guar.nameLFM");
						//GT1.5, Guarantor Address
						//GT1.5.20, comment, is used to populate patient.AddrNote with '\.br\' signaling a line break.
						//The '\' is the default escape character, may be different in the incoming message and parses correctly
						//Example: ...^^Emergency Contact: Mom Test\.br\Mother\.br\(503)555-1234
						seg.AddField(5,"guar.addressCityStateZip");
						//GT1.6, Guarantor Phone Number - Home
						seg.AddField(6,"guar.HmPhone");
						//GT1.7, Guarantor Phone Number - Business
						seg.AddField(7,"guar.WkPhone");
						//GT1.8, Guarantor Date/Time of Birth
						seg.AddField(8,"guar.birthdateTime");
						//GT1.9, Guarantor Administrative Sex
						seg.AddField(9,"guar.Gender");
						//GT1.12, Guarantor SSN
						seg.AddField(12,"guar.SSN");
					#endregion GT1 - Guarantor
					#region OBX - Observation/Result
					seg=new HL7DefSegment();
					msg.AddSegment(seg,5,true,true,SegmentNameHL7.OBX);
						//Fields-------------------------------------------------------------------------------------------------------------
						//OBX.3, Observation ID, ID^Descript^CodeSystem
						//For adding current medications, the value will be a CWE (OBX.2 should hold the value type 'CWE') with RXNORM as the code system and the RxCui for the ID
						//RxNorm Code^^RXNORM, the Description is ignored
						seg.AddField(3,"medicationRxNorm");
					#endregion OBX - Observation/Result
					#region AL1 - Allergy Information
					seg=new HL7DefSegment();
					msg.AddSegment(seg,6,true,true,SegmentNameHL7.AL1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//AL1.2, Allergen Type Code, DA - Drug allergy, FA - Food allergy, MA - Miscellaneous Allergy
						//For now, we only allow DA for drug allergies
						seg.AddField(2,"allergenType");
						//AL1.3, Allergen Code, currently only RxNorm codes are supported
						//Supplied in CWE data type format with 9 components, of which we only need 2 code^^codeSystem^^^^^^
						//codeSystem must be RxNorm, code must match an existing allergydef.MedicationNum
						seg.AddField(3,"allergenRxNorm");
					#endregion AL1 - Allergy Information
					#region PR1 - Procedures
					seg=new HL7DefSegment();
					msg.AddSegment(seg,7,true,true,SegmentNameHL7.PR1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PR1.3, Procedure Code, CNE data type
						//ProcCode^descript (ignored)^CD2^^^^2014^^Layman Term (ignored)
						//Example: D1351^^CD2^^^^2014
						seg.AddField(3,"proccode.ProcCode");
						//PR1.5, Procedure Date/Time, DTM
						seg.AddField(5,"proc.procDateTime");
						//PR1.16, Procedure Code Modifier, CNE data type
						//This will hold the treatment area for the procedure (tooth,tooth/surf,quad,sextant,arch,tooth range).
						//If this is empty or blank, default will be mouth and the proccode sent must have a treatment area of mouth or the code will not be inserted.
						//We will validate the information conforms to the tooth numbering system in use by the office and will handle international toothnums.
						//If it is for a tooth surface, it will be 2 subcomponents, toothnum&surface(s)
						//Quad, sextant, and arch will be in subcomponent 2 with the first subcomponent blank
						//Tooth range will be comma-delimited list of tooth numbers in subcomponent 1
						//Examples: 1,2,3,4 or 12&MODL or &UL or &2 (sextant 2)
						seg.AddField(16,"proc.toothSurfRange");
						//PR1.19, Procedure Identifier, EI data type
						//Id^^UniversalId
						//They should send us a unique ID for this procedure with their UniversalId root for a procedure object.
						//If we get this data, we will store our procedurelog.ProcNum linked to the external ID and root in the oidexternals table.
						//This will be useful in preventing multiple copies of the same procedure from being inserted due to duplicate messages.
						//However, if they do not specify a unique ID and root, or if it is not in our oidexternals table linked to our ProcNum with type of Procedure, we will insert a new one.
						//This field could be blank and we will insert a new procedure every time, regardless of whether or not there is already a procedure with this code for this patient.
						seg.AddField(19,"proc.uniqueId");
					#endregion PR1 - Procedures
				#endregion ADT - Patient Demographics (Admits, Discharges, and Transfers)
				#region PPR - Patient Problem
				msg=new HL7DefMessage();
				def.AddMessage(msg,MessageTypeHL7.PPR,MessageStructureHL7.PPR_PC1,InOutHL7.Incoming,2);
					#region MSH - Message Header
					seg=new HL7DefSegment();
					msg.AddSegment(seg,0,SegmentNameHL7.MSH);
						//Fields-------------------------------------------------------------------------------------------------------------
						//MSH.8, Message Type
						seg.AddField(8,"messageType");
						//MSH.9, Message Control ID
						seg.AddField(9,"messageControlId");
					#endregion MSH - Message Header
					#region PID - Patient Identification
					seg=new HL7DefSegment();
					msg.AddSegment(seg,1,SegmentNameHL7.PID);//order 1 since PPR's don't have an EVN segment
						//Fields-------------------------------------------------------------------------------------------------------------
						//PID.2, Patient ID (retained for backward compatibility only).  Defined as 'external' ID but we've always used it as our PatNum for eCW.
						//The standard will be to continue to use PID.2 as the PatNum for incoming messages and attempt to locate the patient if this field is populated.
						seg.AddField(2,"pat.PatNum");
						//PID.3, Patient Identifier List, contains a list of identifiers separated by the repetition character (usually ~)
						//We will use the OID root for the office, stored in the table oidinternal with IDType Patient.
						//The Patient ID data type CX contains the Assigning Authority data type HD - Heirarchic Designator.
						//Within the Assigning Authority, sub-component 2 is the Universal ID that needs to have the OID root for the office.
						//Sub-component 3 of the Assigning Authority, Universal ID Type, will be 'HL7' for our PatNums since our root is registered with HL7.
						//The Patient ID CX type will also have the Identifier Type Code of 'PI', Patient internal identifier.
						//Once located, PatNum is the first component
						//Example: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.2&HL7^PI~7684^8^M11^&Other.Software.OID&OIDType^PI|
						seg.AddField(3,"patientIds");
						//PID.4, Alternate Patient ID, (retained for backward compatibility only).
						//We've used PID.4 for ChartNumber in the past and will continue to use this as a backup method for locating a patient if the ID in PID.2 is not present
						//or if no patient can be found using that value.
						seg.AddField(4,"pat.ChartNumber");
						//PID.5, Patient Name
						//This will contain the last, first, and middle names as well as the title
						//Example:  LName^FName^MiddleI^^Title
						seg.AddField(5,"pat.nameLFM");
						//PID.7, Date/Time of Birth
						seg.AddField(7,"pat.birthdateTime");
						//PID.8, Administrative Sex
						seg.AddField(8,"pat.Gender");
						//PID.10, Race
						//The old race parsing will still work and matches to an exact string to find the race.  The string can be the only component of the field or the first of many.
						//The old parse translates the string to the PatRaceOld enum, then reconciles them into one or more of the PatRace enums, then adds/deletes entries in the patientrace table.
						//The old race strings are: "American Indian Or Alaska Native", "Asian", "Native Hawaiian or Other Pacific", "Black or African American", "White", "Hispanic", "Other Race"
						//The new race parse accepts the CWE - Coded with Exceptions data type with 9 fields.
						//The 9 fields are: Code^Description^CodeSystem^AlternateCode^AltDescript^AltCodeSystem^CodeSystemVersionID^AltCodeSystemVersionID^OriginalText
						//We will make sure CodeSystem, PID.10.2, is "CDCREC" and use Code, PID.10.0, to find the correct race from the new PatRace enum and update the patientrace table.
						//The race field can repeat, so any number of races can be sent and will add to the patientrace table.
						seg.AddField(10,"pat.Race");
						//PID.11, Patient Address
						//PID.11.20, comment, is used to populate patient.AddrNote with '\.br\' signaling a line break. (the '\' is the default escape character, may be different and parses correctly)
						//Example: ...^^Emergency Contact: Mom Test\.br\Mother\.br\(503)555-1234
						seg.AddField(11,"pat.addressCityStateZip");
						//PID.13, Phone Number - Home, XTN data type (can repeat)
						//This field will also contain the patient's email address as a repetition as well as the WirelessPhone as a repetition
						//PRN stands for Primary Residence Number, equipment type: PH is Telephone, CP is Cell Phone, Internet is Internet Address (email)
						//Example: ^PRN^PH^^^503^3635432~^PRN^Internet^[email protected]~^PRN^CP^^^503^6895555
						seg.AddField(13,"pat.HmPhone");
						//PID.14, Phone Number - Business, XTN data type (can repeat)
						//We will send just one repetition, the WkPhone, but we will adhere to the data type
						//WPN=Work Number
						//Example: ^WPN^PH^^^503^3635432
						seg.AddField(14,"pat.WkPhone");
						//PID.16, Marital Status
						seg.AddField(16,"pat.Position");
						//PID.19, SSN - Patient
						seg.AddField(19,"pat.SSN");
					#endregion  PID - Patient Identification
					#region PV1 - Patient Visit
					seg=new HL7DefSegment();
					msg.AddSegment(seg,2,false,true,SegmentNameHL7.PV1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PV1.2, Patient Class, IS data type (coded value for user-defined tables)
						//If this field is populated, it will set the patient.GradeLevel if the field can be converted to an integer between 1 and 12
						seg.AddField(2,"pat.GradeLevel");
						//PV1.3, Assigned Patient Location, PL - Person Location Data Type: Point of Care^Room^^Facility^^Person Location Type
						//Facility is a HD data type, so Namespace&ID&IDType.  We will just use &PracticeTitle with no namespace or IDType.
						//Example: ClinicDescript^OpName^^&PracticeTitle^^C  (C for clinic)
						//Used to set patient.ClinicNum if the location description matches clinic.Description
						seg.AddField(3,"pat.location");
						//PV1.7, Attending/Primary Care Doctor, XCN data type, ProviderId^LastName^FirstName^MI^^Abbr
						//In the PV1 segment, the primary provider will be set for the patient if provider is found by ProviderId or by name and abbr
						//A new provider will not be inserted if not found, the default practice provider will be used
						seg.AddField(7,"prov.provIdNameLFM");
						//PV1.11, Temporary Location, PL - Person Location data type: PointOfCare^^^^^Person Location Type
						//Using the location type field to identify this field as a "Site (or Grade School)", we will attempt to match the description to a site.Description in the db
						//If exact match is found, set the patient.SiteNum=site.SiteNum
						//Example: |West Salem Elementary^^^^^S| ('S' for site)
						seg.AddField(11,"pat.site");
						//PV1.18, Patient Type, 0 - Unknown, 1 - NoProblems, 2 - NeedsCare, 3 - Urgent
						//Stored in the patient.Urgency field for treatment urgnecy, used in public health screening
						seg.AddField(18,"pat.Urgency");
					#endregion PV1 - Patient Visit
					#region PRB - Problem Detail
					seg=new HL7DefSegment();
					msg.AddSegment(seg,3,true,false,SegmentNameHL7.PRB);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PRB.1, Action Code, AD-ADD,CO-Correct,DE-Delete,LI-Link,UC-Unchanged,UN-Unlink,UP-Update.  AD/UP are currently supported and are treated the same
						seg.AddField(1,"problemAction");
						//PRB.2, Action Date/Time, DTM data type
						seg.AddField(2,"dateTime.Now");
						//PRB.3, Problem ID, CWE data type
						//Currently only SNOMEDCT codes are supported, code^descript^codeSystem (descript is not required and is ignored)
						//Example: 1234^^SNM
						seg.AddField(3,"problemCode");
						//PRB.4, Problem Instance ID, EI data type
						//Uniquely identifies this instance of a problem
						//If we were to send this, it would be the oidinternal root for problems (root+".5") with the disease.DiseaseNum as the ID
						//We expect the sending software to send an ID with an assigning authority root ID and we will link that to our disease.DiseaseNum in the oidexternals table
						//Example: |76543^^OtherSoftwareRoot.ProblemOID|
						seg.AddField(4,"problemUniqueId");
						//PRB.7, Problem Established Date/Time
						seg.AddField(7,"problemStartDate");
						//PRB.9, Actual Problem Resolution Date/Time
						seg.AddField(9,"problemStopDate");
					#endregion PRB - Problem Detail
				#endregion PPR - Patient Problem
				#region SRM - Schedule Request
				//The only incoming SRM event types we will accept by default will be S03 - Request Appointment Modification or S04 - Request Appointment Cancellation (for now)
				//The message must refer to an appointment already existing in OD by AptNum
				//The S03 message will only be allowed to modify a limited amount of information about the appointment
				//The S04 message will set the appointment status to Broken (enum 5)
				msg=new HL7DefMessage();
				def.AddMessage(msg,MessageTypeHL7.SRM,MessageStructureHL7.SRM_S01,InOutHL7.Incoming,3);
					#region MSH - Message Header
					seg=new HL7DefSegment();
					msg.AddSegment(seg,0,SegmentNameHL7.MSH);
						//Fields-------------------------------------------------------------------------------------------------------------
						//MSH.8, Message Type
						seg.AddField(8,"messageType");
						//MSH.9, Message Control ID
						seg.AddField(9,"messageControlId");
					#endregion MSH - Message Header
					#region ARQ - Appointment Request Information
					seg=new HL7DefSegment();
					msg.AddSegment(seg,1,SegmentNameHL7.ARQ);
						//Fields-------------------------------------------------------------------------------------------------------------
						//ARQ.1, Placer Appointment ID.  This will be the other software appointment ID.
						//We will store this in the oidexternals table linked to our AptNum.
						//The first component will be the external application appointment ID (stored as IDExternal)
						//The third component will be the external application assigning authority root ID (stored as RootExternal)
						//Example: |12345^^OtherSoftware.Root^|
						seg.AddField(1,"apt.externalAptID");
						//ARQ.2, Filler Appointment ID, EI data type, EntityID^NamespaceID^UniversalID^UniversalIDType
						//We will expect the first component to be our AptNum
						//We could check to make sure the UniversalID is our OID for an appointment, but for this incoming segment we won't enforce it for now and just accept the first component as AptNum
						//Example: 1234^^2.16.840.1.113883.3.4337.1486.6566.6^HL7
						seg.AddField(2,"apt.AptNum");
					#endregion ARQ - Appointment Request Information
					#region NTE - Notes and Comments
					seg=new HL7DefSegment();
					msg.AddSegment(seg,2,true,true,SegmentNameHL7.NTE);
						//Fields-------------------------------------------------------------------------------------------------------------
						//NTE.3, Comment, FT data type (formatted text)
						//We will append this comment to appointment.Note if the Note for this appointment does not already contain the exact text received
						//This is formatted text, so we will allow new lines.
						//As in the address note field (see PID.11) we will accept '\.br\' (where the '\' is the defined escape char, \ by default) to signal a new line.
						seg.AddField(3,"apt.Note");
					#endregion NTE - Notes and Comments
					#region PID - Patient Identification
					seg=new HL7DefSegment();
					msg.AddSegment(seg,3,SegmentNameHL7.PID);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PID.2, Patient ID (retained for backward compatibility only).  Defined as 'external' ID but we've always used it as our PatNum for eCW.
						//The standard will be to continue to use PID.2 as the PatNum for incoming messages and attempt to locate the patient if this field is populated.
						seg.AddField(2,"pat.PatNum");
						//PID.3, Patient Identifier List, contains a list of identifiers separated by the repetition character (usually ~)
						//We will use the OID root for the office, stored in the table oidinternal with IDType Patient.
						//The Patient ID data type CX contains the Assigning Authority data type HD - Heirarchic Designator.
						//Within the Assigning Authority, sub-component 2 is the Universal ID that needs to have the OID root for the office.
						//Sub-component 3 of the Assigning Authority, Universal ID Type, will be 'HL7' for our PatNums since our root is registered with HL7.
						//The Patient ID CX type will also have the Identifier Type Code of 'PI', Patient internal identifier.
						//Once located, PatNum is the first component
						//Example: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.2&HL7^PI~7684^8^M11^&Other.Software.OID&OIDType^PI|
						seg.AddField(3,"patientIds");
						//PID.4, Alternate Patient ID, (retained for backward compatibility only).
						//We've used PID.4 for ChartNumber in the past and will continue to use this as a backup method for locating a patient if the ID in PID.2 is not present
						//or if no patient can be found using that value.
						seg.AddField(4,"pat.ChartNumber");
						//PID.5, Patient Name
						//This will contain the last, first, and middle names as well as the title
						//Example:  LName^FName^MiddleI^^Title
						seg.AddField(5,"pat.nameLFM");
						//PID.7, Date/Time of Birth
						seg.AddField(7,"pat.birthdateTime");
						//PID.8, Administrative Sex
						seg.AddField(8,"pat.Gender");
						//PID.10, Race
						//The old race parsing will still work and matches to an exact string to find the race.  The string can be the only component of the field or the first of many.
						//The old parse translates the string to the PatRaceOld enum, then reconciles them into one or more of the PatRace enums, then adds/deletes entries in the patientrace table.
						//The old race strings are: "American Indian Or Alaska Native", "Asian", "Native Hawaiian or Other Pacific", "Black or African American", "White", "Hispanic", "Other Race"
						//The new race parse accepts the CWE - Coded with Exceptions data type with 9 fields.
						//The 9 fields are: Code^Description^CodeSystem^AlternateCode^AltDescript^AltCodeSystem^CodeSystemVersionID^AltCodeSystemVersionID^OriginalText
						//We will make sure CodeSystem, PID.10.2, is "CDCREC" and use Code, PID.10.0, to find the correct race from the new PatRace enum and update the patientrace table.
						//The race field can repeat, so any number of races can be sent and will add to the patientrace table.
						seg.AddField(10,"pat.Race");
						//PID.11, Patient Address
						//PID.11.20, comment, is used to populate patient.AddrNote with '\.br\' signaling a line break. (the '\' is the default escape character, may be different and parses correctly)
						//Example: ...^^Emergency Contact: Mom Test\.br\Mother\.br\(503)555-1234
						seg.AddField(11,"pat.addressCityStateZip");
						//PID.13, Phone Number - Home, XTN data type (can repeat)
						//This field will also contain the patient's email address as a repetition as well as the WirelessPhone as a repetition
						//PRN stands for Primary Residence Number, equipment type: PH is Telephone, CP is Cell Phone, Internet is Internet Address (email)
						//Example: ^PRN^PH^^^503^3635432~^PRN^Internet^[email protected]~^PRN^CP^^^503^6895555
						seg.AddField(13,"pat.HmPhone");
						//PID.14, Phone Number - Business, XTN data type (can repeat)
						//We will send just one repetition, the WkPhone, but we will adhere to the data type
						//WPN=Work Number
						//Example: ^WPN^PH^^^503^3635432
						seg.AddField(14,"pat.WkPhone");
						//PID.16, Marital Status
						seg.AddField(16,"pat.Position");
						//PID.19, SSN - Patient
						seg.AddField(19,"pat.SSN");
					#endregion PID - Patient Identification
					#region PV1 - Patient Visit
					seg=new HL7DefSegment();
					msg.AddSegment(seg,4,false,true,SegmentNameHL7.PV1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PV1.2, Patient Class, IS data type (coded value for user-defined tables)
						//If this field is populated, it will set the patient.GradeLevel if the field can be converted to an integer between 1 and 12
						seg.AddField(2,"pat.GradeLevel");
						//PV1.3, Assigned Patient Location, PL - Person Location Data Type: Point of Care^Room^^Facility^^Person Location Type
						//Facility is a HD data type, so Namespace&ID&IDType.  We will just use &PracticeTitle with no namespace or IDType.
						//Example: ClinicDescript^OpName^^&PracticeTitle^^C  (C for clinic)
						//Used to set patient.ClinicNum if the location description matches clinic.Description
						seg.AddField(3,"pat.location");
						//PV1.7, Attending/Primary Care Doctor, XCN data type, ProviderId^LastName^FirstName^MI
						//In the PV1 segment, the primary provider will be set for the patient and the appointment
						//If there is an AIL or AIG segment, the appointment.ProvNum will be set to the provider referenced in that segment.
						seg.AddField(7,"prov.provIdNameLFM");
						//PV1.11, Temporary Location, PL - Person Location data type: PointOfCare^^^^^Person Location Type
						//Using the location type field to identify this field as a "Site (or Grade School)", we will attempt to match the description to a site.Description in the db
						//If exact match is found, set the patient.SiteNum=site.SiteNum
						//Example: |West Salem Elementary^^^^^S| ('S' for site)
						seg.AddField(11,"pat.site");
						//PV1.18, Patient Type, 0 - Unknown, 1 - NoProblems, 2 - NeedsCare, 3 - Urgent
						//Stored in the patient.Urgency field for treatment urgnecy, used in public health screening
						seg.AddField(18,"pat.Urgency");
					#endregion PV1 - Patient Visit
					#region AIG - Appointment Information - General Resource
					//This segment is for setting the provider(s) on the appointment and setting the confirmation status
					//It is repeatable so that the user can send one to set the dentist and one to set the hygienist on the appt
					seg=new HL7DefSegment();
					msg.AddSegment(seg,5,true,true,SegmentNameHL7.AIG);
						//Fields-------------------------------------------------------------------------------------------------------------
						//AIG.3, Resource ID, CWE data type
						//If this is included in the AIG segment for a general resource, we will try to find the provider using the resource ID as the OD ProvNum.
						//If not found by ProvNum, we will try to find the provider using the second component - Text, which should be populated with 'LName, FName',
						//combined with the 4th component - Alternate Identifier, which should be populated with the provider.Abbr.
						//Only if LName, FName, and Abbr all match will we use that provider.
						//When the provider is identified in an AIG or AIP segment, it is used to set the provider on the appointment, not the patient's primary provider.
						//For setting a patient's primary provider, the PV1 segment is used.
						//Example: |1234^Abbott, Sarah^^DrAbbott|
						seg.AddField(3,"prov.provIdName");
						//AIG.4, Resource Type, CWE data type
						//Accepted values are 'd' or 'D' for dentist and 'h' or 'H' for hygienist
						//If included, we will set either the dentist or the hygienist on the appt.
						//If not included, the provider will assumed to refer to the dentist
						seg.AddField(4,"prov.provType");
						//AIG.14, Filler Status Code, CWE data type
						//We will use this to set the confirmation status of the appointment
						//We will use the second component (text) and attempt to match exactly the ItemName (confirm Name) or ItemValue (confirm Abbreviation) from their definition table
						//If there is a match, we will update the confirmation status
						//Example: |^Appointment Confirmed|
						seg.AddField(14,"apt.confirmStatus");
					#endregion AIG - Appointment Information - General Resource
					#region AIL - Appointment Information - Location Resource
					//This segment is used to set the clinic on the appointment.
					//This may differ from the patient's assigned clinic, only the appointment.ClinicNum will be set from this segment.
					//This is not repeatable as we only have one clinic value to assign for the location resource
					seg=new HL7DefSegment();
					msg.AddSegment(seg,6,false,true,SegmentNameHL7.AIL);
						//Fields-------------------------------------------------------------------------------------------------------------
						//AIL.3, Location Resource ID, PL data type: Point of Care^Room^^Facility^^Person Location Type
						//Facility is a HD data type, so Namespace&ID&IDType.  We will just use &PracticeTitle with no namespace or IDType.
						//Example: ClinicDescript^OpName^^&PracticeTitle^^C  (C for clinic)
						//Room-Operatory (not set from inbound messages), Facility-Practice (not set from inbound messages), Building-Clinic (used to set apt.ClinicNum)
						//Used to set the appointment.ClinicNum if this is included in the message
						seg.AddField(3,"apt.location");
						//AIL.12, Filler Status Code, CWE data type
						//We will use this to set the confirmation status of the appointment
						//We will use the second component (text) and attempt to match exactly the ItemName (confirm Name) or ItemValue (confirm Abbreviation) from their definition table
						//If there is a match, we will update the confirmation status
						//Example: |^Appointment Confirmed|
						seg.AddField(12,"apt.confirmStatus");
					#endregion AIL - Appointment Information - Location Resource
					#region AIP - Appointment Information - Personnel Resource
					//This segment is used to set the dentist and/or hygienist on an appointment
					//This may differ from the patient's primary provider and it could cause an appointment to be in an operatory with a provider not assigned to that operatory
					seg=new HL7DefSegment();
					msg.AddSegment(seg,7,true,true,SegmentNameHL7.AIP);
						//Fields-------------------------------------------------------------------------------------------------------------
						//AIP.3, Personnel Resource ID, XCN data type
						//ProviderId^LastName^FirstName^MI^Suffix^Prefix
						//According to the HL7 standards, we are free to use the components as needed to identify the provider
						//We will use ProviderID as the OD ProvNum, and if not found in the db we will use LName, FName and the 'Prefix' component as the Abbr
						//Used to set the appointment.ProvNum or appointment.ProvHyg if this is included in the message
						//Field AIP.4 will determine whether it is the dentist or hygienist for the appt
						//This field is repeatable, but if they want to set both the dentist and the hygienist for the same appointment
						//they would have to repeat the whole segment with different provTypes in field 4
						//Example: |1234^Abbott^Sarah^L^DMD^DrAbbott|
						seg.AddField(3,"prov.provIdNameLFM");
						//AIP.4, Resource Type, CWE data type
						//Accepted values are 'd' or 'D' for dentist and 'h' or 'H' for hygienist
						seg.AddField(4,"prov.provType");
						//AIP.12, Filler Status Code, CWE data type
						//We will use this to set the confirmation status of the appointment
						//We will use the second component (text) and attempt to match exactly the ItemName (confirm Name) or ItemValue (confirm Abbreviation) from their definition table
						//If there is a match, we will update the confirmation status
						//Example: |^Appointment Confirmed|
						seg.AddField(12,"apt.confirmStatus");
					#endregion AIP - Appointment Information - Personnel Resource
				#endregion SRM - Schedule Request
			#endregion Inbound Messages
			#region Outbound Messages
				#region ACK - General Acknowledgment
				msg=new HL7DefMessage();
				def.AddMessage(msg,MessageTypeHL7.ACK,MessageStructureHL7.ADT_A01,InOutHL7.Outgoing,4);
					#region MSH - Message Header
					seg=new HL7DefSegment();
					msg.AddSegment(seg,0,SegmentNameHL7.MSH);
						//Fields-------------------------------------------------------------------------------------------------------------
						//MSH.1, Encoding Characters (DataType.ST)
						seg.AddField(1,"separators^~\\&");
						//MSH.2, Sending Application, HD data type, Namespace ID^Universal ID^Universal ID Type
						//We originally sent 'OD' in this field, but this is a HD data type, so should consist of three components
						//We will send the Open Dental HL7 root assigned to the office and stored in the oidinternal table with the IDType of Root
						//The recommeded value for this field in the table is ^2.16.840.1.113883.3.4337.1486.CustomerPatNum^HL7.
						//If the oidinternal row with IDType=Root does not have an IDRoot assigned, we will revert to sending 'OD'
						seg.AddField(2,"sendingApp");
						//MSH.3, Sending Facility, not used
						//MSH.4, Receiving Application
						//This field will have to be a fixed text field and would have to be modified in a custom definition
						//if they want the outbound messages to have a specific receiving application identifier
						seg.AddField(4,"0361",DataTypeHL7.HD,"","NamespaceID^UniversalID^UniversalIDType");
						//MSH.5, Receiving Facility, not used
						//MSH.6, Message Date and Time (YYYYMMDDHHMMSS)
						seg.AddField(6,"dateTime.Now");
						//MSH.8, Message Type, MSG data type
						//This segment should contain MessageType^EventType^MessageStructure, example SRR^S04^SRR_S04
						seg.AddField(8,"messageType");
						//MSH.9, Message Control ID
						//A GUID that uniquely identifies this message
						seg.AddField(9,"messageControlId");
						//MSH.10, Processing ID, PT data type, Processing ID^Processing Mode
						//Processing mode is optional and not included, we will use P for production (P-Production, T-Training, D-Debugging)
						seg.AddField(10,"0103",DataTypeHL7.PT,"","P");
						//MSH.11, Version ID, VID data type, Version ID^Internationalization Code^International Version ID
						//All components are optional, we will only send Version ID, which is currently 2.6
						seg.AddField(11,"0104",DataTypeHL7.VID,"","2.6");
						//MSH.15, Application Ack Type (AL=Always, NE=Never, ER=Error/reject conditions only, SU=Successful completion only)
						//This is for enhanced acknowledgment mode, which we do not currently support, but we will send our mode just in case
						//With field MSH.15, Accept Ack Type, not present it will default to NE
						//Field MSH.15 set to AL means we will require an ack for every message that is sent, meaning it was processed successfully by the receiving application
						//But MSH.15 not present or null means we do not require a separate accept ACK message, just the accept and validate response meaning the message was accepted and processed
						seg.AddField(15,"0155",DataTypeHL7.ID,"","AL");
					#endregion MSH - Message Header
					#region MSA - Message Acknowledgment
					seg=new HL7DefSegment();
					msg.AddSegment(seg,1,SegmentNameHL7.MSA);
						//Fields-------------------------------------------------------------------------------------------------------------
						//MSA.1, Acknowledgment Code
						seg.AddField(1,"ackCode");
						//MSA.2, Message Control ID
						seg.AddField(2,"messageControlId");
					#endregion MSA - Message Acknowledgment
				#endregion ACK - General Acknowledgment
				#region ADT - Patient Demographics (Admits, Discharges, and Transfers)
				//Outbound ADT messages will be triggered when specific data is changed in OD, but not if the data change is due to an inbound HL7 message.
				//ADT's created when:
				//1. Pressing OK from FormPatientEdit
				//2. Pressing OK from FormPatientAddAll
				//3. Pressing the Set Guarantor button (ContrFamily)
				//4. Pressing the Move button (ContrFamily) to move a patient to a different family
				//5. Retrieving web forms in FormWebForms if a form is for/creates a new patient
				//If the Synch Clone feature is enabled, we would not want the clone to exist in the other software, so we would want to make sure we were not sending ADT's for clones.
				msg=new HL7DefMessage();
				def.AddMessage(msg,MessageTypeHL7.ADT,MessageStructureHL7.ADT_A01,InOutHL7.Outgoing,5);
					#region MSH - Message Header
					seg=new HL7DefSegment();
					msg.AddSegment(seg,0,SegmentNameHL7.MSH);
						//Fields-------------------------------------------------------------------------------------------------------------
						//MSH.1, Encoding Characters (DataType.ST)
						seg.AddField(1,"separators^~\\&");
						//MSH.2, Sending Application, HD data type, Namespace ID^Universal ID^Universal ID Type
						//We originally sent 'OD' in this field, but this is a HD data type, so should consist of three components
						//We will send the Open Dental HL7 root assigned to the office and stored in the oidinternal table with the IDType of Root
						//The recommeded value for this field in the table is ^2.16.840.1.113883.3.4337.1486.CustomerPatNum^HL7.
						//If the oidinternal row with IDType=Root does not have an IDRoot assigned, we will revert to sending 'OD'
						seg.AddField(2,"sendingApp");
						//MSH.3, Sending Facility, not used
						//MSH.4, Receiving Application
						//This field will have to be a fixed text field and would have to be modified in a custom definition
						//if they want the outbound messages to have a specific receiving application identifier
						seg.AddField(4,"0361",DataTypeHL7.HD,"","NamespaceID^UniversalID^UniversalIDType");
						//MSH.5, Receiving Facility, not used
						//MSH.6, Message Date and Time (YYYYMMDDHHMMSS)
						seg.AddField(6,"dateTime.Now");
						//MSH.8, Message Type, MSG data type
						//This segment should contain MessageType^EventType^MessageStructure, example ADT^A04^ADT_A04
						seg.AddField(8,"messageType");
						//MSH.9, Message Control ID
						//A GUID that uniquely identifies this message
						seg.AddField(9,"messageControlId");
						//MSH.10, Processing ID, PT data type, Processing ID^Processing Mode
						//Processing mode is optional and not included, we will use P for production (P-Production, T-Training, D-Debugging)
						seg.AddField(10,"0103",DataTypeHL7.PT,"","P");
						//MSH.11, Version ID, VID data type, Version ID^Internationalization Code^International Version ID
						//All components are optional, we will only send Version ID, which is currently 2.6
						seg.AddField(11,"0104",DataTypeHL7.VID,"","2.6");
						//MSH.15, Application Ack Type (AL=Always, NE=Never, ER=Error/reject conditions only, SU=Successful completion only)
						//This is for enhanced acknowledgment mode, which we do not currently support, but we will send our mode just in case
						//With field MSH.15, Accept Ack Type, not present it will default to NE
						//Field MSH.15 set to AL means we will require an ack for every message that is sent, meaning it was processed successfully by the receiving application
						//But MSH.15 not present or null means we do not require a separate accept ACK message, just the accept and validate response meaning the message was accepted and processed
						seg.AddField(15,"0155",DataTypeHL7.ID,"","AL");
					#endregion MSH - Message Header
					#region EVN - Event Type
					seg=new HL7DefSegment();
					msg.AddSegment(seg,1,SegmentNameHL7.EVN);
						//Fields-------------------------------------------------------------------------------------------------------------
						//EVN.1, Event Type, example P03
						//Retained for backward compatibility only, we will not add this field by default
						//EVN.2, Recorded Date/Time
						seg.AddField(2,"dateTime.Now");
						//EVN.4, Event Reason Code (01 - Patient request; 02 - Physician/health practitioner order;03 - Census Management;O - Other;U - Unknown)
						seg.AddField(4,"0062",DataTypeHL7.IS,"","01");
					#endregion EVN - Event Type
					#region PID - Patient Identification
					seg=new HL7DefSegment();
					msg.AddSegment(seg,2,SegmentNameHL7.PID);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PID.1, Set ID, SI data type
						//"This field contains the number that identifies this transaction.  For the first occurrence of the segment, the sequence number shall be one" (HL7 v2.6 documentation)
						//We only send 1 PID segment in ADT's so this number will always be 1.
						seg.AddFieldFixed(1,DataTypeHL7.SI,"1");
						//PID.2, Patient ID (retained for backward compatibility only).  Defined as 'external' ID, we've always sent the ChartNumber in this field as the eCW patient ID
						//The standard will be to continue to use PID.2 for sending the ChartNumber, which was set from PID.4 of an incoming message.  This could be the other software patient ID.
						seg.AddField(2,"pat.ChartNumber");
						//PID.3, Patient Identifier List, contains a list of identifiers separated by the repetition character (usually ~)
						//PatientID^IDCheckDigit^CheckDigitScheme^AssigningAuthority^IDTypeCode
						//Assigning Authority is a HD data type and is composed of 3 subcomponents, NamespaceID&UniversalID&UniversalIDType
						//Sub-component 2, UniversalID, we will use the OID root for a Patient object stored in the oidinternal table
						//If retrieved from OD it will be 2.16.840.1.113883.3.4337.1486.CustomerNumber.2
						//Sub-component 3, Universal ID Type, will be 'HL7' since our root is registered with HL7.
						//The IDTypeCode will be 'PI', Patient internal identifier.
						//We will also get all of the identifiers in the oidexternals table for the patient and create repetitions for each external ID using the IDExternal and RootExternal
						//Example: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.2&HL7^PI~7684^8^M11^&Other.Software.OID&^PI|
						seg.AddField(3,"patientIds");
						//PID.4, Alternate Patient ID, (retained for backward compatibility only).
						//We've used PID.4 for sending the OD PatNum in the past and will continue to send this in PID.4
						seg.AddField(4,"pat.PatNum");
						//PID.5, Patient Name
						seg.AddField(5,"pat.nameLFM");
						//PID.7, Date/Time of Birth
						seg.AddField(7,"pat.birthdateTime");
						//PID.8, Administrative Sex
						seg.AddField(8,"pat.Gender");
						//PID.10, Race, CWE - Coded with Exceptions data type
						//This data type is composed of 9 fields, Code^Description^CodeSystem^AlternateCode^AltDescript^AltCodeSystem^CodeSystemVersionID^AltCodeSystemVersionID^OriginalText
						//We will send Code^Description^CodeSystem^^^^CodeSystemVersionID
						//The race field can repeat, so any number of races can be sent and will come from the patientrace table.
						//Example: 2106-3^White^CDCREC^^^^1~2186-5^NotHispanic^CDCREC^^^^1
						seg.AddField(10,"pat.Race");
						//PID.11, Patient Address
						//PID.11.20, comment, will come from the patient.AddrNote column and each new line character will be replaced with '\.br\' where the '\' is the defined escape char
						//Example: 123 Main St^Apt 1^Dallas^OR^97338^^^^^^^^^^^^^^^Emergency Contact: Mom Test1\.br\Mother\.br\(503)623-3072
						seg.AddField(11,"pat.addressCityStateZip");
						//PID.13, Phone Number - Home, XTN data type (can repeat)
						//This field will also contain the patient's email address as a repetition as well as the WirelessPhone as a repetition
						//PRN stands for Primary Residence Number, equipment type: PH is Telephone, CP is Cell Phone, Internet is Internet Address (email)
						//Example: ^PRN^PH^^^503^3635432~^PRN^Internet^[email protected]~^PRN^CP^^^503^6895555
						seg.AddField(13,"pat.HmPhone");
						//PID.14, Phone Number - Business, XTN data type (can repeat)
						//We will send just one repetition, the WkPhone, but we will adhere to the data type
						//WPN=Work Number
						//Example: ^WPN^PH^^^503^3635432
						seg.AddField(14,"pat.WkPhone");
						//PID.16, Marital Status
						//S-Single, M-Married, W-Widowed, D-Divorced
						seg.AddField(16,"pat.Position");
						//PID.19, SSN - Patient
						seg.AddField(19,"pat.SSN");
					#endregion PID - Patient Identification
					#region PV1 - Patient Visit
					seg=new HL7DefSegment();
					msg.AddSegment(seg,3,SegmentNameHL7.PV1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PV1.1, Set ID - PV1
						//See the comment above for the Sequence Number of the PID segment.  Always 1 since we only send one PV1 segment per ADT message.
						seg.AddFieldFixed(1,DataTypeHL7.SI,"1");
						//PV1.2, Patient Class, IS data type (coded value for user-defined tables)
						//Suggested values E=Emergency, I=Inpatient, O=Outpatient, P=Preadmit, R=Recurring patient, B=Obstetrics, C=Commercial Account, N=Not Applicable, U=Unkown
						//We will defualt to send 'O' for outpatient for outbound messages, but for incoming we will use this field for pat.GradeLevel if it's an integer from 1-12
						seg.AddField(2,"0004",DataTypeHL7.IS,"","O");
						//PV1.3, Assigned Patient Location, PL - Person Location Data Type: Point of Care^Room^^Facility^^Person Location Type
						//Facility is a HD data type, so Namespace&ID&IDType.  We will just use &PracticeTitle with no namespace or IDType.
						//Example: ClinicDescript^OpName^^&PracticeTitle^^C  (C for clinic)
						seg.AddField(3,"pat.location");
						//PV1.7, Attending/Primary Care Doctor, ProviderId^LastName^FirstName^MI
						seg.AddField(7,"0010",DataTypeHL7.XCN,"prov.provIdNameLFM","");
						//PV1.11, Temporary Location, PL - Person Location data type: PointOfCare^^^^^Person Location Type
						//Filled with the "Site (or Grade School)" value in the database, using 'S' to designate the location type site and the site.Description value
						//If no site assigned in OD, this will be blank as it is optional
						//Example: |West Salem Elementary^^^^^S| ('S' for site)
						seg.AddField(11,"pat.site");
						//PV1.18, Patient Type, IS data type (coded value for user-defined tables)
						//We will send one of the following values retrieved from the patient.Urgency field for treatment urgency: 0 - Unknown, 1 - NoProblems, 2 - NeedsCare, 3 - Urgent
						seg.AddField(18,"pat.Urgency");
						//PV1.19, Visit Number
						//Outbound ADT messages will not have an appointment number, no appointment selected
						//seg.AddField(19,"apt.AptNum");
						//PV1.44, Admit Date/Time
						//Outbound ADT messages will not have a procedure or appt to get the date/time from
						//seg.AddField(44,"proc.procDateTime");
					#endregion PV1 - Patient Visit
					#region IN1 - Insurance
					seg=new HL7DefSegment();
					msg.AddSegment(seg,4,true,true,SegmentNameHL7.IN1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//IN1.1, Set ID (starts with 1)
						//This will be 1 for primary ins and increment for additional repetitions for secondary ins etc.
						seg.AddField(1,"sequenceNum");
						//IN1.2, Insurance Plan ID, CWE data type
						//We do not have unique ID's for insurance plans.
						//We have created an oidinternal ID for insplan, root+.7, and will use this with the insplan.PlanNum to uniquely identify an insplan.
						//Example: 2.16.840.1.113883.3.4337.1486.6566.7.1234
						seg.AddField(2,"insplan.planNum");
						//IN1.3, Insurance Company ID, CX data type
						seg.AddField(3,"carrier.ElectID");
						//IN1.4, Insurance Company Name, XON data type
						seg.AddField(4,"carrier.CarrierName");
						//IN1.5, Insurance Company Address, XAD data type
						//carrier.Address^Address2^City^State^Zip
						seg.AddField(5,"carrier.addressCityStateZip");
						//IN1.7, Insurance Company Phone Number, XTN data type
						//Example: ^WPN^PH^^^503^3635432
						seg.AddField(7,"carrier.Phone");
						//IN1.8, Group Number, ST data type
						seg.AddField(8,"insplan.GroupNum");
						//IN1.9, Group Name, XON data type
						seg.AddField(9,"insplan.GroupName");
						//IN1.11, Insured's Group Employer Name, XON data type
						//insplan.EmployerNum to employer.EmpName
						seg.AddField(11,"insplan.empName");
						//IN1.12, Plan Effective Date, DT data type
						seg.AddField(12,"inssub.DateEffective");
						//IN1.13, Plan Expiration Date, DT data type
						seg.AddField(13,"inssub.DateTerm");
						//IN1.15, Plan Type, IS data type
						//insplan.PlanType, Category Percentage, PPO Percentage, Medicaid or Flat Copay, Capitation
						seg.AddField(15,"insplan.PlanType");
						//IN1.16, Name of Insured, XPN data type
						//insplan.InsSubNum->inssub.Subscriber->patient name
						seg.AddField(16,"inssub.subscriberName");
						//IN1.17, Insured's Relationship to Patient, CWE data type
						//SEL-Self, SPO-Spouse, DOM-LifePartner, CHD-Child (PAR-Parent), EME-Employee (EMR-Employer)
						//DEP-HandicapDep (GRD-Guardian), DEP-Dependent, OTH-SignifOther (OTH-Other), OTH-InjuredPlantiff
						//We store relationship to subscriber and they want subscriber's relationship to patient, therefore
						//Relat.Child will return "PAR" for Parent, Relat.Employee will return "EMR" for Employer, and Relat.HandicapDep and Relat.Dependent will return "GRD" for Guardian
						seg.AddField(17,"patplan.subRelationToPat");
						//IN1.18, Insured's Date of Birth, DTM data type
						seg.AddField(18,"inssub.subBirthdate");
						//IN1.19, Insured's Address, XAD data type
						seg.AddField(19,"inssub.subAddrCityStateZip");
						//IN1.20, Assignment of Benefits, IS data type
						//inssub.AssignBen 1-Y, 0-N
						seg.AddField(20,"inssub.AssignBen");
						//IN1.21, Coordination of Benefits, IS data type
						//CO-Coordination, IN-Independent.  Will be CO if more than one patplan
						seg.AddField(21,"insplan.cob");
						//IN1.22, Coordination of Benefits Priority, ST data type
						//1-Primary, 2-Secondary, 3,4,5...
						seg.AddField(22,"patplan.Ordinal");
						//IN1.27, Release of Information Code, IS data type
						//inssub.ReleaseInfo, 1-Y, 2-N
						seg.AddField(27,"inssub.ReleaseInfo");
						//IN1.36, Policy Number, ST data type
						//patplan.PatID, if blank then inssub.SubscriberID
						seg.AddField(36,"patplan.policyNum");
						//IN1.47, Coverage Type, IS data type
						//D-Dental, M-Medical using insplan.IsMedical flag
						seg.AddField(47,"insplan.coverageType");
						//IN1.49, Insured's ID Number, CX data type
						seg.AddField(49,"inssub.SubscriberID");
					#endregion IN1 - Insurance
				#endregion ADT - Patient Demographics (Admits, Discharges, and Transfers)
				#region DFT - Detailed Financial Transaction
				//Outbound DFT messages will be triggered by pressing the tool bar button for this enabled definition.
				//In the future there may be automation for sending these when procedures are set complete.
				msg=new HL7DefMessage();
				def.AddMessage(msg,MessageTypeHL7.DFT,MessageStructureHL7.DFT_P03,InOutHL7.Outgoing,6);
					#region MSH - Message Header
					seg=new HL7DefSegment();
					msg.AddSegment(seg,0,SegmentNameHL7.MSH);
						//Fields-------------------------------------------------------------------------------------------------------------
						//MSH.1, Encoding Characters (DataType.ST)
						seg.AddField(1,"separators^~\\&");
						//MSH.2, Sending Application, HD data type, Namespace ID^Universal ID^Universal ID Type
						//We originally sent 'OD' in this field, but this is a HD data type, so should consist of three components
						//We will send the Open Dental HL7 root assigned to the office and stored in the oidinternal table with the IDType of Root
						//The recommeded value for this field in the table is ^2.16.840.1.113883.3.4337.1486.CustomerPatNum^HL7.
						//If the oidinternal row with IDType=Root does not have an IDRoot assigned, we will revert to sending 'OD'
						seg.AddField(2,"sendingApp");
						//MSH.3, Sending Facility, not used
						//MSH.4, Receiving Application
						//This field will have to be a fixed text field and would have to be modified in a custom definition
						//if they want the outbound messages to have a specific receiving application identifier
						seg.AddField(4,"0361",DataTypeHL7.HD,"","NamespaceID^UniversalID^UniversalIDType");
						//MSH.5, Receiving Facility, not used
						//MSH.6, Message Date and Time (YYYYMMDDHHMMSS)
						seg.AddField(6,"dateTime.Now");
						//MSH.8, Message Type, MSG data type
						//This segment should contain MessageType^EventType^MessageStructure, example DFT^P03^DFT_P03
						seg.AddField(8,"messageType");
						//MSH.9, Message Control ID
						//A GUID that uniquely identifies this message
						seg.AddField(9,"messageControlId");
						//MSH.10, Processing ID, PT data type, Processing ID^Processing Mode
						//Processing mode is optional and not included, we will use P for production (P-Production, T-Training, D-Debugging)
						seg.AddField(10,"0103",DataTypeHL7.PT,"","P");
						//MSH.11, Version ID, VID data type, Version ID^Internationalization Code^International Version ID
						//All components are optional, we will only send Version ID, which is currently 2.6
						seg.AddField(11,"0104",DataTypeHL7.VID,"","2.6");
						//MSH.15, Application Ack Type (AL=Always, NE=Never, ER=Error/reject conditions only, SU=Successful completion only)
						//This is for enhanced acknowledgment mode, which we do not currently support, but we will send our mode just in case
						//With field MSH.15, Accept Ack Type, not present it will default to NE
						//Field MSH.15 set to AL means we will require an ack for every message that is sent, meaning it was processed successfully by the receiving application
						//But MSH.15 not present or null means we do not require a separate accept ACK message, just the accept and validate response meaning the message was accepted and processed
						seg.AddField(15,"0155",DataTypeHL7.ID,"","AL");
					#endregion MSH - Message Header
					#region EVN - Event Type
					seg=new HL7DefSegment();
					msg.AddSegment(seg,1,SegmentNameHL7.EVN);
						//Fields-------------------------------------------------------------------------------------------------------------
						//EVN.1, Event Type, example P03
						//Retained for backward compatibility only, we will not add this field by default
						//EVN.2, Recorded Date/Time
						seg.AddField(2,"dateTime.Now");
						//EVN.4, Event Reason Code (01 - Patient request; 02 - Physician/health practitioner order;03 - Census Management;O - Other;U - Unknown)
						seg.AddField(4,"0062",DataTypeHL7.IS,"","01");
					#endregion EVN - Event Type
					#region PID - Patient Identification
					seg=new HL7DefSegment();
					msg.AddSegment(seg,2,SegmentNameHL7.PID);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PID.1, Set ID, SI data type
						//"This field contains the number that identifies this transaction.  For the first occurrence of the segment, the sequence number shall be one" (HL7 v2.6 documentation)
						//We only send 1 PID segment in DFT's so this number will always be 1.
						seg.AddFieldFixed(1,DataTypeHL7.SI,"1");
						//PID.2, Patient ID (retained for backward compatibility only).  Defined as 'external' ID, we've always sent the ChartNumber in this field as the eCW patient ID
						//The standard will be to continue to use PID.2 for sending the ChartNumber, which was set from PID.4 of an incoming message.  This could be the other software patient ID.
						seg.AddField(2,"pat.ChartNumber");
						//PID.3, Patient Identifier List, contains a list of identifiers separated by the repetition character (usually ~)
						//PatientID^IDCheckDigit^CheckDigitScheme^AssigningAuthority^IDTypeCode
						//Assigning Authority is a HD data type and is composed of 3 subcomponents, NamespaceID&UniversalID&UniversalIDType
						//Sub-component 2, UniversalID, we will use the OID root for a Patient object stored in the oidinternal table
						//If retrieved from OD it will be 2.16.840.1.113883.3.4337.1486.CustomerNumber.2
						//Sub-component 3, Universal ID Type, will be 'HL7' since our root is registered with HL7.
						//The IDTypeCode will be 'PI', Patient internal identifier.
						//We will also get all of the identifiers in the oidexternals table for the patient and create repetitions for each external ID using the IDExternal and RootExternal
						//Example: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.2&HL7^PI~7684^8^M11^&Other.Software.OID&^PI|
						seg.AddField(3,"patientIds");
						//PID.4, Alternate Patient ID, (retained for backward compatibility only).
						//We've used PID.4 for sending the OD PatNum in the past and will continue to send this in PID.4
						seg.AddField(4,"pat.PatNum");
						//PID.5, Patient Name
						seg.AddField(5,"pat.nameLFM");
						//PID.7, Date/Time of Birth
						seg.AddField(7,"pat.birthdateTime");
						//PID.8, Administrative Sex
						seg.AddField(8,"pat.Gender");
						//PID.10, Race, CWE - Coded with Exceptions data type
						//This data type is composed of 9 fields, Code^Description^CodeSystem^AlternateCode^AltDescript^AltCodeSystem^CodeSystemVersionID^AltCodeSystemVersionID^OriginalText
						//We will send Code^Description^CodeSystem^^^^CodeSystemVersionID
						//The race field can repeat, so any number of races can be sent and will come from the patientrace table.
						//Example: 2106-3^White^CDCREC^^^^1~2186-5^NotHispanic^CDCREC^^^^1
						seg.AddField(10,"pat.Race");
						//PID.11, Patient Address
						//PID.11.20, comment, will come from the patient.AddrNote column and each new line character will be replaced with '\.br\' where the '\' is the defined escape char
						//Example: 123 Main St^Apt 1^Dallas^OR^97338^^^^^^^^^^^^^^^Emergency Contact: Mom Test1\.br\Mother\.br\(503)623-3072
						seg.AddField(11,"pat.addressCityStateZip");
						//PID.13, Phone Number - Home, XTN data type (can repeat)
						//This field will also contain the patient's email address as a repetition as well as the WirelessPhone as a repetition
						//PRN stands for Primary Residence Number, equipment type: PH is Telephone, CP is Cell Phone, Internet is Internet Address (email)
						//Example: ^PRN^PH^^^503^3635432~^PRN^Internet^[email protected]~^PRN^CP^^^503^6895555
						seg.AddField(13,"pat.HmPhone");
						//PID.14, Phone Number - Business, XTN data type (can repeat)
						//We will send just one repetition, the WkPhone, but we will adhere to the data type
						//WPN=Work Number
						//Example: ^WPN^PH^^^503^3635432
						seg.AddField(14,"pat.WkPhone");
						//PID.16, Marital Status
						//S-Single, M-Married, W-Widowed, D-Divorced
						seg.AddField(16,"pat.Position");
						//PID.19, SSN - Patient
						seg.AddField(19,"pat.SSN");
					#endregion PID - Patient Identification
					#region PV1 - Patient Visit
					seg=new HL7DefSegment();
					msg.AddSegment(seg,3,false,true,SegmentNameHL7.PV1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PV1.1, Set ID - PV1
						//See the comment above for the Sequence Number of the PID segment.  Always 1 since we only send one PV1 segment per DFT message.
						seg.AddFieldFixed(1,DataTypeHL7.SI,"1");
						//PV1.2, Patient Class, IS data type (coded value for user-defined tables)
						//Suggested values E=Emergency, I=Inpatient, O=Outpatient, P=Preadmit, R=Recurring patient, B=Obstetrics, C=Commercial Account, N=Not Applicable, U=Unkown
						//We will defualt to send 'O' for outpatient for outbound messages, but for incoming we will use this field for pat.GradeLevel if it's an integer from 1-12
						seg.AddField(2,"0004",DataTypeHL7.IS,"","O");
						//PV1.3, Assigned Patient Location, PL - Person Location Data Type: Point of Care^Room^^Facility^^Person Location Type
						//Facility is a HD data type, so Namespace&ID&IDType.  We will just use &PracticeTitle with no namespace or IDType.
						//Example: ClinicDescript^OpName^^&PracticeTitle^^C  (C for clinic)
						seg.AddField(3,"apt.location");
						//PV1.7, Attending/Primary Care Doctor, ProviderId^LastName^FirstName^MI
						seg.AddField(7,"0010",DataTypeHL7.XCN,"prov.provIdNameLFM","");
						//PV1.11, Temporary Location, PL - Person Location data type: PointOfCare^^^^^Person Location Type
						//Filled with the "Site (or Grade School)" value in the database, using 'S' to designate the location type site and the site.Description value
						//If no site assigned in OD, this will be blank as it is optional
						//Example: |West Salem Elementary^^^^^S| ('S' for site)
						seg.AddField(11,"pat.site");
						//PV1.18, Patient Type, IS data type (coded value for user-defined tables)
						//We will send one of the following values retrieved from the patient.Urgency field for treatment urgency: 0 - Unknown, 1 - NoProblems, 2 - NeedsCare, 3 - Urgent
						seg.AddField(18,"pat.Urgency");
						//PV1.19, Visit Number, CX data type, AptNum^CheckDigit^CheckDigitScheme^&AssignAuthorityID&IDType^VN  (VN - Visit Number)
						//We will use AptNum, with check digit scheme M11, with the OIDRoot for an appt object (set in oidinternal), ID Type 'HL7', and 'VN' for Visit Number
						//Example: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.6&HL7^VN|
						seg.AddField(19,"apt.AptNum");
						//PV1.44, Admit Date/Time
						seg.AddField(44,"proc.procDateTime");
					#endregion PV1 - Patient Visit
					#region FT1 - Financial Transaction Information
					seg=new HL7DefSegment();
					msg.AddSegment(seg,4,true,true,SegmentNameHL7.FT1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//FT1.1, Sequence Number (starts with 1)
						seg.AddField(1,"sequenceNum");
						//FT1.2, Transaction ID
						seg.AddField(2,"proc.ProcNum");
						//FT1.4, Transaction Date (YYYYMMDDHHMMSS)
						seg.AddField(4,"proc.procDateTime");
						//FT1.5, Transaction Posting Date (YYYYMMDDHHMMSS)
						seg.AddField(5,"proc.procDateTime");
						//FT1.6, Transaction Type
						seg.AddFieldFixed(6,DataTypeHL7.IS,"CG");
						//FT1.7, Transaction Code, CWE data type
						//This is a required field and should contain "the code assigned by the institution for the purpose of uniquely identifying the transaction based on the Transaction Type (FT1-6)".
						//We will just send the ProcNum, not sure if any receiving application will use it
						seg.AddField(7,"proc.ProcNum");
						//FT1.10, Transaction Quantity
						seg.AddFieldFixed(10,DataTypeHL7.NM,"1.0");
						//FT1.11, Transaction Amount Extended, CP data type
						//Total fee to charge for this procedure, independent of transaction quantity
						seg.AddField(11,"proc.ProcFee");
						//FT1.12, Transaction Amount Unit, CP data type
						//Fee for this procedure for each transaction quantity
						seg.AddField(12,"proc.ProcFee");
						//FT1.16, Assigned Patient Location, PL - Person Location Data Type: Point of Care^Room^^Facility^^Person Location Type
						//Facility is a HD data type, so Namespace&ID&IDType.  We will just use &PracticeTitle with no namespace or IDType.
						//Example: ClinicDescript^OpName^^&PracticeTitle^^C  (C for clinic)
						//In the FT1 segment, we will get the clinic from the specific procedure, but if not set (0) we will get it from the patient
						//If no clinic on the proc or assigned to the patient, this will be blank
						seg.AddField(16,"proc.location");
						//FT1.19, Diagnosis Code, CWE data type, repeatable if they have more than 1 code on the proc (currently 4 allowed)
						//Example: |520.2^Abnormal tooth size/form^I9C^^^^31^^~521.81^Cracked tooth^I9C^^^^31^^|
						seg.AddField(19,"proc.DiagnosticCode");
						//FT1.20, Performed by Code
						seg.AddField(20,"prov.provIdNameLFM");
						//FT1.21, Ordering Provider
						seg.AddField(21,"prov.provIdNameLFM");
						//FT1.22, Unit Cost (procedure fee)
						seg.AddField(22,"proc.ProcFee");
						//FT1.25, Procedure Code, CNE data type
						//ProcNum^Descript^CD2^^^^2014^^LaymanTerm
						//Example: D0150^comprehensive oral evaluation - new or established patient^CD2^^^^2014^^Comprehensive Exam
						seg.AddField(25,"proccode.ProcCode");
						//FT1.26, Modifiers (treatment area)
						seg.AddField(26,"proc.toothSurfRange");
					#endregion FT1 - Financial Transaction Information
					#region IN1 - Insurance (global across all FT1s)
					seg=new HL7DefSegment();
					msg.AddSegment(seg,5,true,true,SegmentNameHL7.IN1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//IN1.1, Set ID (starts with 1)
						//This will be 1 for primary ins and increment for additional repetitions for secondary ins etc.
						seg.AddField(1,"sequenceNum");
						//IN1.2, Insurance Plan ID, CWE data type
						//We do not have unique ID's for insurance plans.
						//We have created an oidinternal ID for insplan, root+.7, and will use this with the insplan.PlanNum to uniquely identify an insplan.
						//Example: 2.16.840.1.113883.3.4337.1486.6566.7.1234
						seg.AddField(2,"insplan.planNum");
						//IN1.3, Insurance Company ID, CX data type
						seg.AddField(3,"carrier.ElectID");
						//IN1.4, Insurance Company Name, XON data type
						seg.AddField(4,"carrier.CarrierName");
						//IN1.5, Insurance Company Address, XAD data type
						//carrier.Address^Address2^City^State^Zip
						seg.AddField(5,"carrier.addressCityStateZip");
						//IN1.7, Insurance Company Phone Number, XTN data type
						//Example: ^WPN^PH^^^503^3635432
						seg.AddField(7,"carrier.Phone");
						//IN1.8, Group Number, ST data type
						seg.AddField(8,"insplan.GroupNum");
						//IN1.9, Group Name, XON data type
						seg.AddField(9,"insplan.GroupName");
						//IN1.11, Insured's Group Employer Name, XON data type
						//insplan.EmployerNum to employer.EmpName
						seg.AddField(11,"insplan.empName");
						//IN1.12, Plan Effective Date, DT data type
						seg.AddField(12,"inssub.DateEffective");
						//IN1.13, Plan Expiration Date, DT data type
						seg.AddField(13,"inssub.DateTerm");
						//IN1.15, Plan Type, IS data type
						//insplan.PlanType, Category Percentage, PPO Percentage, Medicaid or Flat Copay, Capitation
						seg.AddField(15,"insplan.PlanType");
						//IN1.16, Name of Insured, XPN data type
						//insplan.InsSubNum->inssub.Subscriber->patient name
						seg.AddField(16,"inssub.subscriberName");
						//IN1.17, Insured's Relationship to Patient, CWE data type
						//SEL-Self, SPO-Spouse, DOM-LifePartner, CHD-Child (PAR-Parent), EME-Employee (EMR-Employer)
						//DEP-HandicapDep (GRD-Guardian), DEP-Dependent, OTH-SignifOther (OTH-Other), OTH-InjuredPlantiff
						//We store relationship to subscriber and they want subscriber's relationship to patient, therefore
						//Relat.Child will return "PAR" for Parent, Relat.Employee will return "EMR" for Employer, and Relat.HandicapDep and Relat.Dependent will return "GRD" for Guardian
						//We will use the first two components, Identifier^Text
						//Example: |PAR^Parent|
						seg.AddField(17,"patplan.subRelationToPat");
						//IN1.18, Insured's Date of Birth, DTM data type
						seg.AddField(18,"inssub.subBirthdate");
						//IN1.19, Insured's Address, XAD data type
						seg.AddField(19,"inssub.subAddrCityStateZip");
						//IN1.20, Assignment of Benefits, IS data type
						//inssub.AssignBen 1-Y, 0-N
						seg.AddField(20,"inssub.AssignBen");
						//IN1.21, Coordination of Benefits, IS data type
						//CO-Coordination, IN-Independent.  Will be CO if more than one patplan
						seg.AddField(21,"insplan.cob");
						//IN1.22, Coordination of Benefits Priority, ST data type
						//1-Primary, 2-Secondary, 3,4,5...
						seg.AddField(22,"patplan.Ordinal");
						//IN1.27, Release of Information Code, IS data type
						//inssub.ReleaseInfo, 1-Y, 2-N
						seg.AddField(27,"inssub.ReleaseInfo");
						//IN1.36, Policy Number, ST data type
						//patplan.PatID, if blank then inssub.SubscriberID
						seg.AddField(36,"patplan.policyNum");
						//IN1.47, Coverage Type, IS data type
						//D-Dental, M-Medical using insplan.IsMedical flag
						seg.AddField(47,"insplan.coverageType");
						//IN1.49, Insured's ID Number, CX data type
						seg.AddField(49,"inssub.SubscriberID");
					#endregion IN1 - Insurance (global across all FT1s)
				#endregion DFT - Detailed Financial Transaction
				#region SIU - Schedule Information Unsolicited
				//Outbound SIU messages will be triggered when specific data is changed in OD, but not if the data change is due to an inbound HL7 message.
				//SIU's created when creating/modifying/cancelling/breaking an appointment
				msg=new HL7DefMessage();
				def.AddMessage(msg,MessageTypeHL7.SIU,MessageStructureHL7.SIU_S12,InOutHL7.Outgoing,7);
					#region MSH - Message Header
					seg=new HL7DefSegment();
					msg.AddSegment(seg,0,SegmentNameHL7.MSH);
						//Fields-------------------------------------------------------------------------------------------------------------
						//MSH.1, Encoding Characters (DataType.ST)
						seg.AddField(1,"separators^~\\&");
						//MSH.2, Sending Application, HD data type, Namespace ID^Universal ID^Universal ID Type
						//We originally sent 'OD' in this field, but this is a HD data type, so should consist of three components
						//We will send the Open Dental HL7 root assigned to the office and stored in the oidinternal table with the IDType of Root
						//The recommeded value for this field in the table is ^2.16.840.1.113883.3.4337.1486.CustomerPatNum^HL7.
						//If the oidinternal row with IDType=Root does not have an IDRoot assigned, we will revert to sending 'OD'
						seg.AddField(2,"sendingApp");
						//MSH.3, Sending Facility, not used
						//MSH.4, Receiving Application
						//This field will have to be a fixed text field and would have to be modified in a custom definition
						//if they want the outbound messages to have a specific receiving application identifier
						seg.AddField(4,"0361",DataTypeHL7.HD,"","NamespaceID^UniversalID^UniversalIDType");
						//MSH.5, Receiving Facility, not used
						//MSH.6, Message Date and Time (YYYYMMDDHHMMSS)
						seg.AddField(6,"dateTime.Now");
						//MSH.8, Message Type, MSG data type
						//This segment should contain MessageType^EventType^MessageStructure, example SIU^S12^SIU_S12
						seg.AddField(8,"messageType");
						//MSH.9, Message Control ID
						//A GUID that uniquely identifies this message
						seg.AddField(9,"messageControlId");
						//MSH.10, Processing ID, PT data type, Processing ID^Processing Mode
						//Processing mode is optional and not included, we will use P for production (P-Production, T-Training, D-Debugging)
						seg.AddField(10,"0103",DataTypeHL7.PT,"","P");
						//MSH.11, Version ID, VID data type, Version ID^Internationalization Code^International Version ID
						//All components are optional, we will only send Version ID, which is currently 2.6
						seg.AddField(11,"0104",DataTypeHL7.VID,"","2.6");
						//MSH.15, Application Ack Type (AL=Always, NE=Never, ER=Error/reject conditions only, SU=Successful completion only)
						//This is for enhanced acknowledgment mode, which we do not currently support, but we will send our mode just in case
						//With field MSH.15, Accept Ack Type, not present it will default to NE
						//Field MSH.15 set to AL means we will require an ack for every message that is sent, meaning it was processed successfully by the receiving application
						//But MSH.15 not present or null means we do not require a separate accept ACK message, just the accept and validate response meaning the message was accepted and processed
						seg.AddField(15,"0155",DataTypeHL7.ID,"","AL");
					#endregion MSH - Message Header
					#region SCH - Schedule Activity Information
					seg=new HL7DefSegment();
					msg.AddSegment(seg,1,SegmentNameHL7.SCH);
						//Fields-------------------------------------------------------------------------------------------------------------
						//SCH.1, Placer Appointment ID, EI data type, OD is the filler application
						//We will store the exernalAptId from an incoming SRM message ARQ segment if they send it to us, so send it here if we have one
						seg.AddField(1,"apt.externalAptID");
						//SCH.2, Filler Appointment ID, EI data type, OD is the filler application
						//We will populate the first component with the AptNum, the third with the OID for an appointment object, the fourth with "HL7"
						//Example: 1234^^2.16.840.1.113883.3.4337.1486.6566.6^HL7
						seg.AddField(2,"apt.AptNum");
						//SCH.5, Schedule ID, CWE data type
						//We will use this to send the operatory name
						seg.AddField(5,"apt.operatory");
						//SCH.7, Appointment Reason
						seg.AddField(7,"apt.Note");
						//SCH.8, Appointment Type, CWE data type
						//Suggested values are Normal - Routine schedule request type, Tentative, or Complete - Request to add a completed appt
						//We will send Normal for all appointment statuses except complete.
						seg.AddField(8,"apt.type");
						//SCH.16, Filler Contact Person, XCN data type
						//The OD user who created/modified the appointment
						seg.AddField(16,"apt.userOD");
						//SCH.20, Entered by Person, XCN data type
						//The OD user who created/modified the appointment
						seg.AddField(20,"apt.userOD");
						//SCH.25, Filler Status Code, CWE data type
						//This will signal to the other software the AptStatus of the appointment
						//Booked - ApptStatus.Scheduled or ApptStatus.ASAP, Complete - ApptStatus.Complete, Cancelled - ApptStatus.Broken or ApptStatus.UnscheduledList, Deleted (when deleted)
						seg.AddField(25,"apt.aptStatus");
					#endregion SCH - Schedule Activity Information
					#region TQ1 - Timing/Quantity
					seg=new HL7DefSegment();
					msg.AddSegment(seg,2,false,true,SegmentNameHL7.TQ1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//TQ1.1, Set ID, SI data type
						//Always 1, only one timing specification in our outbound SIU messages
						seg.AddFieldFixed(1,DataTypeHL7.SI,"1");
						//TQ1.2, Quantity, CQ data type
						//Always default value 1
						seg.AddFieldFixed(2,DataTypeHL7.CQ,"1");
						//TQ1.6, Service Duration, CQ data type
						//apt.Pattern is filled with X's and /'s, stored in 5 minute increments
						//Example: 60^min&&ANS+, ANS+ is the name of the coding system
						seg.AddField(6,"apt.length");
						//TQ1.7, Start Date/Time, DTM data type
						seg.AddField(7,"apt.AptDateTime");
						//TQ1.8, End Date/Time, DTM data type
						seg.AddField(8,"apt.endAptDateTime");
					#endregion TQ1 - Timing/Quantity
					#region PID - Patient Identification
					seg=new HL7DefSegment();
					msg.AddSegment(seg,3,SegmentNameHL7.PID);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PID.1, Set ID, SI data type
						//"This field contains the number that identifies this transaction.  For the first occurrence of the segment, the sequence number shall be one" (HL7 v2.6 documentation)
						//We only send 1 PID segment in SIU's so this number will always be 1.
						seg.AddFieldFixed(1,DataTypeHL7.SI,"1");
						//PID.2, Patient ID (retained for backward compatibility only).  Defined as 'external' ID, we've always sent the ChartNumber in this field as the eCW patient ID
						//The standard will be to continue to use PID.2 for sending the ChartNumber, which was set from PID.4 of an incoming message.  This could be the other software patient ID.
						seg.AddField(2,"pat.ChartNumber");
						//PID.3, Patient Identifier List, contains a list of identifiers separated by the repetition character (usually ~)
						//PatientID^IDCheckDigit^CheckDigitScheme^AssigningAuthority^IDTypeCode
						//Assigning Authority is a HD data type and is composed of 3 subcomponents, NamespaceID&UniversalID&UniversalIDType
						//Sub-component 2, UniversalID, we will use the OID root for a Patient object stored in the oidinternal table
						//If retrieved from OD it will be 2.16.840.1.113883.3.4337.1486.CustomerNumber.2
						//Sub-component 3, Universal ID Type, will be 'HL7' since our root is registered with HL7.
						//The IDTypeCode will be 'PI', Patient internal identifier.
						//We will also get all of the identifiers in the oidexternals table for the patient and create repetitions for each external ID using the IDExternal and RootExternal
						//Example: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.2&HL7^PI~7684^8^M11^&Other.Software.OID&^PI|
						seg.AddField(3,"patientIds");
						//PID.4, Alternate Patient ID, (retained for backward compatibility only).
						//We've used PID.4 for sending the OD PatNum in the past and will continue to send this in PID.4
						seg.AddField(4,"pat.PatNum");
						//PID.5, Patient Name
						seg.AddField(5,"pat.nameLFM");
						//PID.7, Date/Time of Birth
						seg.AddField(7,"pat.birthdateTime");
						//PID.8, Administrative Sex
						seg.AddField(8,"pat.Gender");
						//PID.10, Race, CWE - Coded with Exceptions data type
						//This data type is composed of 9 fields, Code^Description^CodeSystem^AlternateCode^AltDescript^AltCodeSystem^CodeSystemVersionID^AltCodeSystemVersionID^OriginalText
						//We will send Code^Description^CodeSystem^^^^CodeSystemVersionID
						//The race field can repeat, so any number of races can be sent and will come from the patientrace table.
						//Example: 2106-3^White^CDCREC^^^^1~2186-5^NotHispanic^CDCREC^^^^1
						seg.AddField(10,"pat.Race");
						//PID.11, Patient Address
						//PID.11.20, comment, will come from the patient.AddrNote column and each new line character will be replaced with '\.br\' where the '\' is the defined escape char
						//Example: 123 Main St^Apt 1^Dallas^OR^97338^^^^^^^^^^^^^^^Emergency Contact: Mom Test1\.br\Mother\.br\(503)623-3072
						seg.AddField(11,"pat.addressCityStateZip");
						//PID.13, Phone Number - Home, XTN data type (can repeat)
						//This field will also contain the patient's email address as a repetition as well as the WirelessPhone as a repetition
						//PRN stands for Primary Residence Number, equipment type: PH is Telephone, CP is Cell Phone, Internet is Internet Address (email)
						//Example: ^PRN^PH^^^503^3635432~^PRN^Internet^[email protected]~^PRN^CP^^^503^6895555
						seg.AddField(13,"pat.HmPhone");
						//PID.14, Phone Number - Business, XTN data type (can repeat)
						//We will send just one repetition, the WkPhone, but we will adhere to the data type
						//WPN=Work Number
						//Example: ^WPN^PH^^^503^3635432
						seg.AddField(14,"pat.WkPhone");
						//PID.16, Marital Status
						//S-Single, M-Married, W-Widowed, D-Divorced
						seg.AddField(16,"pat.Position");
						//PID.19, SSN - Patient
						seg.AddField(19,"pat.SSN");
					#endregion PID - Patient Identification
					#region PV1 - Patient Visit
					seg=new HL7DefSegment();
					msg.AddSegment(seg,4,false,true,SegmentNameHL7.PV1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PV1.1, Set ID - PV1
						//See the comment above for the Sequence Number of the PID segment.  Always 1 since we only send one PV1 segment per SIU message.
						seg.AddFieldFixed(1,DataTypeHL7.SI,"1");
						//PV1.2, Patient Class, IS data type (coded value for user-defined tables)
						//Suggested values E=Emergency, I=Inpatient, O=Outpatient, P=Preadmit, R=Recurring patient, B=Obstetrics, C=Commercial Account, N=Not Applicable, U=Unkown
						//We will defualt to send 'O' for outpatient for outbound messages, but for incoming we will use this field for pat.GradeLevel if it's an integer from 1-12
						seg.AddField(2,"0004",DataTypeHL7.IS,"","O");
						//PV1.3, Assigned Patient Location, PL - Person Location Data Type: Point of Care^Room^^Facility^^Person Location Type
						//Facility is a HD data type, so Namespace&ID&IDType.  We will just use &PracticeTitle with no namespace or IDType.
						//Example: ClinicDescript^OpName^^&PracticeTitle^^C  (C for clinic)
						seg.AddField(3,"apt.location");
						//PV1.7, Attending/Primary Care Doctor, ProviderId^LastName^FirstName^MI
						seg.AddField(7,"0010",DataTypeHL7.XCN,"prov.provIdNameLFM","");
						//PV1.11, Temporary Location, PL - Person Location data type: PointOfCare^^^^^Person Location Type
						//Filled with the "Site (or Grade School)" value in the database, using 'S' to designate the location type site and the site.Description value
						//If no site assigned in OD, this will be blank as it is optional
						//Example: |West Salem Elementary^^^^^S| ('S' for site)
						seg.AddField(11,"pat.site");
						//PV1.18, Patient Type, IS data type (coded value for user-defined tables)
						//We will send one of the following values retrieved from the patient.Urgency field for treatment urgency: 0 - Unknown, 1 - NoProblems, 2 - NeedsCare, 3 - Urgent
						seg.AddField(18,"pat.Urgency");
						//PV1.19, Visit Number, CX data type, AptNum^CheckDigit^CheckDigitScheme^&AssignAuthorityID&IDType^VN  (VN - Visit Number)
						//We will use AptNum, with check digit scheme M11, with the OIDRoot for an appt object (set in oidinternal), ID Type 'HL7', and 'VN' for Visit Number
						//Example: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.6&HL7^VN|
						seg.AddField(19,"apt.AptNum");
						//PV1.44, Admit Date/Time
						seg.AddField(44,"apt.AptDateTime");
					#endregion PV1 - Patient Visit
					#region RGS - Resource Group
					seg=new HL7DefSegment();
					msg.AddSegment(seg,5,SegmentNameHL7.RGS);
						//Fields-------------------------------------------------------------------------------------------------------------
						//RGS.1, Set ID, SI data type
						//Always 1, only one resourece group in our outbound SIU's
						seg.AddFieldFixed(1,DataTypeHL7.SI,"1");
						//RGS.2, Segment Action Code, ID data type
						//A-Add/Insert, D-Delete, U-Update, X-No Change
						seg.AddField(2,"segmentAction");
					#endregion RGB - Resource Group
					#region AIL - Appointment Information - Location Resource
					//We will use the AIL segment to identify the clinic and operatory for the appointment
					seg=new HL7DefSegment();
					msg.AddSegment(seg,6,false,true,SegmentNameHL7.AIL);
						//Fields-------------------------------------------------------------------------------------------------------------
						//AIL.1, Set ID, SI data type
						//Always 1, only one location identified by our SIU messsage
						seg.AddFieldFixed(1,DataTypeHL7.SI,"1");
						//AIL.2, Segment Action Code, ID data type
						//A-Add/Insert, D-Delete, U-Update, X-No Change
						seg.AddField(2,"segmentAction");
						//AIL.3, Location Resource ID, PL - Person Location Data Type: Point of Care^Room^^Facility^^Person Location Type
						//Facility is a HD data type, so Namespace&ID&IDType.  We will just use &PracticeTitle with no namespace or IDType.
						//Example: ClinicDescript^OpName^^&PracticeTitle^^C  (C for clinic)
						seg.AddField(3,"apt.location");
						//AIL.12, Filler Status Code, CWE data type
						//We will use this to send the confirmation status of the appointment
						//We will use the second component (text) and send the ItemName (confirm Name) from the definition table that is set for this appointment
						//Example: |^Appointment Confirmed|
						seg.AddField(12,"apt.confirmStatus");
					#endregion AIL - Appointment Information - Location Resource
					#region AIP - Appointment Information - Personnel Resource
					//We will use the AIP segment to identify the dentist and hygienist on the appointment
					//If there is both a dentist and a hygienist assigned to an appointment, we will send two repetitions of the AIP segment
					seg=new HL7DefSegment();
					msg.AddSegment(seg,7,true,true,SegmentNameHL7.AIP);
						//Fields-------------------------------------------------------------------------------------------------------------
						//AIP.1, Set ID, SI data type
						//This segment can repeat for an appt, sequence 1 will be the dentist, 2 will be the hygienist on the appt
						seg.AddField(1,"sequenceNum");
						//AIP.2, Segment Action Code, ID data type
						//A-Add/Insert, D-Delete, U-Update, X-No Change
						seg.AddField(2,"segmentAction");
						//AIP.3, Personnel Resource ID, XCN data type
						//ProviderId^LastName^FirstName^MI^Suffix^Prefix
						//According to the HL7 standards, we are free to use the components as needed to identify the provider
						//We will use 'ProviderID' to send the OD ProvNum, LName, FName and the 'Prefix' component as the Abbr
						//We will retrieve the provider from the appointment and use AIP.4 to differentiate between the dentist and hygienist
						//Example: |1234^Abbott^Sarah^L^DMD^DrAbbott|
						seg.AddField(3,"prov.provIdNameLFM");
						//AIP.4, Resource Type, CWE data type
						//We will send 'd' for dentist (apt.ProvNum) and 'h' for hygienist (apt.ProvHyg)
						seg.AddField(4,"prov.provType");
						//AIP.12, Filler Status Code, CWE data type
						//We will use this to send the confirmation status of the appointment
						//We will use the second component (text) and send the ItemName (confirm Name) from the definition table that is set for this appointment
						//Example: |^Appointment Confirmed|
						seg.AddField(12,"apt.confirmStatus");
					#endregion AIP - Appointment Information - Personnel Resource
				#endregion SIU - Schedule Information Unsolicited
				#region SRR - Schedule Request Response
				msg=new HL7DefMessage();
				def.AddMessage(msg,MessageTypeHL7.SRR,MessageStructureHL7.SRR_S01,InOutHL7.Outgoing,8);
					#region MSH - Message Header
					seg=new HL7DefSegment();
					msg.AddSegment(seg,0,SegmentNameHL7.MSH);
						//Fields-------------------------------------------------------------------------------------------------------------
						//MSH.1, Encoding Characters (DataType.ST)
						seg.AddField(1,"separators^~\\&");
						//MSH.2, Sending Application, HD data type, Namespace ID^Universal ID^Universal ID Type
						//We originally sent 'OD' in this field, but this is a HD data type, so should consist of three components
						//We will send the Open Dental HL7 root assigned to the office and stored in the oidinternal table with the IDType of Root
						//The recommeded value for this field in the table is ^2.16.840.1.113883.3.4337.1486.CustomerPatNum^HL7.
						//If the oidinternal row with IDType=Root does not have an IDRoot assigned, we will revert to sending 'OD'
						seg.AddField(2,"sendingApp");
						//MSH.3, Sending Facility, not used
						//MSH.4, Receiving Application
						//This field will have to be a fixed text field and would have to be modified in a custom definition
						//if they want the outbound messages to have a specific receiving application identifier
						seg.AddField(4,"0361",DataTypeHL7.HD,"","NamespaceID^UniversalID^UniversalIDType");
						//MSH.5, Receiving Facility, not used
						//MSH.6, Message Date and Time (YYYYMMDDHHMMSS)
						seg.AddField(6,"dateTime.Now");
						//MSH.8, Message Type, MSG data type
						//This segment should contain MessageType^EventType^MessageStructure, example SRR^S04^SRR_S04
						seg.AddField(8,"messageType");
						//MSH.9, Message Control ID
						//A GUID that uniquely identifies this message
						seg.AddField(9,"messageControlId");
						//MSH.10, Processing ID, PT data type, Processing ID^Processing Mode
						//Processing mode is optional and not included, we will use P for production (P-Production, T-Training, D-Debugging)
						seg.AddField(10,"0103",DataTypeHL7.PT,"","P");
						//MSH.11, Version ID, VID data type, Version ID^Internationalization Code^International Version ID
						//All components are optional, we will only send Version ID, which is currently 2.6
						seg.AddField(11,"0104",DataTypeHL7.VID,"","2.6");
						//MSH.15, Application Ack Type (AL=Always, NE=Never, ER=Error/reject conditions only, SU=Successful completion only)
						//This is for enhanced acknowledgment mode, which we do not currently support, but we will send our mode just in case
						//With field MSH.15, Accept Ack Type, not present it will default to NE
						//Field MSH.15 set to AL means we will require an ack for every message that is sent, meaning it was processed successfully by the receiving application
						//But MSH.15 not present or null means we do not require a separate accept ACK message, just the accept and validate response meaning the message was accepted and processed
						seg.AddField(15,"0155",DataTypeHL7.ID,"","AL");
					#endregion MSH - Message Header
					#region MSA - Message Acknowledgment
					seg=new HL7DefSegment();
					msg.AddSegment(seg,1,SegmentNameHL7.MSA);
						//Fields-------------------------------------------------------------------------------------------------------------
						//MSA.1, Acknowledgment Code
						seg.AddField(1,"ackCode");
						//MSA.2, Message Control ID
						seg.AddField(2,"messageControlId");
					#endregion MSA - Message Acknowledgment
					#region SCH - Schedule Activity Information
					seg=new HL7DefSegment();
					msg.AddSegment(seg,2,false,true,SegmentNameHL7.SCH);
						//Fields-------------------------------------------------------------------------------------------------------------
						//SCH.1, Placer Appointment ID, EI data type, OD is the filler application
						//We will store the exernalAptId from an incoming SRM message ARQ segment if they send it to us, so send it here if we have one
						seg.AddField(1,"apt.externalAptID");
						//SCH.2, Filler Appointment ID, EI data type, OD is the filler application
						//AptNum^^AssignAuthorityID^IDType
						//Example: |1234^^2.16.840.1.113883.3.4337.1486.6566.6^HL7|  root.6 is appointment
						seg.AddField(2,"apt.AptNum");
						//SCH.5, Schedule ID, CWE data type
						//We will use this to send the operatory name
						seg.AddField(5,"apt.operatory");
						//SCH.7, Appointment Reason
						seg.AddField(7,"apt.Note");
						//SCH.8, Appointment Type, CWE data type
						//Suggested values are Normal - Routine schedule request type, Tentative, or Complete - Request to add a completed appt
						//We will send Normal for all appointment statuses except complete.
						seg.AddField(8,"apt.type");
						//SCH.16, Filler Contact Person, XCN data type
						//The OD user who created/modified the appointment
						seg.AddField(16,"apt.userOD");
						//SCH.20, Entered by Person, XCN data type
						//The OD user who created/modified the appointment
						seg.AddField(20,"apt.userOD");
						//SCH.25, Filler Status Code, CWE data type
						//This will signal to the other software the AptStatus of the appointment
						//Booked - ApptStatus.Scheduled or ApptStatus.ASAP, Complete - ApptStatus.Complete, Cancelled - ApptStatus.Broken or ApptStatus.UnscheduledList, Deleted (when deleted)
						seg.AddField(25,"apt.aptStatus");
					#endregion SCH - Schedule Activity Information
					#region NTE - Notes and Comments
					seg=new HL7DefSegment();
					msg.AddSegment(seg,2,true,true,SegmentNameHL7.NTE);
						//Fields-------------------------------------------------------------------------------------------------------------
						//NTE.1, Set ID, SI data type
						//We will only ever send one NTE segment in outbound messages, so this will always be 1
						seg.AddFieldFixed(1,DataTypeHL7.SI,"1");
						//NTE.3, Comment, FT data type (formatted text)
						//We will send the appointment.Note value in this field for outbound messages
						//This is formatted text, so new line characters in the appointment.Note will be replaced with
						//the designated new line character sequence '\.br\' (where the '\' is the defined escape char, \ by default)
						seg.AddField(3,"apt.Note");
					#endregion NTE - Notes and Comments
					#region PID - Patient Identification
					seg=new HL7DefSegment();
					msg.AddSegment(seg,3,SegmentNameHL7.PID);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PID.1, Set ID, SI data type
						//"This field contains the number that identifies this transaction.  For the first occurrence of the segment, the sequence number shall be one" (HL7 v2.6 documentation)
						//We only send 1 PID segment in SRR's so this number will always be 1.
						seg.AddFieldFixed(1,DataTypeHL7.SI,"1");
						//PID.2, Patient ID (retained for backward compatibility only).  Defined as 'external' ID, we've always sent the ChartNumber in this field as the eCW patient ID
						//The standard will be to continue to use PID.2 for sending the ChartNumber, which was set from PID.4 of an incoming message.  This could be the other software patient ID.
						seg.AddField(2,"pat.ChartNumber");
						//PID.3, Patient Identifier List, contains a list of identifiers separated by the repetition character (usually ~)
						//PatientID^IDCheckDigit^CheckDigitScheme^AssigningAuthority^IDTypeCode
						//Assigning Authority is a HD data type and is composed of 3 subcomponents, NamespaceID&UniversalID&UniversalIDType
						//Sub-component 2, UniversalID, we will use the OID root for a Patient object stored in the oidinternal table
						//If retrieved from OD it will be 2.16.840.1.113883.3.4337.1486.CustomerNumber.2
						//Sub-component 3, Universal ID Type, will be 'HL7' since our root is registered with HL7.
						//The IDTypeCode will be 'PI', Patient internal identifier.
						//We will also get all of the identifiers in the oidexternals table for the patient and create repetitions for each external ID using the IDExternal and RootExternal
						//Example: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.2&HL7^PI~7684^8^M11^&Other.Software.OID&^PI|
						seg.AddField(3,"patientIds");
						//PID.4, Alternate Patient ID, (retained for backward compatibility only).
						//We've used PID.4 for sending the OD PatNum in the past and will continue to send this in PID.4
						seg.AddField(4,"pat.PatNum");
						//PID.5, Patient Name
						seg.AddField(5,"pat.nameLFM");
						//PID.7, Date/Time of Birth
						seg.AddField(7,"pat.birthdateTime");
						//PID.8, Administrative Sex
						seg.AddField(8,"pat.Gender");
						//PID.10, Race, CWE - Coded with Exceptions data type
						//This data type is composed of 9 fields, Code^Description^CodeSystem^AlternateCode^AltDescript^AltCodeSystem^CodeSystemVersionID^AltCodeSystemVersionID^OriginalText
						//We will send Code^Description^CodeSystem^^^^CodeSystemVersionID
						//The race field can repeat, so any number of races can be sent and will come from the patientrace table.
						//Example: 2106-3^White^CDCREC^^^^1~2186-5^NotHispanic^CDCREC^^^^1
						seg.AddField(10,"pat.Race");
						//PID.11, Patient Address
						//PID.11.20, comment, will come from the patient.AddrNote column and each new line character will be replaced with '\.br\' where the '\' is the defined escape char
						//Example: 123 Main St^Apt 1^Dallas^OR^97338^^^^^^^^^^^^^^^Emergency Contact: Mom Test1\.br\Mother\.br\(503)623-3072
						seg.AddField(11,"pat.addressCityStateZip");
						//PID.13, Phone Number - Home, XTN data type (can repeat)
						//This field will also contain the patient's email address as a repetition as well as the WirelessPhone as a repetition
						//PRN stands for Primary Residence Number, equipment type: PH is Telephone, CP is Cell Phone, Internet is Internet Address (email)
						//Example: ^PRN^PH^^^503^3635432~^PRN^Internet^[email protected]~^PRN^CP^^^503^6895555
						seg.AddField(13,"pat.HmPhone");
						//PID.14, Phone Number - Business, XTN data type (can repeat)
						//We will send just one repetition, the WkPhone, but we will adhere to the data type
						//WPN=Work Number
						//Example: ^WPN^PH^^^503^3635432
						seg.AddField(14,"pat.WkPhone");
						//PID.16, Marital Status
						//S-Single, M-Married, W-Widowed, D-Divorced
						seg.AddField(16,"pat.Position");
						//PID.19, SSN - Patient
						seg.AddField(19,"pat.SSN");
					#endregion PID - Patient Identification
					#region PV1 - Patient Visit
					seg=new HL7DefSegment();
					msg.AddSegment(seg,4,false,true,SegmentNameHL7.PV1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PV1.1, Set ID - PV1
						//See the comment above for the Sequence Number of the PID segment.  Always 1 since we only send one PV1 segment per SRR message.
						seg.AddFieldFixed(1,DataTypeHL7.SI,"1");
						//PV1.2, Patient Class, IS data type (coded value for user-defined tables)
						//Suggested values E=Emergency, I=Inpatient, O=Outpatient, P=Preadmit, R=Recurring patient, B=Obstetrics, C=Commercial Account, N=Not Applicable, U=Unkown
						//We will defualt to send 'O' for outpatient for outbound messages, but for incoming we will use this field for pat.GradeLevel if it's an integer from 1-15
						seg.AddField(2,"0004",DataTypeHL7.IS,"","O");
						//PV1.3, Assigned Patient Location, PL - Person Location Data Type: Point of Care^Room^^Facility^^Person Location Type
						//Facility is a HD data type, so Namespace&ID&IDType.  We will just use &PracticeTitle with no namespace or IDType.
						//Example: ClinicDescript^OpName^^&PracticeTitle^^C  (C for clinic)
						seg.AddField(3,"apt.location");
						//PV1.7, Attending/Primary Care Doctor, ProviderId^LastName^FirstName^MI
						seg.AddField(7,"0010",DataTypeHL7.XCN,"prov.provIdNameLFM","");
						//PV1.11, Temporary Location, PL - Person Location data type: PointOfCare^^^^^Person Location Type
						//Filled with the "Site (or Grade School)" value in the database, using 'S' to designate the location type site and the site.Description value
						//If no site assigned in OD, this will be blank as it is optional
						//Example: |West Salem Elementary^^^^^S| ('S' for site)
						seg.AddField(11,"pat.site");
						//PV1.18, Patient Type, IS data type (coded value for user-defined tables)
						//We will send one of the following values retrieved from the patient.Urgency field for treatment urgency: 0 - Unknown, 1 - NoProblems, 2 - NeedsCare, 3 - Urgent
						seg.AddField(18,"pat.Urgency");
						//PV1.19, Visit Number, CX data type, AptNum^CheckDigit^CheckDigitScheme^&AssignAuthorityID&IDType^VN  (VN - Visit Number)
						//We will use AptNum, with check digit scheme M11, with the OIDRoot for an appt object (set in oidinternal), ID Type 'HL7', and 'VN' for Visit Number
						//Example: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.6&HL7^VN|
						seg.AddField(19,"apt.AptNum");
						//PV1.44, Admit Date/Time
						seg.AddField(44,"apt.AptDateTime");
					#endregion PV1 - Patient Visit
					#region RGS - Resource Group
					seg=new HL7DefSegment();
					msg.AddSegment(seg,5,SegmentNameHL7.RGS);
						//Fields-------------------------------------------------------------------------------------------------------------
						//RGS.1, Set ID, SI data type
						//Always 1, only one resourece group in our outbound SRR's
						seg.AddFieldFixed(1,DataTypeHL7.SI,"1");
						//RGS.2, Segment Action Code, ID data type
						//A-Add/Insert, D-Delete, U-Update, X-No Change
						seg.AddField(2,"segmentAction");
					#endregion RGB - Resource Group
					#region AIL - Appointment Information - Location Resource
					//We will use the AIL segment to identify the clinic and operatory for the appointment
					seg=new HL7DefSegment();
					msg.AddSegment(seg,6,false,true,SegmentNameHL7.AIL);
						//Fields-------------------------------------------------------------------------------------------------------------
						//AIL.1, Set ID, SI data type
						//Always 1, only one location identified by our SRR messsage
						seg.AddFieldFixed(1,DataTypeHL7.SI,"1");
						//AIL.2, Segment Action Code, ID data type
						//A-Add/Insert, D-Delete, U-Update, X-No Change
						seg.AddField(2,"segmentAction");
						//AIL.3, Location Resource ID, PL - Person Location Data Type: Point of Care^Room^^Facility^^Person Location Type
						//Facility is a HD data type, so Namespace&ID&IDType.  We will just use &PracticeTitle with no namespace or IDType.
						//Example: ClinicDescript^OpName^^&PracticeTitle^^C  (C for clinic)
						seg.AddField(3,"apt.location");
						//AIL.12, Filler Status Code, CWE data type
						//We will use this to send the confirmation status of the appointment
						//We will use the second component (text) and send the ItemName (confirm Name) from the definition table that is set for this appointment
						//Example: |^Appointment Confirmed|
						seg.AddField(12,"apt.confirmStatus");
					#endregion AIL - Appointment Information - Location Resource
					#region AIP - Appointment Information - Personnel Resource
					//We will use the AIP segment to identify the dentist and hygienist on the appointment
					//If there is both a dentist and a hygienist assigned to an appointment, we will send two repetitions of the AIP segment
					seg=new HL7DefSegment();
					msg.AddSegment(seg,7,true,true,SegmentNameHL7.AIP);
						//Fields-------------------------------------------------------------------------------------------------------------
						//AIP.1, Set ID, SI data type
						//This segment can repeat for an appt, sequence 1 will be the dentist, 2 will be the hygienist on the appt
						seg.AddField(1,"sequenceNum");
						//AIP.2, Segment Action Code, ID data type
						//A-Add/Insert, D-Delete, U-Update, X-No Change
						seg.AddField(2,"segmentAction");
						//AIP.3, Personnel Resource ID, XCN data type
						//ProviderId^LastName^FirstName^MI^Suffix^Prefix
						//According to the HL7 standards, we are free to use the components as needed to identify the provider
						//We will use 'ProviderID' to send the OD ProvNum, LName, FName and the 'Prefix' component as the Abbr
						//We will retrieve the provider from the appointment and use AIP.4 to differentiate between the dentist and hygienist
						//Example: |1234^Abbott^Sarah^L^DMD^DrAbbott|
						seg.AddField(3,"prov.provIdNameLFM");
						//AIP.4, Resource Type, CWE data type
						//We will send 'd' for dentist (apt.ProvNum) and 'h' for hygienist (apt.ProvHyg)
						seg.AddField(4,"prov.provType");
						//AIP.12, Filler Status Code, CWE data type
						//We will use this to send the confirmation status of the appointment
						//We will use the second component (text) and send the ItemName (confirm Name) from the definition table that is set for this appointment
						//Example: |^Appointment Confirmed|
						seg.AddField(12,"apt.confirmStatus");
					#endregion AIP - Appointment Information - Personnel Resource
				#endregion SRR - Schedule Request Response
			#endregion Outbound Messages
			return def;
		}
Esempio n. 38
0
		///<summary>This is used to set the provider (either dentist or hygienist depending on provType) and the confirmation status of the appointment.  If the apt is null, does nothing.  If this is an AIG, the provider field will be in the format ProvNum^LName, FName^^Abbr.  AIP and PV1 have the provider field in the format ProvNum^LName^FName^^^Abbr.  segDef.SegmentName will be used to determine how to parse the field.</summary>
		public static void ProcessAIGorAIP(Patient pat,Appointment apt,HL7DefSegment segDef,SegmentHL7 seg) {
			if(apt==null) {//We have to have an appt to process the AIG or AIP segment
				return;
			}
			Appointment aptOld=apt.Clone();
			long provNum=0;
			string strProvType="";
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				if(itemOrder<1) {
					continue;
				}
				switch(segDef.hl7DefFields[i].FieldName) {
					case "prov.provIdNameLFM":
					case "prov.provIdName":
						if(_isEcwHL7Def) {
							//for eCW interfaces, we allow inserting a new provider from the AIG or AIP segment and store the provider ID they supply in the prov.EcwId column
							provNum=FieldParser.ProvProcessEcw(seg.GetField(itemOrder));
						}
						else {
							//for all other interfaces, we will only accept provider ID's that match the OD ProvNum
							//if not found by ProvNum, we will attempt to match LName, FName, and Abbr
							//if still not found, we will not set the provider on the appt
							provNum=FieldParser.ProvParse(seg.GetField(itemOrder),segDef.SegmentName,_isVerboseLogging);
						}
						//provNum may still be 0
						continue;
					case "prov.provType":
						strProvType=seg.GetFieldComponent(itemOrder);
						//provType could still be an empty string, which is treated the same as 'd' or 'D' for dentist
						continue;
					case "apt.confirmStatus":
						long aptConfirmDefNum=0;
						Def[] listConfirmStats=DefC.GetList(DefCat.ApptConfirmed);
						for(int j=0;j<listConfirmStats.Length;j++) {
							if(seg.GetFieldComponent(itemOrder,1).ToLower()==listConfirmStats[j].ItemName.ToLower()//ItemName is the confirmation name
								|| (listConfirmStats[j].ItemValue!="" && seg.GetFieldComponent(itemOrder,1).ToLower()==listConfirmStats[j].ItemValue.ToLower()))//ItemValue is the confirmation abbreviation, which may be blank
							{
								aptConfirmDefNum=listConfirmStats[j].DefNum;
								break;
							}
						}
						if(aptConfirmDefNum>0) {
							apt.Confirmed=aptConfirmDefNum;
						}
						continue;
					default:
						continue;
				}
			}
			if(provNum>0) {
				if(strProvType.ToLower()=="h") {//only set ProvHyg if they specifically send 'h' or 'H' as the provType
					apt.ProvHyg=provNum;
				}
				else {//if 'd' or 'D' or not specified or invalid provType, default to setting the ProvNum
					apt.ProvNum=provNum;
				}
				if(_isEcwHL7Def) {
					pat.PriProv=provNum;
				}
			}
			Appointments.Update(apt,aptOld);
			_aptProcessed=apt;
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Updated appointment for patient "+pat.GetNameFLnoPref()+" due to an incoming AIG or AIP segment.",EventLogEntryType.Information);
			}
			return;
		}
Esempio n. 39
0
        public static HL7Def GetDeepInternal(HL7Def def)
        {
            //ok to pass in null
            //HL7Def def=HL7Defs.GetInternalFromDb("eCWStandalone");
            if (def == null)           //wasn't in the database
            {
                def                       = new HL7Def();
                def.IsNew                 = true;
                def.Description           = "eCW Standalone";
                def.ModeTx                = ModeTxHL7.File;
                def.IncomingFolder        = "";
                def.OutgoingFolder        = "";
                def.IncomingPort          = "";
                def.OutgoingIpPort        = "";
                def.FieldSeparator        = "|";
                def.ComponentSeparator    = "^";
                def.SubcomponentSeparator = "&";
                def.RepetitionSeparator   = "~";
                def.EscapeCharacter       = @"\";
                def.IsInternal            = true;
                def.InternalType          = "eCWStandalone";
                def.InternalTypeVersion   = Assembly.GetAssembly(typeof(Db)).GetName().Version.ToString();
                def.IsEnabled             = false;
                def.Note                  = "";
                def.ShowDemographics      = HL7ShowDemographics.ChangeAndAdd;
                def.ShowAccount           = true;
                def.ShowAppts             = true;
            }
            def.hl7DefMessages = new List <HL7DefMessage>();         //so that if this is called repeatedly, it won't pile on duplicate messages.
            //in either case, now get all child objects, which can't be in the database.
            //----------------------------------------------------------------------------------------------------------------------------------
            //eCW incoming patient information (ADT).
            HL7DefMessage msg = new HL7DefMessage();

            def.AddMessage(msg, MessageTypeHL7.ADT, EventTypeHL7.A04, InOutHL7.Incoming, 0);
            //MSH segment------------------------------------------------------------------
            HL7DefSegment seg = new HL7DefSegment();

            msg.AddSegment(seg, 0, SegmentNameHL7.MSH);
            //MSH.8, Message Type
            seg.AddField(8, "messageType");
            //MSH.9, Message Control ID
            seg.AddField(9, "messageControlId");
            //PID segment------------------------------------------------------------------
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 2, SegmentNameHL7.PID);
            //PID.2, Patient ID
            seg.AddField(2, "pat.ChartNumber");
            //PID.4, Alternate Patient ID, PID.4 is not saved with using standalone integration
            //PID.5, Patient Name
            seg.AddField(5, "pat.nameLFM");
            //PID.7, Date/Time of Birth
            seg.AddField(7, "pat.birthdateTime");
            //PID.8, Administrative Sex
            seg.AddField(8, "pat.Gender");
            //PID.10, Race
            seg.AddField(10, "pat.Race");
            //PID.11, Patient Address
            seg.AddField(11, "pat.addressCityStateZip");
            //PID.13, Phone Number - Home
            seg.AddField(13, "pat.HmPhone");
            //PID.14, Phone Number - Business
            seg.AddField(14, "pat.WkPhone");
            //PID.16, Marital Status
            seg.AddField(16, "pat.Position");
            //PID.19, SSN - Patient
            seg.AddField(19, "pat.SSN");
            //PID.22, Fee Schedule
            seg.AddField(22, "pat.FeeSched");
            //GT1 segment------------------------------------------------------------------
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 5, SegmentNameHL7.GT1);
            //GT1.2, Guarantor Number
            seg.AddField(2, "guar.ChartNumber");
            //GT1.3, Guarantor Name
            seg.AddField(3, "guar.nameLFM");
            //GT1.5, Guarantor Address
            seg.AddField(5, "guar.addressCityStateZip");
            //GT1.6, Guarantor Phone Number - Home
            seg.AddField(6, "guar.HmPhone");
            //GT1.7, Guarantor Phone Number - Business
            seg.AddField(7, "guar.WkPhone");
            //GT1.8, Guarantor Date/Time of Birth
            seg.AddField(8, "guar.birthdateTime");
            //GT1.9, Guarantor Administrative Sex
            seg.AddField(9, "guar.Gender");
            //GT1.12, Guarantor SSN
            seg.AddField(12, "guar.SSN");
            return(def);
        }
Esempio n. 40
0
		public static void ProcessAL1(Patient pat,HL7DefSegment segDef,SegmentHL7 seg) {
			//If there is an allergydef with SnomedType 2 or 3 (DrugAllergy or DrugIntolerance) with attached medication with RxCui=rxnorm supplied
			//And if there is not already an active allergy with that AllergyDefNum for the patient
			//Then insert an allergy with that AllergyDefNum for this patient
			long rxnorm=0;
			string strAllergenType="";
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int intItemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "allergenType":
						strAllergenType=seg.GetFieldComponent(intItemOrder).ToLower();
						continue;
					case "allergenRxNorm":
						if(seg.GetFieldComponent(intItemOrder,2).ToLower()!="rxnorm") {
							//if not an RXNORM code, do nothing.  Only RXNORM codes are currently supported
							EventLog.WriteEntry("OpenDentHL7","A drug allergy was not added for patient "+pat.GetNameFLnoPref()
								+".  Only RxNorm codes are currently allowed in the AL1 segment.  The code system name provided was "
								+seg.GetFieldComponent(intItemOrder,2)+".",EventLogEntryType.Information);
							return;
						}
						try {
							rxnorm=PIn.Long(seg.GetFieldComponent(intItemOrder,0));
						}
						catch(Exception ex) {//PIn.Long throws an exception if converting to an Int64 fails
							//do nothing, rxnorm will remain 0
						}
						continue;
					default:
						continue;
				}
			}
			if(rxnorm==0 || strAllergenType!="da") {
				EventLog.WriteEntry("OpenDentHL7","A drug allergy was not added for patient "+pat.GetNameFLnoPref()
					+".  Only drug allergies, identified by type 'DA', are currently allowed in the AL1 segment.  The allergen type received was '"
					+strAllergenType+"'.",EventLogEntryType.Information);
				return;//not able to assign drug allergy if not given a valid rxnorm or allergen type is not a drug allergy
			}
			AllergyDef allergyDefCur=AllergyDefs.GetAllergyDefFromRxnorm(rxnorm);
			if(allergyDefCur==null) {
				EventLog.WriteEntry("OpenDentHL7","A drug allergy was not added for patient "+pat.GetNameFLnoPref()+
					".  There is not a drug allergy in the database with an RxNorm code of "+rxnorm.ToString()+".",EventLogEntryType.Information);
				return;//no allergydef for this rxnorm exists
			}
			//see if there is already an active allergy with this AllergyDefNum for this patient
			List<Allergy> listAllergForPat=Allergies.GetAll(pat.PatNum,false);
			for(int i=0;i<listAllergForPat.Count;i++) {
				if(listAllergForPat[i].AllergyDefNum==allergyDefCur.AllergyDefNum) {
					return;//already an active allergy with this AllergyDefNum
				}
			}
			Allergy allergyCur=new Allergy();
			allergyCur.AllergyDefNum=allergyDefCur.AllergyDefNum;
			allergyCur.PatNum=pat.PatNum;
			allergyCur.StatusIsActive=true;
			Allergies.Insert(allergyCur);
			if(_isVerboseLogging) {
				EventLog.WriteEntry("OpenDentHL7","Inserted a new allergy for patient "+pat.GetNameFLnoPref()+" due to an incoming AL1 segment.",EventLogEntryType.Information);
			}
			return;
		}
Esempio n. 41
0
		public static HL7Def GetDeepInternal(HL7Def def) {
			//ok to pass in null
			if(def==null) {//wasn't in the database
				def=new HL7Def();
				def.IsNew=true;
				def.Description="MedLab HL7 v2.3";
				def.ModeTx=ModeTxHL7.Sftp;
				def.IncomingFolder="";
				def.OutgoingFolder="";
				def.IncomingPort="";
				def.OutgoingIpPort="";
				def.SftpInSocket="";
				def.SftpUsername="";
				def.SftpPassword="";
				def.FieldSeparator="|";
				def.ComponentSeparator="^";
				def.SubcomponentSeparator="&";
				def.RepetitionSeparator="~";
				def.EscapeCharacter=@"\";
				def.IsInternal=true;
				def.InternalType=HL7InternalType.MedLabv2_3;
				def.InternalTypeVersion=Assembly.GetAssembly(typeof(Db)).GetName().Version.ToString();
				def.IsEnabled=false;
				def.Note="";
				def.ShowDemographics=HL7ShowDemographics.ChangeAndAdd;//these last four properties will not be editable for a lab interface type
				def.ShowAccount=true;
				def.ShowAppts=true;
				def.IsQuadAsToothNum=false;
			}
			def.hl7DefMessages=new List<HL7DefMessage>();
			HL7DefMessage msg=new HL7DefMessage();
			HL7DefSegment seg=new HL7DefSegment();
			#region Inbound Messages
				#region ORU - Unsolicited Observation Message
				def.AddMessage(msg,MessageTypeHL7.ORU,MessageStructureHL7.ORU_R01,InOutHL7.Incoming,0);
					#region MSH - Message Header
					msg.AddSegment(seg,0,SegmentNameHL7.MSH);
						//Fields-------------------------------------------------------------------------------------------------------------
						//MSH.2, Sending Application.  To identify the LabCorp Lab System sending the results.
						//Possible values for LabCorp (as of their v10.7 specs): '1100' - LabCorp Lab System, 'DIANON' - DIANON Systems,
						//'ADL' - Acupath Diagnostic Laboratories, 'EGL' - Esoterix Genetic Laboratories.
						//For backward compatibility only: 'CMBP', 'LITHOLINK', 'USLABS'
						seg.AddField(2,"sendingApp");
						//MSH.3, Sending Facility.  Identifies the LabCorp laboratory responsible for the client.
						//It could be a LabCorp assigned 'Responsible Lab Code' representing the responsible laboratory or it could be a CLIA number.
						seg.AddField(3,"sendingFacility");
						//MSH.8, Message Type
						seg.AddField(8,"messageType");
						//MSH.9, Message Control ID
						seg.AddField(9,"messageControlId");
					#endregion MSH - Message Header
					#region PID - Patient Identification
					seg=new HL7DefSegment();
					msg.AddSegment(seg,1,SegmentNameHL7.PID);
						//Fields-------------------------------------------------------------------------------------------------------------
						//PID.2, External Patient ID.  LabCorp defines this as 'client' assigned patient id, just like they do PID.4.
						//This should be the Open Dental patient number, sent in outbound PID.4 and returned in PID.2.
						seg.AddField(2,"pat.PatNum");
						//PID.3, Lab Assigned Patient ID.  LabCorp assigned specimen number.
						seg.AddField(3,"labPatID");
						//PID.4, Alternate Patient ID.  LabCorp defines this as a 'client' assigned patient id, just like they do PID.2.
						//This will be in outbound PID.2, returned in PID.4.
						seg.AddField(4,"altPatID");
						//PID.5, Patient Name
						//This will contain the last, first, and middle names as well as the title
						//Example:  LName^FName^MiddleI
						seg.AddField(5,"pat.nameLFM");
						//PID.7, Date/Time of Birth with Age
						//LabCorp uses this for the birthdate as well as the age in years, months, and days of the patient in the format bday^years^months^days.
						//All age components are left padded with 0's, the years is padded to 3 chars, the months and days are padded to 2 chars
						//Example: 19811213^033^02^19
						seg.AddField(7,"patBirthdateAge");
						//PID.8, Patient Gender
						//We use this field to assist the user in selecting a patient if one is not found when importing the message, but we don't store it
						seg.AddField(8,"pat.Gender");
						//PID.18.1, Patient Account Number.  LabCorp assigned account number.  This field is also used to send the Fasting flag in component 7.
						//Fasting flag values are 'Y', 'N', or blank
						//Example: AccountNum^^^BillCode^ABNFlag^SpecimenStatus^FastingFlag
						seg.AddField(18,"accountNum");
						//PID.19, Patient SSN Number
						//We use this field to assist the user in selecting a patient if one is not found when importing the message, but we don't store it
						seg.AddField(19,"pat.SSN");
					#endregion PID - Patient Identification
					#region NK1 - Next of Kin
					//This segment is for future use only, nothing is currently imported from this segment
					seg=new HL7DefSegment();
					msg.AddSegment(seg,2,false,true,SegmentNameHL7.NK1);
						//Fields-------------------------------------------------------------------------------------------------------------
						//NK1.2, Next of Kin Name
						//Example: LName^FName^Middle
						//seg.AddField(2,"nextOfKinName");
						//NK1.4, Next of Kin Address
						//Example: Address^Address2^City^State^Zip
						//seg.AddField(4,"nextOfKinAddress");
						//NK1.5, Next of Kin Phone
						//seg.AddField(5,"nextOfKinPhone");
						seg.hl7DefFields=new List<HL7DefField>();
					#endregion NK1 - Next of Kin
					#region NTE - Notes and Comments
					seg=new HL7DefSegment();
					msg.AddSegment(seg,3,true,true,SegmentNameHL7.NTE);
						//Fields-------------------------------------------------------------------------------------------------------------
						//NTE.2, Comment Source, ID data type
						//LabCorp supported values: 'L' - Laboratory is the source of comment, 'AC' - Accession Comment,
						//'RC' - Result comment, 'RI' - Normal Comment, 'UK' - Undefined comment type
						//We might pull out the source and prepend it to the note, but we won't explicitly add it to the definition or store it separately
						//NTE.3, Comment Text, FT data type (formatted text)
						//Stored in the medlab.NotePat field
						seg.AddField(3,"patNote");
					#endregion NTE - Notes and Comments
					#region ORC - Common Order
					seg=new HL7DefSegment();
					msg.AddSegment(seg,4,true,false,SegmentNameHL7.ORC);
						//Fields-------------------------------------------------------------------------------------------------------------
						//ORC.2, Unique Foreign Accession or Specimen ID
						//Must match the value in OBR.2 and is the ID value sent on the specimen container and is unique per patient order, not test order.
						//ORC.2.2 is the constant value 'LAB'
						//Example: L2435^LAB
						seg.AddField(2,"specimenID");
						//ORC.3, Filler Accession ID.  The LabCorp assigned specimen number.  These are reused on a yearly basis, but used with the client
						//specific specimen ID in ORC.2, these two numbers should uniquely identify a specimen/order.  ORC.3.2 is the constant value 'LAB'.
						//This should match OBR.3.
						//Example: 08599499950^LAB
						seg.AddField(3,"specimenIDFiller");
						//ORC.12, Ordering Provider, XCN Data Type
						//ProvID^ProvLName^ProvFName^ProvMiddleI^^^^SourceTable
						//This field repeats for every ID available for the provider with the SourceTable component identifying the type of ID in each repetition.
						//SourceTable possible values: 'U' - UPIN, 'P' - Provider Number (Medicaid or Commercial Insurance Provider ID),
						//'N' - NPI Number (Required for Third Party Billing), 'L' - Local (Physician ID)
						//Example: A12345^LNAME^FNAME^M^^^^U~23462^LNAME^FNAME^M^^^^L~0123456789^LNAME^FNAME^M^^^^N~1234567890^LNAME^FNAME^M^^^^P
						seg.AddField(12,"orderingProv");
					#endregion ORC - Common Order
					#region OBR - Observation Request
					seg=new HL7DefSegment();
					msg.AddSegment(seg,5,true,false,SegmentNameHL7.OBR);
						//Fields-------------------------------------------------------------------------------------------------------------
						//OBR.2, Unique Foreign Accession or Specimen ID
						//Must match the value in ORC.2 and is the ID value sent on the specimen container and is unique per patient order, not test order.
						//OBR.2.2 is the constant value 'LAB'.
						//Example: L2435^LAB
						seg.AddField(2,"specimenID");
						//OBR.3, Internal Accession ID.  The LabCorp assigned specimen number.  These are reused on a yearly basis, but used with the client
						//specific specimen ID in OBR.2, these two numbers should uniquely identify a specimen/order.  OBR.3.2 is the constant value 'LAB'.
						//This should match ORC.3.
						//Example: 08599499950^LAB
						seg.AddField(3,"specimenIDFiller");
						//OBR.4, Universal Service Identifier, CWE data type
						//This identifies the observation.  This will be the ID and text description of the test, as well as the LOINC code and description.
						//Example: 006072^RPR^L^20507-0^Reagin Ab^LN
						seg.AddField(4,"obsTestID");
						//OBR.7, Observation/Specimen Collection Date/Time
						//Format for LabCorp: yyyyMMddHHmm
						seg.AddField(7,"dateTimeCollected");
						//OBR.9, Collection/Urine Volume
						seg.AddField(9,"totalVolume");
						//OBR.11, Action Code
						//Used to identify the type of result being returned.  'A' - Add on, 'G' - Reflex, Blank for standard results
						seg.AddField(11,"specimenAction");
						//OBR.13, Relevant Clinical Information.  Used for informational purposes.
						seg.AddField(13,"clinicalInfo");
						//OBR.14, Date/Time of Specimen Receipt in Lab.
						//LabCorp format: yyyMMddHHmm
						seg.AddField(14,"dateTimeEntered");
						//OBR.16, Ordering Provider.
						//ProvID^ProvLName^ProvFName^ProvMiddleI^^^^SourceTable
						//This field repeats for every ID available for the provider with the SourceTable component identifying the type of ID in each repetition.
						//SourceTable possible values: 'U' - UPIN, 'P' - Provider Number (Medicaid or Commercial Insurance Provider ID),
						//'N' - NPI Number (Required for Third Party Billing), 'L' - Local (Physician ID)
						//Example: A12345^LNAME^FNAME^M^^^^U~23462^LNAME^FNAME^M^^^^L~0123456789^LNAME^FNAME^M^^^^N~1234567890^LNAME^FNAME^M^^^^P
						seg.AddField(16,"orderingProv");
						//OBR.18, Alternate Specimen ID.
						seg.AddField(18,"specimenIDAlt");
						//OBR.22, Date/Time Observation Reported.
						//LabCorp format: yyyyMMddHHmm
						seg.AddField(22,"dateTimeReported");
						//OBR.24, Producer's Section ID, used by LabCorp to identify the facility responsible for performing the testing.
						//This will be the footnote ID of the ZPS segment and will be used to attach a MedLab object to a MedLabFacility object.
						seg.AddField(24,"facilityID");
						//OBR.25, Order Result Status.
						//LabCorp values: 'F' - Final, 'P' - Preliminary, 'X' - Cancelled, 'C' - Corrected
						seg.AddField(25,"resultStatus");
						//OBR.26, Link to Parent Result.
						//If this is a reflex result, the value from the OBX.3.1 field of the parent result will be here.
						seg.AddField(26,"parentObsID");
						//OBR.29, Link to Parent Order.
						//If this is a reflex test, the value from the OBR.4.1 field of the parent test will be here.
						seg.AddField(29,"parentObsTestID");
					#endregion OBR - Observation Request
					#region NTE - Notes and Comments
					seg=new HL7DefSegment();
					msg.AddSegment(seg,6,true,true,SegmentNameHL7.NTE);
						//Fields-------------------------------------------------------------------------------------------------------------
						//NTE.2, Comment Source, ID data type
						//LabCorp supported values: 'L' - Laboratory is the source of comment, 'AC' - Accession Comment,
						//'RC' - Result comment, 'RI' - Normal Comment, 'UK' - Undefined comment type
						//We might pull out the source and prepend it to the note, but we won't explicitly add it to the definition or store it separately
						//NTE.3, Comment Text, FT data type (formatted text)
						//Stored in the medlab.NoteLab field
						seg.AddField(3,"labNote");
					#endregion NTE - Notes and Comments
					#region OBX - Observation/Result
					seg=new HL7DefSegment();
					msg.AddSegment(seg,7,true,false,SegmentNameHL7.OBX);
						//Fields-------------------------------------------------------------------------------------------------------------
						//OBX.2, Value Type.  This field is not stored explicitly, but it is used to determine the value type of the observation.
						//If this field is 'TX' for text, the value will be >21 chars and will be sent in the attached NTEs.
						seg.AddField(2,"obsValueType");
						//OBX.3, Observation ID.  This field has the same structure as the OBR.4.
						//ID^Text^CodeSystem^AltID^AltIDText^AltIDCodeSystem, the AltID is the LOINC code so the AltIDCodeSystem will be 'LN'
						//Example: 006072^RPR^L^20507-0^Reagin Ab^LN
						seg.AddField(3,"obsID");
						//OBX.4, Observation Sub ID.  This field is used to aid in the identification of results with the same observation ID (OBX.3) within a
						//given OBR.  If OBX.5.3 is 'ORM' (organism) this field will link a result to an organism, whether this is for organism #1, organism #2,
						//or organism #3.
						seg.AddField(4,"obsIDSub");
						//OBX.5, Observation Value.  ObsValue^TypeOfData^DataSubtype^Encoding^Data.  LabCorp report will display OBX.5.1 as the result.
						//For value >21 chars in length: OBX.2 will be 'TX' for text, OBX.5 will be NULL (empty field), and the value will be in attached NTEs.
						//"TNP" will be reported for Test Not Performed.
						seg.AddField(5,"obsValue");
						//OBX.6, Units.
						//Identifier^Text^CodeSystem.  Id is units of measure abbreviation, text is full text version of units, coding system is 'L' (local id).
						seg.AddField(6,"obsUnits");
						//OBX.7, Reference Range.
						seg.AddField(7,"obsRefRange");
						//OBX.8, Abnormal Flags.  For values see enum OpenDentBusiness.AbnormalFlag
						seg.AddField(8,"obsAbnormalFlag");
						//OBX.11, Observation Result Status.
						//LabCorp values: 'F' - Final, 'P' - Preliminary, 'X' - Cancelled, 'C' - Corrected, 'I' - Incomplete
						seg.AddField(11,"resultStatus");
						//OBX.14, Date/Time of Observation.
						//LabCorp format yyyyMMddHHmm
						seg.AddField(14,"dateTimeObs");
						//OBX.15, Producer's ID.
						//For LabCorp this is used to report the facility responsible for performing the testing.  This will hold the lab ID that will reference
						//a ZPS segment with the lab name, address, and director details.  Used to link a MedLabResult object to a MedLabFacility object.
						seg.AddField(15,"facilityID");
					#endregion OBX - Observation/Result
					#region ZEF - Encapsulated Data Format
					seg=new HL7DefSegment();
					msg.AddSegment(seg,8,true,true,SegmentNameHL7.ZEF);
						//Fields-------------------------------------------------------------------------------------------------------------
						//ZEF.1, Sequence Number, 1 through 9999
						seg.AddField(1,"sequenceNum");
						//ZEF.2, Embedded File.
						//Base64 embedded file, sent in 50k blocks and will be concatenated together to and converted back into
						seg.AddField(2,"base64File");
					#endregion ZEF - Encapsulated Data Format
					#region NTE - Notes and Comments
					seg=new HL7DefSegment();
					msg.AddSegment(seg,9,true,true,SegmentNameHL7.NTE);
						//Fields-------------------------------------------------------------------------------------------------------------
						//NTE.2, Comment Source, ID data type
						//LabCorp supported values: 'L' - Laboratory is the source of comment, 'AC' - Accession Comment,
						//'RC' - Result comment, 'RI' - Normal Comment, 'UK' - Undefined comment type
						//We might pull out the source and prepend it to the note, but we won't explicitly add it to the definition or store it separately
						//NTE.3, Comment Text, FT data type (formatted text)
						//Stored in the medlabresult.Note field
						seg.AddField(3,"obsNote");
					#endregion NTE - Notes and Comments
					#region SPM - Specimen
					seg=new HL7DefSegment();
					msg.AddSegment(seg,10,true,true,SegmentNameHL7.SPM);
						//Fields-------------------------------------------------------------------------------------------------------------
						//SPM.2, Specimen ID.
						//Unique ID of the specimen as sent on the specimen container.  Same as the value in ORC.2.
						seg.AddField(2,"specimenID");
						//SPM.4, Specimen Type
						//SPM.8, Specimen Source Site
						//SPM.4, Specimen Source Site Modifier
						//SPM.14, Specimen Description.  Text field used to send additional information about the specimen
						seg.AddField(14,"specimenDescript");
						//SPM.17, Date/Time Specimen Collected
						seg.AddField(17,"dateTimeSpecimen");
					#endregion SPM - Specimen
					#region ZPS - Place of Service
					seg=new HL7DefSegment();
					msg.AddSegment(seg,11,true,false,SegmentNameHL7.ZPS);
						//Fields-------------------------------------------------------------------------------------------------------------
						//ZPS.2, Facility Mnemonic.  Footnote ID for the lab facility used to reference this segment from OBX.15.
						seg.AddField(2,"facilityID");
						//ZPS.3, Facility Name.
						seg.AddField(3,"facilityName");
						//ZPS.4, Facility Address.
						//Address^^City^State^Zip
						seg.AddField(4,"facilityAddress");
						//ZPS.5, Facility Phone.  (LabCorp document says numberic characters only, so we can assume no dashes or parentheses.)
						seg.AddField(5,"facilityPhone");
						//ZPS.7, Facility Director.
						//Title^LName^FName^MiddleI
						seg.AddField(7,"facilityDirector");
					#endregion ZPS - Place of Service
				#endregion ORU - Unsolicited Observation Message
			#endregion Inbound Messages
			#region Outbound Messages
				//Results only interface for now, so no outbound messages yet
				//In the future, we will implement the orders portion of the interface and have outbound ORM messages
			#endregion Outbound Messages
			return def;
		}
Esempio n. 42
0
		///<summary>If relationship is self, this method does nothing.  A new pat will later change guarantor to be same as patnum. </summary>
		public static void ProcessGT1(Patient pat,HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			char escapeChar='\\';
			if(msg.Delimiters.Length>2) {//it is possible they did not send all 4 of the delimiter chars, in which case we will use the default \
				escapeChar=msg.Delimiters[2];
			}
			char subcompChar='&';
			if(msg.Delimiters.Length>3) {
				subcompChar=msg.Delimiters[3];
			}
			#region Get And Validate Definition Field Ordinals
			//Find the position of the guarNum, guarChartNum, guarName, and guarBirthdate in this HL7 segment based on the definition of a GT1
			int guarPatNumOrdinal=-1;
			int guarChartNumOrdinal=-1;
			int guarNameOrdinal=-1;
			int guarBirthdateOrdinal=-1;
			int guarIdsOrdinal=-1;
			string patOidRoot="";
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				switch(segDef.hl7DefFields[i].FieldName) {
					case "guar.PatNum":
						guarPatNumOrdinal=segDef.hl7DefFields[i].OrdinalPos;
						continue;
					case "guar.ChartNumber":
						guarChartNumOrdinal=segDef.hl7DefFields[i].OrdinalPos;
						continue;
					case "guar.nameLFM":
						guarNameOrdinal=segDef.hl7DefFields[i].OrdinalPos;
						continue;
					case "guar.birthdateTime":
						guarBirthdateOrdinal=segDef.hl7DefFields[i].OrdinalPos;
						continue;
					case "guarIdList":
						//get the id with the assigning authority equal to the internal OID root stored in their database for a patient object
						patOidRoot=OIDInternals.GetForType(IdentifierType.Patient).IDRoot;
						if(patOidRoot=="") {
							//if they have not set their internal OID root, we cannot identify which repetition in this field contains the OD PatNum, guarIdListOrdinal will remain -1
							continue;
						}
						guarIdsOrdinal=segDef.hl7DefFields[i].OrdinalPos;
						continue;
					default://not supported
						continue;
				}
			}
			//If neither guar.PatNum nor guar.ChartNumber are included in this GT1 definition log a message in the event log and return
			if(guarPatNumOrdinal==-1 && guarChartNumOrdinal==-1 && guarIdsOrdinal==-1) {
				_hl7MsgCur.Note="Guarantor not processed.  guar.PatNum, guar.ChartNumber, or guarIdList must be included in the GT1 definition.  PatNum of patient: "+pat.PatNum.ToString();
				HL7Msgs.Update(_hl7MsgCur);
				EventLog.WriteEntry("OpenDentHL7","Guarantor not processed.  guar.PatNum, guar.ChartNumber, or guarIdList must be included in the GT1 definition.  "
					+"PatNum of patient: "+pat.PatNum.ToString(),EventLogEntryType.Information);
				return;
			}
			//If guar.nameLFM is not included in this GT1 definition log a message in the event log and return
			if(guarNameOrdinal==-1) {
				_hl7MsgCur.Note="Guarantor not processed due to guar.nameLFM not included in the GT1 definition.  Patnum of patient: "+pat.PatNum.ToString();
				HL7Msgs.Update(_hl7MsgCur);
				EventLog.WriteEntry("OpenDentHL7","Guarantor not processed due to guar.nameLFM not included in the GT1 definition.  Patnum of patient: "
					+pat.PatNum.ToString(),EventLogEntryType.Information);
				return;
			}
			//If the first or last name are not included in this GT1 segment, log a message in the event log and return
			if(seg.GetFieldComponent(guarNameOrdinal,0)=="" || seg.GetFieldComponent(guarNameOrdinal,1)=="") {
				_hl7MsgCur.Note="Guarantor not processed due to missing first or last name.  PatNum of patient: "+pat.PatNum.ToString();
				HL7Msgs.Update(_hl7MsgCur);
				EventLog.WriteEntry("OpenDentHL7","Guarantor not processed due to missing first or last name.  PatNum of patient: "
					+pat.PatNum.ToString(),EventLogEntryType.Information);
				return;
			}
			#endregion Get And Validate Definition Field Ordinals
			#region Get guar.PatNum, guar.ChartNumber, and guarIdList IDs
			//Only process GT1 if guar.PatNum, guar.ChartNumber, or guarIdList is included and both guar.LName and guar.FName are included
			long guarPatNum=0;
			string guarChartNum="";
			long guarPatNumFromIds=0;
			List<OIDExternal> listOids=new List<OIDExternal>();
			if(guarPatNumOrdinal!=-1) {
				try {
					guarPatNum=PIn.Long(seg.GetFieldFullText(guarPatNumOrdinal));
				}
				catch(Exception ex) {
					//do nothing, guarPatNum will remain 0
				}
			}
			if(guarChartNumOrdinal!=-1) {
				guarChartNum=seg.GetFieldComponent(guarChartNumOrdinal);
			}
			if(guarIdsOrdinal!=-1) {//if OIDInternal root for a patient object is not defined, guarIdListOrdinal will be -1
				FieldHL7 fieldGuarIds=seg.GetField(guarIdsOrdinal);
				//Example field: |1234^3^M11^&2.16.840.1.113883.3.4337.1486.6566.2&HL7^PI~7684^8^M11^&Other.Software.OID&OIDType^PI|
				//field component values will be the first repetition, repeats will be in field.ListRepeatFields
				string[] arrayGuarIdSubComps=fieldGuarIds.GetComponentVal(3).Split(new char[] { subcompChar },StringSplitOptions.None);
				if(arrayGuarIdSubComps.Length>1 //must be at least two subcomponents in the assigning authority component so we can identify whose ID this is
					&& fieldGuarIds.GetComponentVal(4).ToLower()=="pi") //PI=patient internal identifier; a number that is unique to a patient within an assigning authority
				{
					int intCheckDigit=-1;
					try {
						intCheckDigit=PIn.Int(fieldGuarIds.GetComponentVal(1));
					}
					catch(Exception ex) {
						//checkDigit will remain -1
					}
					//if using the M10 or M11 check digit algorithm and it passes the respective test, or not using either algorithm
					//and only if there's at least 2 components in field 3 for the assigning authority so we can identify whose ID we are dealing with, then use the ID
					if((fieldGuarIds.GetComponentVal(2).ToLower()=="m10"
							&& intCheckDigit!=-1
							&& M10CheckDigit(fieldGuarIds.GetComponentVal(0))==intCheckDigit)//using M10 scheme and the check digit is valid and matches calc
						|| (fieldGuarIds.GetComponentVal(2).ToLower()=="m11"
							&& intCheckDigit!=-1
							&& M11CheckDigit(fieldGuarIds.GetComponentVal(0))==intCheckDigit)//using M11 scheme and the check digit is valid and matches calc
						|| (fieldGuarIds.GetComponentVal(2).ToLower()!="m10"
							&& fieldGuarIds.GetComponentVal(2).ToLower()!="m11"))//not using either check digit scheme
					{
						if(arrayGuarIdSubComps[1].ToLower()==patOidRoot.ToLower()) {
							try {
								guarPatNumFromIds=PIn.Long(fieldGuarIds.GetComponentVal(0));
							}
							catch(Exception ex) {
								//do nothing, guarPatNumFromList will remain 0
							}
						}
						else {
							OIDExternal oidCur=new OIDExternal();
							oidCur.IDType=IdentifierType.Patient;
							oidCur.IDExternal=fieldGuarIds.GetComponentVal(0);
							oidCur.rootExternal=arrayGuarIdSubComps[1];
							listOids.Add(oidCur);
						}
					}
				}
				for(int r=0;r<fieldGuarIds.ListRepeatFields.Count;r++) {
					arrayGuarIdSubComps=fieldGuarIds.ListRepeatFields[r].GetComponentVal(3).Split(new char[] { subcompChar },StringSplitOptions.None);
					if(arrayGuarIdSubComps.Length<2) {//must be at least two sub-components to the assigning authority component so we can identify whose ID this is
						continue;
					}
					if(fieldGuarIds.ListRepeatFields[r].GetComponentVal(4).ToLower()!="pi")
					{
						continue;
					}
					int intCheckDigit=-1;
					try {
						intCheckDigit=PIn.Int(fieldGuarIds.ListRepeatFields[r].GetComponentVal(1));
					}
					catch(Exception ex) {
						//checkDigit will remain -1
					}
					if(fieldGuarIds.ListRepeatFields[r].GetComponentVal(2).ToLower()=="m10"
						&& (intCheckDigit==-1 || M10CheckDigit(fieldGuarIds.ListRepeatFields[r].GetComponentVal(0))!=intCheckDigit))//using M10 scheme and either invalid check digit or doesn't match calc
					{
						continue;
					}
					if(fieldGuarIds.ListRepeatFields[r].GetComponentVal(2).ToLower()=="m11"
						&& (intCheckDigit==-1 || M11CheckDigit(fieldGuarIds.ListRepeatFields[r].GetComponentVal(0))!=intCheckDigit))//using M11 scheme and either invalid check digit or doesn't match calc
					{
						continue;
					}
					//if not using the M10 or M11 check digit scheme or if the check digit is good, trust the ID in component 0 to be valid and attempt to use
					if(arrayGuarIdSubComps[1].ToLower()==patOidRoot.ToLower()) {
						try {
							guarPatNumFromIds=PIn.Long(fieldGuarIds.ListRepeatFields[r].GetComponentVal(0));
						}
						catch(Exception ex) {
							//do nothing, guarPatNumFromList will remain 0
						}
					}
					else {
						OIDExternal oidCur=new OIDExternal();
						oidCur.IDType=IdentifierType.Patient;
						oidCur.IDExternal=fieldGuarIds.ListRepeatFields[r].GetComponentVal(0);
						oidCur.rootExternal=arrayGuarIdSubComps[1];
						listOids.Add(oidCur);
					}
				}
			}
			if(guarPatNum==0 && guarChartNum=="" && guarPatNumFromIds==0 && listOids.Count==0) {//because we have an example where they sent us this (position 2 (guarPatNumOrder or guarChartNumOrder for eCW) is empty): GT1|1||^^||^^^^||||||||
				_hl7MsgCur.Note="Guarantor not processed due to missing guar.PatNum, guar.ChartNumber, and guarIdList.  One of those numbers must be included.  "
					+"PatNum of patient: "+pat.PatNum.ToString();
				HL7Msgs.Update(_hl7MsgCur);
				EventLog.WriteEntry("OpenDentHL7","Guarantor not processed due to missing guar.PatNum, guar.ChartNumber, and guarIdList.  "
					+"One of those numbers must be included.  PatNum of patient: "+pat.PatNum.ToString(),EventLogEntryType.Information);
				return;
			}
			#endregion Get guar.PatNum, guar.ChartNumber, and guarIdList IDs
			if(guarPatNum==pat.PatNum
				|| (guarChartNum!="" && guarChartNum==pat.ChartNumber)
				|| guarPatNumFromIds==pat.PatNum)
			{//if relationship is self
				return;
			}
			#region Get Patient from Ids
			//Guar must be someone else
			Patient guar=null;
			Patient guarOld=null;
			//Find guarantor by guar.PatNum if defined and in this segment
			if(guarPatNum!=0) {
				guar=Patients.GetPat(guarPatNum);
			}
			else if(guarPatNumFromIds!=0) {
				guar=Patients.GetPat(guarPatNumFromIds);
			}
			else if(guarChartNum!="") {//guarPatNum and guarPatNumFromList was 0 so try to get guar by guar.ChartNumber or name and birthdate
				//try to find guarantor using chartNumber
				guar=Patients.GetPatByChartNumber(guarChartNum);
				if(guar==null) {
					//try to find the guarantor by using name and birthdate
					string strGuarLName=seg.GetFieldComponent(guarNameOrdinal,0);
					string strGuarFName=seg.GetFieldComponent(guarNameOrdinal,1);
					DateTime guarBirthdate=FieldParser.DateTimeParse(seg.GetFieldFullText(guarBirthdateOrdinal));
					long guarNamePatNum=Patients.GetPatNumByNameAndBirthday(strGuarLName,strGuarFName,guarBirthdate);
					if(guarNamePatNum==0) {//guarantor does not exist in OD
						//so guar will still be null, triggering creation of new guarantor further down.
					}
					else {
						guar=Patients.GetPat(guarNamePatNum);
						guarOld=guar.Copy();
						guar.ChartNumber=guarChartNum;//from now on, we will be able to find guar by chartNumber
						Patients.Update(guar,guarOld);
					}
				}
			}
			long guarExtPatNum=0;
			if(guar==null) {//As a last resort, use the external IDs for this patient in the oidexternal to find the guar
				//Use the external OIDs stored in the oidexternal table to find the patient
				//Only trust the external IDs if all OIDs refer to the same patient
				for(int i=0;i<listOids.Count;i++) {
					OIDExternal oidExternalCur=OIDExternals.GetByRootAndExtension(listOids[i].rootExternal,listOids[i].IDExternal);
					if(oidExternalCur==null || oidExternalCur.IDInternal==0 || oidExternalCur.IDType!=IdentifierType.Patient) {//must have an IDType of Patient
						continue;
					}
					if(guarExtPatNum==0) {
						guarExtPatNum=oidExternalCur.IDInternal;
					}
					else if(guarExtPatNum!=oidExternalCur.IDInternal) {//the current ID refers to a different patient than a previously found ID, don't trust the external IDs
						guarExtPatNum=0;
						break;
					}
				}
				if(guarExtPatNum>0) {//will be 0 if not in the OIDExternal table or no external IDs supplied or more than one supplied and they point to different pats (ambiguous)
					guar=Patients.GetPat(guarExtPatNum);
				}
			}
			//At this point we have a guarantor located in OD or guar=null so guar is new patient
			bool isNewGuar=(guar==null);
			if(isNewGuar) {//then we need to add guarantor to db
				guar=new Patient();
				if(guarChartNum!="") {
					guar.ChartNumber=guarChartNum;
				}
				if(guarPatNum!=0) {
					guar.PatNum=guarPatNum;
					guar.Guarantor=guarPatNum;
				}
				else if(guarPatNumFromIds!=0) {
					guar.PatNum=guarPatNumFromIds;
					guar.Guarantor=guarPatNumFromIds;
				}
				else if(guarExtPatNum!=0) {
					guar.PatNum=guarExtPatNum;
					guar.Guarantor=guarExtPatNum;
				}
				guar.PriProv=PrefC.GetLong(PrefName.PracticeDefaultProv);
				guar.BillingType=PrefC.GetLong(PrefName.PracticeDefaultBillType);
			}
			else {
				guarOld=guar.Copy();
			}
			#endregion Get Patient from Ids
			#region Update Guarantor Data
			//Now that we have our guarantor, process the GT1 segment
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				int itemOrder=segDef.hl7DefFields[i].OrdinalPos;
				switch(segDef.hl7DefFields[i].FieldName) {
					case "guar.addressCityStateZip":
						guar.Address=seg.GetFieldComponent(itemOrder,0);
						guar.Address2=seg.GetFieldComponent(itemOrder,1);
						guar.City=seg.GetFieldComponent(itemOrder,2);
						guar.State=seg.GetFieldComponent(itemOrder,3);
						guar.Zip=seg.GetFieldComponent(itemOrder,4);
						guar.AddrNote=FieldParser.StringNewLineParse(seg.GetFieldComponent(itemOrder,19),escapeChar);
						continue;
					case "guar.birthdateTime":
						guar.Birthdate=FieldParser.DateTimeParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "guar.ChartNumber":
						guar.ChartNumber=seg.GetFieldComponent(itemOrder);
						continue;
					case "guar.Gender":
						guar.Gender=FieldParser.GenderParse(seg.GetFieldComponent(itemOrder));
						continue;
					case "guar.HmPhone":
						if(seg.GetFieldComponent(itemOrder,2)=="" && seg.GetField(itemOrder).ListRepeatFields.Count==0) {
							//either no component 2 or left blank, and there are no repetitions, process the old way
							//the first repetition is considered the primary number, but if the primary number is not sent then it will be blank followed by the list of other numbers
							guar.HmPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
						}
						else {
							//XTN data type, repeatable.
							//Component 2 values: PH-Phone, FX-Fax, MD-Modem, CP-Cell Phone, Internet-Internet Address, X.400-X.400 email address, TDD-Tel Device for the Deaf, TTY-Teletypewriter.
							//We will support PH for pat.HmPhone, CP for pat.WirelessPhone, and Internet for pat.Email
							//Component 5 is area code, 6 is number
							//Component 3 will be Email if the type is Internet
							//Example: ^PRN^PH^^^503^3635432~^PRN^Internet^[email protected]
							FieldHL7 fieldPh=seg.GetField(itemOrder);
							if(fieldPh==null) {
								continue;
							}
							string strPhType=seg.GetFieldComponent(itemOrder,2);
							string strPh=seg.GetFieldComponent(itemOrder,5)+seg.GetFieldComponent(itemOrder,6);
							string strEmail=seg.GetFieldComponent(itemOrder,3);
							for(int p=-1;p<fieldPh.ListRepeatFields.Count;p++) {
								if(p>=0) {
									strPhType=fieldPh.ListRepeatFields[p].GetComponentVal(2);
									strPh=fieldPh.ListRepeatFields[p].GetComponentVal(5)+fieldPh.ListRepeatFields[p].GetComponentVal(6);
									strEmail=fieldPh.ListRepeatFields[p].GetComponentVal(3);
								}
								switch(strPhType) {
									case "PH":
										guar.HmPhone=FieldParser.PhoneParse(strPh);
										continue;
									case "CP":
										guar.WirelessPhone=FieldParser.PhoneParse(strPh);
										continue;
									case "Internet":
										guar.Email=strEmail;
										continue;
									default:
										continue;
								}
							}
						}
						continue;
					case "guar.nameLFM":
						guar.LName=seg.GetFieldComponent(itemOrder,0);
						guar.FName=seg.GetFieldComponent(itemOrder,1);
						guar.MiddleI=seg.GetFieldComponent(itemOrder,2);
						guar.Title=seg.GetFieldComponent(itemOrder,4);
						continue;
					//case "guar.PatNum": Maybe do nothing??
					case "guar.SSN":
						guar.SSN=seg.GetFieldComponent(itemOrder);
						continue;
					case "guar.WkPhone":
						if(seg.GetFieldComponent(itemOrder,2)=="PH") {
							//Component 2 value: PH-Phone
							//Component 5 is area code, 6 is number
							//Example: ^WPN^PH^^^503^3635432
							guar.WkPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder,5)+seg.GetFieldComponent(itemOrder,6));
							continue;
						}
						//either no component 2 or left blank, process the old way
						guar.WkPhone=FieldParser.PhoneParse(seg.GetFieldComponent(itemOrder));
						continue;
					default:
						continue;
				}
			}
			if(isNewGuar) {
				if(guar.PatNum==0) {
					guarOld=guar.Copy();
					guar.PatNum=Patients.Insert(guar,false);
					guar.Guarantor=guar.PatNum;
					Patients.Update(guar,guarOld);
				}
				else {
					guar.PatNum=Patients.Insert(guar,true);
				}
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Inserted patient "+guar.GetNameFLnoPref()+" when processing a GT1 segment.",EventLogEntryType.Information);
				}
			}
			else {
				Patients.Update(guar,guarOld);
				if(_isVerboseLogging) {
					EventLog.WriteEntry("OpenDentHL7","Updated patient "+guar.GetNameFLnoPref()+" when processing a GT1 segment.",EventLogEntryType.Information);
				}
			}
			#endregion Update Guarantor Data
			pat.Guarantor=guar.PatNum;
			//store external IDs in the oidexternal table if they do not already exist in the table
			string strVerboseMsg="";
			for(int i=0;i<listOids.Count;i++) {
				if(listOids[i].IDExternal==""//not a good external ID OR
					|| listOids[i].rootExternal==""//not a good external root OR
					|| OIDExternals.GetByRootAndExtension(listOids[i].rootExternal,listOids[i].IDExternal)!=null)//already exists in the oidexternal table
				{
					continue;
				}
				listOids[i].IDInternal=guar.PatNum;
				OIDExternals.Insert(listOids[i]);
				strVerboseMsg+="\r\nExternal patient ID: "+listOids[i].IDExternal+", External root: "+listOids[i].rootExternal;
			}
			if(_isVerboseLogging && strVerboseMsg.Length>0) {
				EventLog.WriteEntry("OpenDentHL7","Added the following external patient ID(s) to the oidexternals table due to an incoming GT1 segment for PatNum: "+guar.PatNum+"."
					+strVerboseMsg+".",EventLogEntryType.Information);
			}
			return;
		}
Esempio n. 43
0
		public static HL7Def GetDeepInternal(HL7Def def) {
			//ok to pass in null
			if(def==null) {//wasn't in the database
				def=new HL7Def();
				def.IsNew=true;
				def.Description="eCW Full";
				def.ModeTx=ModeTxHL7.File;
				def.IncomingFolder="";
				def.OutgoingFolder="";
				def.IncomingPort="";
				def.OutgoingIpPort="";
				def.SftpInSocket="";
				def.SftpUsername="";
				def.SftpPassword="";
				def.FieldSeparator="|";
				def.ComponentSeparator="^";
				def.SubcomponentSeparator="&";
				def.RepetitionSeparator="~";
				def.EscapeCharacter=@"\";
				def.IsInternal=true;
				def.InternalType=HL7InternalType.eCWFull;
				def.InternalTypeVersion=Assembly.GetAssembly(typeof(Db)).GetName().Version.ToString();
				def.IsEnabled=false;
				def.Note="";
				def.ShowDemographics=HL7ShowDemographics.Show;
				def.ShowAccount=true;
				def.ShowAppts=false;//for now
				def.IsQuadAsToothNum=false;
			}
			def.hl7DefMessages=new List<HL7DefMessage>();//so that if this is called repeatedly, it won't pile on duplicate messages.
			//in either case, now get all child objects, which can't be in the database.
			#region Inbound Messages
				#region ADT - Patient Demographics (Admits, Discharges, and Transfers)
				//======================================================================================================================
				//eCW incoming patient information (ADT).
				HL7DefMessage msg=new HL7DefMessage();
				def.AddMessage(msg,MessageTypeHL7.ADT,MessageStructureHL7.ADT_A01,InOutHL7.Incoming,0);
				//MSH segment------------------------------------------------------------------
				HL7DefSegment seg=new HL7DefSegment();
				msg.AddSegment(seg,0,SegmentNameHL7.MSH);
				//MSH.8, Message Type
				seg.AddField(8,"messageType");
				//MSH.9, Message Control ID
				seg.AddField(9,"messageControlId");
				//PID segment------------------------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,2,SegmentNameHL7.PID);
				//PID.2, Patient ID
				seg.AddField(2,"pat.PatNum");
				//PID.4, Alternate Patient ID
				seg.AddField(4,"pat.ChartNumber");
				//PID.5, Patient Name
				seg.AddField(5,"pat.nameLFM");
				//PID.7, Date/Time of Birth
				seg.AddField(7,"pat.birthdateTime");
				//PID.8, Administrative Sex
				seg.AddField(8,"pat.Gender");
				//PID.10, Race
				seg.AddField(10,"pat.Race");
				//PID.11, Patient Address
				seg.AddField(11,"pat.addressCityStateZip");
				//PID.13, Phone Number - Home
				seg.AddField(13,"pat.HmPhone");
				//PID.14, Phone Number - Business
				seg.AddField(14,"pat.WkPhone");
				//PID.16, Marital Status
				seg.AddField(16,"pat.Position");
				//PID.19, SSN - Patient
				seg.AddField(19,"pat.SSN");
				//PID.22, Fee Schedule
				seg.AddField(22,"pat.FeeSched");
				//GT1 segment------------------------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,5,SegmentNameHL7.GT1);
				//GT1.2, Guarantor Number
				seg.AddField(2,"guar.PatNum");
				//GT1.3, Guarantor Name
				seg.AddField(3,"guar.nameLFM");
				//GT1.5, Guarantor Address
				seg.AddField(5,"guar.addressCityStateZip");
				//GT1.6, Guarantor Phone Number - Home
				seg.AddField(6,"guar.HmPhone");
				//GT1.7, Guarantor Phone Number - Business
				seg.AddField(7,"guar.WkPhone");
				//GT1.8, Guarantor Date/Time of Birth
				seg.AddField(8,"guar.birthdateTime");
				//GT1.9, Guarantor Administrative Sex
				seg.AddField(9,"guar.Gender");
				//GT1.12, Guarantor SSN
				seg.AddField(12,"guar.SSN");
				#endregion ADT - Patient Demographics (Admits, Discharges, and Transfers)
				#region SIU - Schedule Information Unsolicited
				//======================================================================================================================
				//eCW incoming appointment information (SIU - Schedule information unsolicited).
				msg=new HL7DefMessage();
				def.AddMessage(msg,MessageTypeHL7.SIU,MessageStructureHL7.SIU_S12,InOutHL7.Incoming,1);
				//MSH segment------------------------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,0,SegmentNameHL7.MSH);
				//MSH.8, Message Type
				seg.AddField(8,"messageType");
				//MSH.9, Message Control ID
				seg.AddField(9,"messageControlId");
				//PID segment------------------------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,2,SegmentNameHL7.PID);
				//PID.2
				seg.AddField(2,"pat.PatNum");
				//PID.4, Alternate Patient ID
				seg.AddField(4,"pat.ChartNumber");
				//PID.5, Patient Name
				seg.AddField(5,"pat.nameLFM");
				//PID.7, Date/Time of Birth
				seg.AddField(7,"pat.birthdateTime");
				//PID.8, Administrative Sex
				seg.AddField(8,"pat.Gender");
				//PID.10, Race
				seg.AddField(10,"pat.Race");
				//PID.11, Patient Address
				seg.AddField(11,"pat.addressCityStateZip");
				//PID.13, Phone Number - Home
				seg.AddField(13,"pat.HmPhone");
				//PID.14, Phone Number - Business
				seg.AddField(14,"pat.WkPhone");
				//PID.16, Marital Status
				seg.AddField(16,"pat.Position");
				//PID.19, SSN - Patient
				seg.AddField(19,"pat.SSN");
				//PID.22, Fee Schedule
				seg.AddField(22,"pat.FeeSched");
				//SCH segment------------------------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,1,SegmentNameHL7.SCH);
				//SCH.2, Filler Appointment ID.  In the old eCW interface, we were pulling from SCH.2, which was always the same as SCH.1.
				seg.AddField(2,"apt.AptNum");
				//SCH.7, Appointment Reason
				seg.AddField(7,"apt.Note");
				//SCH.11, Appointment Timing Quantity
				seg.AddField(11,"apt.lengthStartEnd");
				//AIG segment------------------------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,4,false,true,SegmentNameHL7.AIG);
				//AIG.3, Resource ID^Resource Name (Lname, Fname all as a string)
				seg.AddField(3,"prov.provIdName");
				//PV1 segment.-----------------------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,3,false,true,SegmentNameHL7.PV1);
				//PV1.7, Attending/Primary Care Doctor, UPIN^LastName^FirstName^MI
				seg.AddField(7,"prov.provIdNameLFM");
				#endregion SIU - Schedule Information Unsolicited
				#region ACK - General Acknowledgment
				//=======================================================================================================================
				//Acknowledgment message (ACK)
				msg=new HL7DefMessage();
				def.AddMessage(msg,MessageTypeHL7.ACK,MessageStructureHL7.ADT_A01,InOutHL7.Incoming,2);
				//MSH segment------------------------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,0,SegmentNameHL7.MSH);
				//MSH.8, Message Type
				seg.AddField(8,"messageType");
				//MSA (Message Acknowledgment) segment-----------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,1,SegmentNameHL7.MSA);
				//MSA.1, Acknowledgment Code
				seg.AddField(1,"ackCode");
				//MSA.2, Message Control ID
				seg.AddField(2,"messageControlId");
				#endregion ACK - General Acknowledgment
			#endregion Inbound Messages
			#region Outbound Messages
				#region DFT - Detailed Financial Transaction
				//=======================================================================================================================
				//Detail financial transaction (DFT)
				msg=new HL7DefMessage();
				def.AddMessage(msg,MessageTypeHL7.DFT,MessageStructureHL7.DFT_P03,InOutHL7.Outgoing,3);
				//MSH (Message Header) segment-------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,0,SegmentNameHL7.MSH);
				//MSH.1, Encoding Characters (DataType.ST)
				seg.AddField(1,"separators^~\\&");
				//MSH.2, Sending Application
				seg.AddFieldFixed(2,DataTypeHL7.HD,"OD");
				//MSH.4, Receiving Application
				seg.AddFieldFixed(4,DataTypeHL7.HD,"ECW");
				//MSH.6, Message Date and Time (YYYYMMDDHHMMSS)
				seg.AddField(6,"dateTime.Now");
				//MSH.8, Message Type^Event Type, example DFT^P03
				seg.AddField(8,"messageType");
				//MSH.9, Message Control ID
				seg.AddField(9,"messageControlId");
				//MSH.10, Processing ID (P-production, T-test)
				seg.AddFieldFixed(10,DataTypeHL7.PT,"P");
				//MSH.11, Version ID
				seg.AddFieldFixed(11,DataTypeHL7.VID,"2.3");
				//EVN (Event Type) segment-----------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,1,SegmentNameHL7.EVN);
				//EVN.1, Event Type, example P03
				seg.AddField(1,"eventType");
				//EVN.2, Recorded Date/Time
				seg.AddField(2,"dateTime.Now");
				//PID (Patient Identification) segment-----------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,2,SegmentNameHL7.PID);
				//PID.1, Sequence Number (1 for DFT's)
				seg.AddFieldFixed(1,DataTypeHL7.ST,"1");
				//PID.2, Patient ID (Account number.  eCW requires this to be the same # as came in on PID.4.)
				seg.AddField(2,"pat.ChartNumber");
				//PID.3, Patient MRN number
				seg.AddField(3,"pat.PatNum");
				//PID.5, Patient Name (Last^First^MI)
				seg.AddField(5,"pat.nameLFM");
				//PID.7, Birthdate
				seg.AddField(7,"pat.birthdateTime");
				//PID.8, Gender
				seg.AddField(8,"pat.Gender");
				//PID.10, Race
				seg.AddField(10,"pat.Race");
				//PID.11, Address
				seg.AddField(11,"pat.addressCityStateZip");
				//PID.13, Home Phone
				seg.AddField(13,"pat.HmPhone");
				//PID.14, Work Phone
				seg.AddField(14,"pat.WkPhone");
				//PID.16, Marital Status
				seg.AddField(16,"pat.Position");
				//PID.19, SSN
				seg.AddField(19,"pat.SSN");
				//PV1 (Patient Visit) segment--------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,3,SegmentNameHL7.PV1);
				//PV1.7, Attending/Primary Care Doctor
				seg.AddField(7,"prov.provIdNameLFM");
				//PV1.19, Visit Number
				seg.AddField(19,"apt.AptNum");
				//FT1 (Financial Transaction Information) segment------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,4,true,true,SegmentNameHL7.FT1);
				//FT1.1, Sequence Number (starts with 1)
				seg.AddField(1,"sequenceNum");
				//FT1.4, Transaction Date (YYYYMMDDHHMMSS)
				seg.AddField(4,"proc.procDateTime");
				//FT1.5, Transaction Posting Date (YYYYMMDDHHMMSS)
				seg.AddField(5,"proc.procDateTime");
				//FT1.6, Transaction Type
				seg.AddFieldFixed(6,DataTypeHL7.IS,"CG");
				//FT1.10, Transaction Quantity
				seg.AddFieldFixed(10,DataTypeHL7.NM,"1.0");
				//FT1.19, Diagnosis Code
				seg.AddField(19,"proc.DiagnosticCode");
				//FT1.20, Performed by Code (provider)
				seg.AddField(20,"prov.provIdNameLFM");
				//FT1.21, Ordering Provider
				seg.AddField(21,"prov.provIdNameLFM");
				//FT1.22, Unit Cost (procedure fee)
				seg.AddField(22,"proc.ProcFee");
				//FT1.25, Procedure Code
				seg.AddField(25,"proccode.ProcCode");
				//FT1.26, Modifiers (treatment area)
				seg.AddField(26,"proc.toothSurfRange");
				//DG1 (Diagnosis) segment is optional, skip for now
				//ZX1 (PDF Data) segment-------------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,5,SegmentNameHL7.ZX1);
				//ZX1.1
				seg.AddFieldFixed(1,DataTypeHL7.ST,"6");
				//ZX1.2
				seg.AddFieldFixed(2,DataTypeHL7.ST,"PDF");
				//ZX1.3
				seg.AddFieldFixed(3,DataTypeHL7.ST,"PATHOLOGY^Pathology Report^L");
				//ZX1.4
				seg.AddField(4,"pdfDescription");
				//ZX1.5
				seg.AddField(5,"pdfDataAsBase64");
				#endregion DFT - Detailed Financial Transaction
				#region ACK - General Acknowledgment
				//=======================================================================================================================
				//Message Acknowledgment (ACK)
				msg=new HL7DefMessage();
				def.AddMessage(msg,MessageTypeHL7.ACK,MessageStructureHL7.ADT_A01,InOutHL7.Outgoing,4);
				//MSH (Message Header) segment-------------------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,0,SegmentNameHL7.MSH);
				//MSH.1, Encoding Characters (DataType.ST)
				seg.AddField(1,"separators^~\\&");
				//MSH.2, Sending Application
				seg.AddFieldFixed(2,DataTypeHL7.HD,"OD");
				//MSH.4, Receiving Application
				seg.AddFieldFixed(4,DataTypeHL7.HD,"ECW");
				//MSH.6, Message Date and Time (YYYYMMDDHHMMSS)
				seg.AddField(6,"dateTime.Now");
				//MSH.8, Message Type^Event Type, example DFT^P03
				seg.AddField(8,"messageType");
				//MSH.9, Message Control ID
				seg.AddField(9,"messageControlId");
				//MSH.10, Processing ID (P-production, T-test)
				seg.AddFieldFixed(10,DataTypeHL7.PT,"P");
				//MSH.11, Version ID
				seg.AddFieldFixed(11,DataTypeHL7.VID,"2.3");
				//MSA (Message Acknowledgment) segment-----------------------------------------
				seg=new HL7DefSegment();
				msg.AddSegment(seg,1,SegmentNameHL7.MSA);
				//MSA.1, Acknowledgment Code
				seg.AddField(1,"ackCode");
				//MSA.2, Message Control ID
				seg.AddField(2,"messageControlId");
				#endregion ACK - General Acknowledgment
			#endregion Outbound Messages
			return def;
		}
		///<summary>Inserts one HL7DefSegment into the database.  Provides option to use the existing priKey.</summary>
		public static long Insert(HL7DefSegment hL7DefSegment,bool useExistingPK){
			if(!useExistingPK && PrefC.RandomKeys) {
				hL7DefSegment.HL7DefSegmentNum=ReplicationServers.GetKey("hl7defsegment","HL7DefSegmentNum");
			}
			string command="INSERT INTO hl7defsegment (";
			if(useExistingPK || PrefC.RandomKeys) {
				command+="HL7DefSegmentNum,";
			}
			command+="HL7DefMessageNum,ItemOrder,CanRepeat,IsOptional,SegmentName,Note) VALUES(";
			if(useExistingPK || PrefC.RandomKeys) {
				command+=POut.Long(hL7DefSegment.HL7DefSegmentNum)+",";
			}
			command+=
				     POut.Long  (hL7DefSegment.HL7DefMessageNum)+","
				+    POut.Int   (hL7DefSegment.ItemOrder)+","
				+    POut.Bool  (hL7DefSegment.CanRepeat)+","
				+    POut.Bool  (hL7DefSegment.IsOptional)+","
				+"'"+POut.String(hL7DefSegment.SegmentName.ToString())+"',"
				+DbHelper.ParamChar+"paramNote)";
			if(hL7DefSegment.Note==null) {
				hL7DefSegment.Note="";
			}
			OdSqlParameter paramNote=new OdSqlParameter("paramNote",OdDbType.Text,hL7DefSegment.Note);
			if(useExistingPK || PrefC.RandomKeys) {
				Db.NonQ(command,paramNote);
			}
			else {
				hL7DefSegment.HL7DefSegmentNum=Db.NonQ(command,true,paramNote);
			}
			return hL7DefSegment.HL7DefSegmentNum;
		}
Esempio n. 45
0
		public static void ProcessPV1(Patient pat,long aptNum,HL7DefSegment segDef,SegmentHL7 seg) {
			long provNum;
			int provNumOrder=0;
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				if(segDef.hl7DefFields[i].FieldName=="prov.provIdName" || segDef.hl7DefFields[i].FieldName=="prov.provIdNameLFM") {
					provNumOrder=segDef.hl7DefFields[i].OrdinalPos;
					break;
				}
			}
			if(provNumOrder==0) {//No provIdName or provIdNameLFM field in this segment definition so do nothing with it
				return;
			}
			provNum=FieldParser.ProvProcess(seg.Fields[provNumOrder]);
			if(provNum==0) {//This segment didn't have a valid provider id in it to locate the provider (must have been blank) so do nothing
				return;
			}
			Appointment apt=Appointments.GetOneApt(aptNum);//SCH segment was found and aptNum was retrieved, if no SCH segment for this message then 0
			if(apt==null) {//Just in case we can't find an apt with the aptNum from SCH segment
				return;
			}
			Appointment aptOld=apt.Clone();
			Patient patOld=pat.Copy();
			apt.ProvNum=provNum;
			pat.PriProv=provNum;
			Appointments.Update(apt,aptOld);
			Patients.Update(pat,patOld);
			return;
		}
Esempio n. 46
0
 public static HL7Def GetDeepInternal(HL7Def def)
 {
     //ok to pass in null
     //HL7Def def=HL7Defs.GetInternalFromDb("eCWTight");
     if (def == null)           //wasn't in the database
     {
         def                       = new HL7Def();
         def.IsNew                 = true;
         def.Description           = "eCW Tight";
         def.ModeTx                = ModeTxHL7.File;
         def.IncomingFolder        = "";
         def.OutgoingFolder        = "";
         def.IncomingPort          = "";
         def.OutgoingIpPort        = "";
         def.SftpInSocket          = "";
         def.SftpUsername          = "";
         def.SftpPassword          = "";
         def.FieldSeparator        = "|";
         def.ComponentSeparator    = "^";
         def.SubcomponentSeparator = "&";
         def.RepetitionSeparator   = "~";
         def.EscapeCharacter       = @"\";
         def.IsInternal            = true;
         def.InternalType          = HL7InternalType.eCWTight;
         def.InternalTypeVersion   = Assembly.GetAssembly(typeof(Db)).GetName().Version.ToString();
         def.IsEnabled             = false;
         def.Note                  = "";
         def.ShowDemographics      = HL7ShowDemographics.Hide;
         def.ShowAccount           = false;
         def.ShowAppts             = false;
         def.IsQuadAsToothNum      = false;
     }
     def.hl7DefMessages = new List <HL7DefMessage>();         //so that if this is called repeatedly, it won't pile on duplicate messages.
     //in either case, now get all child objects, which can't be in the database.
     #region Inbound Messages
     #region ADT - Patient Demographics (Admits, Discharges, and Transfers)
     //======================================================================================================================
     //eCW incoming patient information (ADT).
     HL7DefMessage msg = new HL7DefMessage();
     def.AddMessage(msg, MessageTypeHL7.ADT, MessageStructureHL7.ADT_A01, InOutHL7.Incoming, 0);
     //MSH segment------------------------------------------------------------------
     HL7DefSegment seg = new HL7DefSegment();
     msg.AddSegment(seg, 0, SegmentNameHL7.MSH);
     //MSH.8, Message Type
     seg.AddField(8, "messageType");
     //MSH.9, Message Control ID
     seg.AddField(9, "messageControlId");
     //PID segment------------------------------------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 2, SegmentNameHL7.PID);
     //PID.2, Patient ID
     seg.AddField(2, "pat.PatNum");
     //PID.4, Alternate Patient ID
     seg.AddField(4, "pat.ChartNumber");
     //PID.5, Patient Name
     seg.AddField(5, "pat.nameLFM");
     //PID.7, Date/Time of Birth
     seg.AddField(7, "pat.birthdateTime");
     //PID.8, Administrative Sex
     seg.AddField(8, "pat.Gender");
     //PID.10, Race
     seg.AddField(10, "pat.Race");
     //PID.11, Patient Address
     seg.AddField(11, "pat.addressCityStateZip");
     //PID.13, Phone Number - Home
     seg.AddField(13, "pat.HmPhone");
     //PID.14, Phone Number - Business
     seg.AddField(14, "pat.WkPhone");
     //PID.16, Marital Status
     seg.AddField(16, "pat.Position");
     //PID.19, SSN - Patient
     seg.AddField(19, "pat.SSN");
     //PID.22, Fee Schedule
     seg.AddField(22, "pat.FeeSched");
     //GT1 segment------------------------------------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 5, SegmentNameHL7.GT1);
     //GT1.2, Guarantor Number
     seg.AddField(2, "guar.PatNum");
     //GT1.3, Guarantor Name
     seg.AddField(3, "guar.nameLFM");
     //GT1.5, Guarantor Address
     seg.AddField(5, "guar.addressCityStateZip");
     //GT1.6, Guarantor Phone Number - Home
     seg.AddField(6, "guar.HmPhone");
     //GT1.7, Guarantor Phone Number - Business
     seg.AddField(7, "guar.WkPhone");
     //GT1.8, Guarantor Date/Time of Birth
     seg.AddField(8, "guar.birthdateTime");
     //GT1.9, Guarantor Administrative Sex
     seg.AddField(9, "guar.Gender");
     //GT1.12, Guarantor SSN
     seg.AddField(12, "guar.SSN");
     #endregion ADT - Patient Demographics (Admits, Discharges, and Transfers)
     #region SIU - Schedule Information Unsolicited
     //======================================================================================================================
     //eCW incoming appointment information (SIU - Schedule information unsolicited).
     msg = new HL7DefMessage();
     def.AddMessage(msg, MessageTypeHL7.SIU, MessageStructureHL7.SIU_S12, InOutHL7.Incoming, 1);
     //MSH segment------------------------------------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 0, SegmentNameHL7.MSH);
     //MSH.8, Message Type
     seg.AddField(8, "messageType");
     //MSH.9, Message Control ID
     seg.AddField(9, "messageControlId");
     //PID segment------------------------------------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 2, SegmentNameHL7.PID);
     //PID.2
     seg.AddField(2, "pat.PatNum");
     //PID.4, Alternate Patient ID
     seg.AddField(4, "pat.ChartNumber");
     //PID.5, Patient Name
     seg.AddField(5, "pat.nameLFM");
     //PID.7, Date/Time of Birth
     seg.AddField(7, "pat.birthdateTime");
     //PID.8, Administrative Sex
     seg.AddField(8, "pat.Gender");
     //PID.10, Race
     seg.AddField(10, "pat.Race");
     //PID.11, Patient Address
     seg.AddField(11, "pat.addressCityStateZip");
     //PID.13, Phone Number - Home
     seg.AddField(13, "pat.HmPhone");
     //PID.14, Phone Number - Business
     seg.AddField(14, "pat.WkPhone");
     //PID.16, Marital Status
     seg.AddField(16, "pat.Position");
     //PID.19, SSN - Patient
     seg.AddField(19, "pat.SSN");
     //PID.22, Fee Schedule
     seg.AddField(22, "pat.FeeSched");
     //SCH segment------------------------------------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 1, SegmentNameHL7.SCH);
     //SCH.2, Filler Appointment ID.  In the old eCW interface, we were pulling from SCH.2, which was always the same as SCH.1.
     seg.AddField(2, "apt.AptNum");
     //SCH.7, Appointment Reason
     seg.AddField(7, "apt.Note");
     //SCH.11, Appointment Timing Quantity
     seg.AddField(11, "apt.lengthStartEnd");
     //AIG segment------------------------------------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 4, false, true, SegmentNameHL7.AIG);
     //AIG.3, Resource ID^Resource Name (Lname, Fname all as a string)
     seg.AddField(3, "prov.provIdName");
     //PV1 segment.-----------------------------------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 3, false, true, SegmentNameHL7.PV1);
     //PV1.7, Attending/Primary Care Doctor, UPIN^LastName^FirstName^MI
     seg.AddField(7, "prov.provIdNameLFM");
     #endregion SIU - Schedule Information Unsolicited
     #region ACK - General Acknowledgment
     //=======================================================================================================================
     //Acknowledgment message (ACK)
     msg = new HL7DefMessage();
     def.AddMessage(msg, MessageTypeHL7.ACK, MessageStructureHL7.ADT_A01, InOutHL7.Incoming, 2);
     //MSH segment------------------------------------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 0, SegmentNameHL7.MSH);
     //MSH.8, Message Type
     seg.AddField(8, "messageType");
     //MSA (Message Acknowledgment) segment-----------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 1, SegmentNameHL7.MSA);
     //MSA.1, Acknowledgment Code
     seg.AddField(1, "ackCode");
     //MSA.2, Message Control ID
     seg.AddField(2, "messageControlId");
     #endregion ACK - General Acknowledgment
     #endregion Inbound Messages
     #region Outbound Messages
     #region DFT - Detailed Financial Transaction
     //=======================================================================================================================
     //Detail financial transaction (DFT)
     msg = new HL7DefMessage();
     def.AddMessage(msg, MessageTypeHL7.DFT, MessageStructureHL7.DFT_P03, InOutHL7.Outgoing, 3);
     //MSH (Message Header) segment-------------------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 0, SegmentNameHL7.MSH);
     //MSH.1, Encoding Characters (DataType.ST)
     seg.AddField(1, "separators^~\\&");
     //MSH.2, Sending Application
     seg.AddFieldFixed(2, DataTypeHL7.HD, "OD");
     //MSH.4, Receiving Application
     seg.AddFieldFixed(4, DataTypeHL7.HD, "ECW");
     //MSH.6, Message Date and Time (YYYYMMDDHHMMSS)
     seg.AddField(6, "dateTime.Now");
     //MSH.8, Message Type^Event Type, example DFT^P03
     seg.AddField(8, "messageType");
     //MSH.9, Message Control ID
     seg.AddField(9, "messageControlId");
     //MSH.10, Processing ID (P-production, T-test)
     seg.AddFieldFixed(10, DataTypeHL7.PT, "P");
     //MSH.11, Version ID
     seg.AddFieldFixed(11, DataTypeHL7.VID, "2.3");
     //EVN (Event Type) segment-----------------------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 1, SegmentNameHL7.EVN);
     //EVN.1, Event Type, example P03
     seg.AddField(1, "eventType");
     //EVN.2, Recorded Date/Time
     seg.AddField(2, "dateTime.Now");
     //PID (Patient Identification) segment-----------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 2, SegmentNameHL7.PID);
     //PID.1, Sequence Number (1 for DFT's)
     seg.AddFieldFixed(1, DataTypeHL7.ST, "1");
     //PID.2, Patient ID (Account number.  eCW requires this to be the same # as came in on PID.4.)
     seg.AddField(2, "pat.ChartNumber");
     //PID.3, Patient MRN number
     seg.AddField(3, "pat.PatNum");
     //PID.5, Patient Name (Last^First^MI)
     seg.AddField(5, "pat.nameLFM");
     //PID.7, Birthdate
     seg.AddField(7, "pat.birthdateTime");
     //PID.8, Gender
     seg.AddField(8, "pat.Gender");
     //PID.10, Race
     seg.AddField(10, "pat.Race");
     //PID.11, Address
     seg.AddField(11, "pat.addressCityStateZip");
     //PID.13, Home Phone
     seg.AddField(13, "pat.HmPhone");
     //PID.14, Work Phone
     seg.AddField(14, "pat.WkPhone");
     //PID.16, Marital Status
     seg.AddField(16, "pat.Position");
     //PID.19, SSN
     seg.AddField(19, "pat.SSN");
     //PV1 (Patient Visit) segment--------------------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 3, SegmentNameHL7.PV1);
     //PV1.7, Attending/Primary Care Doctor
     seg.AddField(7, "prov.provIdNameLFM");
     //PV1.19, Visit Number
     seg.AddField(19, "apt.AptNum");
     //FT1 (Financial Transaction Information) segment------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 4, true, true, SegmentNameHL7.FT1);
     //FT1.1, Sequence Number (starts with 1)
     seg.AddField(1, "sequenceNum");
     //FT1.4, Transaction Date (YYYYMMDDHHMMSS)
     seg.AddField(4, "proc.procDateTime");
     //FT1.5, Transaction Posting Date (YYYYMMDDHHMMSS)
     seg.AddField(5, "proc.procDateTime");
     //FT1.6, Transaction Type
     seg.AddFieldFixed(6, DataTypeHL7.IS, "CG");
     //FT1.10, Transaction Quantity
     seg.AddFieldFixed(10, DataTypeHL7.NM, "1.0");
     //FT1.19, Diagnosis Code
     seg.AddField(19, "proc.DiagnosticCode");
     //FT1.20, Performed by Code (provider)
     seg.AddField(20, "prov.provIdNameLFM");
     //FT1.21, Ordering Provider
     seg.AddField(21, "prov.provIdNameLFM");
     //FT1.22, Unit Cost (procedure fee)
     seg.AddField(22, "proc.ProcFee");
     //FT1.25, Procedure Code
     seg.AddField(25, "proccode.ProcCode");
     //FT1.26, Modifiers (treatment area)
     seg.AddField(26, "proc.toothSurfRange");
     //DG1 (Diagnosis) segment is optional, skip for now
     //ZX1 (PDF Data) segment-------------------------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 5, SegmentNameHL7.ZX1);
     //ZX1.1
     seg.AddFieldFixed(1, DataTypeHL7.ST, "6");
     //ZX1.2
     seg.AddFieldFixed(2, DataTypeHL7.ST, "PDF");
     //ZX1.3
     seg.AddFieldFixed(3, DataTypeHL7.ST, "PATHOLOGY^Pathology Report^L");
     //ZX1.4
     seg.AddField(4, "pdfDescription");
     //ZX1.5
     seg.AddField(5, "pdfDataAsBase64");
     #endregion DFT - Detailed Financial Transaction
     #region ACK - General Acknowledgment
     //=======================================================================================================================
     //Message Acknowledgment (ACK)
     msg = new HL7DefMessage();
     def.AddMessage(msg, MessageTypeHL7.ACK, MessageStructureHL7.ADT_A01, InOutHL7.Outgoing, 4);
     //MSH (Message Header) segment-------------------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 0, SegmentNameHL7.MSH);
     //MSH.1, Encoding Characters (DataType.ST)
     seg.AddField(1, "separators^~\\&");
     //MSH.2, Sending Application
     seg.AddFieldFixed(2, DataTypeHL7.HD, "OD");
     //MSH.4, Receiving Application
     seg.AddFieldFixed(4, DataTypeHL7.HD, "ECW");
     //MSH.6, Message Date and Time (YYYYMMDDHHMMSS)
     seg.AddField(6, "dateTime.Now");
     //MSH.8, Message Type^Event Type, example DFT^P03
     seg.AddField(8, "messageType");
     //MSH.9, Message Control ID
     seg.AddField(9, "messageControlId");
     //MSH.10, Processing ID (P-production, T-test)
     seg.AddFieldFixed(10, DataTypeHL7.PT, "P");
     //MSH.11, Version ID
     seg.AddFieldFixed(11, DataTypeHL7.VID, "2.3");
     //MSA (Message Acknowledgment) segment-----------------------------------------
     seg = new HL7DefSegment();
     msg.AddSegment(seg, 1, SegmentNameHL7.MSA);
     //MSA.1, Acknowledgment Code
     seg.AddField(1, "ackCode");
     //MSA.2, Message Control ID
     seg.AddField(2, "messageControlId");
     #endregion ACK - General Acknowledgment
     #endregion Outbound Messages
     return(def);
 }
Esempio n. 47
0
		//public static void ProcessIN1() {
		//	return;
		//}

		public static void ProcessMSA(HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			int ackCodeOrder=0;
			int msgControlIdOrder=0;
			//find position of AckCode in segDef for MSA seg
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				if(segDef.hl7DefFields[i].FieldName=="ackCode") {
					ackCodeOrder=segDef.hl7DefFields[i].OrdinalPos;
				}
				if(segDef.hl7DefFields[i].FieldName=="messageControlId") {
					msgControlIdOrder=segDef.hl7DefFields[i].OrdinalPos;
				}
			}
			if(ackCodeOrder==0) {//no ackCode defined for this def of MSA, do nothing with it?
				return;
			}
			if(msgControlIdOrder==0) {//no messageControlId defined for this def of MSA, do nothing with it?
				return;
			}
			//set msg.AckCode to value in position located in def of ackcode in seg
			msg.AckCode=seg.GetFieldComponent(ackCodeOrder).ToString();
			msg.ControlId=seg.GetFieldComponent(msgControlIdOrder).ToString();
		}
Esempio n. 48
0
        public static HL7Def GetDeepInternal(HL7Def def)
        {
            //ok to pass in null
            if (def == null)           //wasn't in the database
            {
                def                       = new HL7Def();
                def.IsNew                 = true;
                def.Description           = "Centricity";
                def.ModeTx                = ModeTxHL7.File;
                def.IncomingFolder        = "";
                def.OutgoingFolder        = "";
                def.IncomingPort          = "";
                def.OutgoingIpPort        = "";
                def.SftpInSocket          = "";
                def.SftpUsername          = "";
                def.SftpPassword          = "";
                def.FieldSeparator        = "|";
                def.ComponentSeparator    = "^";
                def.SubcomponentSeparator = "&";
                def.RepetitionSeparator   = "~";
                def.EscapeCharacter       = @"\";
                def.IsInternal            = true;
                def.InternalType          = HL7InternalType.Centricity;
                def.InternalTypeVersion   = Assembly.GetAssembly(typeof(Db)).GetName().Version.ToString();
                def.IsEnabled             = false;
                def.Note                  = "";
                def.ShowDemographics      = HL7ShowDemographics.ChangeAndAdd;
                def.ShowAccount           = true;
                def.ShowAppts             = true;
                def.IsQuadAsToothNum      = false;
            }
            def.hl7DefMessages = new List <HL7DefMessage>();
            HL7DefMessage msg = new HL7DefMessage();
            HL7DefSegment seg = new HL7DefSegment();

            #region Outbound Messages
            #region DFT - Detailed Financial Transaction
            //=======================================================================================================================
            //Detail financial transaction (DFT)
            def.AddMessage(msg, MessageTypeHL7.DFT, MessageStructureHL7.DFT_P03, InOutHL7.Outgoing, 2);
            //MSH (Message Header) segment-------------------------------------------------
            msg.AddSegment(seg, 0, SegmentNameHL7.MSH);
            //HL7 documentation says field 1 is Field Separator.  "This field contains the separator between the segment ID and the first real field.  As such it serves as the separator and defines the character to be used as a separator for the rest of the message." (HL7 v2.6 documentation) The separator is usually | (pipes) and is part of field 0, which is the segment ID followed by a |.  Encoding Characters is the first real field, so it will be numbered starting with 1 in our def.
            //MSH.1, Encoding Characters (DataType.ST)
            seg.AddField(1, "separators^~\\&");
            //MSH.2, Sending Application
            seg.AddFieldFixed(2, DataTypeHL7.HD, "OD");
            //MSH.4, Receiving Application
            seg.AddFieldFixed(4, DataTypeHL7.HD, def.Description);
            //MSH.6, Message Date and Time (YYYYMMDDHHMMSS)
            seg.AddField(6, "dateTime.Now");
            //MSH.8, Message Type^Event Type, example DFT^P03
            seg.AddField(8, "messageType");
            //MSH.9, Message Control ID
            seg.AddField(9, "messageControlId");
            //MSH.10, Processing ID (P-production, T-test)
            seg.AddFieldFixed(10, DataTypeHL7.PT, "P");
            //MSH.11, Version ID
            seg.AddFieldFixed(11, DataTypeHL7.VID, "2.3");
            //MSH.16, Application Ack Type (AL=Always, NE=Never, ER=Error/reject conditions only, SU=Successful completion only)
            seg.AddFieldFixed(15, DataTypeHL7.ID, "NE");
            //EVN (Event Type) segment-----------------------------------------------------
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 1, SegmentNameHL7.EVN);
            //EVN.1, Event Type, example P03
            seg.AddField(1, "eventType");
            //EVN.2, Recorded Date/Time
            seg.AddField(2, "dateTime.Now");
            //EVN.3, Event Reason Code
            seg.AddFieldFixed(3, DataTypeHL7.IS, "01");
            //PID (Patient Identification) segment-----------------------------------------
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 2, SegmentNameHL7.PID);
            //PID.1, Sequence Number (1 for DFT's)  "This field contains the number that identifies this transaction.  For the first occurrence of the segment, the sequence number shall be one, for the second occurrence, the sequence number shall be two, etc." (HL7 v2.6 documentation)  We only send 1 PID segment in DFT's so this number will always be 1.
            seg.AddFieldFixed(1, DataTypeHL7.SI, "1");
            //PID.2, Patient ID (External)
            seg.AddField(2, "pat.ChartNumber");
            //PID.3, Patient ID (Internal)
            seg.AddField(3, "pat.PatNum");
            //PV1 (Patient Visit) segment--------------------------------------------------
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 3, SegmentNameHL7.PV1);
            //PV1.1, Set ID - PV1 (1 for DFT's)  See the comment above for the Sequence Number of the PID segment.  Always 1 since we only send one PV1 segment per DFT message.
            seg.AddFieldFixed(1, DataTypeHL7.SI, "1");
            //PV1.2, Patient Class  (E=Emergency, I=Inpatient, O=Outpatient, P=Preadmit, R=Recurring patient, B=Obstetrics, C=Commercial Account, N=Not Applicable, U=Unkown)  We will just send O for outpatient for every DFT message.
            seg.AddFieldFixed(2, DataTypeHL7.IS, "O");
            //todo: ClinicNum?
            //PV1.3, Assigned Patient Location
            //PV1.7, Attending/Primary Care Doctor
            seg.AddField(7, "prov.provIdNameLFM");
            //todo: Referring Dr?
            //PV1.8, Referring Doctor
            //PV1.19, Visit Number
            seg.AddField(19, "apt.AptNum");
            //PV1.44, Admit Date/Time
            seg.AddField(44, "proc.procDateTime");
            //PV1.50, Alternate Visit ID
            //FT1 (Financial Transaction Information) segment------------------------------
            seg = new HL7DefSegment();
            msg.AddSegment(seg, 4, true, true, SegmentNameHL7.FT1);
            //FT1.1, Sequence Number (starts with 1)
            seg.AddField(1, "sequenceNum");
            //FT1.2, Transaction ID
            seg.AddField(2, "proc.ProcNum");
            //FT1.4, Transaction Date (YYYYMMDDHHMMSS)
            seg.AddField(4, "proc.procDateTime");
            //FT1.5, Transaction Posting Date (YYYYMMDDHHMMSS)
            seg.AddField(5, "proc.procDateTime");
            //FT1.6, Transaction Type
            seg.AddFieldFixed(6, DataTypeHL7.IS, "CG");
            //FT1.10, Transaction Quantity
            seg.AddFieldFixed(10, DataTypeHL7.NM, "1.0");
            //FT1.11, Transaction Amount Extended (Total fee to charge for this procedure, independent of transaction quantity)
            seg.AddField(11, "proc.ProcFee");
            //FT1.12, Transaction Amount Unit (Fee for this procedure for each transaction quantity)
            seg.AddField(12, "proc.ProcFee");
            //todo: ClinicNum?
            //FT1.16, Assigned Patient Location
            //FT1.19, Diagnosis Code
            seg.AddField(19, "proc.DiagnosticCode");
            //FT1.21, Ordering Provider
            seg.AddField(21, "prov.provIdNameLFM");
            //FT1.22, Unit Cost (procedure fee)
            seg.AddField(22, "proc.ProcFee");
            //FT1.25, Procedure Code
            seg.AddField(25, "proccode.ProcCode");
            //FT1.26, Modifiers (treatment area)
            seg.AddField(26, "proc.toothSurfRange");
            //DG1 (Diagnosis) segment is optional, skip for now
            //PR1 (Procedures) segment is optional, skip for now
            #endregion DFT - Detailed Financial Transaction
            #endregion Outbound Messages
            return(def);
        }
Esempio n. 49
0
		public static void ProcessMSH(HL7DefSegment segDef,SegmentHL7 seg,MessageHL7 msg) {
			int msgControlIdOrder=0;
			//find position of messageControlId in segDef for MSH seg
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				if(segDef.hl7DefFields[i].FieldName=="messageControlId") {
					msgControlIdOrder=segDef.hl7DefFields[i].OrdinalPos;
					continue;
				}
			}
			if(msgControlIdOrder==0) {
				return;
			}
			msg.ControlId=seg.GetFieldComponent(msgControlIdOrder).ToString();
		}
Esempio n. 50
0
        ///<summary>Gets the patient info from the MedLab.OriginalPIDSegments.  Returns null if there is an error processing the PID segments.</summary>
        private List <string[]> GetPatInfoFromPidSegments()
        {
            List <string[]> listPats  = new List <string[]>();
            HL7Def          hl7DefCur = HL7Defs.GetOneDeepEnabled(true);

            if (hl7DefCur == null)
            {
                MsgBox.Show(this, "There must be an enabled MedLab HL7 interface in order to parse the message details.");
                return(null);
            }
            HL7DefMessage hl7defmsg = null;

            for (int i = 0; i < hl7DefCur.hl7DefMessages.Count; i++)
            {
                //for now there are only incoming ORU messages supported, so there should only be one defined message type and it should be inbound
                if (hl7DefCur.hl7DefMessages[i].MessageType == MessageTypeHL7.ORU && hl7DefCur.hl7DefMessages[i].InOrOut == InOutHL7.Incoming)
                {
                    hl7defmsg = hl7DefCur.hl7DefMessages[i];
                    break;
                }
            }
            if (hl7defmsg == null)
            {
                MsgBox.Show(this, "There must be a message definition for an inbound ORU message in order to parse this message.");
                return(null);
            }
            //for MedLab interfaces, we limit the ability to rearrange the message structure, so the PID segment is always in position 1
            if (hl7defmsg.hl7DefSegments.Count < 2)
            {
                MsgBox.Show(this, "The message definition for an inbound ORU message does not have the correct number of segments.");
                return(null);
            }
            HL7DefSegment pidSegDef = hl7defmsg.hl7DefSegments[1];

            if (pidSegDef.SegmentName != SegmentNameHL7.PID)
            {
                MsgBox.Show(this, "The message definition for an inbound ORU message does not have the PID segment as the second segment.");
                return(null);
            }
            for (int i = 0; i < ListMedLabs.Count; i++)
            {
                string[]        fields     = ListMedLabs[i].OriginalPIDSegment.Split(new string[] { "|" }, StringSplitOptions.None);
                List <FieldHL7> listFields = new List <FieldHL7>();
                for (int j = 0; j < fields.Length; j++)
                {
                    listFields.Add(new FieldHL7(fields[j]));
                }
                string patName   = "";
                string birthdate = "";
                string gender    = "";
                string ssn       = "";
                for (int j = 0; j < pidSegDef.hl7DefFields.Count; j++)
                {
                    int itemOrder = pidSegDef.hl7DefFields[j].OrdinalPos;
                    if (itemOrder > listFields.Count - 1)
                    {
                        continue;
                    }
                    switch (pidSegDef.hl7DefFields[j].FieldName)
                    {
                    case "pat.nameLFM":
                        patName = listFields[itemOrder].GetComponentVal(1);
                        if (patName != "" && listFields[itemOrder].GetComponentVal(2) != "")
                        {
                            patName += " ";
                        }
                        patName += listFields[itemOrder].GetComponentVal(2);
                        if (patName != "" && listFields[itemOrder].GetComponentVal(0) != "")
                        {
                            patName += " ";
                        }
                        patName += listFields[itemOrder].GetComponentVal(0);
                        continue;

                    case "patBirthdateAge":
                        //LabCorp sends the birthdate and age in years, months, and days like yyyyMMdd^YYY^MM^DD
                        birthdate = FieldParser.DateTimeParse(listFields[itemOrder].GetComponentVal(0)).ToShortDateString();
                        continue;

                    case "pat.Gender":
                        gender = Lan.g("enumPatientGender", FieldParser.GenderParse(listFields[itemOrder].GetComponentVal(0)).ToString());
                        continue;

                    case "pat.SSN":
                        if (listFields[itemOrder].GetComponentVal(0).Length > 3)
                        {
                            ssn  = "***-**-";
                            ssn += listFields[itemOrder].GetComponentVal(0).Substring(listFields[itemOrder].GetComponentVal(0).Length - 4, 4);
                        }
                        continue;

                    default:
                        continue;
                    }
                }
                bool isDuplicate = false;
                for (int j = 0; j < listPats.Count; j++)
                {
                    if (listPats[j].Length < 4)                   //should never happen
                    {
                        continue;
                    }
                    if (listPats[j][0] == patName && listPats[j][1] == birthdate && listPats[j][2] == gender && listPats[j][3] == ssn)
                    {
                        isDuplicate = true;
                    }
                }
                if (!isDuplicate)
                {
                    listPats.Add(new string[] { patName, birthdate, gender, ssn });
                }
            }
            return(listPats);
        }
Esempio n. 51
0
 ///<summary>Inserts one HL7DefSegment into the database.  Returns the new priKey.  Doesn't use the cache.</summary>
 public static long InsertNoCache(HL7DefSegment hL7DefSegment)
 {
     return(InsertNoCache(hL7DefSegment, false));
 }