nacha 0.1.10 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -2
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +17 -0
  5. data/exe/nacha +51 -20
  6. data/lib/nacha/aba_number.rb +17 -14
  7. data/lib/nacha/ach_date.rb +15 -8
  8. data/lib/nacha/field.rb +69 -58
  9. data/lib/nacha/has_errors.rb +12 -8
  10. data/lib/nacha/numeric.rb +13 -10
  11. data/lib/nacha/parser.rb +22 -27
  12. data/lib/nacha/parser_context.rb +4 -9
  13. data/lib/nacha/record/ack_entry_detail.rb +15 -8
  14. data/lib/nacha/record/adv_batch_control.rb +12 -7
  15. data/lib/nacha/record/adv_entry_detail.rb +3 -2
  16. data/lib/nacha/record/adv_file_control.rb +9 -5
  17. data/lib/nacha/record/adv_file_header.rb +11 -6
  18. data/lib/nacha/record/arc_entry_detail.rb +2 -2
  19. data/lib/nacha/record/base.rb +121 -106
  20. data/lib/nacha/record/batch_control.rb +13 -7
  21. data/lib/nacha/record/batch_header.rb +20 -11
  22. data/lib/nacha/record/batch_header_record_type.rb +1 -1
  23. data/lib/nacha/record/boc_entry_detail.rb +3 -2
  24. data/lib/nacha/record/ccd_addenda.rb +2 -2
  25. data/lib/nacha/record/ccd_entry_detail.rb +3 -2
  26. data/lib/nacha/record/cie_addenda.rb +2 -2
  27. data/lib/nacha/record/cie_entry_detail.rb +5 -3
  28. data/lib/nacha/record/ctx_addenda.rb +2 -2
  29. data/lib/nacha/record/ctx_corporate_entry_detail.rb +2 -2
  30. data/lib/nacha/record/dne_addenda.rb +2 -2
  31. data/lib/nacha/record/dne_entry_detail.rb +6 -4
  32. data/lib/nacha/record/enr_addenda.rb +3 -2
  33. data/lib/nacha/record/enr_entry_detail.rb +4 -3
  34. data/lib/nacha/record/fifth_iat_addenda.rb +8 -4
  35. data/lib/nacha/record/file_control.rb +9 -5
  36. data/lib/nacha/record/file_control_record_type.rb +1 -1
  37. data/lib/nacha/record/file_header.rb +12 -8
  38. data/lib/nacha/record/file_header_record_type.rb +1 -1
  39. data/lib/nacha/record/filler.rb +3 -3
  40. data/lib/nacha/record/filler_record_type.rb +3 -1
  41. data/lib/nacha/record/first_iat_addenda.rb +3 -2
  42. data/lib/nacha/record/fourth_iat_addenda.rb +7 -4
  43. data/lib/nacha/record/iat_batch_header.rb +5 -3
  44. data/lib/nacha/record/iat_entry_detail.rb +7 -4
  45. data/lib/nacha/record/iat_foreign_coorespondent_bank_information_addenda.rb +10 -6
  46. data/lib/nacha/record/iat_remittance_information_addenda.rb +3 -2
  47. data/lib/nacha/record/mte_addenda.rb +4 -3
  48. data/lib/nacha/record/mte_entry_detail.rb +5 -3
  49. data/lib/nacha/record/pop_entry_detail.rb +3 -2
  50. data/lib/nacha/record/pos_addenda.rb +6 -3
  51. data/lib/nacha/record/pos_entry_detail.rb +5 -3
  52. data/lib/nacha/record/ppd_addenda.rb +3 -2
  53. data/lib/nacha/record/ppd_entry_detail.rb +5 -3
  54. data/lib/nacha/record/rck_entry_detail.rb +3 -2
  55. data/lib/nacha/record/second_iat_addenda.rb +3 -2
  56. data/lib/nacha/record/seventh_iat_addenda.rb +3 -2
  57. data/lib/nacha/record/shr_addenda.rb +5 -3
  58. data/lib/nacha/record/shr_entry_detail.rb +3 -2
  59. data/lib/nacha/record/sixth_iat_addenda.rb +5 -3
  60. data/lib/nacha/record/tel_entry_detail.rb +5 -3
  61. data/lib/nacha/record/third_iat_addenda.rb +3 -2
  62. data/lib/nacha/record/trc_entry_detail.rb +3 -2
  63. data/lib/nacha/record/trx_addenda.rb +3 -2
  64. data/lib/nacha/record/trx_entry_detail.rb +5 -3
  65. data/lib/nacha/record/validations/field_validations.rb +26 -14
  66. data/lib/nacha/record/validations/record_validations.rb +2 -1
  67. data/lib/nacha/record/web_addenda.rb +3 -2
  68. data/lib/nacha/record/web_entry_detail.rb +5 -3
  69. data/lib/nacha/record/xck_entry_detail.rb +3 -2
  70. data/lib/nacha/version.rb +4 -1
  71. data/lib/nacha.rb +21 -14
  72. data/nacha.gemspec +13 -16
  73. metadata +22 -8
@@ -2,13 +2,9 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  class Nacha::ParserContext
5
- attr_accessor :file_name
6
- attr_accessor :line_number
7
- attr_accessor :line_length
8
- attr_accessor :line_errors
9
- attr_accessor :parser_started_at
10
- attr_accessor :parser_ended_at # nil 'till the end of parsing
11
- attr_accessor :previous_record
5
+ attr_accessor :file_name, :line_number, :line_length, :line_errors,
6
+ :parser_started_at, :previous_record,
7
+ :parser_ended_at # nil 'till the end of parsing
12
8
  attr_reader :validated
13
9
 
14
10
  def initialize(opts = {})
@@ -16,7 +12,7 @@ class Nacha::ParserContext
16
12
  @line_number = opts[:line_number] || 0
17
13
  @line_length = opts[:line_length] || 0
18
14
  @current_line_errors = []
19
- @parser_started_at = Time.now
15
+ @parser_started_at = Time.now.utc
20
16
  @parser_ended_at = nil
21
17
  @previous_record = nil
22
18
  @validated = false
@@ -29,5 +25,4 @@ class Nacha::ParserContext
29
25
  def valid?
30
26
  @valid ||= errors.empty?
31
27
  end
32
-
33
28
  end
@@ -1,22 +1,29 @@
1
1
  # coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'nacha/record/base.rb'
5
- require 'nacha/record/detail_record_type.rb'
4
+ require 'nacha/record/base'
5
+ require 'nacha/record/detail_record_type'
6
6
 
7
7
  module Nacha
8
8
  module Record
9
9
  class AckEntryDetail < Nacha::Record::Base
10
10
  include DetailRecordType
11
+
11
12
  nacha_field :record_type_code, inclusion: 'M', contents: 'C6', position: 1..1
12
13
  nacha_field :transaction_code, inclusion: 'M', contents: 'Numeric', position: 2..3
13
- nacha_field :receiving_dfi_identification, inclusion: 'M', contents: 'TTTTAAAAC', position: 4..12
14
- nacha_field :dfi_account_number, inclusion: 'R', contents: 'Alphameric', position: 13..29
14
+ nacha_field :receiving_dfi_identification,
15
+ inclusion: 'M', contents: 'TTTTAAAAC', position: 4..12
16
+ nacha_field :dfi_account_number,
17
+ inclusion: 'R', contents: 'Alphameric', position: 13..29
15
18
  nacha_field :amount, inclusion: 'M', contents: '$$$$$$$$¢¢', position: 30..39
16
- nacha_field :originl_entry_trace_number, inclusion: 'M', contents: 'Numeric', position: 40..54
17
- nacha_field :receiving_company_name, inclusion: 'R', contents: 'Alphameric', position: 55..76
18
- nacha_field :discretionary_data, inclusion: 'O', contents: 'Alphameric', position: 77..78
19
- nacha_field :addenda_record_indicator, inclusion: 'M', contents: 'Numeric', position: 79..79
19
+ nacha_field :originl_entry_trace_number,
20
+ inclusion: 'M', contents: 'Numeric', position: 40..54
21
+ nacha_field :receiving_company_name,
22
+ inclusion: 'R', contents: 'Alphameric', position: 55..76
23
+ nacha_field :discretionary_data,
24
+ inclusion: 'O', contents: 'Alphameric', position: 77..78
25
+ nacha_field :addenda_record_indicator,
26
+ inclusion: 'M', contents: 'Numeric', position: 79..79
20
27
  nacha_field :trace_number, inclusion: 'M', contents: 'Numeric', position: 80..94
21
28
  end
22
29
  end
@@ -1,22 +1,27 @@
1
1
  # coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'nacha/record/base.rb'
5
- require 'nacha/record/batch_control_record_type.rb'
4
+ require 'nacha/record/base'
5
+ require 'nacha/record/batch_control_record_type'
6
6
 
7
7
  module Nacha
8
8
  module Record
9
-
10
9
  # The AdvBatchControl record is used to control the batch of adv entry detail records.
11
10
  class AdvBatchControl < Nacha::Record::Base
11
+ include BatchControlRecordType
12
+
12
13
  nacha_field :record_type_code, inclusion: 'M', contents: 'C8', position: 1..1
13
14
  nacha_field :service_class_code, inclusion: 'M', contents: 'Numeric', position: 2..4
14
15
  nacha_field :entry_addenda_count, inclusion: 'M', contents: 'Numeric', position: 5..10
15
16
  nacha_field :entry_hash, inclusion: 'M', contents: 'Numeric', position: 11..20
16
- nacha_field :total_debit_entry_dollar_amount, inclusion: 'M', contents: '$$$$$$$$$$$$$$$$$$¢¢', position: 21..40
17
- nacha_field :total_credit_entry_dollar_amount, inclusion: 'M', contents: '$$$$$$$$$$$$$$$$$$¢¢', position: 41..60
18
- nacha_field :ach_operator_data, inclusion: 'O', contents: 'Alphameric', position: 61..79
19
- nacha_field :originating_dfi_identification, inclusion: 'M', contents: 'TTTAAAA', position: 80..87
17
+ nacha_field :total_debit_entry_dollar_amount,
18
+ inclusion: 'M', contents: '$$$$$$$$$$$$$$$$$$¢¢', position: 21..40
19
+ nacha_field :total_credit_entry_dollar_amount,
20
+ inclusion: 'M', contents: '$$$$$$$$$$$$$$$$$$¢¢', position: 41..60
21
+ nacha_field :ach_operator_data,
22
+ inclusion: 'O', contents: 'Alphameric', position: 61..79
23
+ nacha_field :originating_dfi_identification,
24
+ inclusion: 'M', contents: 'TTTAAAA', position: 80..87
20
25
  nacha_field :batch_number, inclusion: 'M', contents: 'Numeric', position: 88..94
21
26
  end
22
27
  end
@@ -1,13 +1,14 @@
1
1
  # coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'nacha/record/base.rb'
5
- require 'nacha/record/detail_record_type.rb'
4
+ require 'nacha/record/base'
5
+ require 'nacha/record/detail_record_type'
6
6
 
7
7
  module Nacha
8
8
  module Record
9
9
  class AdvEntryDetail < Nacha::Record::Base
10
10
  include DetailRecordType
11
+
11
12
  nacha_field :record_type_code, inclusion: 'M', contents: 'C6', position: 1..1
12
13
  nacha_field :transaction_code, inclusion: 'M', contents: 'Numeric', position: 2..3
13
14
  nacha_field :receiving_dfi_identification, inclusion: 'M', contents: 'TTTTAAAAC', position: 4..12
@@ -1,20 +1,24 @@
1
1
  # coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'nacha/record/base.rb'
5
- require 'nacha/record/file_control_record_type.rb'
4
+ require 'nacha/record/base'
5
+ require 'nacha/record/file_control_record_type'
6
6
 
7
7
  module Nacha
8
8
  module Record
9
9
  class AdvFileControl < Nacha::Record::Base
10
10
  include FileControlRecordType
11
+
11
12
  nacha_field :record_type_code, inclusion: 'M', contents: 'C9', position: 1..1
12
13
  nacha_field :batch_count, inclusion: 'M', contents: 'Numeric', position: 2..7
13
14
  nacha_field :block_count, inclusion: 'M', contents: 'Numeric', position: 8..13
14
- nacha_field :entry_addenda_count, inclusion: 'M', contents: 'Numeric', position: 14..21
15
+ nacha_field :entry_addenda_count,
16
+ inclusion: 'M', contents: 'Numeric', position: 14..21
15
17
  nacha_field :entry_hash, inclusion: 'M', contents: 'Numeric', position: 22..31
16
- nacha_field :total_debit_entry_dollar_amount_in_file, inclusion: 'M', contents: '$$$$$$$$$$¢¢', position: 32..51
17
- nacha_field :total_credit_entry_dollar_amount_in_file, inclusion: 'M', contents: '$$$$$$$$$$¢¢', position: 52..71
18
+ nacha_field :total_debit_entry_dollar_amount_in_file,
19
+ inclusion: 'M', contents: '$$$$$$$$$$¢¢', position: 32..51
20
+ nacha_field :total_credit_entry_dollar_amount_in_file,
21
+ inclusion: 'M', contents: '$$$$$$$$$$¢¢', position: 52..71
18
22
  nacha_field :reserved, inclusion: 'M', contents: 'C', position: 72..94
19
23
  end
20
24
  end
@@ -1,25 +1,30 @@
1
1
  # coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'nacha/record/base.rb'
5
- require 'nacha/record/file_header_record_type.rb'
4
+ require 'nacha/record/base'
5
+ require 'nacha/record/file_header_record_type'
6
6
 
7
7
  module Nacha
8
8
  module Record
9
9
  class AdvFileHeader < Nacha::Record::Base
10
10
  include FileHeaderRecordType
11
+
11
12
  nacha_field :record_type_code, inclusion: 'M', contents: 'C1', position: 1..1
12
13
  nacha_field :priority_code, inclusion: 'R', contents: 'Numeric', position: 2..3
13
- nacha_field :immediate_destination, inclusion: 'M', contents: 'bTTTTAAAAC', position: 4..13
14
- nacha_field :immediate_origin, inclusion: 'M', contents: 'bTTTTAAAAC', position: 14..23
14
+ nacha_field :immediate_destination, inclusion: 'M',
15
+ contents: 'bTTTTAAAAC', position: 4..13
16
+ nacha_field :immediate_origin, inclusion: 'M',
17
+ contents: 'bTTTTAAAAC', position: 14..23
15
18
  nacha_field :file_creation_date, inclusion: 'M', contents: 'YYMMDD', position: 24..29
16
19
  nacha_field :file_creation_time, inclusion: 'M', contents: 'HHMM', position: 30..33
17
20
  nacha_field :file_id_modifier, inclusion: 'M', contents: 'A-Z0-9', position: 34..34
18
21
  nacha_field :record_size, inclusion: 'M', contents: 'C094', position: 35..37
19
22
  nacha_field :blocking_factor, inclusion: 'M', contents: 'C10', position: 38..39
20
23
  nacha_field :format_code, inclusion: 'M', contents: 'C1', position: 40..40
21
- nacha_field :immediate_destination_name, inclusion: 'M', contents: 'Alphameric', position: 41..63
22
- nacha_field :immediate_origin_name, inclusion: 'M', contents: 'Alphameric', position: 64..86
24
+ nacha_field :immediate_destination_name, inclusion: 'M',
25
+ contents: 'Alphameric', position: 41..63
26
+ nacha_field :immediate_origin_name, inclusion: 'M',
27
+ contents: 'Alphameric', position: 64..86
23
28
  nacha_field :reference_code, inclusion: 'M', contents: 'CADV FILE', position: 87..94
24
29
  end
25
30
  end
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'nacha/record/base.rb'
5
- require 'nacha/record/detail_record_type.rb'
4
+ require 'nacha/record/base'
5
+ require 'nacha/record/detail_record_type'
6
6
 
7
7
  module Nacha
8
8
  module Record
@@ -4,42 +4,47 @@ require 'json'
4
4
  require 'nacha/field'
5
5
  require 'nacha/record/validations/field_validations'
6
6
 
7
+ # :reek:TooManyInstanceVariables, :reek:TooManyMethods
7
8
  module Nacha
8
9
  module Record
10
+ # Base class for all Nacha records.
9
11
  class Base
10
12
  include Validations::FieldValidations
11
13
 
12
- attr_accessor :children, :parent, :fields
13
- attr_reader :name, :validations, :errors, :original_input_line
14
- attr_accessor :line_number
14
+ attr_reader :children, :name, :validations, :original_input_line, :fields
15
+ # :reek:Attribute
16
+ attr_accessor :parent, :line_number
15
17
 
18
+ # :reek:ManualDispatch
16
19
  def initialize(opts = {})
17
20
  @children = []
21
+ @parent = nil
18
22
  @errors = []
19
23
  @original_input_line = nil
24
+ @line_number = nil
25
+ @dirty = false
26
+ @fields = {}
20
27
  create_fields_from_definition
21
- opts.each do |k, v|
22
- setter = "#{k}="
23
- next unless respond_to? setter
24
-
28
+ opts.each do |key, value|
29
+ setter = "#{key}="
25
30
  # rubocop:disable GitlabSecurity/PublicSend
26
- send(setter, v) unless v.nil?
31
+ public_send(setter, value) if value && respond_to?(setter)
27
32
  # rubocop:enable GitlabSecurity/PublicSend
28
33
  end
29
34
  end
30
35
 
31
36
  class << self
37
+ # :reek:LongParameterList, :reek:ManualDispatch
32
38
  def nacha_field(name, inclusion:, contents:, position:)
33
39
  Nacha.add_ach_record_type(self)
34
40
  definition[name] = { inclusion: inclusion,
35
41
  contents: contents,
36
42
  position: position,
37
- name: name}
38
- validation_method = "valid_#{name}".to_sym
43
+ name: name }
44
+ validation_method = :"valid_#{name}"
39
45
  return unless respond_to?(validation_method)
40
46
 
41
- validations[name] ||= []
42
- validations[name] << validation_method
47
+ (validations[name] ||= []) << validation_method
43
48
  end
44
49
 
45
50
  def definition
@@ -51,72 +56,51 @@ module Nacha
51
56
  end
52
57
 
53
58
  def unpack_str
54
- @unpack_str ||= definition.values.collect do |d|
55
- Nacha::Field.unpack_str(d)
59
+ @unpack_str ||= definition.values.collect do |field_def|
60
+ Nacha::Field.unpack_str(field_def)
56
61
  end.join.freeze
57
62
  end
58
63
 
59
- def old_matcher
60
- @matcher ||=
61
- Regexp.new('\A' + definition.values.collect do |d|
62
- if d[:contents] =~ /\AC(.+)\z/ || d['contents'] =~ /\AC(.+)\z/
63
- Regexp.last_match(1)
64
- else
65
- '.' * (d[:position] || d['position']).size
66
- end
67
- end.join + '\z')
68
- end
69
-
70
- # A more strict matcher that accounts for numeric and date fields
71
- # and allows for spaces in those fields, but not alphabetic characters
72
- # Also matches strings that might not be long enough.
73
- #
74
- # Processes the definition in reverse order to allow later fields to be
75
- # skipped if they are not present in the input string.
64
+ # :reek:TooManyStatements
65
+ # rubocop:disable Layout/BlockAlignment,
66
+ # rubocop:disable Style/StringConcatenation:
76
67
  def matcher
77
- return @matcher if @matcher
78
-
79
- output_started = false
80
- skipped_output = false
81
- @matcher ||=
82
- Regexp.new('\A' + definition.values.reverse.collect do |d|
83
- if d[:contents] =~ /\AC(.+)\z/
68
+ @matcher ||= begin
69
+ output_started = false
70
+ skipped_output = false
71
+ Regexp.new('\A' + definition.values.reverse.collect do |field|
72
+ contents = field[:contents]
73
+ position = field[:position]
74
+ size = position.size
75
+ if contents =~ /\AC(.+)\z/
84
76
  last_match = Regexp.last_match(1)
85
- if last_match =~ /\A *\z/
77
+ if last_match.match?(/ */) && !output_started
86
78
  skipped_output = true
87
79
  ''
88
80
  else
89
81
  output_started = true
90
82
  last_match
91
83
  end
92
- elsif d[:contents] =~ /\ANumeric\z/
84
+ elsif contents.match?(/\ANumeric\z/) || contents.match?(/\AYYMMDD\z/)
93
85
  output_started = true
94
- '[0-9 ]' + "{#{(d[:position] || d['position']).size}}"
95
- elsif d[:contents] =~ /\AYYMMDD\z/
96
- if output_started
97
- '[0-9 ]' + "{#{(d[:position] || d['position']).size}}"
98
- else
99
- skipped_output = true
100
- ''
101
- end
86
+ '[0-9 ]' + "{#{size}}"
87
+ elsif output_started
88
+ '.' + "{#{size}}"
102
89
  else
103
- if output_started
104
- '.' + "{#{(d[:position] || d['position']).size}}"
105
- else
106
- skipped_output = true
107
- ''
108
- end
90
+ skipped_output = true
91
+ ''
109
92
  end
110
93
  end.reverse.join + (skipped_output ? '.*' : '') + '\z')
94
+ end
111
95
  end
112
-
96
+ # rubocop:enable Layout/BlockAlignment,
97
+ # rubocop:enable Style/StringConcatenation:
113
98
 
114
99
  def parse(ach_str)
115
- rec = new
100
+ rec = new(original_input_line: ach_str)
116
101
  ach_str.unpack(unpack_str).zip(rec.fields.values) do |input_data, field|
117
102
  field.data = input_data
118
103
  end
119
- rec.original_input_line = ach_str
120
104
  rec.validate
121
105
  rec
122
106
  end
@@ -124,14 +108,35 @@ module Nacha
124
108
  def record_type
125
109
  Nacha.record_name(self)
126
110
  end
127
- end # end class methods
128
111
 
112
+ # :reek:ManualDispatch, :reek:TooManyStatements
113
+ def to_h
114
+ fields = definition.transform_values do |field_def|
115
+ {
116
+ inclusion: field_def[:inclusion],
117
+ contents: field_def[:contents],
118
+ position: field_def[:position].to_s
119
+ }
120
+ end
121
+
122
+ fields[:child_record_types] = child_record_types.to_a
123
+ fields[:child_record_types] ||= []
124
+ fields[:klass] = name.to_s
125
+
126
+ { record_type.to_sym => fields }
127
+ end
128
+
129
+ def to_json(*_args)
130
+ JSON.pretty_generate(to_h)
131
+ end
132
+ end
133
+
134
+ # :reek:FeatureEnvy
129
135
  def original_input_line=(line)
130
136
  @original_input_line = line.dup if line.is_a?(String)
131
137
  end
132
138
 
133
139
  def create_fields_from_definition
134
- @fields ||= {}
135
140
  definition.each_pair do |field_name, field_def|
136
141
  @fields[field_name.to_sym] = Nacha::Field.new(field_def)
137
142
  end
@@ -152,11 +157,10 @@ module Nacha
152
157
  errors: errors,
153
158
  line_number: @line_number,
154
159
  original_input_line: original_input_line
155
- }
156
- }.merge(
157
- @fields.keys.map do |key|
158
- [key, @fields[key].to_json_output]
159
- end.to_h)
160
+ } }.merge(
161
+ @fields.keys.to_h do |key|
162
+ [key, @fields[key].to_json_output]
163
+ end)
160
164
  end
161
165
 
162
166
  def to_json(*_args)
@@ -169,17 +173,18 @@ module Nacha
169
173
  end.join
170
174
  end
171
175
 
172
- def to_html(opts = {})
176
+ def to_html(_opts = {})
173
177
  record_error_class = nil
174
178
 
175
- field_html = @fields.keys.collect do |key|
176
- record_error_class ||= 'error' if @fields[key].errors.any?
177
- @fields[key].to_html
179
+ field_html = @fields.values.collect do |field|
180
+ record_error_class ||= 'error' if field.errors.any?
181
+ field.to_html
178
182
  end.join
179
- "<div class=\"nacha-record tooltip #{record_type} #{record_error_class}\">" +
180
- "<span class=\"nacha-field\" data-name=\"record-number\">#{"%05d" % [line_number]}&nbsp;|&nbsp</span>" +
181
- field_html +
182
- "<span class=\"record-type\" data-name=\"record-type\">#{human_name}</span>" +
183
+ "<div class=\"nacha-record tooltip #{record_type} #{record_error_class}\">" \
184
+ "<span class=\"nacha-field\" data-name=\"record-number\">#{format('%05d',
185
+ line_number)}&nbsp;|&nbsp</span>" \
186
+ "#{field_html}" \
187
+ "<span class=\"record-type\" data-name=\"record-type\">#{human_name}</span>" \
183
188
  "</div>"
184
189
  end
185
190
 
@@ -193,19 +198,10 @@ module Nacha
193
198
 
194
199
  def validate
195
200
  # Run field-level validations first
196
- @fields.values.each(&:validate)
197
-
201
+ @fields.each_value(&:validate)
198
202
  # Then run record-level validations that might depend on multiple fields
199
- self.class.definition.keys.each do |field|
200
- next unless self.class.validations[field]
201
-
202
- # rubocop:disable GitlabSecurity/PublicSend
203
- field_data = send(field)
204
-
205
- self.class.validations[field].map do |validation_method|
206
- self.class.send(validation_method, field_data)
207
- end
208
- # rubocop:enable GitlabSecurity/PublicSend
203
+ self.class.definition.each_key do |field|
204
+ run_record_level_validations_for(field)
209
205
  end
210
206
  end
211
207
 
@@ -229,7 +225,8 @@ module Nacha
229
225
  # # Assuming transaction_code is "201" and DEBIT_TRANSACTION_CODES includes "201"
230
226
  # debit? #=> true
231
227
  #
232
- # # Assuming transaction_code is "100" and DEBIT_TRANSACTION_CODES does not include "100"
228
+ # # Assuming transaction_code is "100" and DEBIT_TRANSACTION_CODES
229
+ # # does not include "100"
233
230
  # debit? #=> false
234
231
  #
235
232
  # # Assuming transaction_code is nil
@@ -268,7 +265,8 @@ module Nacha
268
265
  # # Assuming transaction_code is "101" and CREDIT_TRANSACTION_CODES includes "101"
269
266
  # credit? #=> true
270
267
  #
271
- # # Assuming transaction_code is "200" and CREDIT_TRANSACTION_CODES does not include "200"
268
+ # # Assuming transaction_code is "200" and CREDIT_TRANSACTION_CODES
269
+ # # does not include "200"
272
270
  # credit? #=> false
273
271
  #
274
272
  # # Assuming transaction_code is nil
@@ -294,37 +292,54 @@ module Nacha
294
292
  end
295
293
 
296
294
  def errors
297
- (@errors + @fields.values.map { |field| field.errors }).flatten
295
+ (@errors + @fields.values.map(&:errors)).flatten
298
296
  end
299
297
 
300
-
301
298
  def add_error(err_string)
302
299
  @errors << err_string
303
300
  end
304
301
 
305
- def respond_to?(method_name, include_private = false)
306
- field_name = method_name.to_s.gsub(/=$/, '').to_sym
302
+ # :reek:TooManyStatements
303
+ def method_missing(method_name, *args, &block)
304
+ method = method_name.to_s
305
+ field_name = method.gsub(/=$/, '').to_sym
306
+ field = @fields[field_name]
307
+ return super unless field
307
308
 
308
- definition[field_name] || super
309
+ if method.end_with?('=')
310
+ assign_field_data(field, args)
311
+ else
312
+ field
313
+ end
309
314
  end
310
315
 
311
- def method_missing(method_name, *args, &block)
316
+ def respond_to_missing?(method_name, *)
312
317
  field_name = method_name.to_s.gsub(/=$/, '').to_sym
313
- is_assignment = (/[^=]*=$/o =~ method_name.to_s)
314
- if @fields[field_name]
315
- if is_assignment
316
- # @fields[field_name].send(:data=,*args)
317
- # rubocop:disable GitlabSecurity/PublicSend
318
- @fields[field_name].public_send(:data=, *args)
319
- # rubocop:enable GitlabSecurity/PublicSend
320
- @dirty = true
321
- else
322
- # @fields[field_name].data
323
- @fields[field_name]
324
- end
325
- else
326
- super
318
+ definition[field_name] || super
319
+ end
320
+
321
+ private
322
+
323
+ def assign_field_data(field, args)
324
+ # rubocop:disable GitlabSecurity/PublicSend
325
+ field.public_send(:data=, *args)
326
+ # rubocop:enable GitlabSecurity/PublicSend
327
+ @dirty = true
328
+ end
329
+
330
+ # :reek:TooManyStatements
331
+ def run_record_level_validations_for(field)
332
+ klass = self.class
333
+ validations = klass.validations[field]
334
+ return unless validations
335
+
336
+ # rubocop:disable GitlabSecurity/PublicSend
337
+ field_data = send(field)
338
+
339
+ validations.each do |validation_method|
340
+ klass.send(validation_method, field_data)
327
341
  end
342
+ # rubocop:enable GitlabSecurity/PublicSend
328
343
  end
329
344
  end
330
345
  end
@@ -1,23 +1,29 @@
1
1
  # coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'nacha/record/base.rb'
5
- require 'nacha/record/batch_control_record_type.rb'
4
+ require 'nacha/record/base'
5
+ require 'nacha/record/batch_control_record_type'
6
6
 
7
7
  module Nacha
8
8
  module Record
9
9
  class BatchControl < Nacha::Record::Base
10
10
  include BatchControlRecordType
11
+
11
12
  nacha_field :record_type_code, inclusion: 'M', contents: 'C8', position: 1..1
12
13
  nacha_field :service_class_code, inclusion: 'M', contents: 'Numeric', position: 2..4
13
14
  nacha_field :entry_addenda_count, inclusion: 'M', contents: 'Numeric', position: 5..10
14
15
  nacha_field :entry_hash, inclusion: 'M', contents: 'Numeric', position: 11..20
15
- nacha_field :total_debit_entry_dollar_amount, inclusion: 'M', contents: '$$$$$$$$$$¢¢', position: 21..32
16
- nacha_field :total_credit_entry_dollar_amount, inclusion: 'M', contents: '$$$$$$$$$$¢¢', position: 33..44
17
- nacha_field :company_identification, inclusion: 'R', contents: 'Alphameric', position: 45..54
18
- nacha_field :message_authentication_code, inclusion: 'O', contents: 'Alphameric', position: 55..73
16
+ nacha_field :total_debit_entry_dollar_amount,
17
+ inclusion: 'M', contents: '$$$$$$$$$$¢¢', position: 21..32
18
+ nacha_field :total_credit_entry_dollar_amount,
19
+ inclusion: 'M', contents: '$$$$$$$$$$¢¢', position: 33..44
20
+ nacha_field :company_identification,
21
+ inclusion: 'R', contents: 'Alphameric', position: 45..54
22
+ nacha_field :message_authentication_code,
23
+ inclusion: 'O', contents: 'Alphameric', position: 55..73
19
24
  nacha_field :reserved, inclusion: 'O', contents: 'C ', position: 74..79
20
- nacha_field :originating_dfi_identification, inclusion: 'M', contents: 'TTTTAAAA', position: 80..87
25
+ nacha_field :originating_dfi_identification,
26
+ inclusion: 'M', contents: 'TTTTAAAA', position: 80..87
21
27
  nacha_field :batch_number, inclusion: 'M', contents: 'Numeric', position: 88..94
22
28
  end
23
29
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'nacha/record/base.rb'
4
- require 'nacha/record/batch_header_record_type.rb'
3
+ require 'nacha/record/base'
4
+ require 'nacha/record/batch_header_record_type'
5
5
 
6
6
  module Nacha
7
7
  module Record
@@ -11,15 +11,24 @@ module Nacha
11
11
  nacha_field :record_type_code, inclusion: 'M', contents: 'C5', position: 1..1
12
12
  nacha_field :service_class_code, inclusion: 'M', contents: 'Numeric', position: 2..4
13
13
  nacha_field :company_name, inclusion: 'M', contents: 'Alphameric', position: 5..20
14
- nacha_field :company_discretionary_data, inclusion: 'O', contents: 'Alphameric', position: 21..40
15
- nacha_field :company_identification, inclusion: 'M', contents: 'Alphameric', position: 41..50
16
- nacha_field :standard_entry_class_code, inclusion: 'M', contents: 'Alphameric', position: 51..53
17
- nacha_field :company_entry_description, inclusion: 'M', contents: 'Alphameric', position: 54..63
18
- nacha_field :company_descriptive_date, inclusion: 'O', contents: 'Alphameric', position: 64..69
19
- nacha_field :effective_entry_date, inclusion: 'R', contents: 'YYMMDD', position: 70..75
20
- nacha_field :settlement_date_julian, inclusion: 'O', contents: 'Numeric', position: 76..78
21
- nacha_field :originator_status_code, inclusion: 'M', contents: 'Alphameric', position: 79..79
22
- nacha_field :originating_dfi_identification, inclusion: 'M', contents: 'TTTTAAAA', position: 80..87
14
+ nacha_field :company_discretionary_data,
15
+ inclusion: 'O', contents: 'Alphameric', position: 21..40
16
+ nacha_field :company_identification,
17
+ inclusion: 'M', contents: 'Alphameric', position: 41..50
18
+ nacha_field :standard_entry_class_code,
19
+ inclusion: 'M', contents: 'Alphameric', position: 51..53
20
+ nacha_field :company_entry_description,
21
+ inclusion: 'M', contents: 'Alphameric', position: 54..63
22
+ nacha_field :company_descriptive_date,
23
+ inclusion: 'O', contents: 'Alphameric', position: 64..69
24
+ nacha_field :effective_entry_date,
25
+ inclusion: 'R', contents: 'YYMMDD', position: 70..75
26
+ nacha_field :settlement_date_julian,
27
+ inclusion: 'O', contents: 'Numeric', position: 76..78
28
+ nacha_field :originator_status_code,
29
+ inclusion: 'M', contents: 'Alphameric', position: 79..79
30
+ nacha_field :originating_dfi_identification,
31
+ inclusion: 'M', contents: 'TTTTAAAA', position: 80..87
23
32
  nacha_field :batch_number, inclusion: 'M', contents: 'Numeric', position: 88..94
24
33
  end
25
34
  end
@@ -16,7 +16,7 @@ module Nacha
16
16
  def child_record_types
17
17
  sec = standard_entry_class_code.to_s.capitalize
18
18
  [
19
- 'Nacha::Record::' + sec + 'EntryDetail',
19
+ "Nacha::Record::#{sec}EntryDetail",
20
20
  'Nacha::Record::BatchControl'
21
21
  ]
22
22
  end