/// <summary> /// Append query results to the message /// </summary> public virtual IMessage AppendQueryResult(IEnumerable results, Expression queryDefinition, IMessage currentResponse, Hl7MessageReceivedEventArgs evt, String matchConfiguration = null, int offset = 0) { var patients = results.OfType <Patient>(); if (patients.Count() == 0) { return(currentResponse); } var retVal = currentResponse as RSP_K21; var pidHandler = SegmentHandlers.GetSegmentHandler("PID"); var pd1Handler = SegmentHandlers.GetSegmentHandler("PD1"); var nokHandler = SegmentHandlers.GetSegmentHandler("NK1"); var matchService = ApplicationServiceContext.Current.GetService <IRecordMatchingService>(); var matchConfigService = ApplicationServiceContext.Current.GetService <IRecordMatchingConfigurationService>(); // Return domains var rqo = evt.Message as QBP_Q21; List <AssigningAuthority> returnDomains = new List <AssigningAuthority>(); foreach (var rt in rqo.QPD.GetField(8).OfType <Varies>()) { var rid = new CX(rqo.Message); DeepCopy.copy(rt.Data as GenericComposite, rid); var authority = rid.AssigningAuthority.ToModel(); returnDomains.Add(authority); } if (returnDomains.Count == 0) { returnDomains = null; } // Process results int i = offset + 1; foreach (var itm in patients) { var queryInstance = retVal.GetQUERY_RESPONSE(retVal.QUERY_RESPONSERepetitionsUsed); pidHandler.Create(itm, queryInstance, returnDomains?.ToArray()); pd1Handler.Create(itm, queryInstance, null); nokHandler.Create(itm, queryInstance, null); queryInstance.PID.SetIDPID.Value = (i++).ToString(); // QRI? if (matchService != null && !String.IsNullOrEmpty(matchConfiguration)) { var score = matchService.Score <Patient>(itm, queryDefinition as Expression <Func <Patient, bool> >, matchConfiguration); queryInstance.QRI.CandidateConfidence.Value = score.Score.ToString(); queryInstance.QRI.AlgorithmDescriptor.Identifier.Value = matchConfiguration; } } return(retVal); }
/// <summary> /// Append query results to the message /// </summary> public virtual IMessage AppendQueryResult(IEnumerable results, Expression queryDefinition, IMessage currentResponse, Hl7MessageReceivedEventArgs evt, int offset = 0) { var patients = results.OfType <Patient>(); if (patients.Count() == 0) { return(currentResponse); } var retVal = currentResponse as RSP_K21; var pidHandler = SegmentHandlers.GetSegmentHandler("PID"); var pd1Handler = SegmentHandlers.GetSegmentHandler("PD1"); var nokHandler = SegmentHandlers.GetSegmentHandler("NK1"); var matchService = ApplicationServiceContext.Current.GetService <IRecordMatchingService>(); var matchConfigService = ApplicationServiceContext.Current.GetService <IRecordMatchingConfigurationService>(); // Return domains var rqo = evt.Message as QBP_Q21; List <AssigningAuthority> returnDomains = new List <AssigningAuthority>(); foreach (var rt in rqo.QPD.GetField(8).OfType <Varies>()) { var rid = new CX(rqo.Message); DeepCopy.Copy(rt.Data as GenericComposite, rid); var authority = rid.AssigningAuthority.ToModel(); returnDomains.Add(authority); } if (returnDomains.Count == 0) { returnDomains = null; } // Process results int i = offset + 1; IEnumerable <dynamic> resultScores = patients.Select(o => new { Patient = o, WasScored = false }); if (this.m_scoringService != null) { resultScores = this.m_scoringService.Score <Patient>(queryDefinition as Expression <Func <Patient, bool> >, patients).Select(o => new { Patient = o.Result, Score = o.Score, Method = o.Method, WasScored = true }); } foreach (var itm in resultScores) { var queryInstance = retVal.GetQUERY_RESPONSE(retVal.QUERY_RESPONSERepetitionsUsed); pidHandler.Create(itm.Patient, queryInstance, returnDomains?.ToArray()); pd1Handler.Create(itm.Patient, queryInstance, null); nokHandler.Create(itm.Patient, queryInstance, null); queryInstance.PID.SetIDPID.Value = (i++).ToString(); if (itm.WasScored) { queryInstance.QRI.CandidateConfidence.Value = itm.Score.ToString(); switch ((RecordMatchMethod)itm.Method) { case RecordMatchMethod.Identifier: queryInstance.QRI.GetMatchReasonCode(0).Value = "SS"; break; case RecordMatchMethod.Simple: queryInstance.QRI.GetMatchReasonCode(0).Value = "NA"; break; case RecordMatchMethod.Weighted: queryInstance.QRI.GetMatchReasonCode(0).Value = "NP"; break; } queryInstance.QRI.AlgorithmDescriptor.Identifier.Value = this.m_scoringService.ServiceName; } else { queryInstance.QRI.CandidateConfidence.Value = "1.0"; queryInstance.QRI.AlgorithmDescriptor.Identifier.Value = "PTNM"; } } return(retVal); }
/// <summary> /// Represents when the ADT registration occurs /// </summary> protected void AdtPatientRegistrationInterceptor_Behavior(object sender, DataPersistedEventArgs <Patient> e) { ApplicationServiceContext.Current.GetService <IThreadPoolService>().QueueNonPooledWorkItem( (p) => { AuthenticationContext.Current = new AuthenticationContext(AuthenticationContext.SystemPrincipal); Patient pat = p as Patient; // We want to construct an ADT message if (and only if) the guards are met and if the last ADT was not this version var tag = pat.LoadCollection <EntityTag>("Tags").FirstOrDefault(o => o.TagKey == TagName); if (tag?.Value == e.Data.VersionKey.ToString()) { return; // No need } else if (base.ExecuteGuard(pat)) { // Perform notification IMessage notificationMessage; IGroup patientGroup; if (tag?.Value == null) { // Set the tag value and send an ADMIT patientGroup = notificationMessage = new ADT_A01(); ApplicationServiceContext.Current.GetService <ITagPersistenceService>().Save(pat.Key.Value, new EntityTag(TagName, pat.VersionKey.ToString())); (notificationMessage.GetStructure("MSH") as MSH).MessageType.TriggerEvent.Value = "A04"; (notificationMessage.GetStructure("MSH") as MSH).MessageType.MessageStructure.Value = "ADT_A01"; } else if (pat.LoadCollection <EntityRelationship>("Relationships").Any(o => o.RelationshipTypeKey == EntityRelationshipTypeKeys.Replaces && o.EffectiveVersionSequenceId == pat.VersionSequence)) { // Set the tag value and send an ADMIT notificationMessage = new ADT_A39(); patientGroup = (notificationMessage as ADT_A39).GetPATIENT(); ApplicationServiceContext.Current.GetService <ITagPersistenceService>().Save(pat.Key.Value, new EntityTag(TagName, pat.VersionKey.ToString())); (notificationMessage.GetStructure("MSH") as MSH).MessageType.TriggerEvent.Value = "A40"; (notificationMessage.GetStructure("MSH") as MSH).MessageType.MessageStructure.Value = "ADT_A40"; foreach (var mrg in pat.LoadCollection <EntityRelationship>("Relationships").Where(o => o.RelationshipTypeKey == EntityRelationshipTypeKeys.Replaces && o.EffectiveVersionSequenceId == pat.VersionSequence)) { var seg = patientGroup.GetStructure("MRG", patientGroup.GetAll("MRG").Length) as MRG; if (this.Configuration.ExportDomains.Any(o => o.DomainName == this.m_configuration.LocalAuthority.DomainName)) { var key = seg.PriorAlternatePatientIDRepetitionsUsed; seg.GetPriorAlternatePatientID(key).IDNumber.Value = mrg.TargetEntityKey.Value.ToString(); seg.GetPriorAlternatePatientID(key).IdentifierTypeCode.Value = "PI"; seg.GetPriorAlternatePatientID(key).AssigningAuthority.NamespaceID.Value = this.m_configuration.LocalAuthority.DomainName; seg.GetPriorAlternatePatientID(key).AssigningAuthority.UniversalID.Value = this.m_configuration.LocalAuthority.Oid; seg.GetPriorAlternatePatientID(key).AssigningAuthority.UniversalIDType.Value = "ISO"; } // Alternate identifiers foreach (var extrn in pat.LoadCollection <EntityIdentifier>("Identifiers")) { var key = seg.PriorAlternatePatientIDRepetitionsUsed; if (this.Configuration.ExportDomains.Any(o => o.DomainName == extrn.LoadProperty <AssigningAuthority>("Authority").DomainName)) { seg.GetPriorAlternatePatientID(key).IDNumber.Value = extrn.Value; seg.GetPriorAlternatePatientID(key).IdentifierTypeCode.Value = "PT"; seg.GetPriorAlternatePatientID(key).AssigningAuthority.NamespaceID.Value = extrn.LoadProperty <AssigningAuthority>("Authority")?.DomainName; seg.GetPriorAlternatePatientID(key).AssigningAuthority.UniversalID.Value = extrn.LoadProperty <AssigningAuthority>("Authority")?.Oid; seg.GetPriorAlternatePatientID(key).AssigningAuthority.UniversalIDType.Value = "ISO"; } } } } else { // Set the tag value and send an ADMIT patientGroup = notificationMessage = new ADT_A01(); ApplicationServiceContext.Current.GetService <ITagPersistenceService>().Save(pat.Key.Value, new EntityTag(TagName, pat.VersionKey.ToString())); (notificationMessage.GetStructure("MSH") as MSH).MessageType.TriggerEvent.Value = "A08"; (notificationMessage.GetStructure("MSH") as MSH).MessageType.MessageStructure.Value = "ADT_A08"; } if (!String.IsNullOrEmpty(this.Configuration.Version)) { (notificationMessage.GetStructure("MSH") as MSH).VersionID.VersionID.Value = this.Configuration.Version; } // Add SFT if (new Version(this.Configuration.Version ?? "2.5") >= new Version(2, 4)) { (notificationMessage.GetStructure("SFT", 0) as SFT).SetDefault(); } // Create the PID segment SegmentHandlers.GetSegmentHandler("PID").Create(e.Data, patientGroup, this.Configuration.ExportDomains.ToArray()); SegmentHandlers.GetSegmentHandler("PD1").Create(e.Data, patientGroup, this.Configuration.ExportDomains.ToArray()); SegmentHandlers.GetSegmentHandler("NK1").Create(e.Data, patientGroup, this.Configuration.ExportDomains.ToArray()); //SegmentHandlers.GetSegmentHandler("EVN").Create(e.Data, patientGroup, this.Configuration.ExportDomains.ToArray()); foreach (var itm in this.Configuration.Endpoints) { try { // TODO: Create an HL7 Queue (notificationMessage.GetStructure("MSH") as MSH).SetDefault(itm.ReceivingDevice, itm.ReceivingFacility, itm.SecurityToken); var response = itm.GetSender().SendAndReceive(notificationMessage); if (!(response.GetStructure("MSA") as MSA).AcknowledgmentCode.Value.EndsWith("A")) { throw new HL7Exception("Remote server rejected message"); } } catch (Exception ex) { this.m_tracer.TraceEvent(EventLevel.Error, "Error dispatching message {0} to {1}: {2} \r\n {3}", pat, itm.Address, ex, new PipeParser().Encode(notificationMessage)); } } } }, e.Data ); }
/// <summary> /// Represents a message parser to a bundle /// </summary> internal static Bundle Parse(IGroup message) { Bundle retVal = new Bundle(); var finder = new SegmentFinder(message); while (finder.HasNextChild()) { finder.NextChild(); foreach (var current in finder.CurrentChildReps) { if (current is AbstractGroupItem) { foreach (var s in (current as AbstractGroupItem)?.Structures.OfType <IGroup>()) { var parsed = Parse(s); retVal.Item.AddRange(parsed.Item.Select(i => { var ret = i.Clone(); (ret as ITaggable)?.AddTag("$v2.group", current.GetStructureName()); return(ret); })); retVal.FocalObjects.AddRange(parsed.FocalObjects); } } else if (current is AbstractSegment) { // Empty, don't parse if (PipeParser.Encode(current as AbstractSegment, new EncodingCharacters('|', "^~\\&")).Length == 3) { continue; } var handler = SegmentHandlers.GetSegmentHandler(current.GetStructureName()); if (handler != null) { var parsed = handler.Parse(current as AbstractSegment, retVal.Item); if (parsed.Any()) { retVal.FocalObjects.AddRange(parsed .OfType <ITaggable>() .Where(o => o.GetTag(Hl7Constants.FocalObjectTag) == "true") .OfType <IIdentifiedEntity>() .Select(o => o.Key.GetValueOrDefault()) .Where(o => Guid.Empty != o) ); retVal.Item.AddRange(parsed.Select(i => { var ret = i.Clone(); (ret as ITaggable)?.AddTag("$v2.segment", current.GetStructureName()); return(ret); })); } } } else if (current is AbstractGroup) { var subObject = Parse(current as AbstractGroup); retVal.Item.Add(subObject); retVal.FocalObjects.AddRange(subObject.FocalObjects); } // Tag the objects } } return(retVal); }
/// <summary> /// Represents a message parser to a bundle /// </summary> internal static Bundle Parse(IGroup message) { Bundle retVal = new Bundle(); var finder = new SegmentFinder(message); while (finder.hasNextChild()) { finder.nextChild(); foreach (var current in finder.CurrentChildReps) { if (current is AbstractGroupItem) { foreach (var s in (current as AbstractGroupItem)?.Structures.OfType <IGroup>()) { var parsed = Parse(s); retVal.Item.AddRange(parsed.Item.Select(i => { var ret = i.Clone(); (ret as ITaggable)?.AddTag(".v2.group", current.GetStructureName()); return(ret); })); retVal.ExpansionKeys.AddRange(parsed.ExpansionKeys); } } else if (current is AbstractSegment) { // Empty, don't parse if (PipeParser.Encode(current as AbstractSegment, new EncodingCharacters('|', "^~\\&")).Length == 3) { continue; } var handler = SegmentHandlers.GetSegmentHandler(current.GetStructureName()); if (handler != null) { var parsed = handler.Parse(current as AbstractSegment, retVal.Item); if (parsed.Any()) { retVal.ExpansionKeys.Add(parsed.First().Key.GetValueOrDefault()); retVal.Item.AddRange(parsed.Select(i => { var ret = i.Clone(); (ret as ITaggable)?.AddTag(".v2.segment", current.GetStructureName()); return(ret); })); } } } else if (current is AbstractGroup) { var subObject = Parse(current as AbstractGroup); retVal.Item.AddRange(subObject.Item.Select(i => { var ret = i.Clone(); (ret as ITaggable)?.AddTag(".v2.group", current.GetStructureName()); return(ret); })); retVal.ExpansionKeys.AddRange(subObject.ExpansionKeys); } // Tag the objects } } return(retVal); }