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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +49 -0
- data/Rakefile +17 -0
- data/lib/metro_2.rb +241 -0
- data/lib/metro_2/fields.rb +123 -0
- data/lib/metro_2/metro2_file.rb +112 -0
- data/lib/metro_2/records/base_segment.rb +97 -0
- data/lib/metro_2/records/header_segment.rb +23 -0
- data/lib/metro_2/records/j1_segment.rb +19 -0
- data/lib/metro_2/records/j2_segment.rb +27 -0
- data/lib/metro_2/records/k2_segment.rb +21 -0
- data/lib/metro_2/records/record.rb +24 -0
- data/lib/metro_2/records/trailer_segment.rb +53 -0
- data/lib/metro_2/version.rb +8 -0
- data/metro_2.gemspec +24 -0
- data/spec/records/base_segment_spec.rb +262 -0
- data/spec/records/header_segment_spec.rb +43 -0
- data/spec/records/j1_segment_spec.rb +36 -0
- data/spec/records/j2_segment_spec.rb +51 -0
- data/spec/records/k2_segment_spec.rb +57 -0
- data/spec/records/trailer_segment_spec.rb +72 -0
- data/spec/spec_helper.rb +8 -0
- metadata +117 -0
@@ -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
|
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
|