metro2_format 1.0.0

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.
@@ -0,0 +1,112 @@
1
+ require 'date'
2
+
3
+ module Metro2
4
+ class Metro2File
5
+ include Fields
6
+
7
+ attr_reader :base_segments
8
+ attr_reader :header
9
+ attr_reader :trailer
10
+
11
+ def initialize
12
+ @base_segments = []
13
+ @header = Records::HeaderSegment.new
14
+ end
15
+
16
+ def to_s
17
+ segments = []
18
+ segments << @header
19
+ @base_segments.each { |base| segments << base }
20
+ @trailer ||= trailer_from_base_segments
21
+ segments << @trailer
22
+
23
+ segments.collect { |r| r.to_metro2 }.join("\n") + "\n"
24
+ end
25
+
26
+ def trailer_from_base_segments
27
+ status_code_count = Hash.new(0)
28
+ num_ssn = 0
29
+ num_dob = 0
30
+ num_telephone = 0
31
+ num_ecoa_code_z = 0
32
+ total_k2_segments = 0
33
+ j1_segment_ssn = 0
34
+ j2_segment_ssn = 0
35
+ j1_segment_dob = 0
36
+ j2_segment_dob = 0
37
+ total_j1_segments = 0
38
+ total_j2_segments = 0
39
+
40
+ @base_segments.each do |base|
41
+ status_code_count[base.account_status.upcase] += 1
42
+ num_ssn += 1 if base.social_security_number
43
+ num_dob += 1 if base.date_of_birth
44
+ num_telephone += 1 if base.telephone_number
45
+ num_ecoa_code_z += 1 if base.ecoa_code == 'Z'
46
+
47
+ if base.j1_segment
48
+ for j1_segment in base.j1_segment do
49
+ num_telephone += 1 if j1_segment.telephone_number
50
+ num_ecoa_code_z += 1 if j1_segment.ecoa_code == 'Z'
51
+ j1_segment_ssn += 1 if j1_segment.social_security_number
52
+ j1_segment_dob += 1 if j1_segment.date_of_birth
53
+ total_j1_segments += 1
54
+ end
55
+ end
56
+
57
+ if base.j2_segment
58
+ for j2_segment in base.j2_segment do
59
+ num_telephone += 1 if j2_segment.telephone_number
60
+ num_ecoa_code_z += 1 if j2_segment.ecoa_code == 'Z'
61
+ j2_segment_ssn += 1 if j2_segment.social_security_number
62
+ j2_segment_dob += 1 if j2_segment.date_of_birth
63
+ total_j2_segments += 1
64
+ end
65
+ end
66
+
67
+ total_k2_segments += 1 if base.k2_segment
68
+ end
69
+
70
+ trailer = Records::TrailerSegment.new
71
+ trailer.total_base_records = @base_segments.size
72
+ trailer.total_j1_segments = total_j1_segments
73
+ trailer.total_j2_segments = total_j2_segments
74
+ trailer.total_status_code_df = status_code_count['DF']
75
+ trailer.total_status_code_da = status_code_count['DA']
76
+ trailer.total_status_code_05 = status_code_count['05']
77
+ trailer.total_status_code_11 = status_code_count['11']
78
+ trailer.total_status_code_13 = status_code_count['13']
79
+ trailer.total_status_code_61 = status_code_count['61']
80
+ trailer.total_status_code_62 = status_code_count['62']
81
+ trailer.total_status_code_63 = status_code_count['63']
82
+ trailer.total_status_code_64 = status_code_count['64']
83
+ trailer.total_status_code_65 = status_code_count['65']
84
+ trailer.total_status_code_71 = status_code_count['71']
85
+ trailer.total_status_code_78 = status_code_count['78']
86
+ trailer.total_status_code_80 = status_code_count['80']
87
+ trailer.total_status_code_82 = status_code_count['82']
88
+ trailer.total_status_code_83 = status_code_count['83']
89
+ trailer.total_status_code_84 = status_code_count['84']
90
+ trailer.total_status_code_88 = status_code_count['88']
91
+ trailer.total_status_code_89 = status_code_count['89']
92
+ trailer.total_status_code_93 = status_code_count['93']
93
+ trailer.total_status_code_94 = status_code_count['94']
94
+ trailer.total_status_code_94 = status_code_count['95']
95
+ trailer.total_status_code_96 = status_code_count['96']
96
+ trailer.total_status_code_97 = status_code_count['97']
97
+ trailer.ecoa_code_z = num_ecoa_code_z
98
+ trailer.total_social_security_numbers = num_ssn + j1_segment_ssn + j2_segment_ssn
99
+ trailer.total_social_security_numbers_in_base = num_ssn
100
+ trailer.total_social_security_numbers_in_j1 = j1_segment_ssn
101
+ trailer.total_social_security_numbers_in_j2 = j2_segment_ssn
102
+ trailer.total_date_of_births = num_dob + j1_segment_dob + j2_segment_dob
103
+ trailer.total_date_of_births_in_base = num_dob
104
+ trailer.total_date_of_births_in_j1 = j1_segment_dob
105
+ trailer.total_date_of_births_in_j2 = j2_segment_dob
106
+ trailer.total_telephome_numbers = num_telephone
107
+ trailer.total_k2_segments = total_k2_segments
108
+ trailer
109
+ end
110
+
111
+ end
112
+ end
@@ -0,0 +1,97 @@
1
+ module Metro2::Records
2
+ class BaseSegment < Record
3
+ LENGTH = Metro2::FIXED_LENGTH
4
+
5
+ @fields = []
6
+
7
+ numeric_field :record_descriptor_word, 4
8
+ alphanumeric_const_field :processing_indicator, 1, 1 # always 1
9
+ timestamp_field :time_stamp
10
+ numeric_field :correction_indicator, 1
11
+ alphanumeric_field :identification_number, 20
12
+ alphanumeric_field :cycle_number, 2
13
+ alphanumeric_field :consumer_account_number, 30
14
+ alphanumeric_field :portfolio_type, 1
15
+ alphanumeric_field :account_type, 2
16
+ date_field :date_opened
17
+ monetary_field :credit_limit
18
+ monetary_field :highest_credit_or_loan_amount
19
+ alphanumeric_field :terms_duration, 3
20
+ alphanumeric_field :terms_frequency, 1
21
+ monetary_field :scheduled_monthly_payment_amount
22
+ monetary_field :actual_payment_amount
23
+ alphanumeric_field :account_status, 2
24
+ alphanumeric_field :payment_rating, 1
25
+ alphanumeric_field :payment_history_profile, 24
26
+ alphanumeric_field :special_comment, 2
27
+ alphanumeric_field :compliance_condition_code, 2
28
+ monetary_field :current_balance
29
+ monetary_field :amount_past_due
30
+ monetary_field :original_charge_off_amount
31
+ date_field :account_information_date
32
+ date_field :first_delinquency_date
33
+ date_field :closed_date
34
+ date_field :last_payment_date
35
+ alphanumeric_field :interest_type_indicator, 1
36
+ alphanumeric_const_field :reserved, 16, nil # reserved - blank fill
37
+ alphanumeric_field :consumer_transaction_type, 1
38
+ alphanumeric_field :surname, 25, Metro2::ALPHANUMERIC_PLUS_DASH
39
+ alphanumeric_field :first_name, 20, Metro2::ALPHANUMERIC_PLUS_DASH
40
+ alphanumeric_field :middle_name, 20, Metro2::ALPHANUMERIC_PLUS_DASH
41
+ alphanumeric_field :generation_code, 1
42
+ numeric_field :social_security_number, 9
43
+ date_field :date_of_birth
44
+ numeric_field :telephone_number, 10
45
+ alphanumeric_field :ecoa_code, 1
46
+ alphanumeric_field :consumer_information_indicator, 2
47
+ alphanumeric_field :country_code, 2
48
+ alphanumeric_field :address_1, 32, Metro2::ALPHANUMERIC_PLUS_DOT_DASH_SLASH
49
+ alphanumeric_field :address_2, 32, Metro2::ALPHANUMERIC_PLUS_DOT_DASH_SLASH
50
+ alphanumeric_field :city, 20, Metro2::ALPHANUMERIC_PLUS_DOT_DASH_SLASH
51
+ alphanumeric_field :state, 2
52
+ alphanumeric_field :postal_code, 9
53
+ alphanumeric_field :address_indicator, 1
54
+ alphanumeric_field :residence_code, 1
55
+
56
+ def initialize
57
+ @appendages = []
58
+ end
59
+
60
+ def k2_segment
61
+ @k2_segment
62
+ end
63
+
64
+ def k2_segment=(segment)
65
+ @k2_segment = segment
66
+ @appendages << @k2_segment
67
+ end
68
+
69
+ def j1_segment
70
+ @j1_segment
71
+ end
72
+
73
+ def j1_segment=(segment)
74
+ @j1_segment = segment
75
+ @appendages << @j1_segment
76
+ end
77
+
78
+ def j2_segment
79
+ @j2_segment
80
+ end
81
+
82
+ def j2_segment=(segment)
83
+ @j2_segment = segment
84
+ @appendages << @j2_segment
85
+ end
86
+
87
+ def to_metro2
88
+ @appendages.compact!
89
+ set_record_descriptor_word
90
+ super + @appendages.map(&:to_metro2).join
91
+ end
92
+
93
+ def set_record_descriptor_word
94
+ self.record_descriptor_word = LENGTH + @appendages.sum { |appendage| appendage.class::LENGTH }
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,23 @@
1
+ module Metro2::Records
2
+ class HeaderSegment < Record
3
+ @fields = []
4
+
5
+ numeric_const_field :record_descriptor_word, 4, Metro2::FIXED_LENGTH
6
+ alphanumeric_const_field :record_identifier, 6, 'HEADER'
7
+ alphanumeric_field :cycle_number, 2
8
+ alphanumeric_field :innovis_program_identifier, 10
9
+ alphanumeric_field :equifax_program_identifier, 10
10
+ alphanumeric_field :experian_program_identifier, 5
11
+ alphanumeric_field :transunion_program_identifier, 10
12
+ date_field :activity_date
13
+ date_field :created_date
14
+ date_field :program_date
15
+ date_field :program_revision_date
16
+ alphanumeric_field :reporter_name, 40
17
+ alphanumeric_field :reporter_address, 96, Metro2::ALPHANUMERIC_PLUS_DOT_DASH_SLASH
18
+ numeric_field :reporter_telephone_number, 10
19
+ alphanumeric_const_field :software_vendor_name, 40, 'Upstart Engineer metro 2 gem'
20
+ alphanumeric_const_field :software_version_number, 5, Metro2::version_string
21
+ alphanumeric_const_field :reserved, 156, nil
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ module Metro2::Records
2
+ class J1Segment < Record
3
+ LENGTH = 100
4
+ @fields = []
5
+
6
+ alphanumeric_const_field :segment_identifier, 2, 'J1'
7
+ alphanumeric_const_field :reserved, 1, nil
8
+ alphanumeric_field :surname, 25, Metro2::ALPHANUMERIC_PLUS_DASH
9
+ alphanumeric_field :first_name, 20, Metro2::ALPHANUMERIC_PLUS_DASH
10
+ alphanumeric_field :middle_name, 20, Metro2::ALPHANUMERIC_PLUS_DASH
11
+ alphanumeric_field :generation_code, 1
12
+ numeric_field :social_security_number, 9
13
+ date_field :date_of_birth
14
+ numeric_field :telephone_number, 10
15
+ alphanumeric_field :ecoa_code, 1
16
+ alphanumeric_field :consumer_information_indicator, 2
17
+ alphanumeric_const_field :reserved, 1, nil
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ module Metro2::Records
2
+ class J2Segment < Record
3
+ LENGTH = 200
4
+ @fields = []
5
+
6
+ alphanumeric_const_field :segment_identifier, 2, 'J2'
7
+ alphanumeric_const_field :reserved, 1, nil
8
+ alphanumeric_field :surname, 25, Metro2::ALPHANUMERIC_PLUS_DASH
9
+ alphanumeric_field :first_name, 20, Metro2::ALPHANUMERIC_PLUS_DASH
10
+ alphanumeric_field :middle_name, 20, Metro2::ALPHANUMERIC_PLUS_DASH
11
+ alphanumeric_field :generation_code, 1
12
+ numeric_field :social_security_number, 9
13
+ date_field :date_of_birth
14
+ numeric_field :telephone_number, 10
15
+ alphanumeric_field :ecoa_code, 1
16
+ alphanumeric_field :consumer_information_indicator, 2
17
+ alphanumeric_field :country_code, 2
18
+ alphanumeric_field :address_1, 32, Metro2::ALPHANUMERIC_PLUS_DOT_DASH_SLASH
19
+ alphanumeric_field :address_2, 32, Metro2::ALPHANUMERIC_PLUS_DOT_DASH_SLASH
20
+ alphanumeric_field :city, 20, Metro2::ALPHANUMERIC_PLUS_DOT_DASH_SLASH
21
+ alphanumeric_field :state, 2
22
+ alphanumeric_field :postal_code, 9
23
+ alphanumeric_field :address_indicator, 1
24
+ alphanumeric_field :residence_code, 1
25
+ alphanumeric_const_field :reserved_2, 2, nil
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ module Metro2::Records
2
+ class K2Segment < Record
3
+ LENGTH = 34
4
+
5
+ @fields = []
6
+
7
+ alphanumeric_const_field :segment_identifier, 2, "K2"
8
+ numeric_field :purchased_from_sold_to_indicator, 1,
9
+ possible_values: Metro2::PURCHASED_FROM_SOLD_TO_INDICATOR.values
10
+ alphanumeric_field :purchased_from_sold_to_name, 30, Metro2::ALPHANUMERIC_PLUS_DOT_DASH_SLASH
11
+ alphanumeric_const_field :reserved, 1, nil # reserved - blank fill
12
+
13
+ def validate_fields
14
+ if !purchased_from_sold_to_name.nil? &&
15
+ purchased_from_sold_to_indicator == Metro2::PURCHASED_FROM_SOLD_TO_INDICATOR[:remove_previous]
16
+ str = "purchased_from_sold_to_name must be blank if purchased_from_sold_to_indicator is 9"
17
+ raise ArgumentError.new(str)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ module Metro2
2
+ module Records
3
+ class Record
4
+ @fields = []
5
+
6
+ class << self
7
+ def fields
8
+ @fields
9
+ end
10
+ end
11
+
12
+ extend(Fields)
13
+
14
+ def to_metro2
15
+ validate_fields
16
+ self.class.fields.collect { |f| send("#{f}_to_metro2") }.join
17
+ end
18
+
19
+ def validate_fields
20
+ # this should be implemented by each child
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,53 @@
1
+ module Metro2::Records
2
+ class TrailerSegment < Record
3
+ @fields = []
4
+
5
+ numeric_const_field :record_descriptor_word, 4, Metro2::FIXED_LENGTH
6
+ alphanumeric_const_field :record_identifier, 7, 'TRAILER'
7
+ numeric_field :total_base_records, 9
8
+ alphanumeric_const_field :reserved, 9, nil
9
+ numeric_field :total_status_code_df, 9
10
+ numeric_field :total_j1_segments, 9
11
+ numeric_field :total_j2_segments, 9
12
+ numeric_field :block_count, 9
13
+ numeric_field :total_status_code_da, 9
14
+ numeric_field :total_status_code_05, 9
15
+ numeric_field :total_status_code_11, 9
16
+ numeric_field :total_status_code_13, 9
17
+ numeric_field :total_status_code_61, 9
18
+ numeric_field :total_status_code_62, 9
19
+ numeric_field :total_status_code_63, 9
20
+ numeric_field :total_status_code_64, 9
21
+ numeric_field :total_status_code_65, 9
22
+ numeric_field :total_status_code_71, 9
23
+ numeric_field :total_status_code_78, 9
24
+ numeric_field :total_status_code_80, 9
25
+ numeric_field :total_status_code_82, 9
26
+ numeric_field :total_status_code_83, 9
27
+ numeric_field :total_status_code_84, 9
28
+ numeric_field :total_status_code_88, 9
29
+ numeric_field :total_status_code_89, 9
30
+ numeric_field :total_status_code_93, 9
31
+ numeric_field :total_status_code_94, 9
32
+ numeric_field :total_status_code_95, 9
33
+ numeric_field :total_status_code_96, 9
34
+ numeric_field :total_status_code_97, 9
35
+ numeric_field :ecoa_code_z, 9
36
+ numeric_field :total_n1_segments, 9
37
+ numeric_field :total_k1_segments, 9
38
+ numeric_field :total_k2_segments, 9
39
+ numeric_field :total_k3_segments, 9
40
+ numeric_field :total_k4_segments, 9
41
+ numeric_field :total_l1_segments, 9
42
+ numeric_field :total_social_security_numbers, 9
43
+ numeric_field :total_social_security_numbers_in_base, 9
44
+ numeric_field :total_social_security_numbers_in_j1, 9
45
+ numeric_field :total_social_security_numbers_in_j2, 9
46
+ numeric_field :total_date_of_births, 9
47
+ numeric_field :total_date_of_births_in_base, 9
48
+ numeric_field :total_date_of_births_in_j1, 9
49
+ numeric_field :total_date_of_births_in_j2, 9
50
+ numeric_field :total_telephome_numbers, 9
51
+ alphanumeric_const_field :reserved_2, 19, nil
52
+ end
53
+ end
@@ -0,0 +1,8 @@
1
+ module Metro2
2
+ VERSION = "1.0.0"
3
+
4
+ def self.version_string
5
+ str = VERSION.split('.')
6
+ str[0].rjust(2, '0') + str[1].ljust(2, '0') + str[2]
7
+ end
8
+ end
data/metro_2.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'metro_2/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "metro2_format"
8
+ spec.version = Metro2::VERSION
9
+ spec.authors = ["Ranu Lathi"]
10
+ spec.email = ["ranu@peachstreet.com"]
11
+ spec.summary = "Create Metro 2 format files for credit reporting to credit agencies"
12
+ spec.description = "Create Metro 2 format files for credit reporting to credit agencies"
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 2.13"
24
+ end
@@ -0,0 +1,262 @@
1
+ require 'spec_helper'
2
+
3
+ describe Metro2::Records::BaseSegment do
4
+ before do
5
+ @base = Metro2::Records::BaseSegment.new
6
+ @base.time_stamp = Time.new(2014, 9, 15, 17, 7, 45)
7
+ @base.identification_number = 'REPORTERXYZ'
8
+ @base.cycle_number = 1
9
+ @base.consumer_account_number = 'ABC123'
10
+ @base.portfolio_type = 'I'
11
+ @base.account_type = '01'
12
+ @base.date_opened = Date.new(2013, 4, 1)
13
+ @base.highest_credit_or_loan_amount = 25000
14
+ @base.terms_duration = 36
15
+ @base.terms_frequency = 'M'
16
+ @base.scheduled_monthly_payment_amount = 817.8
17
+ @base.actual_payment_amount = 817.8
18
+ @base.account_status = '11'
19
+ @base.payment_history_profile = '00000000000000000BBBBBBB'
20
+ @base.current_balance = 11111
21
+ @base.account_information_date = Date.new(2014, 9, 1)
22
+ @base.last_payment_date = Date.new(2014, 8, 1)
23
+ @base.interest_type_indicator = 'F'
24
+ @base.surname = 'Simpson'
25
+ @base.first_name = 'Homer'
26
+ @base.middle_name = 'Jay'
27
+ @base.social_security_number = '333224444'
28
+ @base.date_of_birth = Date.new(1987, 4, 19)
29
+ @base.telephone_number = '5555555555'
30
+ @base.ecoa_code = 1
31
+ @base.country_code = 'US'
32
+ @base.address_1 = '742 Evergreen Terrace'
33
+ @base.city = 'Springfield'
34
+ @base.state = 'IL'
35
+ @base.postal_code = '54321'
36
+ @base.address_indicator = 'N'
37
+ @base.residence_code = 'O'
38
+ @base.k2_segment = k2_segment
39
+ end
40
+
41
+ let(:k2_segment) { nil }
42
+
43
+ context '#to_metro2' do
44
+ let(:expected) do
45
+ [
46
+ '0426',
47
+ '1',
48
+ '09152014170745',
49
+ '0',
50
+ 'REPORTERXYZ'.ljust(20, ' '),
51
+ '1 ',
52
+ 'ABC123'.ljust(30, ' '),
53
+ 'I',
54
+ '01',
55
+ '04012013',
56
+ '0' * 9,
57
+ '000025000',
58
+ '36 ',
59
+ 'M',
60
+ '000000817',
61
+ '000000817',
62
+ '11',
63
+ ' ',
64
+ '00000000000000000BBBBBBB',
65
+ ' ',
66
+ ' ',
67
+ '000011111',
68
+ '000000000',
69
+ '000000000',
70
+ '09012014',
71
+ '00000000',
72
+ '00000000',
73
+ '08012014',
74
+ 'F',
75
+ ' ' * 16,
76
+ ' ',
77
+ 'Simpson'.ljust(25, ' '),
78
+ 'Homer'.ljust(20, ' '),
79
+ 'Jay'.ljust(20, ' '),
80
+ ' ',
81
+ '333224444',
82
+ '04191987',
83
+ '5555555555',
84
+ '1',
85
+ ' ',
86
+ 'US',
87
+ '742 Evergreen Terrace'.ljust(32, ' '),
88
+ ' ' * 32,
89
+ 'Springfield'.ljust(20, ' '),
90
+ 'IL',
91
+ '54321 ',
92
+ 'N',
93
+ 'O',
94
+ ''
95
+ ]
96
+ end
97
+
98
+ it 'should generate base segment string' do
99
+ @base.record_descriptor_word = 426
100
+ base_str = @base.to_metro2
101
+ expect(base_str).to eql(expected.join(''))
102
+ expect(base_str.size).to eql(Metro2::FIXED_LENGTH)
103
+ end
104
+
105
+ it 'should generate base segment along with the joint segment' do
106
+ joint_segment = Metro2::Records::J1Segment.new
107
+ joint_segment.surname = 'Simpson'
108
+ joint_segment.first_name = 'Homer'
109
+ joint_segment.middle_name = 'Jay'
110
+ joint_segment.social_security_number = '333224444'
111
+ joint_segment.date_of_birth = Date.new(1987, 4, 19)
112
+ joint_segment.telephone_number = '5555555555'
113
+ joint_segment.ecoa_code = 1
114
+
115
+ @base.joint_segment = joint_segment
116
+ exp = [
117
+ '0526',
118
+ '1',
119
+ '09152014170745',
120
+ '0',
121
+ 'REPORTERXYZ'.ljust(20, ' '),
122
+ '1 ',
123
+ 'ABC123'.ljust(30, ' '),
124
+ 'I',
125
+ '01',
126
+ '04012013',
127
+ '0' * 9,
128
+ '000025000',
129
+ '36 ',
130
+ 'M',
131
+ '000000817',
132
+ '000000817',
133
+ '11',
134
+ ' ',
135
+ '00000000000000000BBBBBBB',
136
+ ' ',
137
+ ' ',
138
+ '000011111',
139
+ '000000000',
140
+ '000000000',
141
+ '09012014',
142
+ '00000000',
143
+ '00000000',
144
+ '08012014',
145
+ 'F',
146
+ ' ' * 16,
147
+ ' ',
148
+ 'Simpson'.ljust(25, ' '),
149
+ 'Homer'.ljust(20, ' '),
150
+ 'Jay'.ljust(20, ' '),
151
+ ' ',
152
+ '333224444',
153
+ '04191987',
154
+ '5555555555',
155
+ '1',
156
+ ' ',
157
+ 'US',
158
+ '742 Evergreen Terrace'.ljust(32, ' '),
159
+ ' ' * 32,
160
+ 'Springfield'.ljust(20, ' '),
161
+ 'IL',
162
+ '54321 ',
163
+ 'N',
164
+ 'O',
165
+ '',
166
+ 'J1',
167
+ ' ',
168
+ 'Simpson'.ljust(25, ' '),
169
+ 'Homer'.ljust(20, ' '),
170
+ 'Jay'.ljust(20, ' '),
171
+ ' ',
172
+ '333224444',
173
+ '04191987',
174
+ '5555555555',
175
+ '1',
176
+ ' ',
177
+ ' '
178
+ ]
179
+ @base.record_descriptor_word = 526
180
+ base_str = @base.to_metro2
181
+ expect(base_str).to eql(exp.join(''))
182
+ expect(base_str.size).to eql(526)
183
+ end
184
+
185
+ context 'with a K2 segment' do
186
+ let(:k2_segment) do
187
+ k2 = Metro2::Records::K2Segment.new
188
+ k2.purchased_from_sold_to_indicator = 9
189
+ k2
190
+ end
191
+
192
+ it 'should output the k2 segment in its string and update set_record_descriptor_word' do
193
+ base_str = @base.to_metro2
194
+ expected_length = Metro2::Records::BaseSegment::LENGTH + Metro2::Records::K2Segment::LENGTH
195
+ expect(base_str.size).to eql(expected_length)
196
+ expect(base_str[0..3].to_i).to eql(expected_length)
197
+ end
198
+ end
199
+ end
200
+
201
+ context 'alphanumerics' do
202
+ describe 'alphanumeric with symbols' do
203
+ it 'should raise an error' do
204
+ @base.surname = 'B@d name'
205
+ expect{@base.surname_to_metro2}.to raise_error(ArgumentError)
206
+ end
207
+ end
208
+
209
+ describe 'alphanumeric with dashes' do
210
+ it 'should not raise an error' do
211
+ @base.surname = 'Name A-ok'
212
+ expect{@base.surname_to_metro2}.not_to raise_error
213
+ end
214
+ end
215
+
216
+ describe 'really long alphanumeric' do
217
+ it 'should be truncated' do
218
+ @base.surname = 'Veryveryveryveryverylongname'
219
+ expect(@base.surname_to_metro2).to eql('Veryveryveryveryverylongn')
220
+ end
221
+ end
222
+
223
+ describe 'alphanumeric with dots and slashes' do
224
+ it 'should be truncated' do
225
+ @base.address_1 = 'Test Address /1.'
226
+ expect(@base.address_1_to_metro2).to eql('Test Address /1.'.ljust(32, ' '))
227
+ end
228
+ end
229
+ end
230
+
231
+ context 'numerics' do
232
+ describe 'numeric with alphas' do
233
+ it 'should raise an error' do
234
+ @base.telephone_number = 'abc5555555'
235
+ expect{@base.telephone_number_to_metro2}.to raise_error(ArgumentError)
236
+ end
237
+ end
238
+
239
+ describe 'numeric with symbols' do
240
+ it 'should raise an error' do
241
+ @base.telephone_number = '+555555555'
242
+ expect{@base.telephone_number_to_metro2}.to raise_error(ArgumentError)
243
+ end
244
+ end
245
+
246
+ describe 'numeric that is too long' do
247
+ it 'should raise an error' do
248
+ @base.telephone_number = '12345678901'
249
+ expect{@base.telephone_number_to_metro2}.to raise_error(ArgumentError)
250
+ end
251
+ end
252
+ end
253
+
254
+ context 'monetary field' do
255
+ describe 'more than one billion' do
256
+ it 'should fill with all 9s' do
257
+ @base.credit_limit = '1000000001'
258
+ expect(@base.credit_limit_to_metro2).to eql('999999999')
259
+ end
260
+ end
261
+ end
262
+ end