Wednesday, December 11, 2013

Fix HL7 ORU_R01_ORDER_OBSERVATION in NHapi

This week, I worked on a feature requiring parsing of HL7 lab test results messages (ORU_R01).
Some messages did not parse correctly, and trusting the NHapi library http://sourceforge.net/projects/nhapi/,
I've spent some time tinkering around the problem, namely being unable to parse multiple observations (OBX segment). In the API, OBSERVATION was for a single instance property.
Finding no ways further, I've downloaded the source and took a look inside. The code is structured fairly good and it was easy to compare with other HL7 API documentation, especially http://hl7api.sourceforge.net/v251/apidocs/ca/uhn/hl7v2/model/v251/group/ORU_R01_ORDER_OBSERVATION.html.

There were two issues:
- ORU_R01_OBSERVATION has ORU_R01_OBSERVATION group incorrectly defined as required, non-repeating. It should be optional, repeating. Similarly,
- ORU_R01_SPECIMEN group is defined as required, non-repeating, but should be optional, repeating as well.

Here is a simple code change in the group constructor:

///<summary>
/// Creates new ORU_R01_ORDER_OBSERVATION Group.
///</summary>
public ORU_R01_ORDER_OBSERVATION(IGroup parent, IModelClassFactory factory) : base(parent, factory)
{
  try {
    this.add(typeof(ORC), false, false);
    this.add(typeof(OBR, true, false);
    this.add(typeof(NTE), false, true);
    this.add(typeof(ORU_R01_TIMING_QTY), true, false<);
    this.add(typeof(CTD), false, false);
    this.add(typeof(ORU_R01_OBSERVATION), false, true); //TODO: make ORU_R01_OBSERVATION optional, repeating - was true, false
    this.add(typeof(FT1), false, true);
    this.add(typeof(CTI), false, true);
    this.add(typeof(ORU_R01_SPECIMEN), false, true); //TODO: make ORU_R01_SPECIMEN optional, repeating - was true,false
  }
  catch(HL7Exception e)
  {
    HapiLogFactory.GetHapiLog(GetType()).Error("Unexpected error creating ORU_R01_ORDER_OBSERVATION - this is probably a bug in the source code generator.", e);
  }
}

Also, single instance properties needed change to repetition access methods as follows:

//TODO: replace OBSERVATION instance accessor with collection
//  ///<summary>
//  /// Returns ORU_R01_OBSERVATION(a Group object) - creates it if necessary
//    ///</summary>
//    public ORU_R01_OBSERVATION OBSERVATION { 
//       get{
//       ORU_R01_OBSERVATION ret = null;
//       try {
//          ret = (ORU_R01_OBSERVATION)this.GetStructure("OBSERVATION");
//       } catch(HL7Exception e) {
//          HapiLogFactory.GetHapiLog(GetType()).Error("Unexpected error accessing data - this is probably a bug in the source code generator.", e);
//          throw new System.Exception("An unexpected error ocurred",e);
//       }
//       return ret;
//    }
//    }
    ///<summary>
    ///  Returns  first repetition of ORU_R01_OBSERVATION (a Group object) - creates it if necessary 
    ///</summary> 
    public ORU_R01_OBSERVATION GetOBSERVATION ()
    {
      ORU_R01_OBSERVATION ret = null;
        try 
        {
            ret = (ORU_R01_OBSERVATION)this.GetStructure("OBSERVATION");
        }
        catch (HL7Exception e)
        {
            HapiLogFactory.GetHapiLog(GetType()).Error("Unexpected error accessing data - this is probably a bug in the source code generator." , e);
            throw new System.Exception("An unexpected error ocurred", e);
        }
        return ret;
    }
 
     ///<summary> 
     ///  Returns a specific repetition of OUL_R21_OBSERVATION 
     ///   * (a Group object) - creates it if necessary 
     ///   throws HL7Exception if the repetition requested is more than one  
     ///       greater than the number of existing repetitions. 
     ///</summary> 
    public ORU_R01_OBSERVATION GetOBSERVATION(int rep)
    {
        return (ORU_R01_OBSERVATION)this.GetStructure("OBSERVATION", rep);
    }
 
     /**  
      * Returns the number of existing repetitions of OUL_R21_OBSERVATION  
      */ 
    public int OBSERVATIONRepetitionsUsed
    {
        get 
        {
            int reps = -1;
            try 
            {
                reps = this.GetAll("OBSERVATION").Length;
            }
            catch (HL7Exception e)
            {
                string message = "Unexpected error accessing data - this is probably a bug in the source code generator.";
                HapiLogFactory.GetHapiLog(GetType ()).Error(message, e);
                throw new System.Exception(message);
            }
            return reps;
        }
    }

and
//TODO: replace SPECIMEN instance accessor with collection
//    ///<summary>
//    /// Returns ORU_R01_SPECIMEN (a Group object) - creates it if necessary
//    ///</summary>
//    public ORU_R01_SPECIMEN SPECIMEN { 
//    get {
//       ORU_R01_SPECIMEN ret = null;
//       try {
//          ret = (ORU_R01_SPECIMEN)this.GetStructure("SPECIMEN");
//       } catch(HL7Exception e) {
//          HapiLogFactory.GetHapiLog(GetType()).Error("Unexpected error accessing data - this is probably a bug in the source code generator.", e);
//          throw new System.Exception("An unexpected error ocurred",e);
//       }
//       return ret;
//      }
//    }
    ///<summary>
    /// Returns  first repetition of ORU_R01_SPECIMEN (a Group object) - creates it if necessary
    ///</summary>
    public ORU_R01_SPECIMEN GetSPECIMEN()
    {
        ORU_R01_SPECIMEN ret = null;
        try
        {
            ret = (ORU_R01_SPECIMEN)this.GetStructure("SPECIMEN");
        }
        catch (HL7Exception e)
        {
            HapiLogFactory.GetHapiLog(GetType()).Error("Unexpected error accessing data - this is probably a bug in the source code generator.", e);
            throw new System.Exception("An unexpected error ocurred", e);
        }
        return ret;
    }
 
    ///<summary>
    ///Returns a specific repetition of ORU_R01_SPECIMEN
    /// * (a Group object) - creates it if necessary
    /// throws HL7Exception if the repetition requested is more than one 
    ///     greater than the number of existing repetitions.
    ///</summary>
    public ORU_R01_SPECIMEN GetSPECIMEN(int rep)
    {
        return (ORU_R01_SPECIMEN)this.GetStructure("SPECIMEN", rep);
    }
 
    /** 
     * Returns the number of existing repetitions of ORU_R01_SPECIMEN 
     */
    public int SPECIMENRepetitionsUsed
    {
        get
        {
            int reps = -1;
            try
            {
                reps = this.GetAll("SPECIMEN").Length;
            }
            catch (HL7Exception e)
            {
                string message = "Unexpected error accessing data - this is probably a bug in the source code generator.";
                HapiLogFactory.GetHapiLog(GetType()).Error(message, e);
                throw new System.Exception(message);
            }
            return reps;
        }
    }


Offered to contribute the change back to https://sourceforge.net/projects/nhapi/