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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd854adc4eb6506c3723faddb4af8c465661ca124b45c71ee0d145c671acf4da
4
- data.tar.gz: a834b02f5e35a4525723a887acc63becdc730ac9440eedf5286480bffae2248d
3
+ metadata.gz: d01632b27a1c846c37db947bfb4502ef109d0aa987daf598ffcbd8a810f6fd2b
4
+ data.tar.gz: 4212d0fced1d05b500db2aac38d16a0e0fd935f25933824f9b7a99a8e6c2f9e0
5
5
  SHA512:
6
- metadata.gz: b2a79f917988c78c2c50845d88ebe8f2d566e51d46e2efae46cad9946e2abf298c1249730b7eac3f895a33bfabd4d7e7605cf6526c0f74633914d687dafc6e3f
7
- data.tar.gz: d7bf507c8a3f7b8f845e0bb819b955028eaa62df04024790b3947fa919cf3ee8ea43d2e8c1c9ae138139e61e1fb3ead21f1190ee9f6fc60e6630f8156ffe0622
6
+ metadata.gz: f2680086eed4bd35915d66076af44bb77eb7c8db254b24df7d406e7a3268e76896fbd0c979d41c56845d0f71e55bb241c89d4e5a6f21406c7200d468e2387236
7
+ data.tar.gz: 11e923f3641cf71cf6e572d6255385b853105627fa04cf94be157948ed29bdec2daf1ab68ce89e6d9717bcc6268c54ebef43135f39fe7144ba03b5c2031fab5e
data/.rubocop.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ Layout/LineLength:
3
+ Max: 120
4
+ Description: Limit lines to 120 characters
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ Metro_2 gem versions
4
+
5
+ # 1.2.5
6
+ 1. Adds account types and ECOA codes for business loans
7
+ 2. Adds J2 segment appendage
@@ -0,0 +1,4 @@
1
+ # Repository Ownership
2
+ Repository Owner - @teamupstart/borrower-squad
3
+
4
+ Slack Channel ID - C08UGTUG1
@@ -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
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Metro2
2
- VERSION = "1.2.3"
4
+ VERSION = '1.2.5'
3
5
 
4
6
  def self.version_string
5
7
  str = VERSION.split('.')
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 = /\A([[:alnum:]]|\s|\-|\.|\\|\/)+\z/
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 if val.empty?
204
+ return ' ' * required_length if val.empty?
193
205
 
194
206
  unless !!(val =~ permitted_chars)
195
- raise ArgumentError.new("Content (#{val}) contains invalid characters in field '#{name}'")
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.new("field #{name} has unsupported value: #{val}")
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 >= 1000000000
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.new("numeric field (#{val}) is too long (max #{required_length})")
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) == ".rb"
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
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
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 = "metro_2"
8
+ spec.name = 'metro_2'
8
9
  spec.version = Metro2::VERSION
9
- spec.authors = ["Brian Mascarenhas"]
10
- spec.email = ["brian@upstart.com"]
11
- spec.summary = "Create Metro 2 format files for credit reporting"
12
- spec.description = "Create Metro 2 format files for credit reporting"
13
- spec.homepage = ""
14
- spec.license = "MIT"
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 = ["lib"]
20
+ spec.require_paths = ['lib']
20
21
 
21
- spec.add_development_dependency "bundler", "~> 1.6"
22
- spec.add_development_dependency "rake", "~> 10.0"
23
- spec.add_development_dependency "rspec", "~> 2.13"
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
@@ -32,7 +32,7 @@ describe Metro2::Records::HeaderSegment do
32
32
  '123 Report Dr Address CA 91111'.ljust(96, ' '),
33
33
  '5555555555',
34
34
  'Upstart Engineer metro 2 gem'.ljust(40, ' '),
35
- '01203',
35
+ '01204',
36
36
  ' ' * 156
37
37
  ]
38
38
  header_str = @header.to_metro2
@@ -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.3
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: 2018-10-19 00:00:00.000000000 Z
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.6'
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.6'
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
- rubyforge_project:
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