class EDI::E::Message

Class EDI::E::Message

This class implements a single business document according to UN/EDIFACT

Public Class Methods

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

Creates an empty UN/EDIFACT 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 S009.0065, default = ‘ORDERS’

: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 UNH (0062) is set automatically to a number that is unique for the running process.

  • The trailer segment (usually UNT) is generated automatically.

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

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

      # First param is either a hash or segment UNH
      # - If Hash:    Build UNH from given parameters
      # - If Segment: Extract some crucial parameters
      if user_par.is_a? Hash
        preset_msg( user_par )
        par = {
          :d0065 => @name, :d0052=> @version, :d0054=> @release, 
          :d0051 => @resp_agency, :d0057 => @subset, :is_iedi => root.is_iedi?
        }
        par[:d0002] = self.root.header.cS001.d0002 if %w/CONTRL AUTACK KEYMAN/.include? @name # TODO: Experimental - revise!
        @maindata = EDI::Dir::Directory.create(root.syntax, par )
 
        if root.is_iedi?
          @header = new_segment('UIH')
          @trailer = new_segment('UIT')
          cde = @header.cS306
#          cde.d0113 = @sub_id
          @header.d0340 = p.messages_created
        else
          @header = new_segment('UNH')
          @trailer = new_segment('UNT')
          cde = @header.cS009
          @header.d0062 = p.messages_created
        end
        cde.d0065 = @name
        cde.d0052 = @version
        cde.d0054 = @release
        cde.d0051 = @resp_agency
        cde.d0057 = @subset

      elsif user_par.is_a? Segment
        @header = user_par
        raise "UNH expected, #{@header.name} found!" if @header.name != 'UNH'
        # I-EDI support to be added!
        @header.parent = self
        @header.root = self.root
        @trailer = Segment.new(root, 'UNT') # temporary
        s009 = @header.cS009
        @name = s009.d0065
        @version = s009.d0052
        @release = s009.d0054
        @resp_agency = s009.d0051
        @subset = s009.d0057
        par = {
          :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.d0074 = 2 if @trailer  # Just UNH and UNT 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/edifact.rb, line 1067
def Message.parse (parent, segment_list)

  if parent.root.is_iedi?
    h, t, re_t = 'UIH', 'UIT', /^UIT/
  else
    h, t, re_t = 'UNH', 'UNT', /^UNT/
  end

  # 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( 'BGM' )
seg.d1004 = '220'
# etc.
msg.add seg
Calls superclass method EDI::Message#add
# File lib/edi4r/edifact.rb, line 1112
def add( seg )
  super
  @trailer.d0074 = @trailer.d0074.to_i if @trailer.d0074.is_a? String
  @trailer.d0074 += 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 UN/TDID (not in EDMD/IDMD).

Example:

seg = msg.new_segment( 'BGM' )
seg.d1004 = '220'
# etc.
msg.add seg
# File lib/edi4r/edifact.rb, line 1021
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/edifact.rb, line 1198
def to_s
  postfix = '' << root.una.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/edifact.rb, line 1119
def validate( err_count=0 )
  # Check sequence of segments against library,
  # thereby adding location information to each segment

  par = {
    :d0065 => @name, :d0052=> @version, :d0054=> @release, 
    :d0051 => @resp_agency, :d0057 => @subset, 
    :d0002 => root.version, :is_iedi => root.is_iedi?,
    :d0076 => nil  # SV 4-1 support still missing here
  }
  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.d0074) != (b=self.size+2)
    warn "DE 0074 (#{a}) does not match number of segments (#{b})"
    err_count += 1
  end

  if root.is_iedi?
    a, b = @trailer.d0340, @header.d0340
  else
    a, b = @trailer.d0062, @header.d0062
  end
  if a != b
    warn "Trailer reference (#{a}) does not match header reference (#{b})"
    err_count += 1
  end

  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

  # Now check each segment
  super( err_count )
end