metro_2 1.2.3 → 1.2.5
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 +4 -0
- data/CHANGELOG.md +7 -0
- data/Repositoryowner.md +4 -0
- data/lib/metro_2/records/base_segment.rb +9 -0
- data/lib/metro_2/records/j2_segment.rb +29 -0
- data/lib/metro_2/version.rb +3 -1
- data/lib/metro_2.rb +31 -21
- data/metro_2.gemspec +14 -13
- data/spec/records/base_segment_spec.rb +25 -0
- data/spec/records/header_segment_spec.rb +1 -1
- data/spec/records/j2_segment_spec.rb +53 -0
- metadata +11 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d01632b27a1c846c37db947bfb4502ef109d0aa987daf598ffcbd8a810f6fd2b
|
4
|
+
data.tar.gz: 4212d0fced1d05b500db2aac38d16a0e0fd935f25933824f9b7a99a8e6c2f9e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2680086eed4bd35915d66076af44bb77eb7c8db254b24df7d406e7a3268e76896fbd0c979d41c56845d0f71e55bb241c89d4e5a6f21406c7200d468e2387236
|
7
|
+
data.tar.gz: 11e923f3641cf71cf6e572d6255385b853105627fa04cf94be157948ed29bdec2daf1ab68ce89e6d9717bcc6268c54ebef43135f39fe7144ba03b5c2031fab5e
|
data/.rubocop.yml
ADDED
data/CHANGELOG.md
ADDED
data/Repositoryowner.md
ADDED
@@ -61,11 +61,20 @@ module Metro2::Records
|
|
61
61
|
@k2_segment
|
62
62
|
end
|
63
63
|
|
64
|
+
def j2_segment
|
65
|
+
@j2_segment
|
66
|
+
end
|
67
|
+
|
64
68
|
def k2_segment=(segment)
|
65
69
|
@k2_segment = segment
|
66
70
|
@appendages << @k2_segment
|
67
71
|
end
|
68
72
|
|
73
|
+
def j2_segment=(segment)
|
74
|
+
@j2_segment = segment
|
75
|
+
@appendages << @j2_segment
|
76
|
+
end
|
77
|
+
|
69
78
|
def to_metro2
|
70
79
|
@appendages.compact!
|
71
80
|
set_record_descriptor_word
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Metro2::Records
|
2
|
+
class J2Segment < Record
|
3
|
+
LENGTH = 200
|
4
|
+
|
5
|
+
@fields = []
|
6
|
+
|
7
|
+
alphanumeric_const_field :segment_identifier, 2, "J2"
|
8
|
+
alphanumeric_const_field :reserved, 1, nil # reserved - blank fill
|
9
|
+
alphanumeric_field :surname, 25, Metro2::ALPHANUMERIC_PLUS_DASH
|
10
|
+
alphanumeric_field :first_name, 20, Metro2::ALPHANUMERIC_PLUS_DASH
|
11
|
+
alphanumeric_field :middle_name, 20, Metro2::ALPHANUMERIC_PLUS_DASH
|
12
|
+
alphanumeric_field :generation_code, 1
|
13
|
+
numeric_field :social_security_number, 9
|
14
|
+
date_field :date_of_birth
|
15
|
+
numeric_field :telephone_number, 10
|
16
|
+
alphanumeric_field :ecoa_code, 1
|
17
|
+
alphanumeric_field :consumer_information_indicator, 2
|
18
|
+
alphanumeric_field :country_code, 2
|
19
|
+
alphanumeric_field :address_1, 32, Metro2::ALPHANUMERIC_PLUS_DOT_DASH_SLASH
|
20
|
+
alphanumeric_field :address_2, 32, Metro2::ALPHANUMERIC_PLUS_DOT_DASH_SLASH
|
21
|
+
alphanumeric_field :city, 20, Metro2::ALPHANUMERIC_PLUS_DOT_DASH_SLASH
|
22
|
+
alphanumeric_field :state, 2
|
23
|
+
alphanumeric_field :postal_code, 9
|
24
|
+
alphanumeric_field :address_indicator, 1
|
25
|
+
alphanumeric_field :residence_code, 1
|
26
|
+
alphanumeric_const_field :reserved2, 2, nil # reserved - blank fill
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/lib/metro_2/version.rb
CHANGED
data/lib/metro_2.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'metro_2/version'
|
2
4
|
|
3
5
|
module Metro2
|
4
|
-
|
5
6
|
PORTFOLIO_TYPE = {
|
6
7
|
line_of_credit: 'C',
|
7
8
|
installment: 'I',
|
@@ -11,31 +12,42 @@ module Metro2
|
|
11
12
|
}.freeze
|
12
13
|
|
13
14
|
ACCOUNT_TYPE = {
|
15
|
+
auto: '00',
|
14
16
|
unsecured: '01',
|
15
|
-
education: '12'
|
17
|
+
education: '12',
|
18
|
+
business_individual_personally_liable: '10'
|
16
19
|
# TODO: add other account types
|
17
20
|
}.freeze
|
18
21
|
|
19
22
|
ECOA_CODE = {
|
20
23
|
individual: '1',
|
21
24
|
deceased: 'X',
|
22
|
-
delete: 'Z'
|
25
|
+
delete: 'Z',
|
26
|
+
comaker_or_guarantor: '5',
|
27
|
+
business: 'W'
|
23
28
|
# TODO: add other ECOA codes
|
24
29
|
}.freeze
|
25
30
|
|
26
31
|
SPECIAL_COMMENT_CODE = {
|
32
|
+
election_of_remedy: 'I',
|
33
|
+
paid_through_insurance: 'AB',
|
27
34
|
partial_payment_agreement: 'AC',
|
28
35
|
purchased_by_another_company: 'AH',
|
36
|
+
voluntarily_surrendered: 'AO',
|
29
37
|
paid_in_full_less_than_full_balance: 'AU',
|
30
38
|
affected_by_natural_or_declared_disaster: 'AW',
|
39
|
+
redeemed_or_reinstated_repossession: 'AZ',
|
40
|
+
involuntary_repossession: 'BI',
|
41
|
+
involuntary_repossession_obligation_satisfied: 'BJ',
|
42
|
+
involuntary_repossession_balance_owing: 'BK',
|
31
43
|
loan_modified: 'CO',
|
32
|
-
forbearance: 'CP'
|
44
|
+
forbearance: 'CP'
|
33
45
|
# TODO: add other special comment codes
|
34
46
|
}.freeze
|
35
47
|
|
36
48
|
COMPLIANCE_CONDITION_CODE = {
|
37
49
|
in_dispute: 'XB',
|
38
|
-
previously_in_dispute_now_resolved: 'XH'
|
50
|
+
previously_in_dispute_now_resolved: 'XH'
|
39
51
|
# TODO: add other compliance condition codes
|
40
52
|
}.freeze
|
41
53
|
|
@@ -161,8 +173,8 @@ module Metro2
|
|
161
173
|
withdrawn_ch7: 'M',
|
162
174
|
withdrawn_ch11: 'N',
|
163
175
|
withdrawn_ch12: 'O',
|
164
|
-
withdrawn_ch13: 'P'
|
165
|
-
}
|
176
|
+
withdrawn_ch13: 'P'
|
177
|
+
}.freeze
|
166
178
|
|
167
179
|
# K2 Segment constants
|
168
180
|
PURCHASED_FROM_SOLD_TO_INDICATOR = {
|
@@ -171,10 +183,10 @@ module Metro2
|
|
171
183
|
remove_previous: 9
|
172
184
|
}.freeze
|
173
185
|
|
174
|
-
ALPHANUMERIC = /\A([[:alnum:]]|\s)+\z
|
175
|
-
ALPHANUMERIC_PLUS_DASH = /\A([[:alnum:]]|\s|\-)+\z
|
176
|
-
ALPHANUMERIC_PLUS_DOT_DASH_SLASH =
|
177
|
-
NUMERIC = /\A\d+\.?\d*\z
|
186
|
+
ALPHANUMERIC = /\A([[:alnum:]]|\s)+\z/.freeze
|
187
|
+
ALPHANUMERIC_PLUS_DASH = /\A([[:alnum:]]|\s|\-)+\z/.freeze
|
188
|
+
ALPHANUMERIC_PLUS_DOT_DASH_SLASH = %r{\A([[:alnum:]]|\s|\-|\.|\\|/)+\z}.freeze
|
189
|
+
NUMERIC = /\A\d+\.?\d*\z/.freeze
|
178
190
|
|
179
191
|
FIXED_LENGTH = 426
|
180
192
|
|
@@ -189,14 +201,14 @@ module Metro2
|
|
189
201
|
# Left justified and blank-filled
|
190
202
|
val = val.to_s
|
191
203
|
|
192
|
-
return ' ' * required_length
|
204
|
+
return ' ' * required_length if val.empty?
|
193
205
|
|
194
206
|
unless !!(val =~ permitted_chars)
|
195
|
-
raise ArgumentError
|
207
|
+
raise ArgumentError, "Content (#{val}) contains invalid characters in field '#{name}'"
|
196
208
|
end
|
197
209
|
|
198
210
|
if val.size > required_length
|
199
|
-
val[0..(required_length-1)]
|
211
|
+
val[0..(required_length - 1)]
|
200
212
|
else
|
201
213
|
val + (' ' * (required_length - val.size))
|
202
214
|
end
|
@@ -205,7 +217,7 @@ module Metro2
|
|
205
217
|
def self.numeric_to_metro2(val, required_length,
|
206
218
|
is_monetary: false, name: nil, possible_values: nil)
|
207
219
|
unless possible_values.nil? || possible_values.include?(val)
|
208
|
-
raise ArgumentError
|
220
|
+
raise ArgumentError, "field #{name} has unsupported value: #{val}"
|
209
221
|
end
|
210
222
|
|
211
223
|
# Right justified and zero-filled
|
@@ -213,17 +225,15 @@ module Metro2
|
|
213
225
|
|
214
226
|
return '0' * required_length if val.empty?
|
215
227
|
|
216
|
-
unless !!(val =~ Metro2::NUMERIC)
|
217
|
-
raise ArgumentError.new("field (#{val}) must be numeric")
|
218
|
-
end
|
228
|
+
raise ArgumentError, "field (#{val}) must be numeric" unless !!(val =~ Metro2::NUMERIC)
|
219
229
|
|
220
230
|
decimal_index = val.index('.')
|
221
231
|
val = val[0..(decimal_index - 1)] if decimal_index
|
222
232
|
|
223
233
|
# any value above 1 billion gets set to 999,999,999
|
224
|
-
return '9' * required_length if is_monetary && val.to_f >=
|
234
|
+
return '9' * required_length if is_monetary && val.to_f >= 1_000_000_000
|
225
235
|
if val.size > required_length
|
226
|
-
raise ArgumentError
|
236
|
+
raise ArgumentError, "numeric field (#{val}) is too long (max #{required_length})"
|
227
237
|
end
|
228
238
|
|
229
239
|
('0' * (required_length - val.size)) + val
|
@@ -237,5 +247,5 @@ require 'metro_2/metro2_file'
|
|
237
247
|
require 'metro_2/records/record'
|
238
248
|
|
239
249
|
Dir.new(File.dirname(__FILE__) + '/metro_2/records').each do |file|
|
240
|
-
require('metro_2/records/' + File.basename(file)) if File.extname(file) ==
|
250
|
+
require('metro_2/records/' + File.basename(file)) if File.extname(file) == '.rb'
|
241
251
|
end
|
data/metro_2.gemspec
CHANGED
@@ -1,24 +1,25 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'metro_2/version'
|
5
6
|
|
6
7
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
8
|
+
spec.name = 'metro_2'
|
8
9
|
spec.version = Metro2::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
10
|
+
spec.authors = ['Brian Mascarenhas']
|
11
|
+
spec.email = ['brian@upstart.com']
|
12
|
+
spec.summary = 'Create Metro 2 format files for credit reporting'
|
13
|
+
spec.description = 'Create Metro 2 format files for credit reporting'
|
14
|
+
spec.homepage = ''
|
15
|
+
spec.license = 'MIT'
|
15
16
|
|
16
17
|
spec.files = `git ls-files -z`.split("\x0")
|
17
18
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
20
|
+
spec.require_paths = ['lib']
|
20
21
|
|
21
|
-
spec.add_development_dependency
|
22
|
-
spec.add_development_dependency
|
23
|
-
spec.add_development_dependency
|
22
|
+
spec.add_development_dependency 'bundler', '~> 2.1'
|
23
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
24
|
+
spec.add_development_dependency 'rspec', '~> 2.13'
|
24
25
|
end
|
@@ -36,9 +36,11 @@ describe Metro2::Records::BaseSegment do
|
|
36
36
|
@base.address_indicator = 'N'
|
37
37
|
@base.residence_code = 'O'
|
38
38
|
@base.k2_segment = k2_segment
|
39
|
+
@base.j2_segment = j2_segment
|
39
40
|
end
|
40
41
|
|
41
42
|
let(:k2_segment) { nil }
|
43
|
+
let(:j2_segment) { nil }
|
42
44
|
|
43
45
|
context '#to_metro2' do
|
44
46
|
let(:expected) do
|
@@ -115,6 +117,29 @@ describe Metro2::Records::BaseSegment do
|
|
115
117
|
expect(base_str[0..3].to_i).to eql(expected_length)
|
116
118
|
end
|
117
119
|
end
|
120
|
+
|
121
|
+
context 'with a J2 segment' do
|
122
|
+
let(:j2_segment) do
|
123
|
+
j2 = Metro2::Records::J2Segment.new
|
124
|
+
j2.surname = "Business Name"
|
125
|
+
j2.social_security_number = '333224444'
|
126
|
+
j2.date_of_birth = Date.new(1987, 4, 19)
|
127
|
+
j2.ecoa_code = 'W'
|
128
|
+
j2.country_code = 'US'
|
129
|
+
j2.address_1 = '742 Evergreen Terrace'
|
130
|
+
j2.city = 'Springfield'
|
131
|
+
j2.state = 'IL'
|
132
|
+
j2.postal_code = '54321'
|
133
|
+
j2
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'should output the j2 segment in its string and update set_record_descriptor_word' do
|
137
|
+
base_str = @base.to_metro2
|
138
|
+
expected_length = Metro2::Records::BaseSegment::LENGTH + Metro2::Records::J2Segment::LENGTH
|
139
|
+
expect(base_str.size).to eql(expected_length)
|
140
|
+
expect(base_str[0..3].to_i).to eql(expected_length)
|
141
|
+
end
|
142
|
+
end
|
118
143
|
end
|
119
144
|
|
120
145
|
context 'alphanumerics' do
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Metro2::Records::BaseSegment do
|
4
|
+
before do
|
5
|
+
@j2_segment = Metro2::Records::J2Segment.new
|
6
|
+
@j2_segment.surname = business_name
|
7
|
+
@j2_segment.social_security_number = "333224444"
|
8
|
+
@j2_segment.date_of_birth = Date.new(1987, 4, 19)
|
9
|
+
@j2_segment.ecoa_code = "W"
|
10
|
+
@j2_segment.country_code = 'US'
|
11
|
+
@j2_segment.address_1 = '742 Evergreen Terrace'
|
12
|
+
@j2_segment.city = 'Springfield'
|
13
|
+
@j2_segment.state = 'IL'
|
14
|
+
@j2_segment.postal_code = '54321'
|
15
|
+
end
|
16
|
+
|
17
|
+
context "#to_metro2" do
|
18
|
+
let(:expected) do
|
19
|
+
[
|
20
|
+
"J2",
|
21
|
+
" ",
|
22
|
+
business_name.to_s.ljust(25, ' '),
|
23
|
+
" " * 20,
|
24
|
+
" " * 20,
|
25
|
+
" ",
|
26
|
+
"333224444",
|
27
|
+
"04191987",
|
28
|
+
"0" * 10,
|
29
|
+
"W",
|
30
|
+
" " * 2,
|
31
|
+
"US",
|
32
|
+
"742 Evergreen Terrace".ljust(32, ' '),
|
33
|
+
" " * 32,
|
34
|
+
"Springfield".ljust(20, ' '),
|
35
|
+
"IL",
|
36
|
+
"54321".ljust(9, ' '),
|
37
|
+
" ",
|
38
|
+
" ",
|
39
|
+
" " * 2
|
40
|
+
]
|
41
|
+
end
|
42
|
+
|
43
|
+
context "with valid attributes set" do
|
44
|
+
let(:business_name) { "Business Name" }
|
45
|
+
|
46
|
+
it "should create output string that matches expected" do
|
47
|
+
j2_segment_str = @j2_segment.to_metro2
|
48
|
+
expect(j2_segment_str).to eql(expected.join)
|
49
|
+
expect(j2_segment_str.size).to eql(Metro2::Records::J2Segment::LENGTH)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metro_2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Mascarenhas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-09-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1
|
19
|
+
version: '2.1'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1
|
26
|
+
version: '2.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -61,15 +61,19 @@ extra_rdoc_files: []
|
|
61
61
|
files:
|
62
62
|
- ".gitignore"
|
63
63
|
- ".rspec"
|
64
|
+
- ".rubocop.yml"
|
65
|
+
- CHANGELOG.md
|
64
66
|
- Gemfile
|
65
67
|
- LICENSE.txt
|
66
68
|
- README.md
|
67
69
|
- Rakefile
|
70
|
+
- Repositoryowner.md
|
68
71
|
- lib/metro_2.rb
|
69
72
|
- lib/metro_2/fields.rb
|
70
73
|
- lib/metro_2/metro2_file.rb
|
71
74
|
- lib/metro_2/records/base_segment.rb
|
72
75
|
- lib/metro_2/records/header_segment.rb
|
76
|
+
- lib/metro_2/records/j2_segment.rb
|
73
77
|
- lib/metro_2/records/k2_segment.rb
|
74
78
|
- lib/metro_2/records/record.rb
|
75
79
|
- lib/metro_2/records/trailer_segment.rb
|
@@ -77,6 +81,7 @@ files:
|
|
77
81
|
- metro_2.gemspec
|
78
82
|
- spec/records/base_segment_spec.rb
|
79
83
|
- spec/records/header_segment_spec.rb
|
84
|
+
- spec/records/j2_segment_spec.rb
|
80
85
|
- spec/records/k2_segment_spec.rb
|
81
86
|
- spec/records/trailer_segment_spec.rb
|
82
87
|
- spec/spec_helper.rb
|
@@ -99,14 +104,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
104
|
- !ruby/object:Gem::Version
|
100
105
|
version: '0'
|
101
106
|
requirements: []
|
102
|
-
|
103
|
-
rubygems_version: 2.7.6
|
107
|
+
rubygems_version: 3.1.4
|
104
108
|
signing_key:
|
105
109
|
specification_version: 4
|
106
110
|
summary: Create Metro 2 format files for credit reporting
|
107
111
|
test_files:
|
108
112
|
- spec/records/base_segment_spec.rb
|
109
113
|
- spec/records/header_segment_spec.rb
|
114
|
+
- spec/records/j2_segment_spec.rb
|
110
115
|
- spec/records/k2_segment_spec.rb
|
111
116
|
- spec/records/trailer_segment_spec.rb
|
112
117
|
- spec/spec_helper.rb
|