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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -2
- data/.ruby-version +1 -1
- data/CHANGELOG.md +17 -0
- data/exe/nacha +51 -20
- data/lib/nacha/aba_number.rb +17 -14
- data/lib/nacha/ach_date.rb +15 -8
- data/lib/nacha/field.rb +69 -58
- data/lib/nacha/has_errors.rb +12 -8
- data/lib/nacha/numeric.rb +13 -10
- data/lib/nacha/parser.rb +22 -27
- data/lib/nacha/parser_context.rb +4 -9
- data/lib/nacha/record/ack_entry_detail.rb +15 -8
- data/lib/nacha/record/adv_batch_control.rb +12 -7
- data/lib/nacha/record/adv_entry_detail.rb +3 -2
- data/lib/nacha/record/adv_file_control.rb +9 -5
- data/lib/nacha/record/adv_file_header.rb +11 -6
- data/lib/nacha/record/arc_entry_detail.rb +2 -2
- data/lib/nacha/record/base.rb +121 -106
- data/lib/nacha/record/batch_control.rb +13 -7
- data/lib/nacha/record/batch_header.rb +20 -11
- data/lib/nacha/record/batch_header_record_type.rb +1 -1
- data/lib/nacha/record/boc_entry_detail.rb +3 -2
- data/lib/nacha/record/ccd_addenda.rb +2 -2
- data/lib/nacha/record/ccd_entry_detail.rb +3 -2
- data/lib/nacha/record/cie_addenda.rb +2 -2
- data/lib/nacha/record/cie_entry_detail.rb +5 -3
- data/lib/nacha/record/ctx_addenda.rb +2 -2
- data/lib/nacha/record/ctx_corporate_entry_detail.rb +2 -2
- data/lib/nacha/record/dne_addenda.rb +2 -2
- data/lib/nacha/record/dne_entry_detail.rb +6 -4
- data/lib/nacha/record/enr_addenda.rb +3 -2
- data/lib/nacha/record/enr_entry_detail.rb +4 -3
- data/lib/nacha/record/fifth_iat_addenda.rb +8 -4
- data/lib/nacha/record/file_control.rb +9 -5
- data/lib/nacha/record/file_control_record_type.rb +1 -1
- data/lib/nacha/record/file_header.rb +12 -8
- data/lib/nacha/record/file_header_record_type.rb +1 -1
- data/lib/nacha/record/filler.rb +3 -3
- data/lib/nacha/record/filler_record_type.rb +3 -1
- data/lib/nacha/record/first_iat_addenda.rb +3 -2
- data/lib/nacha/record/fourth_iat_addenda.rb +7 -4
- data/lib/nacha/record/iat_batch_header.rb +5 -3
- data/lib/nacha/record/iat_entry_detail.rb +7 -4
- data/lib/nacha/record/iat_foreign_coorespondent_bank_information_addenda.rb +10 -6
- data/lib/nacha/record/iat_remittance_information_addenda.rb +3 -2
- data/lib/nacha/record/mte_addenda.rb +4 -3
- data/lib/nacha/record/mte_entry_detail.rb +5 -3
- data/lib/nacha/record/pop_entry_detail.rb +3 -2
- data/lib/nacha/record/pos_addenda.rb +6 -3
- data/lib/nacha/record/pos_entry_detail.rb +5 -3
- data/lib/nacha/record/ppd_addenda.rb +3 -2
- data/lib/nacha/record/ppd_entry_detail.rb +5 -3
- data/lib/nacha/record/rck_entry_detail.rb +3 -2
- data/lib/nacha/record/second_iat_addenda.rb +3 -2
- data/lib/nacha/record/seventh_iat_addenda.rb +3 -2
- data/lib/nacha/record/shr_addenda.rb +5 -3
- data/lib/nacha/record/shr_entry_detail.rb +3 -2
- data/lib/nacha/record/sixth_iat_addenda.rb +5 -3
- data/lib/nacha/record/tel_entry_detail.rb +5 -3
- data/lib/nacha/record/third_iat_addenda.rb +3 -2
- data/lib/nacha/record/trc_entry_detail.rb +3 -2
- data/lib/nacha/record/trx_addenda.rb +3 -2
- data/lib/nacha/record/trx_entry_detail.rb +5 -3
- data/lib/nacha/record/validations/field_validations.rb +26 -14
- data/lib/nacha/record/validations/record_validations.rb +2 -1
- data/lib/nacha/record/web_addenda.rb +3 -2
- data/lib/nacha/record/web_entry_detail.rb +5 -3
- data/lib/nacha/record/xck_entry_detail.rb +3 -2
- data/lib/nacha/version.rb +4 -1
- data/lib/nacha.rb +21 -14
- data/nacha.gemspec +13 -16
- metadata +22 -8
data/lib/nacha/parser_context.rb
CHANGED
@@ -2,13 +2,9 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
class Nacha::ParserContext
|
5
|
-
attr_accessor :file_name
|
6
|
-
|
7
|
-
|
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
|
5
|
-
require 'nacha/record/detail_record_type
|
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,
|
14
|
-
|
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,
|
17
|
-
|
18
|
-
nacha_field :
|
19
|
-
|
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
|
5
|
-
require 'nacha/record/batch_control_record_type
|
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,
|
17
|
-
|
18
|
-
nacha_field :
|
19
|
-
|
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
|
5
|
-
require 'nacha/record/detail_record_type
|
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
|
5
|
-
require 'nacha/record/file_control_record_type
|
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,
|
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,
|
17
|
-
|
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
|
5
|
-
require 'nacha/record/file_header_record_type
|
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',
|
14
|
-
|
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',
|
22
|
-
|
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
|
data/lib/nacha/record/base.rb
CHANGED
@@ -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
|
-
|
13
|
-
|
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 |
|
22
|
-
setter = "#{
|
23
|
-
next unless respond_to? setter
|
24
|
-
|
28
|
+
opts.each do |key, value|
|
29
|
+
setter = "#{key}="
|
25
30
|
# rubocop:disable GitlabSecurity/PublicSend
|
26
|
-
|
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}"
|
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 |
|
55
|
-
Nacha::Field.unpack_str(
|
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
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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
|
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
|
84
|
+
elsif contents.match?(/\ANumeric\z/) || contents.match?(/\AYYMMDD\z/)
|
93
85
|
output_started = true
|
94
|
-
'[0-9 ]' + "{#{
|
95
|
-
elsif
|
96
|
-
|
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
|
-
|
104
|
-
|
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
|
-
|
157
|
-
|
158
|
-
|
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(
|
176
|
+
def to_html(_opts = {})
|
173
177
|
record_error_class = nil
|
174
178
|
|
175
|
-
field_html = @fields.
|
176
|
-
record_error_class ||= 'error' if
|
177
|
-
|
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\">#{
|
181
|
-
|
182
|
-
"
|
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)} | </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.
|
197
|
-
|
201
|
+
@fields.each_value(&:validate)
|
198
202
|
# Then run record-level validations that might depend on multiple fields
|
199
|
-
self.class.definition.
|
200
|
-
|
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
|
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
|
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
|
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
|
-
|
306
|
-
|
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
|
-
|
309
|
+
if method.end_with?('=')
|
310
|
+
assign_field_data(field, args)
|
311
|
+
else
|
312
|
+
field
|
313
|
+
end
|
309
314
|
end
|
310
315
|
|
311
|
-
def
|
316
|
+
def respond_to_missing?(method_name, *)
|
312
317
|
field_name = method_name.to_s.gsub(/=$/, '').to_sym
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
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
|
5
|
-
require 'nacha/record/batch_control_record_type
|
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,
|
16
|
-
|
17
|
-
nacha_field :
|
18
|
-
|
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,
|
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
|
4
|
-
require 'nacha/record/batch_header_record_type
|
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,
|
15
|
-
|
16
|
-
nacha_field :
|
17
|
-
|
18
|
-
nacha_field :
|
19
|
-
|
20
|
-
nacha_field :
|
21
|
-
|
22
|
-
nacha_field :
|
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
|