nacha 0.1.10 → 0.1.14
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/.github/workflows/ci.yml +63 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +4 -2
- data/.ruby-version +1 -1
- data/CHANGELOG.md +42 -0
- data/README.md +10 -2
- data/exe/nacha +46 -29
- data/lib/nacha/aba_number.rb +33 -24
- data/lib/nacha/ach_date.rb +15 -8
- data/lib/nacha/field.rb +62 -77
- data/lib/nacha/formatter/base.rb +52 -0
- data/lib/nacha/formatter/html_formatter.rb +119 -0
- data/lib/nacha/formatter/json_formatter.rb +49 -0
- data/lib/nacha/formatter/markdown_formatter.rb +57 -0
- data/lib/nacha/formatter.rb +24 -0
- data/lib/nacha/has_errors.rb +12 -8
- data/lib/nacha/numeric.rb +13 -10
- data/lib/nacha/parser.rb +32 -31
- data/lib/nacha/parser_context.rb +4 -9
- data/lib/nacha/record/ack_entry_detail.rb +15 -8
- data/lib/nacha/record/addenda_record_type.rb +8 -1
- 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 +124 -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 +5 -4
- 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/detail_record_type.rb +4 -1
- 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 +4 -3
- 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 +9 -6
- 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 +14 -16
- metadata +42 -8
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'nacha/formatter/base'
|
4
|
+
|
5
|
+
module Nacha
|
6
|
+
module Formatter
|
7
|
+
class HtmlFormatter < Base
|
8
|
+
def format
|
9
|
+
[
|
10
|
+
html_preamble,
|
11
|
+
file_statistics_html,
|
12
|
+
records_html,
|
13
|
+
html_postamble
|
14
|
+
].join("\n")
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def html_preamble
|
20
|
+
preamble_content = options.fetch(:preamble, default_preamble)
|
21
|
+
if File.exist?(preamble_content)
|
22
|
+
File.read(preamble_content)
|
23
|
+
else
|
24
|
+
preamble_content
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def html_postamble
|
29
|
+
postamble_content = options.fetch(:postamble, default_postamble)
|
30
|
+
if File.exist?(postamble_content)
|
31
|
+
File.read(postamble_content)
|
32
|
+
else
|
33
|
+
postamble_content
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def file_statistics_html
|
38
|
+
stats = file_statistics
|
39
|
+
<<~HTML
|
40
|
+
<div class="file-statistics">
|
41
|
+
<h2>File Information</h2>
|
42
|
+
<ul>
|
43
|
+
<li><strong>File Name:</strong> #{stats[:file_name]}</li>
|
44
|
+
<li><strong>File Size:</strong> #{stats[:file_size]} bytes</li>
|
45
|
+
<li><strong>Number of Lines:</strong> #{stats[:number_of_lines]}</li>
|
46
|
+
<li><strong>Created At:</strong> #{stats[:created_at]}</li>
|
47
|
+
<li><strong>Modified At:</strong> #{stats[:modified_at]}</li>
|
48
|
+
<li><strong>Checksum (SHA256):</strong> #{stats[:checksum]}</li>
|
49
|
+
<li><strong>Number of Filler Lines:</strong> #{stats[:number_of_filler_lines]}</li>
|
50
|
+
</ul>
|
51
|
+
</div>
|
52
|
+
HTML
|
53
|
+
end
|
54
|
+
|
55
|
+
def records_html
|
56
|
+
records.map { |record| record_to_html(record) }.join("\n")
|
57
|
+
end
|
58
|
+
|
59
|
+
def record_to_html(record)
|
60
|
+
record_error_class = record.errors.any? ? 'error' : ''
|
61
|
+
field_html = record.fields.values.map { |field| field_to_html(field) }.join
|
62
|
+
|
63
|
+
"<div class=\"nacha-record tooltip #{record.record_type} #{record_error_class}\">" \
|
64
|
+
"<span class=\"nacha-record-number\" data-name=\"record-number\">#{Kernel.format('%05d',
|
65
|
+
record.line_number)} | </span>" \
|
66
|
+
"#{field_html}" \
|
67
|
+
"<span class=\"record-type\" data-name=\"record-type\">#{record.human_name}</span>" \
|
68
|
+
"</div>"
|
69
|
+
end
|
70
|
+
|
71
|
+
def field_to_html(field)
|
72
|
+
tooltip_text = "<span class=\"tooltiptext\">#{field.human_name} #{field.errors.join(' ')}</span>"
|
73
|
+
field_classes = %w[nacha-field tooltip]
|
74
|
+
field_classes << 'mandatory' if field.mandatory?
|
75
|
+
field_classes << 'required' if field.required?
|
76
|
+
field_classes << 'optional' if field.optional?
|
77
|
+
field_classes << 'error' if field.errors.any?
|
78
|
+
|
79
|
+
ach_string = field.to_ach.gsub(' ', ' ')
|
80
|
+
"<span data-field-name=\"#{field.name}\" contentEditable=true " \
|
81
|
+
"class=\"#{field_classes.join(' ')}\" data-name=\"#{field.name}\">" \
|
82
|
+
"#{ach_string}#{tooltip_text}</span>"
|
83
|
+
end
|
84
|
+
|
85
|
+
def default_preamble
|
86
|
+
stylesheet = options.fetch(:stylesheet, default_stylesheet)
|
87
|
+
javascript = options.fetch(:javascript, '')
|
88
|
+
<<~HTML
|
89
|
+
<!DOCTYPE html>
|
90
|
+
<html>
|
91
|
+
<head>
|
92
|
+
<title>NACHA File</title>
|
93
|
+
<style>#{stylesheet}</style>
|
94
|
+
<script>#{javascript}</script>
|
95
|
+
</head>
|
96
|
+
<body>
|
97
|
+
HTML
|
98
|
+
end
|
99
|
+
|
100
|
+
def default_postamble
|
101
|
+
<<~HTML
|
102
|
+
</body>
|
103
|
+
</html>
|
104
|
+
HTML
|
105
|
+
end
|
106
|
+
|
107
|
+
def default_stylesheet
|
108
|
+
<<~CSS
|
109
|
+
body { font-family: monospace; }
|
110
|
+
.tooltip { position: relative; display: inline-block; border-bottom: 1px dotted black; }
|
111
|
+
.tooltip .tooltiptext { visibility: hidden; width: 120px; background-color: black; color: #fff; text-align: center; border-radius: 6px; padding: 5px 0; position: absolute; z-index: 1; }
|
112
|
+
.tooltip:hover .tooltiptext { visibility: visible; }
|
113
|
+
.nacha-record { white-space: nowrap; }
|
114
|
+
.error { background-color: #ffdddd; }
|
115
|
+
CSS
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'nacha/formatter/base'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Nacha
|
7
|
+
module Formatter
|
8
|
+
class JsonFormatter < Base
|
9
|
+
def format
|
10
|
+
output = {
|
11
|
+
file: file_statistics,
|
12
|
+
records: records.map { |record| record_to_h(record) }
|
13
|
+
}
|
14
|
+
|
15
|
+
JSON.pretty_generate(output)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def record_to_h(record)
|
21
|
+
{
|
22
|
+
nacha_record_type: record.record_type,
|
23
|
+
metadata: {
|
24
|
+
klass: record.class.name,
|
25
|
+
errors: record.errors,
|
26
|
+
line_number: record.line_number,
|
27
|
+
original_input_line: record.original_input_line
|
28
|
+
}
|
29
|
+
}.merge(
|
30
|
+
record.fields.keys.to_h do |key|
|
31
|
+
[key, field_to_json_output(record.fields[key])]
|
32
|
+
end
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def field_to_json_output(field)
|
37
|
+
if field.json_output
|
38
|
+
# rubocop:disable GitlabSecurity/PublicSend
|
39
|
+
field.json_output.reduce(field.raw) do |memo, operation|
|
40
|
+
memo&.public_send(*operation)
|
41
|
+
end
|
42
|
+
# rubocop:enable GitlabSecurity/PublicSend
|
43
|
+
else
|
44
|
+
field.to_s
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'nacha/formatter/base'
|
4
|
+
|
5
|
+
module Nacha
|
6
|
+
module Formatter
|
7
|
+
class MarkdownFormatter < Base
|
8
|
+
def format
|
9
|
+
[
|
10
|
+
file_statistics_markdown,
|
11
|
+
records_markdown
|
12
|
+
].join("\n")
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def file_statistics_markdown
|
18
|
+
stats = file_statistics
|
19
|
+
<<~MARKDOWN
|
20
|
+
# File Information
|
21
|
+
|
22
|
+
- **File Name:** #{stats[:file_name]}
|
23
|
+
- **File Size:** #{stats[:file_size]} bytes
|
24
|
+
- **Number of Lines:** #{stats[:number_of_lines]}
|
25
|
+
- **Created At:** #{stats[:created_at]}
|
26
|
+
- **Modified At:** #{stats[:modified_at]}
|
27
|
+
- **Checksum (SHA256):** #{stats[:checksum]}
|
28
|
+
- **Number of Filler Lines:** #{stats[:number_of_filler_lines]}
|
29
|
+
MARKDOWN
|
30
|
+
end
|
31
|
+
|
32
|
+
def records_markdown
|
33
|
+
records.map { |record| record_to_markdown(record) }.join("\n")
|
34
|
+
end
|
35
|
+
|
36
|
+
def record_to_markdown(record)
|
37
|
+
if options[:flavor] == :github
|
38
|
+
github_flavored_markdown(record)
|
39
|
+
else
|
40
|
+
common_mark_markdown(record)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def common_mark_markdown(record)
|
45
|
+
"## #{record.human_name}\n\n" +
|
46
|
+
record.fields.map { |name, field| "* **#{name}:** #{field}" }.join("\n")
|
47
|
+
end
|
48
|
+
|
49
|
+
def github_flavored_markdown(record)
|
50
|
+
"### #{record.human_name}\n\n" \
|
51
|
+
"| Field | Value |\n" \
|
52
|
+
"|-------|-------|\n" +
|
53
|
+
record.fields.map { |name, field| "| #{name} | #{field} |" }.join("\n")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'nacha/formatter/json_formatter'
|
4
|
+
require 'nacha/formatter/html_formatter'
|
5
|
+
require 'nacha/formatter/markdown_formatter'
|
6
|
+
|
7
|
+
module Nacha
|
8
|
+
module Formatter
|
9
|
+
class FormatterFactory
|
10
|
+
def self.get(format, records, options = {})
|
11
|
+
case format
|
12
|
+
when :json
|
13
|
+
JsonFormatter.new(records, options)
|
14
|
+
when :html
|
15
|
+
HtmlFormatter.new(records, options)
|
16
|
+
when :markdown
|
17
|
+
MarkdownFormatter.new(records, options)
|
18
|
+
else
|
19
|
+
raise ArgumentError, "Unknown format: #{format}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/nacha/has_errors.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
|
-
|
2
|
-
attr_reader :errors
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module Nacha
|
4
|
+
module HasErrors
|
5
|
+
attr_reader :errors
|
6
|
+
|
7
|
+
def add_error(message)
|
8
|
+
@errors ||= []
|
9
|
+
@errors << message
|
10
|
+
end
|
8
11
|
|
9
|
-
|
10
|
-
|
12
|
+
def has_errors?
|
13
|
+
!@errors.nil? && !@errors.empty?
|
14
|
+
end
|
11
15
|
end
|
12
16
|
end
|
data/lib/nacha/numeric.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
class Nacha::Numeric
|
3
|
-
def initialize
|
4
|
+
def initialize(val = nil)
|
4
5
|
self.value = val
|
5
6
|
end
|
6
7
|
|
@@ -17,14 +18,14 @@ class Nacha::Numeric
|
|
17
18
|
def value=(val)
|
18
19
|
if val.is_a?(String)
|
19
20
|
@value = val.dup
|
20
|
-
if
|
21
|
+
if !val.strip.empty?
|
21
22
|
@op_value = BigDecimal(val.strip)
|
22
23
|
@value = val.dup
|
23
24
|
else
|
24
|
-
@op_value = BigDecimal(0)
|
25
|
+
@op_value = BigDecimal('0')
|
25
26
|
end
|
26
27
|
elsif val.nil?
|
27
|
-
@value = BigDecimal(0)
|
28
|
+
@value = BigDecimal('0')
|
28
29
|
@op_value = @value
|
29
30
|
else
|
30
31
|
@value = BigDecimal(val)
|
@@ -36,8 +37,8 @@ class Nacha::Numeric
|
|
36
37
|
@value ? @value.to_i.to_s : nil
|
37
38
|
end
|
38
39
|
|
39
|
-
def respond_to_missing?(method_name,
|
40
|
-
@op_value.respond_to?
|
40
|
+
def respond_to_missing?(method_name, _include_private = false)
|
41
|
+
@op_value.respond_to?(method_name)
|
41
42
|
end
|
42
43
|
|
43
44
|
# @op_value is the value for operations. @value may still be a string
|
@@ -45,20 +46,22 @@ class Nacha::Numeric
|
|
45
46
|
# should be checked to see if the operation is valid for it, not
|
46
47
|
# necessarily the potentially string @value
|
47
48
|
def method_missing(method_name, *args, &block)
|
48
|
-
if @op_value.respond_to?
|
49
|
+
if @op_value.respond_to?(method_name)
|
49
50
|
old_op_value = @op_value.dup
|
50
|
-
|
51
|
-
|
51
|
+
# rubocop:disable GitlabSecurity/PublicSend
|
52
|
+
if method_name.to_s.end_with?('!')
|
52
53
|
@op_value.send(method_name, *args, &block)
|
53
54
|
return_value = @op_value
|
54
55
|
else
|
55
56
|
return_value = @op_value.send(method_name, *args, &block)
|
56
|
-
# rubocop:enable GitlabSecurity/PublicSend
|
57
57
|
end
|
58
|
+
# rubocop:enable GitlabSecurity/PublicSend
|
59
|
+
|
58
60
|
if old_op_value != return_value
|
59
61
|
@value = return_value
|
60
62
|
@op_value = return_value
|
61
63
|
end
|
64
|
+
|
62
65
|
@value
|
63
66
|
else
|
64
67
|
super
|
data/lib/nacha/parser.rb
CHANGED
@@ -5,9 +5,11 @@ require 'nacha/parser_context'
|
|
5
5
|
|
6
6
|
# Nacha Parser - deal with figuring out what record type a line is
|
7
7
|
class Nacha::Parser
|
8
|
-
DEFAULT_RECORD_TYPES = [
|
9
|
-
|
10
|
-
|
8
|
+
DEFAULT_RECORD_TYPES = [
|
9
|
+
'Nacha::Record::FileHeader',
|
10
|
+
'Nacha::Record::AdvFileHeader',
|
11
|
+
'Nacha::Record::Filler'
|
12
|
+
].freeze
|
11
13
|
|
12
14
|
attr_reader :context
|
13
15
|
|
@@ -16,31 +18,25 @@ class Nacha::Parser
|
|
16
18
|
end
|
17
19
|
|
18
20
|
def parse_file(file)
|
19
|
-
@context.parser_started_at = Time.now
|
21
|
+
@context.parser_started_at = Time.now.utc
|
20
22
|
@context.file_name = file
|
21
23
|
parse_string(file.read)
|
22
24
|
end
|
23
25
|
|
24
26
|
def detect_possible_record_types(line)
|
25
|
-
Nacha.ach_record_types.
|
26
|
-
record_type if record_type.matcher
|
27
|
-
end.compact
|
28
|
-
end
|
29
|
-
|
30
|
-
def parse_line(line)
|
31
|
-
record_types = detect_possible_record_types(line)
|
32
|
-
|
33
|
-
records = record_types.map do |record_type|
|
34
|
-
|
27
|
+
Nacha.ach_record_types.filter_map do |record_type|
|
28
|
+
record_type if record_type.matcher.match?(line)
|
35
29
|
end
|
36
30
|
end
|
37
31
|
|
38
32
|
def parse_string(str)
|
39
33
|
line_num = -1
|
40
34
|
records = []
|
41
|
-
@context.parser_started_at ||= Time.now
|
42
|
-
str.scan(/(.{94}
|
43
|
-
line = line.first.strip
|
35
|
+
@context.parser_started_at ||= Time.now.utc
|
36
|
+
str.scan(/(.{0,94})[\r\n]*/).each do |line|
|
37
|
+
line = line.compact.first.strip
|
38
|
+
next if line.empty? || line.start_with?('#') # Skip empty lines and comments
|
39
|
+
|
44
40
|
line_num += 1
|
45
41
|
@context.line_number = line_num
|
46
42
|
@context.line_length = line.length
|
@@ -54,15 +50,24 @@ class Nacha::Parser
|
|
54
50
|
parent = previous
|
55
51
|
|
56
52
|
record_types = valid_record_types(parent)
|
53
|
+
|
57
54
|
while record_types
|
58
55
|
record = parse_first_by_types(line, record_types)
|
59
56
|
break if record || !parent
|
60
|
-
|
57
|
+
|
58
|
+
record_types = valid_record_types(parent.parent)
|
61
59
|
parent = parent.parent
|
62
|
-
record_types = valid_record_types(parent)
|
63
60
|
end
|
64
|
-
record
|
65
|
-
|
61
|
+
# Check all record types if no record was found
|
62
|
+
# TODO: remove this fallback logic
|
63
|
+
record ||= parse_first_by_types(line, Nacha.ach_record_types)
|
64
|
+
|
65
|
+
if record
|
66
|
+
record.line_number = line_num
|
67
|
+
record.validate
|
68
|
+
add_child(parent, record)
|
69
|
+
end
|
70
|
+
|
66
71
|
record
|
67
72
|
end
|
68
73
|
|
@@ -80,20 +85,16 @@ class Nacha::Parser
|
|
80
85
|
end
|
81
86
|
|
82
87
|
def parse_first_by_types(line, record_types)
|
83
|
-
record_types.
|
88
|
+
record_types.lazy.filter_map do |rt|
|
84
89
|
record_type = rt.is_a?(Class) ? rt : Object.const_get(rt)
|
85
|
-
|
86
|
-
|
87
|
-
return record if record
|
88
|
-
end
|
90
|
+
record_type.parse(line) if record_type.matcher.match?(line)
|
91
|
+
end.first
|
89
92
|
end
|
90
93
|
|
91
94
|
def parse_all_by_types(line, record_types)
|
92
|
-
record_types.
|
95
|
+
record_types.filter_map do |rt|
|
93
96
|
record_type = rt.is_a?(Class) ? rt : Object.const_get(rt)
|
94
|
-
|
95
|
-
|
96
|
-
record
|
97
|
-
end.compact
|
97
|
+
record_type.parse(line) if record_type.matcher.match?(line)
|
98
|
+
end
|
98
99
|
end
|
99
100
|
end
|
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
|
@@ -9,7 +9,14 @@ module Nacha
|
|
9
9
|
|
10
10
|
module ClassMethods
|
11
11
|
def child_record_types
|
12
|
-
[
|
12
|
+
[
|
13
|
+
"Nacha::Record::SecondIatAddenda",
|
14
|
+
"Nacha::Record::ThirdIatAddenda",
|
15
|
+
"Nacha::Record::FourthIatAddenda",
|
16
|
+
"Nacha::Record::FifthIatAddenda",
|
17
|
+
"Nacha::Record::SixthIatAddenda",
|
18
|
+
"Nacha::Record::SeventhIatAddenda"
|
19
|
+
]
|
13
20
|
end
|
14
21
|
|
15
22
|
def self.next_record_types
|
@@ -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
|