class EDI::A::Message

Class EDI::A::Message

This class implements a single business document according to ANSI X12

Public Class Methods

new( p, user_par={} ) click to toggle source

Creates an empty ANSI X12 message.

Don’t use directly - call method new_message of class Interchange or MsgGroup instead!

First parameter

This is always the parent object, either a message group or an interchange object. Use method new_message in the corresponding object instead of creating messages unattended, and the parent reference will be accounted for automatically.

Second parameter, case “Hash”

List of supported hash keys:

Essentials, should not be changed later

:msg_type

Sets DE 143, default = ‘837’

:ref_no

Sets DE 329, default is a built-in counter

:version

Sets S009.0052, default = ‘D’

:release

Sets S009.0054, default = ‘96A’

:resp_agency

Sets S009.0051, default = ‘UN’

Optional parameters, required depending upon use case

:assigned_code

Sets S009.0057 (subset), default = nil

Second parameter, case “Segment”

This mode is only used internally when parsing data.

Notes

  • The counter in ST (329) is set automatically to a number that is unique for the running process.

  • The trailer segment (SE) is generated automatically.

  • Whenever possible, avoid write access to the message header or trailer segments!

Calls superclass method EDI::Message::new
# File lib/edi4r/ansi_x12.rb, line 625
    def initialize( p, user_par={} )
      super( p, user_par )

      # First param is either a hash or segment ST
      # - If Hash:    Build ST from given parameters
      # - If Segment: Extract some crucial parameters
      if user_par.is_a? Hash
        preset_msg( user_par )
        par = {
          :GS08 => @version
          # :d0065 => @msg_type, :d0052=> @version, :d0054=> @release,
          # :d0051 => @resp_agency, :d0057 => @subset, :is_iedi => root.is_iedi?
        }
        @maindata = EDI::Dir::Directory.create(root.syntax, par )
 
        @header = new_segment('ST')
        @trailer = new_segment('SE')
        @header.d143 = @name
        @header.d329 = user_par[:ref_no].nil? ? p.messages_created : user_par[:ref_no]
        @trailer.d329 = @header.d329

=begin
        cde = @header.cS009
        cde.d0065 = @name
        cde.d0052 = @version
        cde.d0054 = @release
        cde.d0051 = @resp_agency
        cde.d0057 = @subset
=end

      elsif user_par.is_a? Segment
        @header = user_par
        raise "ST expected, #{@header.name} found!" if @header.name != 'ST'
        @header.parent = self
        @header.root = self.root
        @trailer = Segment.new(root, 'SE') # temporary
        #s009 = @header.cS009
        #@name = s009.d0065
        @version = p.header.d480 # GS08
        #@release = s009.d0054
        #@resp_agency = s009.d0051
        #@subset = s009.d0057
        par = {
          :GS08 => @version,
          :ST01 => @header.d143
         # :d0065 => @name, :d0052=> @version, :d0054=> @release,
         # :d0051 => @resp_agency, :d0057 => @subset, :is_iedi => root.is_iedi?
        }
        @maindata = EDI::Dir::Directory.create(root.syntax, par )
      else
        raise "First parameter: Illegal type!"
      end

      @trailer.d96 = 2 if @trailer  # Just ST and SE so far
    end
parse(parent, segment_list) click to toggle source

Returns a new Message object that contains the data of the strings passed in the segment_list array. Uses the context of the given parent object and configures message as a child.

# File lib/edi4r/ansi_x12.rb, line 728
def Message.parse (parent, segment_list)

  h, t, re_t = 'ST', 'SE', /^SE/

  # Segments comprise a single message
  # Temporarily assign a parent, or else service segment lookup fails
  header  = parent.parse_segment(segment_list.shift, h)
  msg     = parent.new_message(header)
  trailer = msg.parse_segment( segment_list.pop, t )

  segment_list.each do |segbuf|
    seg = Segment.parse( msg, segbuf )
    if segbuf =~ re_t # FIXME: Should that case ever occur?
      msg.trailer = seg
    else
      msg.add(seg)
    end
  end
  msg.trailer = trailer
  msg
end

Public Instance Methods

add( seg ) click to toggle source

Add a previously derived segment to the end of this message (append) Make sure that all mandatory elements have been supplied.

Notes

  • Strictly add segments in the sequence described by this message’s branching diagram!

  • Adding a segment will automatically increase the corresponding counter in the message trailer.

Example:

seg = msg.new_segment( 'BHT' )
seg.d353 = 837
# etc.
msg.add seg
Calls superclass method EDI::Message#add
# File lib/edi4r/ansi_x12.rb, line 769
def add( seg )
  super
  @trailer.d96 = @trailer.d96.to_i if @trailer.d96.is_a? String
  @trailer.d96 += 1 # What if new segment is/remains empty??
end
new_segment( tag ) click to toggle source

Derive a new segment with the given name from this message context. The call will fail if the message name is unknown to this message’s Directory (not in EDMD).

Example:

seg = msg.new_segment( 'BHT' )
seg.d353 = '00'
# etc.
msg.add seg
# File lib/edi4r/ansi_x12.rb, line 692
def new_segment( tag )
  Segment.new(self, tag)
end
to_s() click to toggle source
Calls superclass method EDI::Collection_HT#to_s
# File lib/edi4r/ansi_x12.rb, line 852
def to_s
  postfix = '' << root.seg_term << root.e_linebreak
  super( postfix )
end
validate( err_count=0 ) click to toggle source
Calls superclass method EDI::Collection_HT#validate
# File lib/edi4r/ansi_x12.rb, line 776
    def validate( err_count=0 )
      # Check sequence of segments against library,
      # thereby adding location information to each segment

      par = {
        :ST01 => @header.d143, # :d0052=> @version, :d0054=> @release,
        # :d0051 => @resp_agency, :d0057 => @subset,
        # :ISA12 => root.version, # :is_iedi => root.is_iedi?,
        :GS08 => parent.header.d480
      }
      diag = EDI::Diagram::Diagram.create( root.syntax, par )
      ni = EDI::Diagram::NodeInstance.new(diag)

      ni.seek!( @header )
      @header.update_with( ni )
      each do |seg|
        if ni.seek!(seg)
          seg.update_with( ni )
        else
          # FIXME: Do we really have to fail here, or would a "warn" suffice?
          raise "seek! failed for #{seg.name} when starting at #{ni.name}"
        end 
      end
      ni.seek!( @trailer )
      @trailer.update_with( ni )


      # Consistency checks

      if (a=@trailer.d96) != (b=self.size+2)
        EDI::logger.warn "DE 96 (#{a}) does not match number of segments (#{b})"
        err_count += 1
      end

      a, b = @trailer.d329, @header.d329
      if a != b
        EDI::logger.warn "Trailer reference (#{a}) does not match header reference (#{b})"
        err_count += 1
      end

=begin
      if parent.is_a? MsgGroup
        ung = parent.header; s008 = ung.cS008; s009 = header.cS009
        a, b = s009.d0065, ung.d0038
        if a != b
          warn "Message type (#{a}) does not match that of group (#{b})"
          err_count += 1
        end
        a, b = s009.d0052, s008.d0052
        if a != b
          warn "Message version (#{a}) does not match that of group (#{b})"
          err_count += 1
        end
        a, b = s009.d0054, s008.d0054
        if a != b
          warn "Message release (#{a}) does not match that of group (#{b})"
          err_count += 1
        end
        a, b = s009.d0051, ung.d0051
        if a != b
          warn "Message responsible agency (#{a}) does not match that of group (#{b})"
          err_count += 1
        end
        a, b = s009.d0057, s008.d0057
        if a != b
          warn "Message association assigned code (#{a}) does not match that of group (#{b})"
          err_count += 1
        end
      end
=end

      # Now check each segment
      super( err_count )
    end