Class: Bai2::Record

Inherits:
Object
  • Object
show all
Defined in:
lib/bai2/record.rb

Overview

This class represents a record. It knows how to parse the single record information, but has no knowledge of the structure of the file.

Constant Summary collapse

RECORD_CODES =
{'01' => :file_header,
'02' => :group_header,
'03' => :account_identifier,
'16' => :transaction_detail,
'49' => :account_trailer,
'88' => :continuation,
'98' => :group_trailer,
'99' => :file_trailer }
ParseDate =

Returns a date object

->(v) do
  Time.strptime("#{v} utc", '%y%m%d %Z')
end
ParseMilitaryTime =

Returns a time interval in seconds, to be added to the date

-> (v) do
  v = '2400' if (v == '' || v == '9999')
  Time.strptime("#{v} utc", '%H%M %Z').to_i % 86400
end
ParseTypeCode =

Parses a type code, returns a structured informative hash

-> (code) do
  meaning = TypeCodeData[code.to_i] || [nil, nil, nil]
  {
    code:        code.to_i,
    transaction: meaning[0],
    scope:       meaning[1],
    description: meaning[2],
  }
end
CleanContinuedText =

Cleans up text in continuations, removing leading commas

-> (text) do
  text.gsub(/,?,\n/, "\n").gsub(/^\n/, '')
end
AssertVersion2 =

This block ensures that only version 2 of the BAI standard is accepted

->(v) do
  unless v == "2"
    raise ParseError.new("Unsupported BAI version (#{v} != 2)")
  end
  v.to_i
end
SIMPLE_FIELD_MAP =

For each record code, this defines a simple way to automatically parse the fields. Each field has a list of the keys. Some keys are not simply string types, in which case they will be formatted as a tuple (key, fn), where fn is a block (or anything that responds to ‘to_proc`) that will be called to cast the value (e.g. `:to_i`).

{
  file_header: [
    :record_code,
    :sender,
    :receiver,
    [:file_creation_date, ParseDate],
    [:file_creation_time, ParseMilitaryTime],
    :file_identification_number,
    [:physical_record_length, :to_i],
    [:block_size, :to_i],
    [:version_number, AssertVersion2],
  ],
  group_header: [
    :record_code,
    :destination,
    :originator,
    :group_status,
    [:as_of_date, ParseDate],
    [:as_of_time, ParseMilitaryTime],
    :currency_code,
    :as_of_date_modifier,
  ],
  group_trailer: [
    :record_code,
    [:group_control_total, :to_i],
    [:number_of_accounts, :to_i],
    [:number_of_records, :to_i],
  ],
  account_trailer: [
    :record_code,
    [:account_control_total, :to_i],
    [:number_of_records, :to_i],
  ],
  file_trailer: [
    :record_code,
    [:file_control_total, :to_i],
    [:number_of_groups, :to_i],
    [:number_of_records, :to_i],
  ],
  continuation: [ # TODO: could continue any record at any point...
    :record_code,
    :continuation,
  ],
  # NOTE: transaction_detail is not present here, because it is too complex
  # for a simple mapping like this.
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(line, physical_record_count = 1, options: {}) ⇒ Record

Returns a new instance of Record.



115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/bai2/record.rb', line 115

def initialize(line, physical_record_count = 1, options: {})
  @code = RECORD_CODES[line[0..1]]
  @physical_record_count = physical_record_count
  # clean / delimiter
  @raw = if options[:continuations_slash_delimit_end_of_line_only]
          # Continuation records for transaction details extend the text fields
          # and they may begin with 88,/ but should include the rest of the line.
          # A proper fix would involve each continuation record knowing what field it was extending.
          line.sub(/\/$/, '')
         else
          line.sub(/,\/.+$/, '').sub(/\/$/, '')
         end
end

Instance Attribute Details

#codeObject (readonly)

Returns the value of attribute code.



129
130
131
# File 'lib/bai2/record.rb', line 129

def code
  @code
end

#physical_record_countObject (readonly)

Returns the value of attribute physical_record_count.



129
130
131
# File 'lib/bai2/record.rb', line 129

def physical_record_count
  @physical_record_count
end

#rawObject (readonly)

Returns the value of attribute raw.



129
130
131
# File 'lib/bai2/record.rb', line 129

def raw
  @raw
end

Instance Method Details

#[](key) ⇒ Object

A record can be accessed like a hash.



140
141
142
# File 'lib/bai2/record.rb', line 140

def [](key)
  fields[key]
end

#fieldsObject

NOTE: fields is called upon first use, so as not to parse records right away in case they might be merged with a continuation.



134
135
136
# File 'lib/bai2/record.rb', line 134

def fields
  @fields ||= parse_raw(@code, @raw)
end