nacha 0.1.8 → 0.1.10
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 +1 -1
- data/CHANGELOG.md +24 -0
- data/README.md +1 -1
- data/exe/nacha +0 -1
- data/lib/nacha/field.rb +1 -1
- data/lib/nacha/parser.rb +31 -9
- data/lib/nacha/record/adv_batch_control.rb +2 -0
- data/lib/nacha/record/adv_file_control.rb +1 -4
- data/lib/nacha/record/adv_file_header.rb +1 -1
- data/lib/nacha/record/base.rb +7 -2
- data/lib/nacha/record/file_header.rb +3 -1
- data/lib/nacha/version.rb +1 -1
- data/lib/nacha.rb +66 -9
- data/nacha.gemspec +10 -4
- metadata +18 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d8625f3af750aa7ba6e526909ad823f6020b761ab740616e82650f856585a13
|
4
|
+
data.tar.gz: 459d7359527c582eddf7d46770b2527896d465db86be48a1f6a994bc8d15471d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb31a6b021d3a7b7752f079651bfc5d2f78d5623883ab91201e76853273c3002c1d4a0423d971d5c75a2c38b03faee3e31d64d7cf82cb28f632c4c4174a6526b
|
7
|
+
data.tar.gz: 2aaf5af05547d0e0f10afb1f2a310e70b69e11c359979df5d238389c7800ab3f76ff163a5f35275162809f44b923603c2ed69658c96fe11e7f86eb8cbdf204cf
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [0.1.10] - 2025-07-01
|
11
|
+
|
12
|
+
- Added ability to get a list of possible record types and
|
13
|
+
the ability parse just 1 record
|
14
|
+
|
15
|
+
- Fixed a bug where AdvFileControl did not have the FileControlRecordType
|
16
|
+
included
|
17
|
+
|
18
|
+
## [0.1.9] - 2025-06-25
|
19
|
+
|
20
|
+
- Fixed AdvFileHeaer definition to include constant `ADV FILE` mentioned in the
|
21
|
+
NACHA documentation
|
22
|
+
|
23
|
+
- Added automatic debugger gem selection based on ruby version (ruby or jruby)
|
24
|
+
|
25
|
+
- Fixed Nacha.ach_record_types to have the correct list of record types by moving
|
26
|
+
the Nacha.add_ach_record_type(...) call above a possible return
|
27
|
+
|
28
|
+
- Added contentEditable to the generate HTML
|
29
|
+
|
30
|
+
- Added AdvFileHeader as one of the first records that should be found
|
31
|
+
|
32
|
+
- Removed a bunch of versions from nacha.gemspec
|
33
|
+
|
10
34
|
## [0.1.8] - 2025-06-24
|
11
35
|
|
12
36
|
- Now parses filler records correctly (fixed definition)
|
data/README.md
CHANGED
data/exe/nacha
CHANGED
data/lib/nacha/field.rb
CHANGED
@@ -187,7 +187,7 @@ class Nacha::Field
|
|
187
187
|
field_classes += ['error'] if errors.any?
|
188
188
|
|
189
189
|
ach_string = to_ach.gsub(' ', ' ')
|
190
|
-
"<span data-field-name=\"#{@name}\" class=\"#{field_classes.join(' ')}\" data-name=\"#{@name}\">#{ach_string}" +
|
190
|
+
"<span data-field-name=\"#{@name}\" contentEditable=true class=\"#{field_classes.join(' ')}\" data-name=\"#{@name}\">#{ach_string}" +
|
191
191
|
tooltip_text.to_s +
|
192
192
|
"</span>"
|
193
193
|
end
|
data/lib/nacha/parser.rb
CHANGED
@@ -3,25 +3,38 @@
|
|
3
3
|
require 'nacha'
|
4
4
|
require 'nacha/parser_context'
|
5
5
|
|
6
|
+
# Nacha Parser - deal with figuring out what record type a line is
|
6
7
|
class Nacha::Parser
|
7
|
-
DEFAULT_RECORD_TYPES = ['Nacha::Record::
|
8
|
-
|
8
|
+
DEFAULT_RECORD_TYPES = ['Nacha::Record::AdvFileHeader',
|
9
|
+
'Nacha::Record::FileHeader',
|
10
|
+
'Nacha::Record::Filler'].freeze
|
9
11
|
|
10
12
|
attr_reader :context
|
11
13
|
|
12
14
|
def initialize
|
13
15
|
@context = Nacha::ParserContext.new
|
14
|
-
reset!
|
15
16
|
end
|
16
17
|
|
17
|
-
def reset!; end
|
18
|
-
|
19
18
|
def parse_file(file)
|
20
19
|
@context.parser_started_at = Time.now
|
21
20
|
@context.file_name = file
|
22
21
|
parse_string(file.read)
|
23
22
|
end
|
24
23
|
|
24
|
+
def detect_possible_record_types(line)
|
25
|
+
Nacha.ach_record_types.map do |record_type|
|
26
|
+
record_type if record_type.matcher =~ line
|
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
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
25
38
|
def parse_string(str)
|
26
39
|
line_num = -1
|
27
40
|
records = []
|
@@ -39,11 +52,10 @@ class Nacha::Parser
|
|
39
52
|
def process(line, line_num, previous = nil)
|
40
53
|
@context.line_errors = []
|
41
54
|
parent = previous
|
42
|
-
record = nil
|
43
55
|
|
44
56
|
record_types = valid_record_types(parent)
|
45
57
|
while record_types
|
46
|
-
record =
|
58
|
+
record = parse_first_by_types(line, record_types)
|
47
59
|
break if record || !parent
|
48
60
|
record.validate if record
|
49
61
|
parent = parent.parent
|
@@ -67,11 +79,21 @@ class Nacha::Parser
|
|
67
79
|
child.parent = parent
|
68
80
|
end
|
69
81
|
|
70
|
-
def
|
82
|
+
def parse_first_by_types(line, record_types)
|
71
83
|
record_types.detect do |rt|
|
72
|
-
record_type = Object.const_get(rt)
|
84
|
+
record_type = rt.is_a?(Class) ? rt : Object.const_get(rt)
|
85
|
+
record = nil
|
73
86
|
record = record_type.parse(line) if record_type.matcher =~ line
|
74
87
|
return record if record
|
75
88
|
end
|
76
89
|
end
|
90
|
+
|
91
|
+
def parse_all_by_types(line, record_types)
|
92
|
+
record_types.map do |rt|
|
93
|
+
record_type = rt.is_a?(Class) ? rt : Object.const_get(rt)
|
94
|
+
record = nil
|
95
|
+
record = record_type.parse(line) if record_type.matcher =~ line
|
96
|
+
record
|
97
|
+
end.compact
|
98
|
+
end
|
77
99
|
end
|
@@ -6,6 +6,8 @@ require 'nacha/record/batch_control_record_type.rb'
|
|
6
6
|
|
7
7
|
module Nacha
|
8
8
|
module Record
|
9
|
+
|
10
|
+
# The AdvBatchControl record is used to control the batch of adv entry detail records.
|
9
11
|
class AdvBatchControl < Nacha::Record::Base
|
10
12
|
nacha_field :record_type_code, inclusion: 'M', contents: 'C8', position: 1..1
|
11
13
|
nacha_field :service_class_code, inclusion: 'M', contents: 'Numeric', position: 2..4
|
@@ -7,6 +7,7 @@ require 'nacha/record/file_control_record_type.rb'
|
|
7
7
|
module Nacha
|
8
8
|
module Record
|
9
9
|
class AdvFileControl < Nacha::Record::Base
|
10
|
+
include FileControlRecordType
|
10
11
|
nacha_field :record_type_code, inclusion: 'M', contents: 'C9', position: 1..1
|
11
12
|
nacha_field :batch_count, inclusion: 'M', contents: 'Numeric', position: 2..7
|
12
13
|
nacha_field :block_count, inclusion: 'M', contents: 'Numeric', position: 8..13
|
@@ -15,10 +16,6 @@ module Nacha
|
|
15
16
|
nacha_field :total_debit_entry_dollar_amount_in_file, inclusion: 'M', contents: '$$$$$$$$$$¢¢', position: 32..51
|
16
17
|
nacha_field :total_credit_entry_dollar_amount_in_file, inclusion: 'M', contents: '$$$$$$$$$$¢¢', position: 52..71
|
17
18
|
nacha_field :reserved, inclusion: 'M', contents: 'C', position: 72..94
|
18
|
-
|
19
|
-
# def initialize
|
20
|
-
# create_fields_from_definition
|
21
|
-
# end
|
22
19
|
end
|
23
20
|
end
|
24
21
|
end
|
@@ -20,7 +20,7 @@ module Nacha
|
|
20
20
|
nacha_field :format_code, inclusion: 'M', contents: 'C1', position: 40..40
|
21
21
|
nacha_field :immediate_destination_name, inclusion: 'M', contents: 'Alphameric', position: 41..63
|
22
22
|
nacha_field :immediate_origin_name, inclusion: 'M', contents: 'Alphameric', position: 64..86
|
23
|
-
nacha_field :reference_code, inclusion: 'M', contents: '
|
23
|
+
nacha_field :reference_code, inclusion: 'M', contents: 'CADV FILE', position: 87..94
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
data/lib/nacha/record/base.rb
CHANGED
@@ -30,6 +30,7 @@ module Nacha
|
|
30
30
|
|
31
31
|
class << self
|
32
32
|
def nacha_field(name, inclusion:, contents:, position:)
|
33
|
+
Nacha.add_ach_record_type(self)
|
33
34
|
definition[name] = { inclusion: inclusion,
|
34
35
|
contents: contents,
|
35
36
|
position: position,
|
@@ -39,7 +40,6 @@ module Nacha
|
|
39
40
|
|
40
41
|
validations[name] ||= []
|
41
42
|
validations[name] << validation_method
|
42
|
-
Nacha.add_ach_record_type(self)
|
43
43
|
end
|
44
44
|
|
45
45
|
def definition
|
@@ -120,6 +120,10 @@ module Nacha
|
|
120
120
|
rec.validate
|
121
121
|
rec
|
122
122
|
end
|
123
|
+
|
124
|
+
def record_type
|
125
|
+
Nacha.record_name(self)
|
126
|
+
end
|
123
127
|
end # end class methods
|
124
128
|
|
125
129
|
def original_input_line=(line)
|
@@ -134,7 +138,7 @@ module Nacha
|
|
134
138
|
end
|
135
139
|
|
136
140
|
def record_type
|
137
|
-
|
141
|
+
self.class.record_type
|
138
142
|
end
|
139
143
|
|
140
144
|
def human_name
|
@@ -144,6 +148,7 @@ module Nacha
|
|
144
148
|
def to_h
|
145
149
|
{ nacha_record_type: record_type,
|
146
150
|
metadata: {
|
151
|
+
klass: self.class.name,
|
147
152
|
errors: errors,
|
148
153
|
line_number: @line_number,
|
149
154
|
original_input_line: original_input_line
|
@@ -5,9 +5,11 @@ require 'nacha/record/file_header_record_type.rb'
|
|
5
5
|
|
6
6
|
module Nacha
|
7
7
|
module Record
|
8
|
+
|
9
|
+
# The FileHeader record is the first record in a
|
10
|
+
# Nacha file and contains information about the file itself.
|
8
11
|
class FileHeader < Nacha::Record::Base
|
9
12
|
include FileHeaderRecordType
|
10
|
-
|
11
13
|
nacha_field :record_type_code, inclusion: 'M', contents: 'C1', position: 1..1
|
12
14
|
nacha_field :priority_code, inclusion: 'R', contents: 'Numeric', position: 2..3
|
13
15
|
nacha_field :immediate_destination, inclusion: 'M', contents: 'bTTTTAAAAC', position: 4..13
|
data/lib/nacha/version.rb
CHANGED
data/lib/nacha.rb
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# Uncomment to use debugger
|
4
|
+
# if RUBY_ENGINE == 'ruby'
|
5
|
+
# require "byebug"
|
6
|
+
# end
|
7
|
+
#
|
8
|
+
# if RUBY_ENGINE == 'jruby'
|
9
|
+
# require "pry-nav"
|
10
|
+
# end
|
11
|
+
|
3
12
|
require 'yaml'
|
4
13
|
require 'nacha/version'
|
5
14
|
require 'nacha/aba_number'
|
@@ -7,6 +16,10 @@ require 'nacha/ach_date'
|
|
7
16
|
require 'nacha/field'
|
8
17
|
require 'nacha/numeric'
|
9
18
|
|
19
|
+
# Nacha is a Ruby gem for parsing, validating, and generating NACHA
|
20
|
+
# (National Automated Clearing House Association) files.
|
21
|
+
# It provides a structured way to work with ACH (Automated Clearing House) records,
|
22
|
+
# including various entry detail, addenda, batch, and file control records.
|
10
23
|
module Nacha
|
11
24
|
STANDARD_ENTRY_CLASS_CODES = %w[ACK ADV ARC ATX BOC CCD PPD CIE
|
12
25
|
COR CTX DNE ENR IAT POP POS SHR
|
@@ -20,17 +33,37 @@ module Nacha
|
|
20
33
|
48 49 55 56 82 84 86 88].freeze
|
21
34
|
|
22
35
|
TRANSACTION_CODES = (CREDIT_TRANSACTION_CODES + DEBIT_TRANSACTION_CODES).freeze
|
23
|
-
@@ach_record_types = []
|
24
36
|
|
25
|
-
|
26
|
-
|
27
|
-
|
37
|
+
class << self
|
38
|
+
# Adds a new ACH record type class to the list of defined record types.
|
39
|
+
# This is used internally by the parser to determine which record classes
|
40
|
+
# are available for parsing a NACHA file. As the `nacha_field` method is
|
41
|
+
# executed for each of the record types, these record types are added to
|
42
|
+
# the Nacha module's class variable `@@ach_record_types`.
|
43
|
+
#
|
44
|
+
# @param klass [Class, String] The record class or its name (as a String) to add.
|
45
|
+
# @return [void]
|
46
|
+
def add_ach_record_type(klass)
|
47
|
+
return unless klass
|
28
48
|
|
29
|
-
|
30
|
-
|
31
|
-
|
49
|
+
klass = klass.to_s
|
50
|
+
@ach_record_types ||= []
|
51
|
+
@ach_record_types << klass unless @ach_record_types.include?(klass)
|
52
|
+
end
|
32
53
|
|
33
|
-
|
54
|
+
# Returns an array of all currently registered ACH record type class names.
|
55
|
+
#
|
56
|
+
# @return [Array<String>] An array of strings representing the names of ACH record classes.
|
57
|
+
def ach_record_types
|
58
|
+
@ach_record_types || []
|
59
|
+
end
|
60
|
+
|
61
|
+
# Parses a NACHA file or string into a structured object representation.
|
62
|
+
#
|
63
|
+
# @param object [String, File, IO] The input to parse, either a string containing
|
64
|
+
# NACHA data or an IO object (e.g., a File) representing the NACHA file.
|
65
|
+
# @return [Nacha::Record::Base] The parsed NACHA file object, typically a FileHeader record
|
66
|
+
# with nested batch and entry detail records.
|
34
67
|
def parse(object)
|
35
68
|
parser = Nacha::Parser.new
|
36
69
|
if object.is_a?(String)
|
@@ -40,10 +73,21 @@ module Nacha
|
|
40
73
|
end
|
41
74
|
end
|
42
75
|
|
76
|
+
# Converts a given string into a underscored, lowercase record name.
|
77
|
+
# This is typically used to derive a human-readable or programmatic
|
78
|
+
# name from a class name or similar string.
|
79
|
+
#
|
80
|
+
# @param str [String] The string to convert.
|
81
|
+
# @return [String] The underscored and lowercased record name.
|
43
82
|
def record_name(str)
|
44
83
|
underscore(str.to_s).split('/').last
|
45
84
|
end
|
46
85
|
|
86
|
+
# Converts a camel-cased string to its underscore equivalent.
|
87
|
+
# This method handles module namespaces (::) by converting them to slashes.
|
88
|
+
#
|
89
|
+
# @param str [String] The string to underscore.
|
90
|
+
# @return [String] The underscored string.
|
47
91
|
def underscore(str)
|
48
92
|
str.gsub(/::/, '/').
|
49
93
|
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
@@ -54,6 +98,18 @@ module Nacha
|
|
54
98
|
end
|
55
99
|
end
|
56
100
|
|
101
|
+
# Load all record types from nacha/record/*.rb and nacha/record/**/*.rb
|
102
|
+
# This will ensure that all record classes are loaded before the parser is used
|
103
|
+
|
104
|
+
require 'nacha/record/base'
|
105
|
+
require 'nacha/record/file_header_record_type'
|
106
|
+
require 'nacha/record/file_control_record_type'
|
107
|
+
require 'nacha/record/detail_record_type'
|
108
|
+
|
109
|
+
# Ensure that the record types are loaded before the parser is used
|
110
|
+
# This is necessary because the parser relies on the record types being defined
|
111
|
+
# and available in the Nacha module.
|
112
|
+
|
57
113
|
Gem.find_files('nacha/record/*.rb').reject{|f| f =~ /\/spec\//}.each do |file|
|
58
114
|
require File.expand_path(file)
|
59
115
|
end
|
@@ -62,5 +118,6 @@ Gem.find_files('nacha/record/**/*.rb').reject{|f| f =~ /\/spec\//}.each do |file
|
|
62
118
|
require File.expand_path(file)
|
63
119
|
end
|
64
120
|
|
65
|
-
|
121
|
+
# Load the parser after the records have been defined
|
66
122
|
|
123
|
+
require 'nacha/parser'
|
data/nacha.gemspec
CHANGED
@@ -23,15 +23,21 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.require_paths = ["lib"]
|
24
24
|
spec.add_dependency 'bigdecimal'
|
25
25
|
|
26
|
-
spec.add_development_dependency "bundler"
|
27
|
-
|
26
|
+
spec.add_development_dependency "bundler"
|
27
|
+
# Conditionally add byebug only for MRI Ruby
|
28
|
+
if RUBY_ENGINE == 'ruby'
|
29
|
+
spec.add_development_dependency "byebug"
|
30
|
+
end
|
31
|
+
if RUBY_ENGINE == 'jruby'
|
32
|
+
spec.add_development_dependency "pry-nav"
|
33
|
+
end
|
28
34
|
spec.add_development_dependency "pry"
|
29
35
|
spec.add_development_dependency "factory_bot"
|
30
36
|
spec.add_development_dependency "gitlab-styles"
|
31
37
|
spec.add_development_dependency "guard"
|
32
38
|
spec.add_development_dependency "guard-rspec"
|
33
|
-
spec.add_development_dependency "rake"
|
34
|
-
spec.add_development_dependency "rspec"
|
39
|
+
spec.add_development_dependency "rake"
|
40
|
+
spec.add_development_dependency "rspec"
|
35
41
|
spec.add_development_dependency "rubocop"
|
36
42
|
spec.add_development_dependency 'rubocop-performance'
|
37
43
|
spec.add_development_dependency 'rubocop-rspec'
|
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nacha
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David H. Wilkins
|
8
|
+
autorequire:
|
8
9
|
bindir: exe
|
9
10
|
cert_chain: []
|
10
|
-
date:
|
11
|
+
date: 2025-07-02 00:00:00.000000000 Z
|
11
12
|
dependencies:
|
12
13
|
- !ruby/object:Gem::Dependency
|
13
14
|
name: bigdecimal
|
@@ -27,16 +28,16 @@ dependencies:
|
|
27
28
|
name: bundler
|
28
29
|
requirement: !ruby/object:Gem::Requirement
|
29
30
|
requirements:
|
30
|
-
- - "
|
31
|
+
- - ">="
|
31
32
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
33
|
+
version: '0'
|
33
34
|
type: :development
|
34
35
|
prerelease: false
|
35
36
|
version_requirements: !ruby/object:Gem::Requirement
|
36
37
|
requirements:
|
37
|
-
- - "
|
38
|
+
- - ">="
|
38
39
|
- !ruby/object:Gem::Version
|
39
|
-
version: '
|
40
|
+
version: '0'
|
40
41
|
- !ruby/object:Gem::Dependency
|
41
42
|
name: byebug
|
42
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -125,30 +126,30 @@ dependencies:
|
|
125
126
|
name: rake
|
126
127
|
requirement: !ruby/object:Gem::Requirement
|
127
128
|
requirements:
|
128
|
-
- - "
|
129
|
+
- - ">="
|
129
130
|
- !ruby/object:Gem::Version
|
130
|
-
version: '
|
131
|
+
version: '0'
|
131
132
|
type: :development
|
132
133
|
prerelease: false
|
133
134
|
version_requirements: !ruby/object:Gem::Requirement
|
134
135
|
requirements:
|
135
|
-
- - "
|
136
|
+
- - ">="
|
136
137
|
- !ruby/object:Gem::Version
|
137
|
-
version: '
|
138
|
+
version: '0'
|
138
139
|
- !ruby/object:Gem::Dependency
|
139
140
|
name: rspec
|
140
141
|
requirement: !ruby/object:Gem::Requirement
|
141
142
|
requirements:
|
142
|
-
- - "
|
143
|
+
- - ">="
|
143
144
|
- !ruby/object:Gem::Version
|
144
|
-
version: '
|
145
|
+
version: '0'
|
145
146
|
type: :development
|
146
147
|
prerelease: false
|
147
148
|
version_requirements: !ruby/object:Gem::Requirement
|
148
149
|
requirements:
|
149
|
-
- - "
|
150
|
+
- - ">="
|
150
151
|
- !ruby/object:Gem::Version
|
151
|
-
version: '
|
152
|
+
version: '0'
|
152
153
|
- !ruby/object:Gem::Dependency
|
153
154
|
name: rubocop
|
154
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -306,6 +307,7 @@ homepage: https://github.com/dwilkins/nacha
|
|
306
307
|
licenses:
|
307
308
|
- MIT
|
308
309
|
metadata: {}
|
310
|
+
post_install_message:
|
309
311
|
rdoc_options: []
|
310
312
|
require_paths:
|
311
313
|
- lib
|
@@ -320,7 +322,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
320
322
|
- !ruby/object:Gem::Version
|
321
323
|
version: '0'
|
322
324
|
requirements: []
|
323
|
-
rubygems_version: 3.
|
325
|
+
rubygems_version: 3.4.19
|
326
|
+
signing_key:
|
324
327
|
specification_version: 4
|
325
328
|
summary: Ruby parser for ACH files.
|
326
329
|
test_files: []
|