Пример #1
0
		///<summary>Patient visit.</summary>
		private void PV1(long aptNum,long provNum){
			seg=new SegmentHL7(SegmentNameHL7.PV1);
			seg.SetField(0,"PV1");
			Provider prov=Providers.GetProv(provNum);
			seg.SetField(7,prov.EcwID,prov.LName,prov.FName,prov.MI);
			seg.SetField(19,aptNum.ToString());
			msg.Segments.Add(seg);
		}
		///<summary>Returns null if there is no DFT defined for the enabled HL7Def.</summary>
		public static MessageHL7 GenerateDFT(List<Procedure> procList,EventTypeHL7 eventType,Patient pat,Patient guar,long aptNum,string pdfDescription,string pdfDataString) {//add event (A04 etc) parameters later if needed
			//In \\SERVERFILES\storage\OPEN DENTAL\Programmers Documents\Standards (X12, ADA, etc)\HL7\Version2.6\V26_CH02_Control_M4_JAN2007.doc
			//On page 28, there is a Message Construction Pseudocode as well as a flowchart which might help.
			Provider prov=Providers.GetProv(Patients.GetProvNum(pat));
			Appointment apt=Appointments.GetOneApt(aptNum);
			MessageHL7 messageHL7=new MessageHL7(MessageTypeHL7.DFT);
			HL7Def hl7Def=HL7Defs.GetOneDeepEnabled();
			if(hl7Def==null) {
				return null;
			}
			//find a DFT message in the def
			HL7DefMessage hl7DefMessage=null;
			for(int i=0;i<hl7Def.hl7DefMessages.Count;i++) {
				if(hl7Def.hl7DefMessages[i].MessageType==MessageTypeHL7.DFT) {
					hl7DefMessage=hl7Def.hl7DefMessages[i];
					//continue;
					break;
				}
			}
			if(hl7DefMessage==null) {//DFT message type is not defined so do nothing and return
				return null;
			}
			for(int s=0;s<hl7DefMessage.hl7DefSegments.Count;s++) {
				int countRepeat=1;
				if(hl7DefMessage.hl7DefSegments[s].SegmentName==SegmentNameHL7.FT1) {
					countRepeat=procList.Count;
				}
				//for example, countRepeat can be zero in the case where we are only sending a PDF of the TP to eCW, and no procs.
				for(int repeat=0;repeat<countRepeat;repeat++) {//FT1 is optional and can repeat so add as many FT1's as procs in procList
					//if(hl7DefMessage.hl7DefSegments[s].SegmentName==SegmentNameHL7.FT1) {
					if(hl7DefMessage.hl7DefSegments[s].SegmentName==SegmentNameHL7.FT1 && procList.Count>repeat) {
						prov=Providers.GetProv(procList[repeat].ProvNum);
					}
					SegmentHL7 seg=new SegmentHL7(hl7DefMessage.hl7DefSegments[s].SegmentName);
					seg.SetField(0,hl7DefMessage.hl7DefSegments[s].SegmentName.ToString());
					for(int f=0;f<hl7DefMessage.hl7DefSegments[s].hl7DefFields.Count;f++) {
						string fieldName=hl7DefMessage.hl7DefSegments[s].hl7DefFields[f].FieldName;
						if(fieldName=="") {//If fixed text instead of field name just add text to segment
							seg.SetField(hl7DefMessage.hl7DefSegments[s].hl7DefFields[f].OrdinalPos,hl7DefMessage.hl7DefSegments[s].hl7DefFields[f].FixedText);
						}
						else {
							//seg.SetField(hl7DefMessage.hl7DefSegments[s].hl7DefFields[f].OrdinalPos,
							//FieldConstructor.GenerateDFT(hl7Def,fieldName,pat,prov,procList[repeat],guar,apt,repeat+1,eventType,pdfDescription,pdfDataString));
							Procedure proc=null;
							if(procList.Count>repeat) {//procList could be an empty list
								proc=procList[repeat];
							}
							seg.SetField(hl7DefMessage.hl7DefSegments[s].hl7DefFields[f].OrdinalPos,
								FieldConstructor.GenerateDFT(hl7Def,fieldName,pat,prov,proc,guar,apt,repeat+1,eventType,pdfDescription,pdfDataString));
						}
					}
					messageHL7.Segments.Add(seg);
				}
			}
			return messageHL7;
		}
Пример #3
0
Файл: EhrORU.cs Проект: mnisl/OD
		///<summary>Message Header Segment</summary>
		private void MSH(){
			seg=new SegmentHL7(@"MSH|^~\&|Open Dental|"//MSH-3: Sending application
				+"OD|"//MSH-4: Sending Facility. Dummy.
				+"Y|"//MSH-5: Receiving Application.  Dummy.
				+"OU|"//MSH-6: Receiving Facility. Dummy.
				+DateTime.Now.ToString("yyyyMMddHHmmss")+"||"
				+"ORU^R01^ORU_R01|"//MSH-9: fixed
				+DateTime.Now.ToString("yyyyMMddHHmmss")+"|"//MSH-10: Control Id, str20. Fixed is ok for testing. We'll send date
				+"P|"//MSH-11: P=production
				+"2.3.1");
			msg.Segments.Add(seg);
		}
Пример #4
0
 public static void ProcessIN1(Patient pat,SegmentHL7 seg)
 {
     //as a general strategy, if certain things are the same, like subscriber and carrier,
     //then we change the existing plan.
     //However, if basics change at all, then we drop the old plan and create a new one
     int ordinal=PIn.Int(seg.GetFieldFullText(1));
     PatPlan oldPatPlan=PatPlans.GetPatPlan(pat.PatNum,ordinal);
     if(oldPatPlan==null) {
         //create a new plan and a new patplan
     }
     //InsPlan oldPlan=InsPlans.g
     //we'll have to get back to this.  This is lower priority than appointments.
 }
Пример #5
0
		public MessageHL7(string msgtext) {
			AckCode="";
			ControlId="";
			AckEvent="";
			originalMsgText=msgtext;
			Segments=new List<SegmentHL7>();
			string[] rows=msgtext.Split(new string[] { "\r","\n" },StringSplitOptions.RemoveEmptyEntries);
			//We need to get the separator characters in order to create the field objects.
			//The separators are part of the MSH segment and we force users to leave them in position 1 for incoming messages.
			Delimiters=new char[] { '^','~','\\','&' };//this is the default, but we will get them from the MSH segment of the incoming message in case they are using something unique.
			for(int i=0;i<rows.Length;i++) {
				string[] fields=rows[i].Split(new string[] { "|" },StringSplitOptions.None);
				if(fields.Length>1 && fields[0]=="MSH" && fields[1].Length>0) {
					//Encoding characters are in the following order:  component separator, repetition separator, escape character, subcomponent separator
					Delimiters=fields[1].ToCharArray();//we force users to leave the delimiters in position 1 of the MSH segment
					break;
				}
			}
			SegmentHL7 segment;
			for(int i=0;i<rows.Length;i++) {
				segment=new SegmentHL7(rows[i],Delimiters);//this creates the field objects.
				Segments.Add(segment);
				if(i==0 && segment.Name==SegmentNameHL7.MSH) {
//js 7/3/12 Make this more intelligent because we also now need the suffix
					string msgtype=segment.GetFieldComponent(8,0);//We force the user to leave the 'messageType' field in this position, position 8 of the MSH segment
					string evnttype=segment.GetFieldComponent(8,1);
					string msgStructure=segment.GetFieldComponent(8,2);
					AckEvent=evnttype;//We will use this when constructing the acknowledgment to echo back to sender the same event type sent to us
					//If message type or event type are not in this list, they will default to the not supported type and will not be processed
					try {
						MsgType=(MessageTypeHL7)Enum.Parse(typeof(MessageTypeHL7),msgtype,true);
					}
					catch(Exception ex) {
						MsgType=MessageTypeHL7.NotDefined;
					}
					try {
						EventType=(EventTypeHL7)Enum.Parse(typeof(EventTypeHL7),evnttype,true);
					}
					catch(Exception ex) {
						EventType=EventTypeHL7.NotDefined;
					}
					try {
						MsgStructure=(MessageStructureHL7)Enum.Parse(typeof(MessageStructureHL7),msgStructure,true);
					}
					catch(Exception ex) {
						MsgStructure=MessageStructureHL7.NotDefined;
					}
				}
			}
		}
Пример #6
0
Файл: EhrORU.cs Проект: mnisl/OD
		///<summary>Patient identification.</summary>
		private void PID(Patient pat){
			seg=new SegmentHL7(SegmentNameHL7.PID);
			seg.SetField(0,"PID");
			seg.SetField(2,pat.PatNum.ToString());
			seg.SetField(3,pat.PatNum.ToString());
			seg.SetField(5,pat.LName,pat.FName);
			if(pat.Birthdate.Year>1880) {//7: dob optional
				seg.SetField(7,pat.Birthdate.ToString("yyyyMMdd"));
			}
			seg.SetField(8,ConvertGender(pat.Gender));
			seg.SetField(10,ConvertRace(PatientRaces.GetPatientRaceOldFromPatientRaces(pat.PatNum)));//Converts entries from PatientRace table to deprecated PatientRaceOld for call.
			seg.SetField(11,pat.Address,pat.Address2,pat.City,pat.State,pat.Zip,"","M");//M is for mailing.
			seg.SetField(13,ConvertPhone(pat.HmPhone));
			seg.SetField(22,ConvertEthnicGroup(PatientRaces.GetPatientRaceOldFromPatientRaces(pat.PatNum)));//Converts entries from PatientRace table to deprecated PatientRaceOld for call.
			msg.Segments.Add(seg);
		}
Пример #7
0
		///<summary>Event Type segment.  Used to communicate trigger event information to receiving applications.  Guide page 38.</summary>
		private void EVN() {
			_seg=new SegmentHL7(SegmentNameHL7.EVN);
			_seg.SetField(0,"EVN");
			//EVN-1 Event Type Code.  No longer used.
			_seg.SetField(2,DateTime.Now.ToString("yyyyMMddHHmmss"));//EVN-2 Recorded Date/Time.  Required (length 12..26).
			//EVN-3 Date/Time Planned Event.  No longer used.
			//EVN-4 Event Reason Code.  No longer used.
			//EVN-5 Operator ID.  No longer used.
			//EVN-6 Event Occurred.  No longer used.
			//EVN-7 Event Facility.  Required (length 1..241).  This is the location where the patient received treatment.
			_seg.SetField(7,
				_sendingFacilityName,//EVN-7.1 Namespace ID.  The name of the originating facility.
				_sendingFacilityNpi,//EVN-7.2 Universal ID.  Suggested value is NPI.
				"NPI"//EVN-7.3 Universal ID Type.
			);
			_msg.Segments.Add(_seg);
		}
Пример #8
0
		///<summary>Patient identification.</summary>
		private void PID(Patient pat){
			seg=new SegmentHL7(SegmentNameHL7.PID);
			seg.SetField(0,"PID");
			seg.SetField(1,"1");
			seg.SetField(2,pat.ChartNumber);//Account number.  eCW requires this to be the same # as came in on PID.4.
			seg.SetField(3,pat.PatNum.ToString());//??what is this MRN?
			seg.SetField(5,pat.LName,pat.FName,pat.MiddleI);
			//we assume that dob is always valid because eCW should always pass us a dob.
			seg.SetField(7,pat.Birthdate.ToString("yyyyMMdd"));
			seg.SetField(8,ConvertGender(pat.Gender));
			seg.SetField(10,ConvertRace(PatientRaces.GetPatientRaceOldFromPatientRaces(pat.PatNum)));//Passes in the deprecated PatientRaceOld enum retrieved from the PatientRace table.
			seg.SetField(11,pat.Address,pat.Address2,pat.City,pat.State,pat.Zip);
			seg.SetField(13,ConvertPhone(pat.HmPhone));
			seg.SetField(14,ConvertPhone(pat.WkPhone));
			seg.SetField(16,ConvertMaritalStatus(pat.Position));
			seg.SetField(19,pat.SSN);
			msg.Segments.Add(seg);
		}
Пример #9
0
Файл: EcwDFT.cs Проект: mnisl/OD
		///<summary>Financial transaction segment.</summary>
		private void FT1(long aptNum,bool justPDF){
			if(justPDF){
				return;//FT1 segment is not necessary when sending only a PDF.
			}
			List<Procedure> procs=Procedures.GetProcsForSingle(aptNum,false);
			ProcedureCode procCode;
			for(int i=0;i<procs.Count;i++) {
				seg=new SegmentHL7(SegmentNameHL7.FT1);
				seg.SetField(0,"FT1");
				seg.SetField(1,(i+1).ToString());
				seg.SetField(4,procs[i].ProcDate.ToString("yyyyMMddHHmmss"));
				seg.SetField(5,procs[i].ProcDate.ToString("yyyyMMddHHmmss"));
				seg.SetField(6,"CG");
				seg.SetField(10,"1.0");
				seg.SetField(16,"");//location code and description???
				seg.SetField(19,procs[i].DiagnosticCode);
				Provider prov=Providers.GetProv(procs[i].ProvNum);
				seg.SetField(20,prov.EcwID,prov.LName,prov.FName,prov.MI);//performed by provider.
				seg.SetField(21,prov.EcwID,prov.LName,prov.FName,prov.MI);//ordering provider.
				seg.SetField(22,procs[i].ProcFee.ToString("F2"));
				procCode=ProcedureCodes.GetProcCode(procs[i].CodeNum);
				if(procCode.ProcCode.Length>5 && procCode.ProcCode.StartsWith("D")) {
					seg.SetField(25,procCode.ProcCode.Substring(0,5));//Remove suffix from all D codes.
				}
				else {
					seg.SetField(25,procCode.ProcCode);
				}
				if(procCode.TreatArea==TreatmentArea.ToothRange){
					seg.SetField(26,procs[i].ToothRange,"");
				}
				else if(procCode.TreatArea==TreatmentArea.Surf){//probably not necessary
					seg.SetField(26,Tooth.ToInternat(procs[i].ToothNum),Tooth.SurfTidyForClaims(procs[i].Surf,procs[i].ToothNum));
				}
				else if(procCode.TreatArea==TreatmentArea.Quad && ProgramProperties.GetPropVal(Programs.GetProgramNum(ProgramName.eClinicalWorks),"IsQuadAsToothNum")=="1") {
					seg.SetField(26,procs[i].Surf,"");
				}
				else{
					seg.SetField(26,Tooth.ToInternat(procs[i].ToothNum),procs[i].Surf);
				}
				msg.Segments.Add(seg);
			}
		}
Пример #10
0
		public MessageHL7(string msgtext) {
			AckCode="";
			ControlId="";
			AckEvent="";
			originalMsgText=msgtext;
			Segments=new List<SegmentHL7>();
			string[] rows=msgtext.Split(new string[] { "\r","\n" },StringSplitOptions.RemoveEmptyEntries);
			SegmentHL7 segment;
			for(int i=0;i<rows.Length;i++) {
				segment=new SegmentHL7(rows[i]);//this creates the field objects.
				Segments.Add(segment);
				if(i==0 && segment.Name==SegmentNameHL7.MSH) {
//js 7/3/12 Make this more intelligent because we also now need the suffix
					string msgtype=segment.GetFieldComponent(8,0);//We force the user to leave the 'messageType' field in this position, position 8 of the MSH segment
					string evnttype=segment.GetFieldComponent(8,1);
					AckEvent=evnttype;//We will use this when constructing the acknowledgment to echo back to sender the same event type sent to us
					//If message type or event type are not in this list, they will default to the not supported type and will not be processed
					if(msgtype==MessageTypeHL7.ADT.ToString()) {
						MsgType=MessageTypeHL7.ADT;
					}
					else if(msgtype==MessageTypeHL7.ACK.ToString()) {
						MsgType=MessageTypeHL7.ACK;
					}
					else if(msgtype==MessageTypeHL7.SIU.ToString()) {
						MsgType=MessageTypeHL7.SIU;
					}
					else if(msgtype==MessageTypeHL7.DFT.ToString()) {
						MsgType=MessageTypeHL7.DFT;
					}
					if(evnttype==EventTypeHL7.A04.ToString()) {
						EventType=EventTypeHL7.A04;
					}
					else if(evnttype==EventTypeHL7.P03.ToString()) {
						EventType=EventTypeHL7.P03;
					}
					else if(evnttype==EventTypeHL7.S12.ToString()) {
						EventType=EventTypeHL7.S12;
					}
				}
			}
		}
Пример #11
0
        private string originalMsgText; //We'll store this for now, but I don't think we'll use it.

        #endregion Fields

        #region Constructors

        public MessageHL7(string msgtext)
        {
            originalMsgText=msgtext;
            Segments=new List<SegmentHL7>();
            string[] rows=msgtext.Split(new string[] { "\r\n" },StringSplitOptions.RemoveEmptyEntries);
            SegmentHL7 segment;
            for(int i=0;i<rows.Length;i++) {
                segment=new SegmentHL7(rows[i]);//this creates the field objects.
                Segments.Add(segment);
                if(i==0 && segment.Name==SegmentName.MSH) {
                    string msgtype=segment.GetFieldComponent(8,0);
                    if(msgtype=="ADT") {
                        MsgType=MessageType.ADT;
                    }
                    else if(msgtype=="SIU") {
                        MsgType=MessageType.SIU;
                    }
                    else if(msgtype=="DFT") {
                        MsgType=MessageType.DFT;
                    }
                }
            }
        }
Пример #12
0
		///<summary>PatNum will not be altered here.  The pat passed in must either have PatNum=0, or must have a PatNum matching the segment.  The reason that isStandalone is passed in is because if using tight integration mode (isStandalone=false), then we need to store the "alternate patient id" aka Account No. that comes in on PID.4 in the ChartNumber field so we can pass it back in PID.2 of the DFT charge message.  However, if not using tight integration (isStandalone=true), the ChartNumber field is already occupied by the eCW patient ID, and we do not want to overwrite it.</summary>
		public static void ProcessPID(Patient pat,SegmentHL7 seg,bool isStandalone,List<PatRace> listPatRaces) {
			long patNum=PIn.Long(seg.GetFieldFullText(2));
			//if(pat.PatNum==0) {
			//	pat.PatNum=patNum;
			//}
			//else 
			if(!isStandalone //in standalone, the patnums won't match, so don't check
				&& pat.PatNum!=0 && pat.PatNum!=patNum) 
			{
				throw new ApplicationException("Invalid patNum");
			}
			if(!isStandalone) {//when in tight integration mode
				pat.ChartNumber=seg.GetFieldFullText(4);
			}
			pat.LName=seg.GetFieldComponent(5,0);
			pat.FName=seg.GetFieldComponent(5,1);
			pat.MiddleI=seg.GetFieldComponent(5,2);
			pat.Birthdate=DateParse(seg.GetFieldFullText(7));
			pat.Gender=GenderParse(seg.GetFieldFullText(8));
			PatientRaceOld patientRaceOld=RaceParse(seg.GetFieldFullText(10));
			//Converts PatientRaceOld to new Patient Races, and adds them to the PatientRace table.
			listPatRaces.AddRange(PatientRaces.GetPatRacesFromPatientRaceOld(patientRaceOld));
			pat.Address=seg.GetFieldComponent(11,0);
			pat.Address2=seg.GetFieldComponent(11,1);
			pat.City=seg.GetFieldComponent(11,2);
			pat.State=seg.GetFieldComponent(11,3);
			pat.Zip=seg.GetFieldComponent(11,4);
			pat.HmPhone=PhoneParse(seg.GetFieldFullText(13));
			pat.WkPhone=PhoneParse(seg.GetFieldFullText(14));
			pat.Position=MaritalStatusParse(seg.GetFieldFullText(16));
			//pat.ChartNumber=seg.GetFieldFullText(18);//this is wrong.  Would also break standalone mode
			pat.SSN=seg.GetFieldFullText(19);
			if(ProgramProperties.GetPropVal(ProgramName.eClinicalWorks,"FeeSchedulesSetManually")=="0") {//if !FeeSchedulesSetManually
				pat.FeeSched=FeeScheduleParse(seg.GetFieldFullText(22));
			}
		}
Пример #13
0
		///<summary>Observation Result segment.  Required if known.  The basic format is question and answer.  Guide page 116.</summary>
		private void OBX(VaccinePat vaccine) {
			List<VaccineObs> listVaccineObservations=VaccineObses.GetForVaccine(vaccine.VaccinePatNum);
			for(int i=0;i<listVaccineObservations.Count;i++) {
				VaccineObs vaccineObs=listVaccineObservations[i];
				_seg=new SegmentHL7(SegmentNameHL7.OBX);
				_seg.SetField(0,"OBX");
				_seg.SetField(1,(i+1).ToString());//OBX-1 Set ID - OBX.  Required (length 1..4).  Cardinality [1..1].
				//OBX-2 Value Type.  Required (length 2..3).  Cardinality [1..1].  Value Set HL70125 (constrained, not in guide).  CE=Coded Entry,DT=Date,NM=Numeric,ST=String,TS=Time Stamp (Date & Time).
				if(vaccineObs.ValType==VaccineObsType.Dated) {
					_seg.SetField(2,"DT");
				}
				else if(vaccineObs.ValType==VaccineObsType.Numeric) {
					_seg.SetField(2,"NM");
				}
				else if(vaccineObs.ValType==VaccineObsType.Text) {
					_seg.SetField(2,"ST");
				}
				else if(vaccineObs.ValType==VaccineObsType.DateAndTime) {
					_seg.SetField(2,"TS");
				}
				else { //vaccineObs.ValType==VaccineObsType.Coded
					_seg.SetField(2,"CE");
				}
				//OBX-3 Observation Identifier.  Required.  Cardinality [1..1].  Value set NIP003 (25 items).  Type CE.  Purpose is to pose the question that is answered by OBX-5.
				if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.DatePublished) {
					WriteCE(3,"29768-9","Date vaccine information statement published","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.DatePresented) {
					WriteCE(3,"29769-7","Date vaccine information statement presented","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.DatePrecautionExpiration) {
					WriteCE(3,"30944-3","Date of vaccination temporary contraindication and or precaution expiration","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.Precaution) {
					WriteCE(3,"30945-0","Vaccination contraindication and or precaution","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.DatePrecautionEffective) {
					WriteCE(3,"30946-8","Date vaccination contraindication and or precaution effective","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.TypeOf) {
					WriteCE(3,"30956-7","Vaccine Type","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.FundsPurchasedWith) {
					WriteCE(3,"30963-3","Funds vaccine purchased with","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.DoseNumber) {
					WriteCE(3,"30973-2","Dose number","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.NextDue) {
					WriteCE(3,"30979-9","Vaccines due next","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.DateDue) {
					WriteCE(3,"30980-7","Date vaccine due","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.DateEarliestAdminister) {
					WriteCE(3,"30981-5","Earliest date to give","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.ReasonForcast) {
					WriteCE(3,"30982-3","Reason applied by forcast logic to project this vaccine","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.Reaction) {
					WriteCE(3,"31044-1","Reaction","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.ComponentType) {
					WriteCE(3,"38890-0","Vaccine component type","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.TakeResponseType) {
					WriteCE(3,"46249-9","Vaccination take-response type","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.DateTakeResponse) {
					WriteCE(3,"46250-7","Vaccination take-response date","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.ScheduleUsed) {
					WriteCE(3,"59779-9","Immunization schedule used","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.Series) {
					WriteCE(3,"59780-7","Immunization series","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.DoseValidity) {
					WriteCE(3,"59781-5","Dose validity","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.NumDosesPrimary) {
					WriteCE(3,"59782-3","Number of doses in primary immunization series","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.StatusInSeries) {
					WriteCE(3,"59783-1","Status in immunization series","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.DiseaseWithImmunity) {
					WriteCE(3,"59784-9","Disease with presumed immunity","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.Indication) {
					WriteCE(3,"59785-6","Indication for Immunization","LN");
				}
				else if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.FundPgmEligCat) {
					WriteCE(3,"64994-7","Vaccine funding program eligibility category","LN");
				}
				else { //vaccineObs.IdentifyingCode==VaccineObsIdentifier.DocumentType
					WriteCE(3,"69764-9","Document type","LN");
				}
				//OBX-4 Observation Sub-ID.  Required (length 1..20).  Cardinality [1..1].  Type ST.
				if(vaccineObs.VaccineObsNumGroup==0) {
					_seg.SetField(4,vaccineObs.VaccineObsNum.ToString());
				}
				else {//vaccineObs.VaccineObsNumGroup!=0
					_seg.SetField(4,vaccineObs.VaccineObsNumGroup.ToString());
				}
				//OBX-5 Observation Value.  Required. Cardinality [1..1].  Value set varies, depending on the value of OBX-2 (Use type CE if OBX-2 is "CE", otherwise treat as a string).  Purpose is to answer the quesiton posed by OBX-3.
				if(vaccineObs.ValType==VaccineObsType.Coded) {
					string codeDescript=vaccineObs.ValReported.Trim();//If we do not know the description, then the code will also be placed into the description. The testing tool required non-empty entries.
					if(vaccineObs.ValCodeSystem==VaccineObsValCodeSystem.CVX) {
						Cvx cvx=Cvxs.GetByCode(vaccineObs.ValReported);
						codeDescript=cvx.Description;
					}
					else if(vaccineObs.ValCodeSystem==VaccineObsValCodeSystem.HL70064) {
						if(vaccineObs.ValReported.ToUpper()=="V01") {
							codeDescript="Not VFC eligible";
						}
						else if(vaccineObs.ValReported.ToUpper()=="V02") {
							codeDescript="VFC eligible-Medicaid/Medicaid Managed Care";
						}
						else if(vaccineObs.ValReported.ToUpper()=="V03") {
							codeDescript="VFC eligible- Uninsured";
						}
						else if(vaccineObs.ValReported.ToUpper()=="V04") {
							codeDescript="VFC eligible- American Indian/Alaskan Native";
						}
						else if(vaccineObs.ValReported.ToUpper()=="V05") {
							codeDescript="VFC eligible-Federally Qualified Health Center Patient (under-insured)";
						}
						else if(vaccineObs.ValReported.ToUpper()=="V06") {
							codeDescript="Deprecated [VFC eligible- State specific eligibility (e.g. S-CHIP plan)]";
						}
						else if(vaccineObs.ValReported.ToUpper()=="V07") {
							codeDescript="Local-specific eligibility";
						}
						else if(vaccineObs.ValReported.ToUpper()=="V08") {
							codeDescript="Deprecated [Not VFC eligible-underinsured]";
						}
					}
					WriteCE(5,vaccineObs.ValReported.Trim(),codeDescript,vaccineObs.ValCodeSystem.ToString());
				}
				else if(vaccineObs.ValType==VaccineObsType.Dated) {
					DateTime dateVal=DateTime.Parse(vaccineObs.ValReported.Trim());
					_seg.SetField(5,dateVal.ToString("yyyyMMdd"));
				}
				else if(vaccineObs.ValType==VaccineObsType.Numeric) {
					_seg.SetField(5,vaccineObs.ValReported.Trim());
				}
				else if(vaccineObs.ValType==VaccineObsType.DateAndTime) {
					DateTime dateVal=DateTime.Parse(vaccineObs.ValReported.Trim());
					string strDateOut=dateVal.ToString("yyyyMMdd");
					//The testing tool threw errors when there were trailing zeros, even though technically valid.
					if(dateVal.Second>0) {
						strDateOut+=dateVal.ToString("HHmmss");
					}
					else if(dateVal.Minute>0) {
						strDateOut+=dateVal.ToString("HHmm");
					}
					else if(dateVal.Hour>0) {
						strDateOut+=dateVal.ToString("HH");
					}
					_seg.SetField(5,strDateOut);
				}
				else { //vaccineObs.ValType==VaccineObsType.Text
					_seg.SetField(5,vaccineObs.ValReported);
				}
				//OBX-6 Units.  Required if OBX-2 is "NM" or "SN" (SN appears to be missing from definition).
				if(vaccineObs.ValType==VaccineObsType.Numeric) {
					Ucum ucum=Ucums.GetByCode(vaccineObs.UcumCode);
					WriteCE(6,ucum.UcumCode,ucum.Description,"UCUM");
				}
				//OBX-7 References Range.  Optional.
				//OBX-8 Abnormal Flags.  Optional.
				//OBX-9 Probability.  Optional.
				//OBX-10 Nature of Abnormal Test.  Optional.
				_seg.SetField(11,"F");//OBX-11 Observation Result Status.  Required (length 1..1).  Cardinality [1..1].  Value set HL70085 (constrained, guide page 198).  We are expected to use value F=Final.
				//OBX-12 Effective Date of Reference Range Values.  Optional.
				//OBX-13 User Defined Access Checks.  Optional.
				//OBX-14 Date/Time of the Observation.  Required if known.  Cardinality [0..1].
				if(vaccineObs.DateObs.Year>1880) {
					_seg.SetField(14,vaccineObs.DateObs.ToString("yyyyMMdd"));
				}
				//OBX-15 Producer's Reference.  Optional.
				//OBX-16 Responsible Observer.  Optional.
				//OBX-17 Observation Method.  Required if OBX-3.1 is “64994-7”.  Value set CDCPHINVS. Type CE.
				if(vaccineObs.IdentifyingCode==VaccineObsIdentifier.FundPgmEligCat) {
					_seg.SetField(17,vaccineObs.MethodCode.Trim(),"","CDCPHINVS");
				}
				//OBX-18 Equipment Instance Identifier.  Optional.
				//OBX-19 Date/Time of the Analysis.  Optional.
				//OBX-20 Reserved for harmonization with V2.6.  Optional.
				//OBX-21 Reserved for harmonization with V2.6.  Optional.
				//OBX-22 Reserved for harmonization with V2.6.  Optional.
				//OBX-23 Performing Organization Name.  Optional.
				//OBX-24 Performing Organization Address.  Optional.
				//OBX-25 Performing Organization Medical Director.  Optional.
				_msg.Segments.Add(_seg);
			}
		}
Пример #14
0
 ///<summary>Message Header Segment</summary>
 private void MSH()
 {
     seg = new SegmentHL7(@"MSH|^~\&|OD||ECW||" + DateTime.Now.ToString("yyyyMMddHHmmss") + "||DFT^P03||P|2.3");
     msg.Segments.Add(seg);
 }
Пример #15
0
 ///<summary>PDF data segment.</summary>
 private void ZX1(string pdfDataAsBase64,string pdfDescription)
 {
     seg=new SegmentHL7(SegmentName.ZX1);
     seg.SetField(0,"ZX1");
     seg.SetField(1,"6");
     seg.SetField(2,"PDF");
     seg.SetField(3,"PATHOLOGY^Pathology Report^L");
     seg.SetField(4,pdfDescription);
     seg.SetField(5,pdfDataAsBase64);
     msg.Segments.Add(seg);
 }
Пример #16
0
 ///<summary>Event type segment.</summary>
 private void EVN()
 {
     seg=new SegmentHL7("EVN|P03|"+DateTime.Now.ToString("yyyyMMddHHmmss")+"|");
     msg.Segments.Add(seg);
 }
Пример #17
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;
		}
Пример #18
0
        ///<summary>Patient Identifier segment.  Required.  Guide page 40.</summary>
        private void PID()
        {
            _seg = new SegmentHL7(SegmentNameHL7.PID);
            _seg.SetField(0, "PID");
            _seg.SetField(1, "1");           //PID-1 Set ID - PID.  Optional.  Cardinality [0..1].  Must be "1" for the first occurrence.  Not sure why there would ever be more than one.
            //PID-2 Patient ID.  No longer used.
            //PID-3 Patient Identifier List.  Required (length up to 478).  Cardinality [1..*].  Type CX.
            _seg.SetField(3,
                          _pat.PatNum.ToString(), //PID-3.1 ID Number.  Required (length 1..15).
                          "",                     //PID-3.2 Check Digit.  Optional (length 1..1).
                          "",                     //PID-3.3 Check Digit Scheme.  No longer used.
                          "Open Dental",          //PID-3.4 Assigning Authority.  Required (1..227).  Value set HL70363.
                          "MR"                    //PID-3.5 Identifier Type Code.  Required (length 2..5).  Value set HL70203.  MR=medical record number.
                                                  //PID-3.6 Assigning Facility.  Optional (length 1..227).
                                                  //PID-3.7 Effective Date.  No longer used.
                                                  //PID-3.8 Expiration Date.  No longer used.
                                                  //PID-3.9 Assigning Jurisdiction.  No longer used.
                                                  //PID-3.10 Assigning Facility.  No longer used.
                          );
            if (_pat.SSN.Trim() != "")
            {
                _seg.RepeatField(3,
                                 _pat.SSN.Trim(), //PID-3.1 ID Number.  Required (length 1..15).
                                 "",              //PID-3.2 Check Digit.  Optional (length 1..1).
                                 "",              //PID-3.3 Check Digit Scheme.  No longer used.
                                 "Open Dental",   //PID-3.4 Assigning Authority.  Required (length 1..227).  Value set HL70363.
                                 "SS"             //PID-3.5 Identifier Type Code.  Required (length 2..5).  Value set HL70203.  SS=Social Security Number.
                                                  //PID-3.6 Assigning Facility.  Optional (length 1..227).
                                                  //PID-3.7 Effective Date.  No longer used.
                                                  //PID-3.8 Expiration Date.  No longer used.
                                                  //PID-3.9 Assigning Jurisdiction.  No longer used.
                                                  //PID-3.10 Assigning Facility.  No longer used.
                                 );
            }
            //PID-4 Alternate Patient ID.  No longer used.
            //PID-5 Patient Name.  Required (length up to 294).  Cardinality [1..*].  Type XPN.  The first repetition must contain the legal name.
            WriteXPN(5, _pat.FName, _pat.LName, _pat.MiddleI, "L");
            //PID-6 Mother's Maiden Name.  No longer used.
            //PID-7 Date/Time of Birth.  Optional.  Cardinality [0..1].
            if (_pat.Birthdate.Year > 1880)
            {
                _seg.SetField(7, _pat.Birthdate.ToString("yyyyMMdd"));
            }
            WriteGender(8, _pat.Gender);           //PID-8 Administrative Sex.  Required if known.  Cardinality [0..1].  Value set HL70001.
            //PID-9 Patient Alias.  No longer used.
            //PID-10 Race.  Required if known.  Cardinality [0..*].  Value set HL70005.  Each race definition must be type CE.
            List <PatientRace> listPatientRaces     = PatientRaces.GetForPatient(_pat.PatNum);
            List <PatientRace> listPatRacesFiltered = new List <PatientRace>();
            bool isHispanicOrLatino = false;

            for (int i = 0; i < listPatientRaces.Count; i++)
            {
                if (listPatientRaces[i].IsEthnicity)
                {
                    if (listPatientRaces[i].CdcrecCode == "2186-5")                   //Not hispanic
                    //Nothing to do. Flag is set to false by default.
                    {
                    }
                    else if (listPatientRaces[i].CdcrecCode != PatientRace.DECLINE_SPECIFY_ETHNICITY_CODE)
                    {
                        isHispanicOrLatino = true;                      //All other ethnicities are Hispanic
                    }
                }
                else
                {
                    if (listPatientRaces[i].CdcrecCode == PatientRace.DECLINE_SPECIFY_RACE_CODE)
                    {
                        listPatRacesFiltered.Clear();
                        break;
                    }
                    listPatRacesFiltered.Add(listPatientRaces[i]);
                }
            }
            for (int i = 0; i < listPatRacesFiltered.Count; i++)
            {
                string strRaceCode = listPatRacesFiltered[i].CdcrecCode;
                string strRaceName = listPatRacesFiltered[i].Description;
                _seg.SetOrRepeatField(10,
                                      strRaceCode, //PID-10.1 Identifier.  Required (length 1..50).
                                      strRaceName, //PID-10.2  Text.  Required if known (length 1..999). Human readable text that is not further used.
                                      "CDCREC"     //PID-10.3 Name of Coding System.  Required (length 1..20).
                                                   //PID-10.4 Alternate Identifier.  Required if known (length 1..50).
                                                   //PID-10.5 Alternate Text.  Required if known (length 1..999).
                                                   //PID-10.6 Name of Alternate Coding system.  Required if PID-10.4 is not blank.
                                      );
            }
            //PID-11 Patient Address.  Required if known (length up to 513).  Cardinality [0..*].  Type XAD.
            WriteXAD(11, _pat.Address, _pat.Address2, _pat.City, _pat.State, _pat.Zip);
            //PID-12 County Code.  No longer used.
            //PID-13 Phone Number - Home.  No longer used.
            //PID-14 Phone Number - Business.  No longer used.
            //PID-15 Primary Language.  No longer used.
            //PID-16 Marital Status.  No longer used.
            //PID-17 Religion.  No longer used.
            //PID-18 Patient Account Number.  Optional.  However, we already sent this above.  Why do they have another field for this data?
            //PID-19 SSN Number - Patient.  No longer used.  We send SSN in PID-3.
            //PID-20 Driver's License Number - Patient.  No longer used.
            //PID-21 Mother's Identifier.  No longer used.
            //PID-22 Ethnic Group.  Required if known (length up to 478).  Cardinality [0..1].  Value set HL70189 (guide page 201).  Type CE.
            if (listPatRacesFiltered.Count > 0)           //The user specified a race and ethnicity and did not select the decline to specify option.
            {
                if (isHispanicOrLatino)
                {
                    WriteCE(22, "2135-2", "Hispanic or Latino", "CDCREC");
                }
                else                  //Not hispanic or latino.
                {
                    WriteCE(22, "2186-5", "not Hispanic or Latino", "CDCREC");
                }
            }
            //PID-23 Birth Place.  No longer used.
            //PID-24 Multiple Birth Indicator.  No longer used.
            //PID-25 Birth Order.  No longer used.
            //PID-26 Citizenship.  No longer used.
            //PID-27 Veterans Military Status.  No longer used.
            //PID-28 Nationality.  No longer used.
            //PID-29 Patient Death Date and Time.  Required if PID-30 is set to "Y" (length 12..26).  Cardinaility [0..1].
            if (_pat.DateTimeDeceased.Year > 1880)
            {
                _seg.SetField(29, _pat.DateTimeDeceased.ToString("yyyyMMddhhmmss"));
            }
            //PID-30 Patient Death Indicator.  Required if known.  Cardinaility [0..1].  Value set HL70136.
            if (_pat.DateTimeDeceased.Year > 1880)
            {
                _seg.SetField(30, "Y");
            }
            //PID-31 Identity Unknown.  No longer used.
            //PID-32 Identity Reliability Code.  No longer used.
            //PID-33 Last Update Date/Time.  Optional.  Cardinaility [0..1].
            //PID-34 Last Update Facility.  Optional.  Cardinaility [0..1].
            //PID-35 Species Code.  No longer used.
            //PID-36 Breed Code.  No longer used.
            //PID-37 Strain.  No longer used.
            //PID-38 Production Class Code.  No longer used.
            //PID-39 Tribal Citizenship.  No longer used.
            _msg.Segments.Add(_seg);
        }
Пример #19
0
		///<summary>Pharmacy/Treatment Route segment.  Required if known.  Guide page 158.</summary>
		private void RXR(VaccinePat vaccine) {
			if(vaccine.AdministrationRoute==VaccineAdministrationRoute.None) {
				return;//Unspecified.  Therefore unknown and the entire segment is not required.
			}
			_seg=new SegmentHL7(SegmentNameHL7.RXR);
			_seg.SetField(0,"RXR");
			//RXR-1 Route.  Required.  Cardinality [1..1].  Value set HL70162 (guide page 200). Type CE (guide page 53).
			if(vaccine.AdministrationRoute==VaccineAdministrationRoute.Intradermal) {
				WriteCE(1,"ID","Intradermal","HL70162");
			}
			else if(vaccine.AdministrationRoute==VaccineAdministrationRoute.Intramuscular) {
				WriteCE(1,"IM","Intramuscular","HL70162");
			}
			else if(vaccine.AdministrationRoute==VaccineAdministrationRoute.Nasal) {
				WriteCE(1,"NS","Nasal","HL70162");
			}
			else if(vaccine.AdministrationRoute==VaccineAdministrationRoute.Intravenous) {
				WriteCE(1,"IV","Intravenous","HL70162");
			}
			else if(vaccine.AdministrationRoute==VaccineAdministrationRoute.Oral) {
				WriteCE(1,"PO","Oral","HL70162");
			}
			else if(vaccine.AdministrationRoute==VaccineAdministrationRoute.Subcutaneous) {
				WriteCE(1,"SC","Subcutaneous","HL70162");
			}
			else if(vaccine.AdministrationRoute==VaccineAdministrationRoute.Transdermal) {
				WriteCE(1,"TD","Transdermal","HL70162");
			}
			else {//Other
				WriteCE(1,"OTH","Other","HL70162");
			}
			//RXR-2 Administration Site.  Required if known.  Cardinality [0..1].  Value set HL70163 (guide page 201, details where the vaccine was physically administered on the patient's body).
			if(vaccine.AdministrationSite==VaccineAdministrationSite.LeftThigh) {
				WriteCE(2,"LT","LeftThigh","HL70163");
			}
			else if(vaccine.AdministrationSite==VaccineAdministrationSite.LeftVastusLateralis) {
				WriteCE(2,"LVL","LeftVastusLateralis","HL70163");
			}
			else if(vaccine.AdministrationSite==VaccineAdministrationSite.LeftGluteousMedius) {
				WriteCE(2,"LG","LeftGluteousMedius","HL70163");
			}
			else if(vaccine.AdministrationSite==VaccineAdministrationSite.LeftArm) {
				WriteCE(2,"LA","LeftArm","HL70163");
			}
			else if(vaccine.AdministrationSite==VaccineAdministrationSite.LeftDeltoid) {
				WriteCE(2,"LD","LeftDeltoid","HL70163");
			}
			else if(vaccine.AdministrationSite==VaccineAdministrationSite.LeftLowerForearm) {
				WriteCE(2,"LLFA","LeftLowerForearm","HL70163");
			}
			else if(vaccine.AdministrationSite==VaccineAdministrationSite.RightThigh) {
				WriteCE(2,"RT","RightThigh","HL70163");
			}
			else if(vaccine.AdministrationSite==VaccineAdministrationSite.RightVastusLateralis) {
				WriteCE(2,"RVL","RightVastusLateralis","HL70163");
			}
			else if(vaccine.AdministrationSite==VaccineAdministrationSite.RightGluteousMedius) {
				WriteCE(2,"RG","RightGluteousMedius","HL70163");
			}
			else if(vaccine.AdministrationSite==VaccineAdministrationSite.RightArm) {
				WriteCE(2,"RA","RightArm","HL70163");
			}			
			else if(vaccine.AdministrationSite==VaccineAdministrationSite.RightDeltoid) {
				WriteCE(2,"RD","RightArm","HL70163");
			}
			else if(vaccine.AdministrationSite==VaccineAdministrationSite.RightLowerForearm) {
				WriteCE(2,"RLFA","RightLowerForearm","HL70163");
			}			
			//RXR-3 Administration Device.  Optional.
			//RXR-4 Administration Method.  Optional.
			//RXR-5 Routing Instruction.  Optional.
			//RXR-6 Administration Site Modifier.  Optional.
			_msg.Segments.Add(_seg);
		}
Пример #20
0
        ///<summary>Returns null if there is no HL7Def enabled or if there is no outbound SIU defined for the enabled HL7Def.</summary>
        public static MessageHL7 GenerateSIU(Patient pat, Patient guar, EventTypeHL7 eventType, Appointment apt)
        {
            HL7Def hl7Def = HL7Defs.GetOneDeepEnabled();

            if (hl7Def == null)
            {
                return(null);
            }
            //find an outbound SIU message in the def
            HL7DefMessage hl7DefMessage = null;

            for (int i = 0; i < hl7Def.hl7DefMessages.Count; i++)
            {
                if (hl7Def.hl7DefMessages[i].MessageType == MessageTypeHL7.SIU && hl7Def.hl7DefMessages[i].InOrOut == InOutHL7.Outgoing)
                {
                    hl7DefMessage = hl7Def.hl7DefMessages[i];
                    //continue;
                    break;
                }
            }
            if (hl7DefMessage == null)           //SIU message type is not defined so do nothing and return
            {
                return(null);
            }
            if (apt == null)           //SIU messages must have an appointment
            {
                return(null);
            }
            if (PrefC.GetBool(PrefName.ShowFeaturePatientClone))
            {
                pat = Patients.GetOriginalPatientForClone(pat);
            }
            MessageHL7 messageHL7 = new MessageHL7(MessageTypeHL7.SIU);
            Provider   prov       = Providers.GetProv(apt.ProvNum);

            for (int i = 0; i < hl7DefMessage.hl7DefSegments.Count; i++)
            {
                int repeatCount = 1;
                //AIP segment can repeat, once for the dentist on the appt and once for the hygienist
                if (hl7DefMessage.hl7DefSegments[i].SegmentName == SegmentNameHL7.AIP && apt.ProvHyg > 0)
                {
                    repeatCount = 2;
                }
                for (int j = 0; j < repeatCount; j++)           //AIP will be repeated if there is a dentist and a hygienist on the appt
                {
                    if (j > 0)
                    {
                        prov = Providers.GetProv(apt.ProvHyg);
                        if (prov == null)
                        {
                            break;                            //shouldn't happen, apt.ProvHyg would have to be set to an invalid ProvNum on the appt, just in case
                        }
                    }
                    SegmentHL7 seg = new SegmentHL7(hl7DefMessage.hl7DefSegments[i].SegmentName);
                    seg.SetField(0, hl7DefMessage.hl7DefSegments[i].SegmentName.ToString());
                    for (int k = 0; k < hl7DefMessage.hl7DefSegments[i].hl7DefFields.Count; k++)
                    {
                        string fieldName = hl7DefMessage.hl7DefSegments[i].hl7DefFields[k].FieldName;
                        if (fieldName == "")                       //If fixed text instead of field name just add text to segment
                        {
                            seg.SetField(hl7DefMessage.hl7DefSegments[i].hl7DefFields[k].OrdinalPos, hl7DefMessage.hl7DefSegments[i].hl7DefFields[k].FixedText);
                        }
                        else
                        {
                            string fieldValue = FieldConstructor.GenerateFieldSIU(hl7Def, fieldName, pat, prov, guar, apt, j + 1, eventType, seg.Name);
                            seg.SetField(hl7DefMessage.hl7DefSegments[i].hl7DefFields[k].OrdinalPos, fieldValue);
                        }
                    }
                    messageHL7.Segments.Add(seg);
                }
            }
            return(messageHL7);
        }
Пример #21
0
        ///<summary>Returns null if no HL7 def is enabled or no SRR is defined in the enabled def.  An SRR - Schedule Request Response message is sent when an SRM - Schedule Request Message is received.  The SRM is acknowledged just like any inbound message, but the SRR notifies the placer application that the requested modification took place.  Currently the only appointment modifications allowed are updating the appt note, setting the dentist and hygienist, updating the confirmation status, and changing the ClinicNum.  Setting the appointment status to Broken is also supported.</summary>
        public static MessageHL7 GenerateSRR(Patient pat, Appointment apt, EventTypeHL7 eventType, string controlId, bool isAck, string ackEvent)
        {
            HL7Def hl7Def = HL7Defs.GetOneDeepEnabled();

            if (hl7Def == null)
            {
                return(null);
            }
            //find an outbound SRR message in the def
            HL7DefMessage hl7DefMessage = null;

            for (int i = 0; i < hl7Def.hl7DefMessages.Count; i++)
            {
                if (hl7Def.hl7DefMessages[i].MessageType == MessageTypeHL7.SRR && hl7Def.hl7DefMessages[i].InOrOut == InOutHL7.Outgoing)
                {
                    hl7DefMessage = hl7Def.hl7DefMessages[i];
                    break;
                }
            }
            if (hl7DefMessage == null)           //SRR message type is not defined so do nothing and return
            {
                return(null);
            }
            if (PrefC.GetBool(PrefName.ShowFeaturePatientClone))
            {
                pat = Patients.GetOriginalPatientForClone(pat);
            }
            MessageHL7 msgHl7  = new MessageHL7(MessageTypeHL7.SRR);
            Provider   provPri = Providers.GetProv(apt.ProvNum);

            //go through each segment in the def
            for (int i = 0; i < hl7DefMessage.hl7DefSegments.Count; i++)
            {
                List <Provider> listProvs = new List <Provider>();
                listProvs.Add(provPri);
                if (hl7DefMessage.hl7DefSegments[i].SegmentName == SegmentNameHL7.AIP && apt.ProvHyg > 0)
                {
                    listProvs.Add(Providers.GetProv(apt.ProvHyg));
                }
                for (int j = 0; j < listProvs.Count; j++)           //AIP will be repeated if there is a dentist and a hygienist on the appt
                {
                    Provider   prov = listProvs[j];
                    SegmentHL7 seg  = new SegmentHL7(hl7DefMessage.hl7DefSegments[i].SegmentName);
                    seg.SetField(0, hl7DefMessage.hl7DefSegments[i].SegmentName.ToString());
                    for (int k = 0; k < hl7DefMessage.hl7DefSegments[i].hl7DefFields.Count; k++)
                    {
                        string fieldName = hl7DefMessage.hl7DefSegments[i].hl7DefFields[k].FieldName;
                        if (fieldName == "")                       //If fixed text instead of field name just add text to segment
                        {
                            seg.SetField(hl7DefMessage.hl7DefSegments[i].hl7DefFields[k].OrdinalPos, hl7DefMessage.hl7DefSegments[i].hl7DefFields[k].FixedText);
                        }
                        else
                        {
                            string fieldValue = "";
                            if (hl7DefMessage.hl7DefSegments[i].SegmentName == SegmentNameHL7.MSA)
                            {
                                fieldValue = FieldConstructor.GenerateFieldACK(hl7Def, fieldName, controlId, isAck, ackEvent);
                            }
                            else
                            {
                                fieldValue = FieldConstructor.GenerateFieldSRR(hl7Def, fieldName, pat, prov, apt, j + 1, eventType, seg.Name);
                            }
                            seg.SetField(hl7DefMessage.hl7DefSegments[i].hl7DefFields[k].OrdinalPos, fieldValue);
                        }
                    }
                    msgHl7.Segments.Add(seg);
                }
            }
            return(msgHl7);
        }
Пример #22
0
        ///<summary>Returns null if there is no HL7Def enabled or if there is no outbound DFT defined for the enabled HL7Def.</summary>
        public static MessageHL7 GenerateDFT(List <Procedure> listProcs, EventTypeHL7 eventType, Patient pat, Patient guar, long aptNum, string pdfDescription, string pdfDataString)
        {
            //In \\SERVERFILES\storage\OPEN DENTAL\Programmers Documents\Standards (X12, ADA, etc)\HL7\Version2.6\V26_CH02_Control_M4_JAN2007.doc
            //On page 28, there is a Message Construction Pseudocode as well as a flowchart which might help.
            MessageHL7 msgHl7 = new MessageHL7(MessageTypeHL7.DFT);
            HL7Def     hl7Def = HL7Defs.GetOneDeepEnabled();

            if (hl7Def == null)
            {
                return(null);
            }
            //find a DFT message in the def
            HL7DefMessage hl7DefMessage = null;

            for (int i = 0; i < hl7Def.hl7DefMessages.Count; i++)
            {
                if (hl7Def.hl7DefMessages[i].MessageType == MessageTypeHL7.DFT && hl7Def.hl7DefMessages[i].InOrOut == InOutHL7.Outgoing)
                {
                    hl7DefMessage = hl7Def.hl7DefMessages[i];
                    //continue;
                    break;
                }
            }
            if (hl7DefMessage == null)           //DFT message type is not defined so do nothing and return
            {
                return(null);
            }
            if (PrefC.GetBool(PrefName.ShowFeaturePatientClone))
            {
                pat = Patients.GetOriginalPatientForClone(pat);
            }
            Provider       prov         = Providers.GetProv(Patients.GetProvNum(pat));
            Appointment    apt          = Appointments.GetOneApt(aptNum);
            List <PatPlan> listPatPlans = PatPlans.Refresh(pat.PatNum);

            for (int i = 0; i < hl7DefMessage.hl7DefSegments.Count; i++)
            {
                int repeatCount = 1;
                if (hl7DefMessage.hl7DefSegments[i].SegmentName == SegmentNameHL7.FT1)
                {
                    repeatCount = listProcs.Count;
                }
                else if (hl7DefMessage.hl7DefSegments[i].SegmentName == SegmentNameHL7.IN1)
                {
                    repeatCount = listPatPlans.Count;
                }
                //for example, countRepeat can be zero in the case where we are only sending a PDF of the TP to eCW, and no procs.
                //or the patient does not have any current insplans for IN1 segments
                for (int j = 0; j < repeatCount; j++)           //FT1 is optional and can repeat so add as many FT1's as procs in procList, IN1 is optional and can repeat as well, repeat for the number of patplans in patplanList
                {
                    if (hl7DefMessage.hl7DefSegments[i].SegmentName == SegmentNameHL7.FT1 && listProcs.Count > j)
                    {
                        prov = Providers.GetProv(listProcs[j].ProvNum);
                    }
                    Procedure proc = null;
                    if (listProcs.Count > j)                   //procList could be an empty list
                    {
                        proc = listProcs[j];
                    }
                    PatPlan patPlanCur = null;
                    InsPlan insPlanCur = null;
                    InsSub  insSubCur  = null;
                    Carrier carrierCur = null;
                    Patient subscriber = null;
                    if (hl7DefMessage.hl7DefSegments[i].SegmentName == SegmentNameHL7.IN1)
                    {
                        patPlanCur = listPatPlans[j];
                        insSubCur  = InsSubs.GetOne(patPlanCur.InsSubNum);
                        insPlanCur = InsPlans.RefreshOne(insSubCur.PlanNum);
                        carrierCur = Carriers.GetCarrier(insPlanCur.CarrierNum);
                        subscriber = Patients.GetPat(insSubCur.Subscriber);
                    }
                    SegmentHL7 seg = new SegmentHL7(hl7DefMessage.hl7DefSegments[i].SegmentName);
                    seg.SetField(0, hl7DefMessage.hl7DefSegments[i].SegmentName.ToString());
                    for (int f = 0; f < hl7DefMessage.hl7DefSegments[i].hl7DefFields.Count; f++)
                    {
                        string fieldName = hl7DefMessage.hl7DefSegments[i].hl7DefFields[f].FieldName;
                        if (fieldName == "")                       //If fixed text instead of field name just add text to segment
                        {
                            seg.SetField(hl7DefMessage.hl7DefSegments[i].hl7DefFields[f].OrdinalPos, hl7DefMessage.hl7DefSegments[i].hl7DefFields[f].FixedText);
                        }
                        else
                        {
                            string fieldValue = "";
                            if (hl7DefMessage.hl7DefSegments[i].SegmentName == SegmentNameHL7.IN1)
                            {
                                fieldValue = FieldConstructor.GenerateFieldIN1(hl7Def, fieldName, j + 1, patPlanCur, insSubCur, insPlanCur, carrierCur, listPatPlans.Count, subscriber);
                            }
                            else
                            {
                                fieldValue = FieldConstructor.GenerateField(hl7Def, fieldName, MessageTypeHL7.DFT, pat, prov, proc, guar, apt, j + 1, eventType,
                                                                            pdfDescription, pdfDataString, MessageStructureHL7.DFT_P03, seg.Name);
                            }
                            seg.SetField(hl7DefMessage.hl7DefSegments[i].hl7DefFields[f].OrdinalPos, fieldValue);
                        }
                    }
                    msgHl7.Segments.Add(seg);
                }
            }
            return(msgHl7);
        }
Пример #23
0
 ///<summary>Event type segment.</summary>
 private void EVN()
 {
     seg = new SegmentHL7("EVN|P03|" + DateTime.Now.ToString("yyyyMMddHHmmss") + "|");
     msg.Segments.Add(seg);
 }
Пример #24
0
        ///<summary>Returns null if there is no DFT defined for the enabled HL7Def.</summary>
        public static MessageHL7 GenerateDFT(List <Procedure> procList, EventTypeHL7 eventType, Patient pat, Patient guar, long aptNum, string pdfDescription, string pdfDataString)   //add event (A04 etc) parameters later if needed
        //In \\SERVERFILES\storage\OPEN DENTAL\Programmers Documents\Standards (X12, ADA, etc)\HL7\Version2.6\V26_CH02_Control_M4_JAN2007.doc
        //On page 28, there is a Message Construction Pseudocode as well as a flowchart which might help.
        {
            Provider    prov       = Providers.GetProv(Patients.GetProvNum(pat));
            Appointment apt        = Appointments.GetOneApt(aptNum);
            MessageHL7  messageHL7 = new MessageHL7(MessageTypeHL7.DFT);
            HL7Def      hl7Def     = HL7Defs.GetOneDeepEnabled();

            if (hl7Def == null)
            {
                return(null);
            }
            //find a DFT message in the def
            HL7DefMessage hl7DefMessage = null;

            for (int i = 0; i < hl7Def.hl7DefMessages.Count; i++)
            {
                if (hl7Def.hl7DefMessages[i].MessageType == MessageTypeHL7.DFT)
                {
                    hl7DefMessage = hl7Def.hl7DefMessages[i];
                    //continue;
                    break;
                }
            }
            if (hl7DefMessage == null)           //DFT message type is not defined so do nothing and return
            {
                return(null);
            }
            for (int s = 0; s < hl7DefMessage.hl7DefSegments.Count; s++)
            {
                int countRepeat = 1;
                if (hl7DefMessage.hl7DefSegments[s].SegmentName == SegmentNameHL7.FT1)
                {
                    countRepeat = procList.Count;
                }
                //for example, countRepeat can be zero in the case where we are only sending a PDF of the TP to eCW, and no procs.
                for (int repeat = 0; repeat < countRepeat; repeat++)           //FT1 is optional and can repeat so add as many FT1's as procs in procList
                //if(hl7DefMessage.hl7DefSegments[s].SegmentName==SegmentNameHL7.FT1) {
                {
                    if (hl7DefMessage.hl7DefSegments[s].SegmentName == SegmentNameHL7.FT1 && procList.Count > repeat)
                    {
                        prov = Providers.GetProv(procList[repeat].ProvNum);
                    }
                    SegmentHL7 seg = new SegmentHL7(hl7DefMessage.hl7DefSegments[s].SegmentName);
                    seg.SetField(0, hl7DefMessage.hl7DefSegments[s].SegmentName.ToString());
                    for (int f = 0; f < hl7DefMessage.hl7DefSegments[s].hl7DefFields.Count; f++)
                    {
                        string fieldName = hl7DefMessage.hl7DefSegments[s].hl7DefFields[f].FieldName;
                        if (fieldName == "")                       //If fixed text instead of field name just add text to segment
                        {
                            seg.SetField(hl7DefMessage.hl7DefSegments[s].hl7DefFields[f].OrdinalPos, hl7DefMessage.hl7DefSegments[s].hl7DefFields[f].FixedText);
                        }
                        else
                        {
                            //seg.SetField(hl7DefMessage.hl7DefSegments[s].hl7DefFields[f].OrdinalPos,
                            //FieldConstructor.GenerateDFT(hl7Def,fieldName,pat,prov,procList[repeat],guar,apt,repeat+1,eventType,pdfDescription,pdfDataString));
                            Procedure proc = null;
                            if (procList.Count > repeat)                           //procList could be an empty list
                            {
                                proc = procList[repeat];
                            }
                            seg.SetField(hl7DefMessage.hl7DefSegments[s].hl7DefFields[f].OrdinalPos,
                                         FieldConstructor.GenerateDFT(hl7Def, fieldName, pat, prov, proc, guar, apt, repeat + 1, eventType, pdfDescription, pdfDataString));
                        }
                    }
                    messageHL7.Segments.Add(seg);
                }
            }
            return(messageHL7);
        }
Пример #25
0
        ///<summary>Observation/result segment.  Used to transmit observations related to the patient and visit.  Guide page 64.</summary>
        private void OBX()
        {
            List <EhrAptObs> listObservations = EhrAptObses.Refresh(_appt.AptNum);

            for (int i = 0; i < listObservations.Count; i++)
            {
                EhrAptObs obs = listObservations[i];
                _seg = new SegmentHL7(SegmentNameHL7.OBX);
                _seg.SetField(0, "OBX");
                _seg.SetField(1, (i + 1).ToString());             //OBX-1 Set ID - OBX.  Required (length 1..4).  Must start at 1 and increment.
                //OBX-2 Value Type.  Required (length 1..3).  Cardinality [1..1].  Identifies the structure of data in observation value OBX-5.  Values allowed: TS=Time Stamp (Date and/or Time),TX=Text,NM=Numeric,CWE=Coded with exceptions,XAD=Address.
                if (obs.ValType == EhrAptObsType.Coded)
                {
                    _seg.SetField(2, "CWE");
                }
                else if (obs.ValType == EhrAptObsType.DateAndTime)
                {
                    _seg.SetField(2, "TS");
                }
                else if (obs.ValType == EhrAptObsType.Numeric)
                {
                    _seg.SetField(2, "NM");
                }
                else                  //obs.ValType==EhrAptObsType.Text
                {
                    _seg.SetField(2, "TX");
                }
                //OBX-3 Observation Identifier.  Required (length up to 478).  Cardinality [1..1].  Value set is HL7 table named "Observation Identifier".  Type CE.  We use LOINC codes because the testing tool used LOINC codes and so do vaccines.
                string obsIdCode         = "";
                string obsIdCodeDescript = "";
                string obsIdCodeSystem   = "LN";
                if (obs.IdentifyingCode == EhrAptObsIdentifier.BodyTemp)
                {
                    obsIdCode         = "11289-6";
                    obsIdCodeDescript = "Body temperature:Temp:Enctrfrst:Patient:Qn:";
                }
                else if (obs.IdentifyingCode == EhrAptObsIdentifier.CheifComplaint)
                {
                    obsIdCode         = "8661-1";
                    obsIdCodeDescript = "Chief complaint:Find:Pt:Patient:Nom:Reported";
                }
                else if (obs.IdentifyingCode == EhrAptObsIdentifier.DateIllnessOrInjury)
                {
                    obsIdCode         = "11368-8";
                    obsIdCodeDescript = "Illness or injury onset date and time:TmStp:Pt:Patient:Qn:";
                }
                else if (obs.IdentifyingCode == EhrAptObsIdentifier.OxygenSaturation)
                {
                    obsIdCode         = "59408-5";
                    obsIdCodeDescript = "Oxygen saturation:MFr:Pt:BldA:Qn:Pulse oximetry";
                }
                else if (obs.IdentifyingCode == EhrAptObsIdentifier.PatientAge)
                {
                    obsIdCode         = "21612-7";
                    obsIdCodeDescript = "Age Time Patient Reported";
                }
                else if (obs.IdentifyingCode == EhrAptObsIdentifier.PrelimDiag)
                {
                    obsIdCode         = "44833-2";
                    obsIdCodeDescript = "Diagnosis.preliminary:Imp:Pt:Patient:Nom:";
                }
                else if (obs.IdentifyingCode == EhrAptObsIdentifier.TreatFacilityID)
                {
                    obsIdCode         = "SS001";
                    obsIdCodeDescript = "Treating Facility Identifier";
                    obsIdCodeSystem   = "PHINQUESTION";
                }
                else if (obs.IdentifyingCode == EhrAptObsIdentifier.TreatFacilityLocation)
                {
                    obsIdCode         = "SS002";
                    obsIdCodeDescript = "Treating Facility Location";
                    obsIdCodeSystem   = "PHINQUESTION";
                }
                else if (obs.IdentifyingCode == EhrAptObsIdentifier.TriageNote)
                {
                    obsIdCode         = "54094-8";
                    obsIdCodeDescript = "Triage note:Find:Pt:Emergency department:Doc:";
                }
                else if (obs.IdentifyingCode == EhrAptObsIdentifier.VisitType)
                {
                    obsIdCode         = "SS003";
                    obsIdCodeDescript = "Facility / Visit Type";
                    obsIdCodeSystem   = "PHINQUESTION";
                }
                WriteCE(3, obsIdCode, obsIdCodeDescript, obsIdCodeSystem);
                //OBX-4 Observation Sub-ID.  No longer used.
                //OBX-5 Observation Value.  Required if known (length 1..99999).  Value must match type in OBX-2.
                if (obs.ValType == EhrAptObsType.Address)
                {
                    WriteXAD(5, _sendingFacilityAddress1, _sendingFacilityAddress2, _sendingFacilityCity, _sendingFacilityState, _sendingFacilityZip);
                }
                else if (obs.ValType == EhrAptObsType.Coded)
                {
                    string codeDescript     = "";
                    string codeSystemAbbrev = "";
                    if (obs.ValCodeSystem.Trim().ToUpper() == "LOINC")
                    {
                        Loinc loincVal = Loincs.GetByCode(obs.ValReported);
                        codeDescript     = loincVal.NameShort;
                        codeSystemAbbrev = "LN";
                    }
                    else if (obs.ValCodeSystem.Trim().ToUpper() == "SNOMEDCT")
                    {
                        Snomed snomedVal = Snomeds.GetByCode(obs.ValReported);
                        codeDescript     = snomedVal.Description;
                        codeSystemAbbrev = "SCT";
                    }
                    else if (obs.ValCodeSystem.Trim().ToUpper() == "ICD9")
                    {
                        ICD9 icd9Val = ICD9s.GetByCode(obs.ValReported);
                        codeDescript     = icd9Val.Description;
                        codeSystemAbbrev = "I9";
                    }
                    else if (obs.ValCodeSystem.Trim().ToUpper() == "ICD10")
                    {
                        Icd10 icd10Val = Icd10s.GetByCode(obs.ValReported);
                        codeDescript     = icd10Val.Description;
                        codeSystemAbbrev = "I10";
                    }
                    WriteCE(5, obs.ValReported.Trim(), codeDescript, codeSystemAbbrev);
                }
                else if (obs.ValType == EhrAptObsType.DateAndTime)
                {
                    DateTime dateVal    = DateTime.Parse(obs.ValReported.Trim());
                    string   strDateOut = dateVal.ToString("yyyyMMdd");
                    //The testing tool threw errors when there were trailing zeros, even though technically valid.
                    if (dateVal.Second > 0)
                    {
                        strDateOut += dateVal.ToString("HHmmss");
                    }
                    else if (dateVal.Minute > 0)
                    {
                        strDateOut += dateVal.ToString("HHmm");
                    }
                    else if (dateVal.Hour > 0)
                    {
                        strDateOut += dateVal.ToString("HH");
                    }
                    _seg.SetField(5, strDateOut);
                }
                else if (obs.ValType == EhrAptObsType.Numeric)
                {
                    _seg.SetField(5, obs.ValReported.Trim());
                }
                else                   //obs.ValType==EhrAptObsType.Text
                {
                    _seg.SetField(5, obs.ValReported);
                }
                //OBX-6 Units.  Required if OBX-2 is NM=Numeric.  Cardinality [0..1].  Type CE.  The guide suggests value sets: Pulse Oximetry Unit, Temperature Unit, or Age Unit.  However, the testing tool used UCUM, so we will use UCUM.
                if (obs.ValType == EhrAptObsType.Numeric)
                {
                    if (String.IsNullOrEmpty(obs.UcumCode))                      //If units are required but known, we must send a null flavor.
                    {
                        WriteCE(6, "UNK", "", "NULLFL");
                    }
                    else
                    {
                        Ucum ucum = Ucums.GetByCode(obs.UcumCode);
                        WriteCE(6, ucum.UcumCode, ucum.Description, "UCUM");
                    }
                }
                //OBX-7 References Range.  No longer used.
                //OBX-8 Abnormal Flags.  No longer used.
                //OBX-9 Probability.  No longer used.
                //OBX-10 Nature of Abnormal Test.  No longer used.
                _seg.SetField(11, "F");               //OBX-11 Observation Result Status.  Required (length 1..1).  Expected value is "F".
                //OBX-12 Effective Date of Reference Range.  No longer used.
                //OBX-13 User Defined Access Checks.  No longer used.
                //OBX-14 Date/Time of the Observation.  Optional.
                //OBX-15 Producer's ID.  No longer used.
                //OBX-16 Responsible Observer.  No longer used.
                //OBX-17 Observation Method.  No longer used.
                //OBX-18 Equipment Instance Identifier.  No longer used.
                //OBX-19 Date/Time of the Analysis.  No longer used.
                _msg.Segments.Add(_seg);
            }
        }
Пример #26
0
		///<summary>Patient Demographic segment.  Required if known.  Additional demographics.  Guide page 132.</summary>
		private void PD1() {
			_seg=new SegmentHL7(SegmentNameHL7.PD1);
			_seg.SetField(0,"PD1");
			//PD1-1 Living Dependency.  Optional.  Cardinality [0..1].
			//PD1-2 Living Arrangement.  Optional.  Cardinality [0..1].
			//PD1-3 Patient Primary Facility.  Optional.  Cardinality [0..1].
			//PD1-4 Patient Primary Care Provider Name & ID Number.  Optional.  Cardinality [0..1].
			//PD1-5 Student Indicator.  Optional.  Cardinality [0..1].
			//PD1-6 Handicap.  Optional.  Cardinality [0..1].
			//PD1-7 Living Will Code.  Optional.  Cardinality [0..1].
			//PD1-8 Organ Donor Code.  Optional.  Cardinality [0..1].
			//PD1-9 Separate Bill.  Optional.  Cardinality [0..1].
			//PD1-10 Duplicate Patient.  Optional.  Cardinality [0..1].
			//PD1-11 Publicity Code.  Required if known (length 2..2).  Cardinality [0..1].  Value set HL70215 (guide page 209).  Type CE.
			if(_pat.PreferRecallMethod==ContactMethod.DoNotCall) {
				WriteCE(11,"07","Recall only - no calls","HL70215");
			}
			else if(_pat.PreferRecallMethod==ContactMethod.None) {
				WriteCE(11,"01","No reminder/Recall","HL70215");
			}
			else {
				WriteCE(11,"02","Reminder/Recall - any method","HL70215");
			}
			//PD1-12 Protection Indicator.  Required if known (length 1..1).  Cardinality [0..1].  Value set HL70136 (guide page 199).  Allowed values are "Y" for yes, "N" for no, or blank for unknown.
			EhrPatient ehrPatient=EhrPatients.Refresh(_pat.PatNum);
			if(ehrPatient.VacShareOk==YN.Yes) {
				_seg.SetField(12,"N");//Do not protect.
			}
			else if(ehrPatient.VacShareOk==YN.No) {
				_seg.SetField(12,"Y");//Protect
			}
			//PD1-13 Protection Indicator Date Effective.  Required if PD1-12 is not blank (length unspecified).  Cardinality [0..1].
			if(ehrPatient.VacShareOk!=YN.Unknown) {
				_seg.SetField(13,_pat.DateTStamp.ToString("yyyyMMdd"));
			}
			//PD1-14 Place of Worship.  Optional (length unspecified).  Cardinality [0..1].
			//PD1-15 Advance Directive Code.  Optional (length unspecified).  Cardinality [0..1].
			//PD1-16 Immunization Registry Status.  Required if known (length unspecified).  Cardinality [0..1].  Value set HL70441 (guide page 232).  The word "registry" refers to the EHR.
			if(_pat.PatStatus==PatientStatus.Patient) {
				_seg.SetField(16,"A");//Active
			}
			else {
				_seg.SetField(16,"I");//Inactive--Unspecified
			}
			//PD1-17 Immunization Registry Status Effective Date.  Required if PD1-16 is not blank.  Cardinality [0..1].
			_seg.SetField(17,DateTime.Today.ToString("yyyyMMdd"));
			//PD1-18 Publicity Code Effective Date.  Required if PD1-11 is not blank.
			_seg.SetField(18,DateTime.Today.ToString("yyyyMMdd"));
			//PD1-19 Military Branch.  Optional.
			//PD1-20 Military Rank/Grade.  Optional.
			//PD1-21 Military Status.  Optional.
			_msg.Segments.Add(_seg);
		}
Пример #27
0
        //Open \\SERVERFILES\storage\OPEN DENTAL\Programmers Documents\Standards (X12, ADA, etc)\HL7\Version2.6\V26_CH02_Control_M4_JAN2007.doc
        //At the top of page 33, there are rules for the recipient.
        //Basically, they state that parsing should not fail just because there are extra unexpected items.
        //And parsing should also not fail if expected items are missing.

        public static void Process(MessageHL7 msg, bool isVerboseLogging)
        {
            HL7MsgCur           = new HL7Msg();
            HL7MsgCur.HL7Status = HL7MessageStatus.InFailed;          //it will be marked InProcessed once data is inserted.
            HL7MsgCur.MsgText   = msg.ToString();
            HL7MsgCur.PatNum    = 0;
            HL7MsgCur.AptNum    = 0;
            List <HL7Msg> hl7Existing = HL7Msgs.GetOneExisting(HL7MsgCur);

            if (hl7Existing.Count > 0)           //This message is already in the db
            {
                HL7MsgCur.HL7MsgNum = hl7Existing[0].HL7MsgNum;
                HL7Msgs.UpdateDateTStamp(HL7MsgCur);
                msg.ControlId = HL7Msgs.GetControlId(HL7MsgCur);
                return;
            }
            else
            {
                //Insert as InFailed until processing is complete.  Update once complete, PatNum will have correct value, AptNum will have correct value if SIU message or 0 if ADT, and status changed to InProcessed
                HL7Msgs.Insert(HL7MsgCur);
            }
            IsVerboseLogging = isVerboseLogging;
            IsNewPat         = false;
            HL7Def def = HL7Defs.GetOneDeepEnabled();

            if (def == null)
            {
                HL7MsgCur.Note = "Could not process HL7 message.  No HL7 definition is enabled.";
                HL7Msgs.Update(HL7MsgCur);
                throw new Exception("Could not process HL7 message.  No HL7 definition is enabled.");
            }
            HL7DefMessage hl7defmsg = null;

            for (int i = 0; i < def.hl7DefMessages.Count; i++)
            {
                if (def.hl7DefMessages[i].MessageType == msg.MsgType)               //&& def.hl7DefMessages[i].EventType==msg.EventType) { //Ignoring event type for now, we will treat all ADT's and SIU's the same
                {
                    hl7defmsg = def.hl7DefMessages[i];
                }
            }
            if (hl7defmsg == null)           //No message definition matches this message's MessageType and EventType
            {
                HL7MsgCur.Note = "Could not process HL7 message.  No definition for this type of message in the enabled HL7Def.";
                HL7Msgs.Update(HL7MsgCur);
                throw new Exception("Could not process HL7 message.  No definition for this type of message in the enabled HL7Def.");
            }
            string   chartNum      = null;
            long     patNum        = 0;
            DateTime birthdate     = DateTime.MinValue;
            string   patLName      = null;
            string   patFName      = null;
            bool     isExistingPID = false;      //Needed to add note to hl7msg table if there isn't a PID segment in the message.

            //Get patient in question, incoming messages must have a PID segment so use that to find the pat in question
            for (int s = 0; s < hl7defmsg.hl7DefSegments.Count; s++)
            {
                if (hl7defmsg.hl7DefSegments[s].SegmentName != SegmentNameHL7.PID)
                {
                    continue;
                }
                int pidOrder = hl7defmsg.hl7DefSegments[s].ItemOrder;
                //we found the PID segment in the def, make sure it exists in the msg
                if (msg.Segments.Count <= pidOrder ||           //If the number of segments in the message is less than the item order of the PID segment
                    msg.Segments[pidOrder].GetField(0).ToString() != "PID"                      //Or if the segment we expect to be the PID segment is not the PID segment
                    )
                {
                    break;
                }
                isExistingPID = true;
                for (int f = 0; f < hl7defmsg.hl7DefSegments[s].hl7DefFields.Count; f++)           //Go through fields of PID segment and get patnum, chartnum, patient name, and/or birthdate to locate patient
                {
                    if (hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName == "pat.ChartNumber")
                    {
                        int chartNumOrdinal = hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
                        chartNum = msg.Segments[pidOrder].Fields[chartNumOrdinal].ToString();
                    }
                    else if (hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName == "pat.PatNum")
                    {
                        int patNumOrdinal = hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
                        patNum = PIn.Long(msg.Segments[pidOrder].Fields[patNumOrdinal].ToString());
                    }
                    else if (hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName == "pat.birthdateTime")
                    {
                        int patBdayOrdinal = hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
                        birthdate = FieldParser.DateTimeParse(msg.Segments[pidOrder].Fields[patBdayOrdinal].ToString());
                    }
                    else if (hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName == "pat.nameLFM")
                    {
                        int patNameOrdinal = hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
                        patLName = msg.Segments[pidOrder].GetFieldComponent(patNameOrdinal, 0);
                        patFName = msg.Segments[pidOrder].GetFieldComponent(patNameOrdinal, 1);
                    }
                }
            }
            if (!isExistingPID)
            {
                HL7MsgCur.Note = "Could not process the HL7 message due to missing PID segment.";
                HL7Msgs.Update(HL7MsgCur);
                throw new Exception("Could not process HL7 message.  Could not process the HL7 message due to missing PID segment.");
            }
            //We now have patnum, chartnum, patname, and/or birthdate so locate pat
            Patient pat    = null;
            Patient patOld = null;

            if (patNum != 0)
            {
                pat = Patients.GetPat(patNum);
            }
            if (def.InternalType != "eCWStandalone" && pat == null)
            {
                IsNewPat = true;
            }
            //In eCWstandalone integration, if we couldn't locate patient by patNum or patNum was 0 then pat will still be null so try to locate by chartNum if chartNum is not null
            if (def.InternalType == "eCWStandalone" && chartNum != null)
            {
                pat = Patients.GetPatByChartNumber(chartNum);
            }
            //In eCWstandalone integration, if pat is still null we need to try to locate patient by name and birthdate
            if (def.InternalType == "eCWStandalone" && pat == null)
            {
                long patNumByName = Patients.GetPatNumByNameAndBirthday(patLName, patFName, birthdate);
                //If patNumByName is 0 we couldn't locate by patNum, chartNum or name and birthdate so this message must be for a new patient
                if (patNumByName == 0)
                {
                    IsNewPat = true;
                }
                else
                {
                    pat             = Patients.GetPat(patNumByName);
                    patOld          = pat.Copy();
                    pat.ChartNumber = chartNum;                  //from now on, we will be able to find pat by chartNumber
                    Patients.Update(pat, patOld);
                }
            }
            if (IsNewPat)
            {
                pat = new Patient();
                if (chartNum != null)
                {
                    pat.ChartNumber = chartNum;
                }
                if (patNum != 0)
                {
                    pat.PatNum    = patNum;
                    pat.Guarantor = patNum;
                }
                pat.PriProv     = PrefC.GetLong(PrefName.PracticeDefaultProv);
                pat.BillingType = PrefC.GetLong(PrefName.PracticeDefaultBillType);
            }
            else
            {
                patOld = pat.Copy();
            }
            //Update hl7msg table with correct PatNum for this message
            HL7MsgCur.PatNum = pat.PatNum;
            HL7Msgs.Update(HL7MsgCur);
            //If this is a message that contains an SCH segment, loop through to find the AptNum.  Pass it to the other segments that will need it.
            long aptNum = 0;

            for (int s = 0; s < hl7defmsg.hl7DefSegments.Count; s++)
            {
                if (hl7defmsg.hl7DefSegments[s].SegmentName != SegmentNameHL7.SCH)
                {
                    continue;
                }
                //we found the SCH segment
                int schOrder = hl7defmsg.hl7DefSegments[s].ItemOrder;
                for (int f = 0; f < hl7defmsg.hl7DefSegments[s].hl7DefFields.Count; f++)           //Go through fields of SCH segment and get AptNum
                {
                    if (hl7defmsg.hl7DefSegments[s].hl7DefFields[f].FieldName == "apt.AptNum")
                    {
                        int aptNumOrdinal = hl7defmsg.hl7DefSegments[s].hl7DefFields[f].OrdinalPos;
                        aptNum = PIn.Long(msg.Segments[schOrder].Fields[aptNumOrdinal].ToString());
                    }
                }
            }
            //We now have a patient object , either loaded from the db or new, and aptNum so process this message for this patient
            //We need to insert the pat to get a patnum so we can compare to guar patnum to see if relationship to guar is self
            if (IsNewPat)
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Inserted patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                if (pat.PatNum == 0)
                {
                    pat.PatNum = Patients.Insert(pat, false);
                }
                else
                {
                    pat.PatNum = Patients.Insert(pat, true);
                }
                patOld = pat.Copy();
            }
            for (int i = 0; i < hl7defmsg.hl7DefSegments.Count; i++)
            {
                try {
                    SegmentHL7 seg = msg.GetSegment(hl7defmsg.hl7DefSegments[i].SegmentName, !hl7defmsg.hl7DefSegments[i].IsOptional);
                    if (seg != null)                   //null if segment was not found but is optional
                    {
                        ProcessSeg(pat, aptNum, hl7defmsg.hl7DefSegments[i], seg, msg);
                    }
                }
                catch (ApplicationException ex) {               //Required segment was missing, or other error.
                    HL7MsgCur.Note = "Could not process this HL7 message.  " + ex;
                    HL7Msgs.Update(HL7MsgCur);
                    throw new Exception("Could not process HL7 message.  " + ex);
                }
            }
            //We have processed the message so now update or insert the patient
            if (pat.FName == "" || pat.LName == "")
            {
                EventLog.WriteEntry("OpenDentHL7", "Patient demographics not processed due to missing first or last name. PatNum:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                HL7MsgCur.Note = "Patient demographics not processed due to missing first or last name. PatNum:" + pat.PatNum.ToString();
                HL7Msgs.Update(HL7MsgCur);
                return;
            }
            if (IsNewPat)
            {
                if (pat.Guarantor == 0)
                {
                    pat.Guarantor = pat.PatNum;
                    Patients.Update(pat, patOld);
                }
                else
                {
                    Patients.Update(pat, patOld);
                }
            }
            else
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Updated patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Patients.Update(pat, patOld);
            }
            HL7MsgCur.HL7Status = HL7MessageStatus.InProcessed;
            HL7Msgs.Update(HL7MsgCur);
        }
Пример #28
0
		///<summary>Pharmacy/Treatment Administration segment.  Required.  Guide page 149.</summary>
		private void RXA(VaccinePat vaccine) {
			_seg=new SegmentHL7(SegmentNameHL7.RXA);
			_seg.SetField(0,"RXA");
			_seg.SetField(1,"0");//RXA-1 Give Sub-ID Counter.  Required.  Must be "0".
			_seg.SetField(2,"1");//RXA-2 Administration Sub-ID Counter.  Required.  Must be "1".
			_seg.SetField(3,vaccine.DateTimeStart.ToString("yyyyMMddHHmm"));//RXA-3 Date/Time Start of Administration.  Required.  This segment can also be used to planned vaccinations.
			if(vaccine.DateTimeEnd.Year>1880) {
				_seg.SetField(4,vaccine.DateTimeEnd.ToString("yyyyMMddHHmm"));//RXA-4 Date/Time End of Administration.  Required if known.  Must be same as RXA-3 or blank.  UI forces RXA-4 and RXA-3 to be equal.  This would be blank if for a planned vaccine.
			}
			//RXA-5 Administered Code.  Required.  Cardinality [1..1].  Type CE (guide page 53).  Must be a CVX code.
			VaccineDef vaccineDef=null;
			if(vaccine.CompletionStatus==VaccineCompletionStatus.NotAdministered) {
				WriteCE(5,"998","no vaccine administered","CVX");
			}
			else {
				vaccineDef=VaccineDefs.GetOne(vaccine.VaccineDefNum);
				Cvx cvx=Cvxs.GetByCode(vaccineDef.CVXCode);
				WriteCE(5,cvx.CvxCode,cvx.Description,"CVX");
			}
			//RXA-6 Administered Amount.  Required (length 1..20).  If amount is not known or not meaningful, then use "999".
			if(vaccine.AdministeredAmt>0) {
				_seg.SetField(6,vaccine.AdministeredAmt.ToString());
			}
			else {
				_seg.SetField(6,"999");//Registries that do not collect administered amount should record the value as "999".
			}
			//RXA-7 Administered Units.  Required if RXA-6 is not "999".  Cadinality [0..1].  Type CE (guide page 53).  Value set HL70396 (guide page 231).  Must be UCUM coding.
			if(vaccine.AdministeredAmt>0 && vaccine.DrugUnitNum!=0) {
				DrugUnit drugUnit=DrugUnits.GetOne(vaccine.DrugUnitNum);
				Ucum ucum=Ucums.GetByCode(drugUnit.UnitIdentifier);
				WriteCE(7,ucum.UcumCode,ucum.Description,"UCUM");//UCUM is not in table HL70396, but it there was a note stating that it was required in the guide and UCUM was required in the test cases.
			}
			//RXA-8 Administered Dosage Form.  Optional.
			//RXA-9 Administration Notes.  Required if RXA-20 is "CP" or "PA".  Value set NIP 0001.  Type CE.
			if(vaccine.CompletionStatus==VaccineCompletionStatus.Complete || vaccine.CompletionStatus==VaccineCompletionStatus.PartiallyAdministered) {
				if(vaccine.AdministrationNoteCode==VaccineAdministrationNote.NewRecord) {
					WriteCE(9,"00","New immunization record","NIP001");
				}
				else if(vaccine.AdministrationNoteCode==VaccineAdministrationNote.HistoricalSourceUnknown) {
					WriteCE(9,"01","Historical information - source unspecified","NIP001");
				}
				else if(vaccine.AdministrationNoteCode==VaccineAdministrationNote.HistoricalOtherProvider) {
					WriteCE(9,"02","Historical information - from other provider","NIP001");
				}
				else if(vaccine.AdministrationNoteCode==VaccineAdministrationNote.HistoricalParentsWrittenRecord) {
					WriteCE(9,"03","Historical information - from parent's written record","NIP001");
				}
				else if(vaccine.AdministrationNoteCode==VaccineAdministrationNote.HistoricalParentsRecall) {
					WriteCE(9,"04","Historical information - from parent's recall","NIP001");
				}
				else if(vaccine.AdministrationNoteCode==VaccineAdministrationNote.HistoricalOtherRegistry) {
					WriteCE(9,"05","Historical information - from other registry","NIP001");
				}
				else if(vaccine.AdministrationNoteCode==VaccineAdministrationNote.HistoricalBirthCertificate) {
					WriteCE(9,"06","Historical information - from birth certificate","NIP001");
				}
				else if(vaccine.AdministrationNoteCode==VaccineAdministrationNote.HistoricalSchoolRecord) {
					WriteCE(9,"07","Historical information - from school record","NIP001");
				}
				else if(vaccine.AdministrationNoteCode==VaccineAdministrationNote.HistoricalPublicAgency) {
					WriteCE(9,"08","Historical information - from public agency","NIP001");
				}
			}
			//RXA-10 Administering Provider.  Required if known.  Type XCN.  This is the person who gave the administration or the vaccinaton.  It is not the ordering clinician.
			Provider provAdministering=Providers.GetProv(vaccine.ProvNumAdminister);//Can be null when vaccine.ProvNumAdminister is zero.
			if(provAdministering!=null) {
				WriteXCN(10,provAdministering.FName,provAdministering.LName,provAdministering.MI,provAdministering.ProvNum.ToString(),cityWhereEntered,stateWhereEntered,"L");
			}
			//RXA-11 Administered-at Location.  Required if known.  Type LA2 (guide page 68).  This is the clinic/site where the vaccine was administered.
			WriteLA2(11,_sendingFacilityName);
			//RXA-12 Administered Per (Time Unit).  Optional.
			//RXA-13 Administered Strength.  Optional.
			//RXA-14 Administered Strength Units.  Optional.
			//RXA-15 Substance Lot Number.  Required if the value in RXA-9.1 is "00".  We decided not to send this field if NotAdministered because we observed such behavior in the testing tool.
			if(vaccine.CompletionStatus!=VaccineCompletionStatus.NotAdministered && vaccine.LotNumber.Trim()!="") {
				_seg.SetField(15,vaccine.LotNumber.Trim());
			}
			//RXA-16 Substance Expiration Date.  Required if RXA-15 is not blank.  Must include at least year and month, but day is not required.  We decided not to send this field if NotAdministered because we observed such behavior in the testing tool.
			if(vaccine.CompletionStatus!=VaccineCompletionStatus.NotAdministered && vaccine.DateExpire.Year>1880) {
				_seg.SetField(16,vaccine.DateExpire.ToString("yyyyMMdd"));
			}
			//RXA-17 Substance Manufacturer Name.  Requred if RXA-9.1 is "00".  Cardinality [0..*].  Value set MVX.  Type CE.
			if(vaccine.CompletionStatus!=VaccineCompletionStatus.NotAdministered && vaccineDef.DrugManufacturerNum!=0) {
				DrugManufacturer manufacturer=DrugManufacturers.GetOne(vaccineDef.DrugManufacturerNum);
				WriteCE(17,manufacturer.ManufacturerCode,manufacturer.ManufacturerName,"MVX");
			}
			//RXA-18 Substance/Treatment Refusal Reason.  Required if RXA-20 is "RE".  Cardinality [0..*].  Required when RXA-20 is "RE", otherwise do not send.  Value set NIP002.
			if(vaccine.RefusalReason==VaccineRefusalReason.ParentalDecision) {
				WriteCE(18,"00","Parental decision","NIP002");
			}
			else if(vaccine.RefusalReason==VaccineRefusalReason.ReligiousExemption) {
				WriteCE(18,"01","Religious exemption","NIP002");
			}
			else if(vaccine.RefusalReason==VaccineRefusalReason.Other) {
				WriteCE(18,"02",vaccine.Note,"NIP002");//The reason is required instead of a generic description for this particular situation.
			}
			else if(vaccine.RefusalReason==VaccineRefusalReason.PatientDecision) {
				WriteCE(18,"03","Patient decision","NIP002");
			}
			//RXA-19 Indication.  Optional.
			//RXA-20 Completion Status.  Required if known (length 2..2).  Value set HL70322 (guide page 225).  CP=Complete, RE=Refused, NA=Not Administered, PA=Partially Administered.
			if(vaccine.CompletionStatus==VaccineCompletionStatus.Refused) {
				_seg.SetField(20,"RE");
			}
			else if(vaccine.CompletionStatus==VaccineCompletionStatus.NotAdministered) {
				_seg.SetField(20,"NA");
			}
			else if(vaccine.CompletionStatus==VaccineCompletionStatus.PartiallyAdministered) {
				_seg.SetField(20,"PA");
			}
			else {//Complete (default)
				_seg.SetField(20,"CP");
			}
			//RXA-21 Action code.  Required if known (length 2..2).  Value set HL70323 (guide page 225).  A=Add, D=Delete, U=Update.
			if(vaccine.ActionCode==VaccineAction.Add) {
				_seg.SetField(21,"A");
			}
			else if(vaccine.ActionCode==VaccineAction.Delete) {
				_seg.SetField(21,"D");
			}
			else if(vaccine.ActionCode==VaccineAction.Update) {
				_seg.SetField(21,"U");
			}
			//RXA-22 System Entry Date/Time.  Optional.
			//RXA-23 Administered Drug Strength.  Optional.
			//RXA-24 Administered Drug Strength Volume Units.  Optional.
			//RXA-25 Administered Barcode Identifier.  Optional.
			//RXA-26 Pharmacy Order Type.  Optional.
			_msg.Segments.Add(_seg);
		}
Пример #29
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;
            }
        }
Пример #30
0
 ///<summary>If relationship is self, this loop does nothing.  A new pat will later change guarantor to be same as patnum. </summary>
 public static void ProcessGT1(Patient pat,SegmentHL7 seg,bool useChartNumber)
 {
     long guarNum=PIn.Long(seg.GetFieldFullText(2));
     if(guarNum==0) {//because we have an example where they sent us this (position 2 is empty): GT1|1||^^||^^^^||||||||
         return;
     }
     if(seg.GetFieldFullText(11)=="1") {//if relationship is self (according to some of their documentation)
         return;
     }
     Patient guar=null;
     Patient guarOld=null;
     //So guarantor is someone else
     if(useChartNumber) {
         //try to find guarantor by using chartNumber
         guar=Patients.GetPatByChartNumber(guarNum.ToString());
         if(guar==null) {
             //try to find the guarantor by using name and birthdate
             string lName=seg.GetFieldComponent(3,0);
             string fName=seg.GetFieldComponent(3,1);
             DateTime birthdate=SegmentPID.DateParse(seg.GetFieldFullText(8));
             long guarNumByName=Patients.GetPatNumByNameAndBirthday(lName,fName,birthdate);
             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);
                 guar.ChartNumber=guarNum.ToString();//from now on, we will be able to find guar by chartNumber
             }
         }
     }
     else {
         guar=Patients.GetPat(guarNum);
     }
     //we can't necessarily set pat.Guarantor yet, because in Standalone mode, we might not know it yet.
     bool isNewGuar= guar==null;
     if(isNewGuar) {//then we need to add guarantor to db
         guar=new Patient();
         if(useChartNumber) {
             guar.ChartNumber=guarNum.ToString();
         }
         else {
             guar.PatNum=guarNum;
         }
         guar.PriProv=PrefC.GetLong(PrefName.PracticeDefaultProv);
         guar.BillingType=PrefC.GetLong(PrefName.PracticeDefaultBillType);
     }
     else {
         guarOld=guar.Copy();
     }
     //guar.Guarantor=guarNum;
     guar.LName=seg.GetFieldComponent(3,0);
     guar.FName=seg.GetFieldComponent(3,1);
     guar.MiddleI=seg.GetFieldComponent(3,2);
     guar.Address=seg.GetFieldComponent(5,0);
     guar.Address2=seg.GetFieldComponent(5,1);
     guar.City=seg.GetFieldComponent(5,2);
     guar.State=seg.GetFieldComponent(5,3);
     guar.Zip=seg.GetFieldComponent(5,4);
     guar.HmPhone=PhoneParse(seg.GetFieldFullText(6));
     guar.WkPhone=PhoneParse(seg.GetFieldFullText(7));
     guar.Birthdate=DateParse(seg.GetFieldFullText(8));
     guar.Gender=GenderParse(seg.GetFieldFullText(9));
     //11. Guarantor relationship to patient.  We can't really do anything with this value
     guar.SSN=seg.GetFieldFullText(12);
     if(isNewGuar) {
         Patients.Insert(guar,true);
         guarOld=guar.Copy();
         guar.Guarantor=guar.PatNum;
         Patients.Update(guar,guarOld);
     }
     else {
         Patients.Update(guar,guarOld);
     }
     pat.Guarantor=guar.PatNum;
 }
Пример #31
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;
        }
Пример #32
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;
		}
Пример #33
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;
        }
Пример #34
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;
		}
Пример #35
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;
        }
Пример #36
0
 ///<summary>Message Header Segment</summary>
 private void MSH()
 {
     seg=new SegmentHL7(@"MSH|^~\&|OD||ECW||"+DateTime.Now.ToString("yyyyMMddHHmmss")+"||DFT^P03||P|2.3");
     msg.Segments.Add(seg);
 }
Пример #37
0
        ///<summary>Returns null if there is no HL7Def enabled or if there is no outbound ADT defined for the enabled HL7Def.</summary>
        public static MessageHL7 GenerateADT(Patient pat, Patient guar, EventTypeHL7 eventType)
        {
            HL7Def hl7Def = HL7Defs.GetOneDeepEnabled();

            if (hl7Def == null)
            {
                return(null);
            }
            //find an outbound ADT message in the def
            HL7DefMessage hl7DefMessage = null;

            for (int i = 0; i < hl7Def.hl7DefMessages.Count; i++)
            {
                if (hl7Def.hl7DefMessages[i].MessageType == MessageTypeHL7.ADT && hl7Def.hl7DefMessages[i].InOrOut == InOutHL7.Outgoing)
                {
                    hl7DefMessage = hl7Def.hl7DefMessages[i];
                    //continue;
                    break;
                }
            }
            if (hl7DefMessage == null)           //ADT message type is not defined so do nothing and return
            {
                return(null);
            }
            if (PrefC.GetBool(PrefName.ShowFeaturePatientClone))
            {
                pat = Patients.GetOriginalPatientForClone(pat);
            }
            MessageHL7     messageHL7   = new MessageHL7(MessageTypeHL7.ADT);
            Provider       prov         = Providers.GetProv(Patients.GetProvNum(pat));
            List <PatPlan> listPatPlans = PatPlans.Refresh(pat.PatNum);

            for (int i = 0; i < hl7DefMessage.hl7DefSegments.Count; i++)
            {
                int countRepeat = 1;
                //IN1 segment can repeat, get the number of current insurance plans attached to the patient
                if (hl7DefMessage.hl7DefSegments[i].SegmentName == SegmentNameHL7.IN1)
                {
                    countRepeat = listPatPlans.Count;
                }
                //countRepeat is usually 1, but for repeatable/optional fields, it may be 0 or greater than 1
                //for example, countRepeat can be zero if the patient does not have any current insplans, in which case no IN1 segments will be included
                for (int j = 0; j < countRepeat; j++)           //IN1 is optional and can repeat so add as many as listPatplans
                {
                    PatPlan patplanCur = null;
                    InsPlan insplanCur = null;
                    InsSub  inssubCur  = null;
                    Carrier carrierCur = null;
                    Patient patSub     = null;
                    if (hl7DefMessage.hl7DefSegments[i].SegmentName == SegmentNameHL7.IN1)                   //index repeat is guaranteed to be less than listPatplans.Count
                    {
                        patplanCur = listPatPlans[j];
                        inssubCur  = InsSubs.GetOne(patplanCur.InsSubNum);
                        insplanCur = InsPlans.RefreshOne(inssubCur.PlanNum);
                        carrierCur = Carriers.GetCarrier(insplanCur.CarrierNum);
                        if (pat.PatNum == inssubCur.Subscriber)
                        {
                            patSub = pat.Copy();
                        }
                        else
                        {
                            patSub = Patients.GetPat(inssubCur.Subscriber);
                        }
                    }
                    SegmentHL7 seg = new SegmentHL7(hl7DefMessage.hl7DefSegments[i].SegmentName);
                    seg.SetField(0, hl7DefMessage.hl7DefSegments[i].SegmentName.ToString());
                    for (int k = 0; k < hl7DefMessage.hl7DefSegments[i].hl7DefFields.Count; k++)
                    {
                        string fieldName = hl7DefMessage.hl7DefSegments[i].hl7DefFields[k].FieldName;
                        if (fieldName == "")                       //If fixed text instead of field name just add text to segment
                        {
                            seg.SetField(hl7DefMessage.hl7DefSegments[i].hl7DefFields[k].OrdinalPos, hl7DefMessage.hl7DefSegments[i].hl7DefFields[k].FixedText);
                        }
                        else
                        {
                            string fieldValue = "";
                            if (hl7DefMessage.hl7DefSegments[i].SegmentName == SegmentNameHL7.IN1)
                            {
                                fieldValue = FieldConstructor.GenerateFieldIN1(hl7Def, fieldName, j + 1, patplanCur, inssubCur, insplanCur, carrierCur, listPatPlans.Count, patSub);
                            }
                            else
                            {
                                fieldValue = FieldConstructor.GenerateFieldADT(hl7Def, fieldName, pat, prov, guar, j + 1, eventType, seg.Name);
                            }
                            seg.SetField(hl7DefMessage.hl7DefSegments[i].hl7DefFields[k].OrdinalPos, fieldValue);
                        }
                    }
                    messageHL7.Segments.Add(seg);
                }
            }
            return(messageHL7);
        }
Пример #38
0
        ///<summary>If relationship is self, this loop does nothing.  A new pat will later change guarantor to be same as patnum. </summary>
        public static void ProcessGT1(Patient pat, SegmentHL7 seg, bool useChartNumber)
        {
            long guarNum = PIn.Long(seg.GetFieldFullText(2));

            if (guarNum == 0)           //because we have an example where they sent us this (position 2 is empty): GT1|1||^^||^^^^||||||||
            {
                return;
            }
            if (seg.GetFieldFullText(11) == "1")           //if relationship is self (according to some of their documentation)
            {
                return;
            }
            Patient guar    = null;
            Patient guarOld = null;

            //So guarantor is someone else
            if (useChartNumber)
            {
                //try to find guarantor by using chartNumber
                guar = Patients.GetPatByChartNumber(guarNum.ToString());
                if (guar == null)
                {
                    //try to find the guarantor by using name and birthdate
                    string   lName         = seg.GetFieldComponent(3, 0);
                    string   fName         = seg.GetFieldComponent(3, 1);
                    DateTime birthdate     = SegmentPID.DateParse(seg.GetFieldFullText(8));
                    long     guarNumByName = Patients.GetPatNumByNameAndBirthday(lName, fName, birthdate);
                    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);
                        guar.ChartNumber = guarNum.ToString();                      //from now on, we will be able to find guar by chartNumber
                    }
                }
            }
            else
            {
                guar = Patients.GetPat(guarNum);
            }
            //we can't necessarily set pat.Guarantor yet, because in Standalone mode, we might not know it yet.
            bool isNewGuar = guar == null;

            if (isNewGuar)             //then we need to add guarantor to db
            {
                guar = new Patient();
                if (useChartNumber)
                {
                    guar.ChartNumber = guarNum.ToString();
                }
                else
                {
                    guar.PatNum = guarNum;
                }
                guar.PriProv     = PrefC.GetLong(PrefName.PracticeDefaultProv);
                guar.BillingType = PrefC.GetLong(PrefName.PracticeDefaultBillType);
            }
            else
            {
                guarOld = guar.Copy();
            }
            //guar.Guarantor=guarNum;
            guar.LName     = seg.GetFieldComponent(3, 0);
            guar.FName     = seg.GetFieldComponent(3, 1);
            guar.MiddleI   = seg.GetFieldComponent(3, 2);
            guar.Address   = seg.GetFieldComponent(5, 0);
            guar.Address2  = seg.GetFieldComponent(5, 1);
            guar.City      = seg.GetFieldComponent(5, 2);
            guar.State     = seg.GetFieldComponent(5, 3);
            guar.Zip       = seg.GetFieldComponent(5, 4);
            guar.HmPhone   = PhoneParse(seg.GetFieldFullText(6));
            guar.WkPhone   = PhoneParse(seg.GetFieldFullText(7));
            guar.Birthdate = DateParse(seg.GetFieldFullText(8));
            guar.Gender    = GenderParse(seg.GetFieldFullText(9));
            //11. Guarantor relationship to patient.  We can't really do anything with this value
            guar.SSN = seg.GetFieldFullText(12);
            if (isNewGuar)
            {
                Patients.Insert(guar, true);
                guarOld        = guar.Copy();
                guar.Guarantor = guar.PatNum;
                Patients.Update(guar, guarOld);
            }
            else
            {
                Patients.Update(guar, guarOld);
            }
            pat.Guarantor = guar.PatNum;
        }
Пример #39
0
        public static void ProcessMessage(MessageHL7 message, bool isStandalone, bool isVerboseLogging)
        {
            /*string triggerevent=message.Segments[0].GetFieldComponent(8,1);
             * switch(triggerevent) {
             *      case "A01"://Admit/Visit Information
             *
             *              break;
             *      case "A04"://New Patient Information
             *              ProcessNewPatient(message);
             *              break;
             *      case "A08"://Update Patient Information
             *
             *              break;
             *      case "A28"://Add Patient Information
             *
             *              break;
             *      case "A31"://Update Patient Information
             *
             *              break;
             * }*/
            //MSH-Ignore
            //EVN-Ignore
            //PID-------------------------------------
            SegmentHL7 seg    = message.GetSegment(SegmentNameHL7.PID, true);
            long       patNum = PIn.Long(seg.GetFieldFullText(2));
            Patient    pat    = null;

            if (isStandalone)
            {
                pat = Patients.GetPatByChartNumber(patNum.ToString());
                if (pat == null)
                {
                    //try to find the patient in question by using name and birthdate
                    string   lName        = seg.GetFieldComponent(5, 0);
                    string   fName        = seg.GetFieldComponent(5, 1);
                    DateTime birthdate    = EcwSegmentPID.DateParse(seg.GetFieldFullText(7));
                    long     patNumByName = Patients.GetPatNumByNameAndBirthday(lName, fName, birthdate);
                    if (patNumByName == 0)                   //patient does not exist in OD
                    //so pat will still be null, triggering creation of new patient further down.
                    {
                    }
                    else
                    {
                        pat             = Patients.GetPat(patNumByName);
                        pat.ChartNumber = patNum.ToString();                      //from now on, we will be able to find pat by chartNumber
                    }
                }
            }
            else
            {
                pat = Patients.GetPat(patNum);
            }
            Patient patOld   = null;
            bool    isNewPat = pat == null;

            if (isNewPat)
            {
                pat = new Patient();
                if (isStandalone)
                {
                    pat.ChartNumber = patNum.ToString();
                    //this line does not work if isStandalone, so moved to end
                    //pat.Guarantor=patNum;
                }
                else
                {
                    pat.PatNum    = patNum;
                    pat.Guarantor = patNum;
                }
                pat.PriProv     = PrefC.GetLong(PrefName.PracticeDefaultProv);
                pat.BillingType = PrefC.GetLong(PrefName.PracticeDefaultBillType);
            }
            else
            {
                patOld = pat.Copy();
            }
            EcwSegmentPID.ProcessPID(pat, seg, isStandalone);
            //PV1-patient visit---------------------------
            //seg=message.GetSegment(SegmentName.PV1,false);
            //if(seg!=null) {//this seg is optional
            //	SegmentPID.ProcessPV1(pat,seg);
            //}
            //PD1-additional patient demographics------------
            //seg=message.GetSegment(SegmentName.PD1,false);
            //if(seg!=null) {//this seg is optional
            //	ProcessPD1(pat,seg);
            //}
            //GT1-Guarantor-------------------------------------
            seg = message.GetSegment(SegmentNameHL7.GT1, true);
            EcwSegmentPID.ProcessGT1(pat, seg, isStandalone);
            //IN1-Insurance-------------------------------------
            //List<SegmentHL7> segments=message.GetSegments(SegmentName.IN1);
            //for(int i=0;i<segments.Count;i++) {
            //	ProcessIN1(pat,seg);
            //}
            if (pat.FName == "" || pat.LName == "")
            {
                EventLog.WriteEntry("OpenDentHL7", "Patient demographics not processed due to missing first or last name. PatNum:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                return;
            }
            if (isNewPat)
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Inserted patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Patients.Insert(pat, true);
                if (pat.Guarantor == 0)
                {
                    patOld        = pat.Copy();
                    pat.Guarantor = pat.PatNum;
                    Patients.Update(pat, patOld);
                }
            }
            else
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Updated patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                Patients.Update(pat, patOld);
            }
        }
Пример #40
0
		///<summary>Next of Kin segment.  Required if known.  Guide page 111.</summary>
		private void NK1() {
			List<Guardian> listGuardians=Guardians.Refresh(_pat.PatNum);
			for(int i=0;i<listGuardians.Count;i++) {//One NK1 segment for each relationship.
				_seg=new SegmentHL7(SegmentNameHL7.NK1);
				_seg.SetField(0,"NK1");
				_seg.SetField(1,(i+1).ToString());//NK1-1 Set ID.  Required (length unspecified).  Cardinality [1..1].
				//NK-2 Name.  Required (length unspecified).  Type XPN (guide page 82).  Cardinarlity [1..1].
				Patient patNextOfKin=Patients.GetPat(listGuardians[i].PatNumGuardian);
				WriteXPN(2,patNextOfKin.FName,patNextOfKin.LName,patNextOfKin.MiddleI,"L");
				//NK1-3 Relationship.  Required.  Cardinality [1..1].  Value set HL70063 (guide page 196).  Type CE.
				GuardianRelationship relat=listGuardians[i].Relationship;
				string strRelatCode="";
				if(relat==GuardianRelationship.Brother) {
					strRelatCode="BRO";
				}
				else if(relat==GuardianRelationship.CareGiver) {
					strRelatCode="CGV";
				}
				else if(relat==GuardianRelationship.Child) {
					strRelatCode="CHD";//This relationship type is not documented in the guide, but it is defined as part of HL7 0063 in a more recent publication.  We added because it seemed like a basic relationship type.
				}
				else if(relat==GuardianRelationship.Father) {
					strRelatCode="FTH";
				}
				else if(relat==GuardianRelationship.FosterChild) {
					strRelatCode="FCH";
				}
				else if(relat==GuardianRelationship.Friend) {
					strRelatCode="FND";//This relationship type is not documented in the guide, but it is defined as part of HL7 0063 in a more recent publication.  We added because it seemed like a basic relationship type.
				}
				else if(relat==GuardianRelationship.Grandchild) {
					strRelatCode="GCH";//This relationship type is not documented in the guide, but it is defined as part of HL7 0063 in a more recent publication.  We added because it seemed like a basic relationship type.
				}
				else if(relat==GuardianRelationship.Grandfather) { //This status is from our older guardian implementation.
					strRelatCode="GRD";//Grandparent
				}
				else if(relat==GuardianRelationship.Grandmother) { //This status is from our older guardian implementation.
					strRelatCode="GRD";//Grandparent
				}
				else if(relat==GuardianRelationship.Grandparent) {
					strRelatCode="GRD";
				}
				else if(relat==GuardianRelationship.Guardian) {
					strRelatCode="GRD";
				}
				else if(relat==GuardianRelationship.LifePartner) {
					strRelatCode="DOM";//This relationship type is not documented in the guide, but it is defined as part of HL7 0063 in a more recent publication.  We added because it seemed like a basic relationship type.
				}
				else if(relat==GuardianRelationship.Mother) {
					strRelatCode="MTH";
				}
				else if(relat==GuardianRelationship.Other) {
					strRelatCode="OTH";
				}
				else if(relat==GuardianRelationship.Parent) {
					strRelatCode="PAR";
				}
				else if(relat==GuardianRelationship.Self) {
					strRelatCode="SEL";
				}
				else if(relat==GuardianRelationship.Sibling) {
					strRelatCode="SIB";
				}
				else if(relat==GuardianRelationship.Sister) {
					strRelatCode="SIS";
				}
				else if(relat==GuardianRelationship.Sitter) { //This status is from our older guardian implementation.
					strRelatCode="CGV";//Caregiver
				}
				else if(relat==GuardianRelationship.Spouse) {
					strRelatCode="SPO";
				}
				else if(relat==GuardianRelationship.Stepchild) {
					strRelatCode="SCH";
				}
				else if(relat==GuardianRelationship.Stepfather) { //This status is from our older guardian implementation.
					strRelatCode="PAR";//parent
				}
				else if(relat==GuardianRelationship.Stepmother) { //This status is from our older guardian implementation.
					strRelatCode="PAR";//parent
				}
				else {
					continue;//Skip the entire segment if the relationship is not known.  Should not happen.
				}
				WriteCE(3,strRelatCode,relat.ToString(),"HL70063");
				//NK-4 Address.  Required if known (length unspecified).  Cardinality [0..1].  Type XAD (guide page 74).  The first instance must be the primary address.
				WriteXAD(4,patNextOfKin.Address,patNextOfKin.Address2,patNextOfKin.City,patNextOfKin.State,patNextOfKin.Zip);
				//NK-5 Phone Number.  Required if known.  Cardinality [0..*].  Type XTN (guide page 84).  The first instance shall be the primary phone number.
				WriteXTN(5,"PRN","PH","F",patNextOfKin.HmPhone,"PRN","CP","",patNextOfKin.WirelessPhone);
				//NK-6 Business Phone Number.  Optional.  Type XTN (guide page 84).
				WriteXTN(6,"WPN","PH","",patNextOfKin.WkPhone);
				//NK-7 Contact Role.  Optional.
				//NK-8 Start Date.  Optional.
				//NK-9 End Date.  Optional.
				//NK-10 Next of Kin/Associated Parties Job Title.  Optional.
				//NK-11 Next of Kin/Associated Parties Job Code/Class.  Optional.
				//NK-12 Next of Kin/Associated Parties Employee Number.  Optional.
				//NK-13 Organization Name - NK1.  Optional.
				//NK-14 Marital Status.  Optional.
				//NK-15 Administrative Sex.  Optional.
				//NK-16 Date/Time of Birth.  Optional.
				//NK-17 Living Dependency.  Optional.
				//NK-18 Ambulatory Status.  Optional.
				//NK-19 Citizenship.  Optional.
				//NK-20 Primary Language.  Optional.
				//NK-21 Living Arrangement.  Optional.
				//NK-22 Publicity Code.  Optional.
				//NK-23 Protection Indicator.  Optional.
				//NK-24 Student Indicator.  Optional.
				//NK-25 Religion.  Optional.
				//NK-26 Mother's Maiden Name.  Optional.
				//NK-27 Nationality.  Optional.
				//NK-28 Ethnic Group.  Optional.
				//NK-29 Contact Reason.  Optional.
				//NK-30 Contact Person's Name.  Optional.
				//NK-31 Contact Person's Telephone Number.  Optional.
				//NK-32 Contact Person's Address.  Optional.
				//NK-33 Next of Kin/Associated Party's Identifiers.  Optional.
				//NK-34 Job Status.  Optional.
				//NK-35 Race.  Optional.
				//NK-36 Handicap.  Optional.
				//NK-37 Contact Person Social Security Number.  Optional.
				//NK-38 Next of Kin Birth Place.  Optional.
				//NK-39 VIP Indicator.  Optional.
				_msg.Segments.Add(_seg);
			}
		}
Пример #41
0
        public MessageHL7(string msgtext)
        {
            AckCode         = "";
            ControlId       = "";
            AckEvent        = "";
            originalMsgText = msgtext;
            Segments        = new List <SegmentHL7>();
            string[] rows = msgtext.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);
            //We need to get the separator characters in order to create the field objects.
            //The separators are part of the MSH segment and we force users to leave them in position 1 for incoming messages.
            Delimiters = new char[] { '^', '~', '\\', '&' };       //this is the default, but we will get them from the MSH segment of the incoming message in case they are using something unique.
            //if def is enabled, set delimiters to user defined values
            HL7Def enabledDef = HL7Defs.GetOneDeepEnabled();

            if (enabledDef != null)
            {
                for (int i = 0; i < rows.Length; i++)
                {
                    //we're going to assume that the user has not inserted an escaped '|' before the second field of the message and just split by '|'s without
                    //checking for escaped '|'s.  Technically '\|' would be a literal pipe and should not indicate a new field, but we only want to retrieve the
                    //delimiters from MSH.1 and we require field 0 to be MSH and field 1 should be ^~\&.
                    string[] fields = rows[i].Split(new string[] { "|" }, StringSplitOptions.None);
                    if (fields.Length > 1 && fields[0] == "MSH" && fields[1].Length == 4)
                    {
                        //Encoding characters are in the following order:  component separator, repetition separator, escape character, subcomponent separator
                        Delimiters = fields[1].ToCharArray();                      //we force users to leave the delimiters in position 1 of the MSH segment
                        break;
                    }
                }
            }
            SegmentHL7 segment;

            for (int i = 0; i < rows.Length; i++)
            {
                segment = new SegmentHL7(rows[i], Delimiters);             //this creates the field objects.
                Segments.Add(segment);
                if (i == 0 && segment.Name == SegmentNameHL7.MSH)
                {
//js 7/3/12 Make this more intelligent because we also now need the suffix
                    string msgtype      = segment.GetFieldComponent(8, 0);            //We force the user to leave the 'messageType' field in this position, position 8 of the MSH segment
                    string evnttype     = segment.GetFieldComponent(8, 1);
                    string msgStructure = segment.GetFieldComponent(8, 2);
                    AckEvent = evnttype;                  //We will use this when constructing the acknowledgment to echo back to sender the same event type sent to us
                    //If message type or event type are not in this list, they will default to the not supported type and will not be processed
                    try {
                        MsgType = (MessageTypeHL7)Enum.Parse(typeof(MessageTypeHL7), msgtype, true);
                    }
                    catch (Exception ex) {
                        ex.DoNothing();
                        MsgType = MessageTypeHL7.NotDefined;
                    }
                    try {
                        EventType = (EventTypeHL7)Enum.Parse(typeof(EventTypeHL7), evnttype, true);
                    }
                    catch (Exception ex) {
                        ex.DoNothing();
                        EventType = EventTypeHL7.NotDefined;
                    }
                    try {
                        MsgStructure = (MessageStructureHL7)Enum.Parse(typeof(MessageStructureHL7), msgStructure, true);
                    }
                    catch (Exception ex) {
                        ex.DoNothing();
                        MsgStructure = MessageStructureHL7.NotDefined;
                    }
                }
            }
        }
Пример #42
0
		///<summary>Order Request segment.  Required.  Guide page 126.</summary>
		private void ORC(VaccinePat vaccine) {
			_seg=new SegmentHL7(SegmentNameHL7.ORC);
			_seg.SetField(0,"ORC");
			_seg.SetField(1,"RE");//ORC-1 Order Control.  Required (length 2).  Cardinality [1..1].  Value set HL70119.  The only allowed value is "RE".
			//ORC-2 Placer Order Number.  Required if known.  Cardinality [0..1].  Type EI (guid page 62).
			//ORC-3 Filler Order Number.  Required.  Cardinality [0..1].  Type EI (guid page 62).  "Shall be the unique ID of the sending system."  The city and state are used to record the region where the vaccine record was filled.
			WriteEI(3,vaccine.VaccinePatNum.ToString(),vaccine.FilledCity.Trim(),vaccine.FilledST.Trim());
			//ORC-4 Placer Group Number.  Optional.
			//ORC-5 Order Status.  Optional.
			//ORD-6 Response Flag.  Optional.
			//ORD-7 Quantity/Timing.  No longer used.
			//ORD-8 Parent.  Optional.
			//ORD-9 Date/Time of Transaction.  Optional.
			//ORD-10 Entered By.  Required if known.  Cardinality [0..1].  Type XCN.  This is the person that entered the immunization record into the system.
			Userod userod=Userods.GetUser(vaccine.UserNum);//Can be null if vaccine.UserNum=0 for older records before the vaccine.UserNum column existed.
			if(userod!=null) {
				if(userod.ProvNum!=0) {
					Provider provEnteredBy=Providers.GetProv(userod.ProvNum);
					WriteXCN(10,provEnteredBy.FName,provEnteredBy.LName,provEnteredBy.MI,vaccine.UserNum.ToString(),cityWhereEntered,stateWhereEntered,"D");
				}
				else if(userod.EmployeeNum!=0) {
					Employee employee=Employees.GetEmp(userod.EmployeeNum);
					WriteXCN(10,employee.FName,employee.LName,employee.MiddleI,vaccine.UserNum.ToString(),cityWhereEntered,stateWhereEntered,"D");
				}
			}
			//ORD-11 Verified By.  Optional.
			//ORD-12 Ordering Provider.  Required if known. Cardinality [0..1].  Type XCN.  This shall be the provider ordering the immunization.  It is expected to be empty if the immunization record is transcribed from a historical record.
			Provider provOrdering=Providers.GetProv(vaccine.ProvNumOrdering);//Can be null if vaccine.ProvNumOrdering is zero.
			if(provOrdering!=null) {
				WriteXCN(12,provOrdering.FName,provOrdering.LName,provOrdering.MI,provOrdering.ProvNum.ToString(),cityWhereEntered,stateWhereEntered,"L");
			}
			//ORD-13 Enterer's Location.  Optional.
			//ORD-14 Call Back Phone Number.  Optional.
			//ORD-15 Order Effective Date/Time.  Optional.
			//ORD-16 Order Control Code Reason.  Optional.
			//ORD-17 Entering Organization.  Optional.
			//ORD-18 Entering Device.  Optional.
			//ORD-19 Action By.  Optional.
			//ORD-20 Advanced Beneficiary Notice Code.  Optional.
			//ORD-21 Ordering Facility Name.  Optional.
			//ORD-22 Ordering Facility Address.  Optional.
			//ORD-23 Ordering Facility.  Optional.
			//ORD-24 Order Provider Address.  Optional.
			//ORD-25 Order Status Modifier.  Optional.
			//ORD-26 Advanced Beneficiary Notice Override Reason.  Optional.
			//ORD-27 Filler's Expected Availability Date/Time.  Optional.
			//ORD-28 Confidentiality Code.  Optional.
			//ORD-29 Order Type.  Optional.
			//ORD-30 Enterer Authorization Mode.  Optional.
			//ORD-31 Parent Universal Service Modifier.  Optional.
			_msg.Segments.Add(_seg);
		}
Пример #43
0
        public static void ProcessMessage(MessageHL7 message, bool isStandalone, bool isVerboseLogging)
        {
            /*string triggerevent=message.Segments[0].GetFieldComponent(8,1);
             * switch(triggerevent) {
             *      case "A01"://Admit/Visit Information
             *
             *              break;
             *      case "A04"://New Patient Information
             *              ProcessNewPatient(message);
             *              break;
             *      case "A08"://Update Patient Information
             *
             *              break;
             *      case "A28"://Add Patient Information
             *
             *              break;
             *      case "A31"://Update Patient Information
             *
             *              break;
             * }*/
            //MSH-Ignore
            //EVN-Ignore
            //PID-------------------------------------
            SegmentHL7 seg    = message.GetSegment(SegmentNameHL7.PID, true);
            long       patNum = PIn.Long(seg.GetFieldFullText(2));
            Patient    pat    = null;

            if (isStandalone)
            {
                pat = Patients.GetPatByChartNumber(patNum.ToString());
                if (pat == null)
                {
                    //try to find the patient in question by using name and birthdate
                    string   lName        = seg.GetFieldComponent(5, 0);
                    string   fName        = seg.GetFieldComponent(5, 1);
                    DateTime birthdate    = EcwSegmentPID.DateParse(seg.GetFieldFullText(7));
                    long     patNumByName = Patients.GetPatNumByNameAndBirthday(lName, fName, birthdate);
                    if (patNumByName == 0)                   //patient does not exist in OD
                    //so pat will still be null, triggering creation of new patient further down.
                    {
                    }
                    else
                    {
                        pat             = Patients.GetPat(patNumByName);
                        pat.ChartNumber = patNum.ToString();                      //from now on, we will be able to find pat by chartNumber
                    }
                }
            }
            else
            {
                pat = Patients.GetPat(patNum);
            }
            Patient patOld   = null;
            bool    isNewPat = pat == null;

            if (isNewPat)
            {
                pat = new Patient();
                if (isStandalone)
                {
                    pat.ChartNumber = patNum.ToString();
                    //this line does not work if isStandalone, so moved to end
                    //pat.Guarantor=patNum;
                }
                else
                {
                    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>();
            bool hasNoRaceInStandalone      = (isStandalone && (pat == null || pat.PatNum == 0));

            EcwSegmentPID.ProcessPID(pat, seg, isStandalone, listPatRaces);
            //PV1-patient visit---------------------------
            //seg=message.GetSegment(SegmentName.PV1,false);
            //if(seg!=null) {//this seg is optional
            //	SegmentPID.ProcessPV1(pat,seg);
            //}
            //PD1-additional patient demographics------------
            //seg=message.GetSegment(SegmentName.PD1,false);
            //if(seg!=null) {//this seg is optional
            //	ProcessPD1(pat,seg);
            //}
            //GT1-Guarantor-------------------------------------
            seg = message.GetSegment(SegmentNameHL7.GT1, true);
            EcwSegmentPID.ProcessGT1(pat, seg, isStandalone);
            //IN1-Insurance-------------------------------------
            //List<SegmentHL7> segments=message.GetSegments(SegmentName.IN1);
            //for(int i=0;i<segments.Count;i++) {
            //	ProcessIN1(pat,seg);
            //}
            if (pat.FName == "" || pat.LName == "")
            {
                EventLog.WriteEntry("OpenDentHL7", "Patient demographics not processed due to missing first or last name. PatNum:" + pat.PatNum.ToString()
                                    , EventLogEntryType.Information);
                return;
            }
            if (isNewPat)
            {
                if (isVerboseLogging)
                {
                    EventLog.WriteEntry("OpenDentHL7", "Inserted patient: " + pat.FName + " " + pat.LName, EventLogEntryType.Information);
                }
                pat.PatNum = Patients.Insert(pat, !isStandalone);             //use existing PK if not standalone, standalone will have PatNum=0, so set PatNum here
                SecurityLogs.MakeLogEntry(Permissions.PatientCreate, pat.PatNum, "Created from HL7 for eCW.", LogSources.HL7);
                if (hasNoRaceInStandalone)
                {
                    Patient patientRaceTemp = pat.Copy();                  //Make a deep copy so that we do not accidentally override something.
                    seg = message.GetSegment(SegmentNameHL7.PID, true);
                    //We have to process the PID again in order to correct the patient race.  Patient race(s) will automatically get inserted if needed.
                    EcwSegmentPID.ProcessPID(patientRaceTemp, seg, isStandalone, listPatRaces);
                }
                if (pat.Guarantor == 0)
                {
                    patOld        = pat.Copy();
                    pat.Guarantor = pat.PatNum;
                    Patients.Update(pat, patOld);
                }
            }
            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);
        }
Пример #44
0
		///<summary>Patient Identifier segment.  Required.  Guide page 137.</summary>
		private void PID() {
			_seg=new SegmentHL7(SegmentNameHL7.PID);
			_seg.SetField(0,"PID");
			_seg.SetField(1,"1");//PID-1 Set ID - PID.  Required if known.  Cardinality [0..1].  Must be "1" for the first occurrence.  Not sure why there would ever be more than one.
			//PID-2 Patient ID.  No longer used.
			//PID-3 Patient Identifier List.  Required.  Cardinality [1..*].  Type CX (see guide page 58 for type definition).
			_seg.SetField(3,
				_pat.PatNum.ToString(),//PID-3.1 ID Number.  Required (length 1..15).
				"",//PID-3.2 Check Digit.  Optional (length 1..1).
				"",//PID-3.3 Check Digit Scheme.  Required if PID-3.2 is specified.  Not required for our purposes.  Value set HL70061.
				"Open Dental",//PID-3.4 Assigning Authority.  Required.  Value set HL70363.
				"MR"//PID-3.5 Identifier Type Code.  Required (length 2..5).  Value set HL70203.  MR=medical record number.
				//PID-3.6 Assigning Facility.  Optional (length undefined).
				//PID-3.7 Effective Date.  Optional (length 4..8).
				//PID-3.8 Expiration Date.  Optional (length 4..8).
				//PID-3.9 Assigning Jurisdiction.  Optional (length undefined).
				//PID-3.10 Assigning Agency or Department.  Optional (length undefined).
			);
			if(_pat.SSN.Trim()!="") {
				_seg.RepeatField(3,
					_pat.SSN.Trim(),//PID-3.1 ID Number.  Required (length 1..15).
					"",//PID-3.2 Check Digit.  Optional (length 1..1).
					"",//PID-3.3 Check Digit Scheme.  Required if PID-3.2 is specified.  Not required for our purposes.  Value set HL70061.
					"Open Dental",//PID-3.4 Assigning Authority.  Required.  Value set HL70363.
					"SS"//PID-3.5 Identifier Type Code.  Required (length 2..5).  Value set HL70203.  SS=Social Security Number.
						//PID-3.6 Assigning Facility.  Optional (length undefined).
						//PID-3.7 Effective Date.  Optional (length 4..8).
						//PID-3.8 Expiration Date.  Optional (length 4..8).
						//PID-3.9 Assigning Jurisdiction.  Optional (length undefined).
						//PID-3.10 Assigning Agency or Department.  Optional (length undefined).
				);
			}
			//PID-4 Alternate Patient ID - 00106.  No longer used.
			WriteXPN(5,_pat.FName,_pat.LName,_pat.MiddleI,"L");//PID-5 Patient Name.  Required (length unspecified).  Cardinality [1..*].  Type XPN.  The first repetition must contain the legal name.
			EhrPatient ehrPatient=EhrPatients.Refresh(_pat.PatNum);
			WriteXPN(6,ehrPatient.MotherMaidenFname,ehrPatient.MotherMaidenLname,"","M");//PID-6 Mother's Maiden Name.  Required if known (length unspecified).  Cardinality [0..1].  Type XPN.
			//PID-7 Date/Time of Birth.  Required.  Cardinality [1..1].  We must specify "UNK" if unknown.
			if(_pat.Birthdate.Year<1880) {
				_seg.SetField(7,"UNK");
			}
			else {
				_seg.SetField(7,_pat.Birthdate.ToString("yyyyMMdd"));
			}
			WriteGender(8,_pat.Gender);//PID-8 Administrative Sex.  Required if known.  Cardinality [0..1].  Value set HL70001.
			//PID-9 Patient Alias.  No longer used.
			//PID-10 Race.  Required if known.  Cardinality [0..*].  Value set HL70005 (guide page 194).  Each race definition must be type CE.  Type CE is defined on guide page 53.
			List<PatientRace> listPatientRaces=PatientRaces.GetForPatient(_pat.PatNum);
			List<PatRace> listPatRacesFiltered=new List<PatRace>();
			bool isHispanicOrLatino=false;
			for(int i=0;i<listPatientRaces.Count;i++) {
				PatRace patRace=listPatientRaces[i].Race;
				if(patRace==PatRace.Hispanic) {
					isHispanicOrLatino=true;
				}
				else if(patRace==PatRace.NotHispanic) {
					//Nothing to do. Flag is set to false by default.
				}
				else if(patRace==PatRace.DeclinedToSpecifyRace) {
					listPatRacesFiltered.Clear();
					break;
				}
				else {
					listPatRacesFiltered.Add(patRace);
				}
			}
			for(int i=0;i<listPatRacesFiltered.Count;i++) {
				PatRace patRace=listPatRacesFiltered[i];
				string strRaceCode="";
				string strRaceName="";
				if(patRace==PatRace.AfricanAmerican) {
					strRaceCode="2054-5";
					strRaceName="Black or African American";
				}
				else if(patRace==PatRace.AmericanIndian) {
					strRaceCode="1002-5";
					strRaceName="American Indian or Alaska Native";
				}
				else if(patRace==PatRace.Asian) {
					strRaceCode="2028-9";
					strRaceName="Asian";
				}
				else if(patRace==PatRace.HawaiiOrPacIsland) {
					strRaceCode="2076-8";
					strRaceName="Native Hawaiian or Other Pacific Islander";
				}
				else if(patRace==PatRace.White) {
					strRaceCode="2106-3";
					strRaceName="White";
				}
				else {//Aboriginal, Other, Multiracial
					strRaceCode="2131-1";
					strRaceName="Other Race";
				}
				_seg.SetOrRepeatField(10,
					strRaceCode,//PID-10.1 Identifier.  Required (length 1..50).
					strRaceName,//PID-10.2  Text.  Required if known (length 1..999). Human readable text that is not further used.
					"HL70005"//PID-10.3 Name of Coding System.  Required (length 1..20).
					//PID-10.4 Alternate Identifier.  Required if known (length 1..50).
					//PID-10.5 Alternate Text.  Required if known (length 1..999).
					//PID-10.6 Name of Alternate Coding system.  Required if PID-10.4 is not blank.
				);
			}
			//PID-11 Patient Address.  Required if known (length unspecified).  Cardinality [0..*].  Type XAD (guide page 74).  First repetition must be the primary address.
			WriteXAD(11,_pat.Address,_pat.Address2,_pat.City,_pat.State,_pat.Zip);
			//PID-12 County Code.  No longer used.
			//PID-13 Phone Number - Home.  Required if known (length unspecified).  Cardinality [0..*].  Type XTN (guide page 84).  The first number must be the primary number (if email only, then blank phone followed by email).
			WriteXTN(13,"PRN","PH","F",_pat.HmPhone,"PRN","CP","",_pat.WirelessPhone,"NET","Internet","",_pat.Email);
			//PID-14 Phone Number - Business.  Optional.
			//PID-15 Primary Language.  Optional.
			//PID-16 Marital Status.  Optional.
			//PID-17 Religion.  Optional.
			//PID-18 Patient Account Number.  Optional.
			//PID-19 SSN Number - Patient.  No longer used.
			//PID-20 Driver's License Number - Patient.  No longer used.
			//PID-21 Mother's Identifier.  No longer used.
			//PID-22 Ethnic Group.  Required if known (length unspecified).  Cardinality [0..1].  Value set HL70189 (guide page 201).  Type CE.
			if(listPatRacesFiltered.Count>0) {//The user specified a race and ethnicity and did not select the decline to specify option.
				if(isHispanicOrLatino) {
					WriteCE(22,"2135-2","Hispanic or Latino","CDCREC");
				}
				else {//Not hispanic or latino.
					WriteCE(22,"2186-5","not Hispanic or Latino","CDCREC");
				}
			}
			//PID-23 Birth Place.  Optional.  Cardinaility [0..1].
			//PID-24 Multiple Birth Indicator.  Optional.  Cardinaility [0..1].
			//PID-25 Birth Order.  Required when PID-24 is set to "Y".  Cardinaility [0..1].
			//PID-26 Citizenship.  Optional.  Cardinaility [0..1].
			//PID-27 Veterans Military Status.  Optional.  Cardinaility [0..1].
			//PID-28 Nationality.  Optional.  Cardinaility [0..1].
			//PID-29 Patient Death Date and Time.  Required if PID-30 is set to "Y".  Cardinaility [0..1].  Date is required, time is not.
			//PID-30 Patient Death Indicator.  Required if known.  Cardinaility [0..1].  Value set HL70136.  Set this field to "Y" if the death date and time year is greater than 1880, otherwise do not set.
			//PID-31 Identity Unknown.  Optional.  Cardinaility [0..1].
			//PID-32 Identity Reliability Code.  Optional.  Cardinaility [0..1].
			//PID-33 Last Update Date/Time.  Optional.  Cardinaility [0..1].
			//PID-34 Last Update Facility.  Optional.  Cardinaility [0..1].
			//PID-35 Species Code.  Optional.  Cardinaility [0..1].
			//PID-36 Breed Code.  Optional.  Cardinaility [0..1].
			//PID-37 Strain.  Optional.  Cardinaility [0..1].
			//PID-38 Production Class Code.  Optional.  Cardinaility [0..1].
			//PID-39 Tribal Citizenship.  Optional.  Cardinaility [0..1].
			_msg.Segments.Add(_seg);
		}
Пример #45
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);
            }
        }
Пример #46
0
		///<summary>Message Segment Header segment.  Required.  Defines intent, source, destination and syntax of the message.  Guide page 104.</summary>
		private void MSH() {
			_seg=new SegmentHL7("MSH"
				+"|"//MSH-1 Field Separator (|).  Required (length 1..1).
				+@"^~\&"//MSH-2 Encoding Characters.  Required (length 4..4).  Component separator (^), then field repetition separator (~), then escape character (\), then Sub-component separator (&).
				+"|Open Dental"//MSH-3 Sending Application.  Required if known (length unspecified).  Value set HL70361  (guide page 229, "no suggested values defined").  Type HD (guide page 65).
				+"|"+_sendingFacilityName//MSH-4 Sending Facility.  Required if known (length unspecified).  Value set HL70362 (guide page 229, "no suggested values defined").  Type HD (guide page 65).
				+"|"//MSH-5 Receiving Application.  Required if known (length unspecified).  Value set HL70361 (guide page 229, "no suggested values defined").  Type HD (guide page 65).
				+"|EHR Facility"//MSH-6 Receiving Facility.  Required if known (length unspecified).  Value set HL70362 (guide page 229, "no suggested values defined").  Type HD (guide page 65).
				+"|"+DateTime.Now.ToString("yyyyMMddHHmmss")//MSH-7 Date/Time of Message.  Required (length 12..19).
				+"|"//MSH-8 Security.  Optional (length unspecified).
				+"|VXU^V04^VXU_V04"//MSH-9 Message Type. Required (length unspecified).
				+"|OD-"+DateTime.Now.ToString("yyyyMMddHHmmss")+"-"+CodeBase.MiscUtils.CreateRandomAlphaNumericString(14)//MSH-10 Message Control ID.  Required (length 1..199).  Our IDs are 32 characters.
				+"|P"//MSH-11 Processing ID.  Required (length unspecified).  P=production.
				+"|2.5.1"//MSH-12 Version ID.  Required (length unspecified).  Must be exactly "2.5.1".
				+"|"//MSH-13 Sequence Number.  Optional (length unspecified).
				+"|"//MSH-14 Continuation Pointer.  Optional (length unspecified).
				+"|NE"//MSH-15 Accept Acknowledgement Type.  Required if known (length unspecified).  Value set HL70155 (AL=Always, ER=Error/rejection conditions only, NE=Never, SU=Successful completion only).
				+"|NE"//MSH-16 Application Acknowledgement Type.  Required if known (length unspecified).  Value set HL70155 (AL=Always, ER=Error/rejection conditions only, NE=Never, SU=Successful completion only).
				//MSH-17 Country Code.  Optional (length unspecified).  Value set HL70399.  Default value is USA.
				//MSH-18 Character Set.  Optional (length unspecified).
				//MSH-19 Principal Language Of Message.  Optional (length unspecified).
				//MSH-20 Alternate Character Set Handling Scheme.  Optional (length unspecified).
				//MSH-21 Message Profile Identifier.  Required if MSH9 component 1 is set to "QBP" or "RSP.  In our case, this field is not required.
			);
			_msg.Segments.Add(_seg);
		}
Пример #47
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;
		}
Пример #48
0
 ///<summary>PatNum will not be altered here.  The pat passed in must either have PatNum=0, or must have a PatNum matching the segment.  The reason that isStandalone is passed in is because if using tight integration mode (isStandalone=false), then we need to store the "alternate patient id" aka Account No. that comes in on PID.4 in the ChartNumber field so we can pass it back in PID.2 of the DFT charge message.  However, if not using tight integration (isStandalone=true), the ChartNumber field is already occupied by the eCW patient ID, and we do not want to overwrite it.</summary>
 public static void ProcessPID(Patient pat,SegmentHL7 seg,bool isStandalone)
 {
     long patNum=PIn.Long(seg.GetFieldFullText(2));
     //if(pat.PatNum==0) {
     //	pat.PatNum=patNum;
     //}
     //else
     if(pat.PatNum!=0 && pat.PatNum != patNum) {
         throw new ApplicationException("Invalid patNum");
     }
     if(!isStandalone) {//when in tight integration mode
         pat.ChartNumber=seg.GetFieldFullText(4);
     }
     pat.LName=seg.GetFieldComponent(5,0);
     pat.FName=seg.GetFieldComponent(5,1);
     pat.MiddleI=seg.GetFieldComponent(5,2);
     pat.Birthdate=DateParse(seg.GetFieldFullText(7));
     pat.Gender=GenderParse(seg.GetFieldFullText(8));
     pat.Race=RaceParse(seg.GetFieldFullText(10));
     pat.Address=seg.GetFieldComponent(11,0);
     pat.Address2=seg.GetFieldComponent(11,1);
     pat.City=seg.GetFieldComponent(11,2);
     pat.State=seg.GetFieldComponent(11,3);
     pat.Zip=seg.GetFieldComponent(11,4);
     pat.HmPhone=PhoneParse(seg.GetFieldFullText(13));
     pat.WkPhone=PhoneParse(seg.GetFieldFullText(14));
     pat.Position=MaritalStatusParse(seg.GetFieldFullText(16));
     //pat.ChartNumber=seg.GetFieldFullText(18);//this is wrong.  Would also break standalone mode
     pat.SSN=seg.GetFieldFullText(19);
     pat.FeeSched=FeeScheduleParse(seg.GetFieldFullText(22));
 }
Пример #49
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;
		}
Пример #50
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);
        }
Пример #51
0
 ///<summary>Patient Visit segment.  Used by Registration/Patient Administration applications to communicate information on a visit-specific basis.  Guide page 51.</summary>
 private void PV1()
 {
     _seg = new SegmentHL7(SegmentNameHL7.PV1);
     _seg.SetField(0, "PV1");
     _seg.SetField(1, "1");           //PV1-1 SET ID - PV1.  Required if known (length 1..4).  Must be set to "1".
     //PV1-2 Patient Class.  Optional.
     //PV1-3 Assigned Patient Location.  Optional.
     //PV1-4 Admission Type.  Optional.
     //PV1-5 Pre-admit Number.  No longer used.
     //PV1-6 Prior Patient Location.  No longer used.
     //PV1-7 Attending Doctor.  No longer used.
     //PV1-8 Referring Doctor.  No longer used.
     //PV1-9 Consulting Doctor.  No longer used.
     //PV1-10 Hospital Service.  Optional.
     //PV1-11 Temporary Location.  No longer used.
     //PV1-12 Preadmit Test Indicator.  No longer used.
     //PV1-13 Re-admission Indicator.  No longer used.
     //PV1-14 Admit Source.  Optional.
     //PV1-15 Ambulatory Status.  Optional.
     //PV1-16 VIP Indicator.  No longer used.
     //PV1-17 Admitting Doctor.  No longer used.
     //PV1-18 Patient Type.  No longer used.
     //PV1-19 Visit Number.  Required (length up to 478).  Cardinality [1..1].
     _seg.SetField(19,
                   _appt.AptNum.ToString(), //PV1-19.1 ID Number.  Required (length 1..15).  Unique identifier for patient visit.
                   "",                      //PV1-19.2 Check Digit.  No longer used.
                   "",                      //PV1-19.3 Check Digit Scheme.  No longer used.
                   "",                      //PV1-19.4 Assigning Authority.  Optional.
                   "VN"                     //PV1-19.5 Identifier Type Code.  Required (length 1..5).  Identifier type corresponding to the ID number from PV1-19.1.  VN=Visit Number.
                                            //PV1-19.6 Assigning Facility.  Optional.
                                            //PV1-19.7 Effective Date.  No longer used.
                                            //PV1-19.8 Expiration Date.  No longer used.
                                            //PV1-19.9 Assigning Jurisdiction.  No longer used.
                                            //PV1-19.10 Assigning Facility.  No longer used.
                   );
     //PV1-20 Financial Class.  No longer used.
     //PV1-21 Charge Price Indicator.  No longer used.
     //PV1-22 Courtesy Code.  No longer used.
     //PV1-23 Credit Rating.  No longer used.
     //PV1-24 Contract Code.  No longer used.
     //PV1-25 Contract Effective Date.  No longer used.
     //PV1-26 Contract Amount.  No longer used.
     //PV1-27 Contract Period.  No longer used.
     //PV1-28 Interest Code.  No longer used.
     //PV1-29 Transfer to Bad Debt Code.  No longer used.
     //PV1-30 Transfer to Bad Debt Date.  No longer used.
     //PV1-31 Bad Debt Agency Code.  No longer used.
     //PV1-32 Bad Debt Transfer Amount.  No longer used.
     //PV1-33 Bad Debt Recovery Amount.  No longer used.
     //PV1-34 Delete Account Indicator.  No longer used.
     //PV1-35 Delete Account Date.  No longer used.
     //PV1-36 Discharge Disposition.  Required if known (length 1..3).  Cardinality [0..1].  Discharge Disposition HL7 table.
     //PV1-37 Discharged to Location.  No longer used.
     //PV1-38 Diet Type.  No longer used.
     //PV1-39 Servicing Facility.  No longer used.
     //PV1-40 Bed Status.  No longer used.
     //PV1-41 Account Status.  No longer used.
     //PV1-42 Pending Location.  No longer used.
     //PV1-43 Prior Temporary Location.  No longer used.
     _seg.SetField(44, _appt.AptDateTime.ToString("yyyyMMddhhmm"));           //PV1-44 Admit Date/Time.  Required (length 12..26).  Date and time of the patient presentation.
     //PV1-45 Discharge Date/Time.  Optional.
     //PV1-46 Current Patient Balance.  No longer used.
     //PV1-47 Total Charges.  No longer used.
     //PV1-48 Total Adjustments.  No longer used.
     //PV1-49 Total Payments.  No longer used.
     //PV1-50 Alternate Visit ID.  No longer used.
     //PV1-51 Visit Indicator.  No longer used.
     //PV1-52 Other Healthcare Provider.  No longer used.
     _msg.Segments.Add(_seg);
 }