Пример #1
0
        public static void ProcessPD1(Patient pat, SegmentHL7 seg)
        {
            long provNum = EcwSegmentPID.ProvProcess(seg.GetField(4));          //don't know why both

            if (provNum != 0)
            {
                pat.PriProv = provNum;
            }
        }
Пример #2
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;
		}
Пример #3
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;
		}
Пример #4
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;
		}
Пример #5
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;
		}
Пример #6
0
        public static void ProcessMessage(MessageHL7 message, bool isVerboseLogging)
        {
            SegmentHL7 seg      = message.GetSegment(SegmentNameHL7.PID, true);
            long       patNum   = PIn.Long(seg.GetFieldFullText(2));
            Patient    pat      = Patients.GetPat(patNum);
            Patient    patOld   = null;
            bool       isNewPat = pat == null;

            if (isNewPat)
            {
                pat             = new Patient();
                pat.PatNum      = patNum;
                pat.Guarantor   = patNum;
                pat.PriProv     = PrefC.GetLong(PrefName.PracticeDefaultProv);
                pat.BillingType = PrefC.GetLong(PrefName.PracticeDefaultBillType);
            }
            else
            {
                patOld = pat.Copy();
            }
            List <PatientRace> listPatRaces = new List <PatientRace>();

            EcwSegmentPID.ProcessPID(pat, seg, false, listPatRaces);         //IsStandalone=false because should never make it this far.
            //PV1-patient visit---------------------------
            //seg=message.GetSegment(SegmentName.PV1,false);
            //if(seg!=null) {
            //	SegmentPID.ProcessPV1(pat,seg);
            //}
            //SCH- Schedule Activity Information
            seg = message.GetSegment(SegmentNameHL7.SCH, true);
            //The documentation is wrong.  SCH.01 is not the appointment ID, but is instead a sequence# (always 1)
            long        aptNum   = PIn.Long(seg.GetFieldFullText(2));
            Appointment apt      = Appointments.GetOneApt(aptNum);
            Appointment aptOld   = null;
            bool        isNewApt = apt == null;

            if (isNewApt)
            {
                apt           = new Appointment();
                apt.AptNum    = aptNum;
                apt.PatNum    = pat.PatNum;
                apt.AptStatus = ApptStatus.Scheduled;
            }
            else
            {
                aptOld = apt.Copy();
            }
            if (apt.PatNum != pat.PatNum)
            {
                EventLog.WriteEntry("OpenDentHL7", "Appointment does not match patient: " + pat.FName + " " + pat.LName
                                    + ", apt.PatNum:" + apt.PatNum.ToString() + ", pat.PatNum:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Error);
                return;                //we can't process this message because wrong patnum.
            }
            apt.Note = seg.GetFieldFullText(7);
            //apt.Pattern=ProcessDuration(seg.GetFieldFullText(9));
            //9 and 10 are not actually available, in spite of the documentation.
            //11-We need start time and stop time
            apt.AptDateTime = DateTimeParse(seg.GetFieldComponent(11, 3));
            DateTime stopTime = DateTimeParse(seg.GetFieldComponent(11, 4));

            apt.Pattern = ProcessPattern(apt.AptDateTime, stopTime);
            apt.ProvNum = pat.PriProv;          //just in case there's not AIG segment.
            //AIG is optional, but looks like the only way to get provider for the appt-----------
            //PV1 seems to frequently be sent instead of AIG.
            SegmentHL7 segAIG = message.GetSegment(SegmentNameHL7.AIG, false);
            SegmentHL7 segPV  = message.GetSegment(SegmentNameHL7.PV1, false);

            if (segAIG != null)
            {
                long provNum = EcwSegmentPID.ProvProcess(segAIG.GetField(3));
                if (provNum != 0)
                {
                    apt.ProvNum = provNum;
                    pat.PriProv = provNum;
                }
            }
            else if (segPV != null)
            {
                long provNum = EcwSegmentPID.ProvProcess(segPV.GetField(7));
                if (provNum != 0)
                {
                    apt.ProvNum = provNum;
                    pat.PriProv = provNum;
                }
            }
            //AIL,AIP seem to be optional, and I'm going to ignore them for now.
            if (pat.FName == "" || pat.LName == "")
            {
                EventLog.WriteEntry("OpenDentHL7", "Appointment not processed due to missing patient first or last name. PatNum:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                return;                //this will also skip the appt insert.
            }
            if (isNewPat)
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Inserted patient: " + pat.FName + " " + pat.LName + ", PatNum:" + pat.PatNum.ToString()
                                        , EventLogEntryType.Information);
                }
                Patients.Insert(pat, true);
                SecurityLogs.MakeLogEntry(Permissions.PatientCreate, pat.PatNum, "Created from HL7 for eCW.", LogSources.HL7);
            }
            else
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Updated patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Patients.Update(pat, patOld);
            }
            //had to move this reconcile here since we might not have a PatNum for new patients until after the insert
            PatientRaces.Reconcile(pat.PatNum, listPatRaces);
            if (isNewApt)
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Inserted appointment for: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Appointments.InsertIncludeAptNum(apt, true);
            }
            else
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Updated appointment for: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Appointments.Update(apt, aptOld);
            }
        }
Пример #7
0
		public static void ProcessPD1(Patient pat,SegmentHL7 seg) {
			long provNum=EcwSegmentPID.ProvProcess(seg.GetField(4));//don't know why both
			if(provNum!=0) {
				pat.PriProv=provNum;
			}
		}
Пример #8
0
		///<summary>Sets values on _medLabCur based on the PID segment fields.  Also sets medlab.OriginalPIDSegment to the full PID segment.</summary>
		public static void ProcessPID(HL7DefSegment segDef,SegmentHL7 pidSeg) {
			_medLabCur.OriginalPIDSegment=pidSeg.ToString();
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				HL7DefField fieldDefCur=segDef.hl7DefFields[i];
				switch(fieldDefCur.FieldName) {
					case "accountNum":
						_medLabCur.PatAccountNum=pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						string fastingStr=pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos,6);
						//if the component is blank or has a value other than "Y" or "N", the PatFasting field will be 0 - Unknown
						if(fastingStr.Length>0) {
							fastingStr=fastingStr.ToLower().Substring(0,1);
							if(fastingStr=="y") {
								_medLabCur.PatFasting=YN.Yes;
							}
							else if(fastingStr=="n") {
								_medLabCur.PatFasting=YN.No;
							}
						}
						continue;
					case "altPatID":
						_medLabCur.PatIDAlt=pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "labPatID":
						_medLabCur.PatIDLab=pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "pat.nameLFM":
						//not currently using this to update any db fields, only used to validate the correct patient was selected
						continue;
					case "pat.PatNum":
						if(_patCur!=null) {
							//If a patient was not located, the MedLab object will have a 0 for PatNum.
							//We will be able to generate a list of all 'unattached' MedLab objects so the user can manually select the correct patient.
							_medLabCur.PatNum=_patCur.PatNum;
						}
						continue;
					case "patBirthdateAge":
						//the birthday field for MedLab is birthdate^age in years^age months^age days.
						//The year component is left padded with 0's to three digits, the month and day components are left padded with 0's to two digits.
						//If the year, age, or month components don't exist or are blank, the default will be to 
						//Example: 19811213^033^02^19
						FieldHL7 fieldCur=pidSeg.GetField(fieldDefCur.OrdinalPos);
						if(fieldCur==null || fieldCur.Components.Count<4) {//if there aren't even 4 components (3 ^'s) in the field, don't set the age
							continue;
						}
						_medLabCur.PatAge=pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos,1).PadLeft(3,'0')+"/"
							+pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos,2).PadLeft(2,'0')+"/"
							+pidSeg.GetFieldComponent(fieldDefCur.OrdinalPos,3).PadLeft(2,'0');
						continue;
					default:
						continue;
				}
			}
			return;
		}
Пример #9
0
		///<summary></summary>
		public static void ProcessORC(HL7DefSegment segDef,SegmentHL7 orcSeg) {
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				HL7DefField fieldDefCur=segDef.hl7DefFields[i];
				switch(fieldDefCur.FieldName) {
					case "orderingProv":
						FieldHL7 fieldCur=orcSeg.GetField(fieldDefCur.OrdinalPos);//fieldCur can be null
						if(fieldCur==null) {
							continue;
						}
						_medLabCur.OrderingProvNPI=FieldParserMedLab.OrderingProvIDParse(fieldCur,"N");
						_medLabCur.OrderingProvLocalID=FieldParserMedLab.OrderingProvIDParse(fieldCur,"L");
						_medLabCur.OrderingProvLName=fieldCur.GetComponentVal(1).Trim();
						_medLabCur.OrderingProvFName=fieldCur.GetComponentVal(2).Trim();
						int j=0;
						while(_medLabCur.OrderingProvLName=="" && j<fieldCur.ListRepeatFields.Count) {//if LName is not present in first repetition, check others
							_medLabCur.OrderingProvLName=fieldCur.ListRepeatFields[j].GetComponentVal(1).Trim();
							j++;
						}
						j=0;
						while(_medLabCur.OrderingProvFName=="" && j<fieldCur.ListRepeatFields.Count) {//if FName is not present in first repetition, check others
							_medLabCur.OrderingProvLName=fieldCur.ListRepeatFields[j].GetComponentVal(2).Trim();
							j++;
						}
						#region Locate Provider
						_medicaidIdCur=FieldParserMedLab.OrderingProvIDParse(fieldCur,"P");
						List<Provider> listProvs=Providers.GetProvsByNpiOrMedicaidId(_medLabCur.OrderingProvNPI,_medicaidIdCur);
						listProvs.Sort(SortByNpiMedicaidIdMatch);
						if(listProvs.Count>0) {//if a provider with either a matching NPI or Medicaid ID is found, use the first matching prov
							_medLabCur.ProvNum=listProvs[0].ProvNum;
							continue;
						}
						//no provider match based on NPI or MedicaidID
						listProvs=Providers.GetProvsByFLName(_medLabCur.OrderingProvLName,_medLabCur.OrderingProvFName);//must have both LName and FName
						if(listProvs.Count>0) {//use the first provider found with matching LName and FName
							_medLabCur.ProvNum=listProvs[0].ProvNum;
						}
						#endregion Locate Provider
						continue;
					case "specimenID":
						if(_medLabCur.SpecimenID!=null && _medLabCur.SpecimenID!="") {//could be filled in by value in OBR
							continue;
						}
						_medLabCur.SpecimenID=orcSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "specimenIDFiller":
						if(_medLabCur.SpecimenIDFiller!=null && _medLabCur.SpecimenIDFiller!="") {//could be filled in by value in OBR
							continue;
						}
						_medLabCur.SpecimenIDFiller=orcSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					default:
						continue;
				}
			}
			return;
		}
Пример #10
0
		///<summary></summary>
		public static void ProcessOBR(HL7DefSegment segDef,SegmentHL7 obrSeg,MessageHL7 obrMsg) {
			char subcompChar='&';
			if(obrMsg.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=obrMsg.Delimiters[3];
			}
			for(int i=0;i<segDef.hl7DefFields.Count;i++) {
				HL7DefField fieldDefCur=segDef.hl7DefFields[i];
				FieldHL7 fieldCur=obrSeg.GetField(fieldDefCur.OrdinalPos);//fieldCur can be null
				if(fieldCur==null) {
					continue;
				}
				switch(fieldDefCur.FieldName) {
					case "clinicalInfo":
						if(_isFirstObr) {
							_medLabCur.ClinicalInfo=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos).Trim();
						}
						continue;
					case "dateTimeCollected":
						_medLabCur.DateTimeCollected=FieldParserMedLab.DateTimeParse(obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						continue;
					case "dateTimeEntered":
						_medLabCur.DateTimeEntered=FieldParserMedLab.DateTimeParse(obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						continue;
					case "dateTimeReported":
						_medLabCur.DateTimeReported=FieldParserMedLab.DateTimeParse(obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						continue;
					case "facilityID":
						string facIdCur=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						if(facIdCur=="") {
							continue;
						}
						if(!_dictFacilityCodeNum.ContainsKey(facIdCur)) {//no ZPS segments with this footnote ID
							continue;
						}
						List<long> facNumList=_dictFacilityCodeNum[facIdCur];//should only be one facility with this footnote ID in this message
						for(int j=0;j<facNumList.Count;j++) {
							MedLabFacAttach medLabAttachCur=new MedLabFacAttach();
							medLabAttachCur.MedLabFacilityNum=facNumList[j];
							medLabAttachCur.MedLabNum=_medLabCur.MedLabNum;
							MedLabFacAttaches.Insert(medLabAttachCur);
						}
						continue;
					case "obsTestID":
						if(obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos,2).ToLower()=="l") {
							_medLabCur.ObsTestID=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
							_medLabCur.ObsTestDescript=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos,1);
						}
						if(obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos,5).ToLower()=="ln") {
							_medLabCur.ObsTestLoinc=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos,3);
							_medLabCur.ObsTestLoincText=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos,4);
						}
						continue;
					case "orderingProv":
						if(_medLabCur.OrderingProvNPI==null || _medLabCur.OrderingProvNPI=="") {//may be filled from the ORC segment
							_medLabCur.OrderingProvNPI=FieldParserMedLab.OrderingProvIDParse(fieldCur,"N");
						}
						if(_medLabCur.OrderingProvLocalID==null || _medLabCur.OrderingProvLocalID=="") {//may be filled from the ORC segment
							_medLabCur.OrderingProvLocalID=FieldParserMedLab.OrderingProvIDParse(fieldCur,"L");
						}
						int k=0;
						if(_medLabCur.OrderingProvLName==null || _medLabCur.OrderingProvLName=="") {//may be filled from the ORC segment
							_medLabCur.OrderingProvLName=fieldCur.GetComponentVal(1).Trim();
							while(_medLabCur.OrderingProvLName=="" && k<fieldCur.ListRepeatFields.Count) {//if LName is not present in first repetition check others
								_medLabCur.OrderingProvLName=fieldCur.ListRepeatFields[k].GetComponentVal(1).Trim();
								k++;
							}
						}
						k=0;
						if(_medLabCur.OrderingProvFName==null || _medLabCur.OrderingProvFName=="") {//may be filled from the ORC segment
							_medLabCur.OrderingProvFName=fieldCur.GetComponentVal(2).Trim();
							while(_medLabCur.OrderingProvFName=="" && k<fieldCur.ListRepeatFields.Count) {//if FName is not present in first repetition check others
								_medLabCur.OrderingProvFName=fieldCur.ListRepeatFields[k].GetComponentVal(2).Trim();
								k++;
							}
						}
						#region Locate Provider
						if(_medLabCur.ProvNum!=0) {//may have located the provider from the ORC segment, nothing left to do
							continue;
						}
						_medicaidIdCur=FieldParserMedLab.OrderingProvIDParse(fieldCur,"P");
						List<Provider> listProvs=Providers.GetProvsByNpiOrMedicaidId(_medLabCur.OrderingProvNPI,_medicaidIdCur);
						listProvs.Sort(SortByNpiMedicaidIdMatch);
						if(listProvs.Count>0) {//if a provider with either a matching NPI or Medicaid ID is found, use the first matching prov
							_medLabCur.ProvNum=listProvs[0].ProvNum;
						}
						else {//no provider match based on NPI or MedicaidID
							listProvs=Providers.GetProvsByFLName(_medLabCur.OrderingProvLName,_medLabCur.OrderingProvFName);//must have both LName and FName
							if(listProvs.Count>0) {//use the first provider found with matching LName and FName
								_medLabCur.ProvNum=listProvs[0].ProvNum;
							}
						}
						#endregion Locate Provider
						continue;
					case "parentObsID":
						_medLabCur.ParentObsID=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "parentObsTestID":
						_medLabCur.ParentObsTestID=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "resultStatus":
						_medLabCur.ResultStatus=FieldParserMedLab.ResultStatusParse(obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						continue;
					case "specimenAction":
						_medLabCur.ActionCode=FieldParserMedLab.ResultActionParse(obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos));
						continue;
					case "specimenID":
						if(_medLabCur.SpecimenID!=null && _medLabCur.SpecimenID!="") {//could be filled by value in ORC
							continue;
						}
						_medLabCur.SpecimenID=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "specimenIDAlt":
						_medLabCur.SpecimenIDAlt=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "specimenIDFiller":
						if(_medLabCur.SpecimenIDFiller!=null && _medLabCur.SpecimenIDFiller!="") {//could be filled by value in ORC
							continue;
						}
						_medLabCur.SpecimenIDFiller=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						continue;
					case "totalVolume":
						_medLabCur.TotalVolume=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos);
						if(_medLabCur.TotalVolume=="") {
							continue;
						}
						string[] unitsSubComp=obrSeg.GetFieldComponent(fieldDefCur.OrdinalPos,1).Split(new char[] { subcompChar },StringSplitOptions.None);
						if(unitsSubComp.Length==0 || unitsSubComp[0]=="") {
							_medLabCur.TotalVolume+=" ml";
							continue;
						}
						_medLabCur.TotalVolume+=" "+unitsSubComp[0];
						continue;
					default:
						continue;
				}
			}
			_isFirstObr=false;
			return;
		}