tufy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 44238a69842a3b828c0ecfa0fdb4c2dfa134bf3c
4
+ data.tar.gz: 03fedb4b647ef3135df86ec6b422216f5830d915
5
+ SHA512:
6
+ metadata.gz: 050d343a3b870b2d779adf1d68be420a2310e5925c351560261ece583249ef156be5c0521be096e2c2e011f461e7d1de8a98a0417caea17f20f538d28a63047e
7
+ data.tar.gz: 802a3b5c17c7cf3762da4ea438c1530d54e7933c3f5caece9ede74e4758a83a803bc4c7fceaf6a087b23490898198b9e359742d40ae653e6168260050e5b98fe
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
13
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.1.5
5
+ before_install: gem install bundler -v 1.14.6
File without changes
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at TODO: Write your email address. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in tufy.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 TODO: Write your name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,158 @@
1
+ # Tufy
2
+
3
+ "Pronounced as T-U-fy"
4
+ Helper gem to convert any raw data into TU-readable format.
5
+
6
+ ### More Information
7
+ See the [TUDF ver. 11 Guide](https://www.dropbox.com/s/ohx8rgdixwwfarw/tudf_guide_version_11.pdf?dl=0) and the [TUDF ver. 11 Walkthrough](https://www.dropbox.com/s/1g1m7797spwpy09/tudf_walkthrough_version_11.pdf?dl=0)
8
+
9
+ ### Installation
10
+
11
+ ```sh
12
+ $ gem install tufy
13
+ ```
14
+
15
+ ### Usage
16
+
17
+ ```ruby
18
+ transform_data_result =
19
+ Tufy.transform(
20
+ {
21
+ # for the header segment
22
+ member_reference_number: member_reference_number,
23
+ processor_name: processor_name,
24
+ user_id: user_id,
25
+ # for the name segment
26
+ first_name: first_name,
27
+ last_name: last_name,
28
+ civil_status: civil_status,
29
+ date_of_birth: date_of_birth,
30
+ gender: gender,
31
+ ac_holder_type: ac_holder_type,
32
+ # for the id segment
33
+ id_number: id_number,
34
+ id_type: id_type,
35
+ # for the address segment
36
+ address_line_1: address_line_1,
37
+ address_line_2: address_line_2,
38
+ address_type: address_type,
39
+ # for contact number segment
40
+ contact_number: contact_number,
41
+ contact_number_format: contact_number_format,
42
+ # for email address segment
43
+ email_address: email_address,
44
+ # for account segment
45
+ account_number: account_number,
46
+ restructured_account_number: restructured_account_number,
47
+ account_status: account_status,
48
+ account_type: account_type,
49
+ currency_code: currency_code,
50
+ opened_date: opened_date,
51
+ payment_amount: payment_amount,
52
+ closed_date: closed_date,
53
+ credit_limit_or_loan_amount: credit_limit_or_loan_amount,
54
+ shared_by: shared_by,
55
+ outstanding_balance: outstanding_balance,
56
+ interest_and_fees: interest_and_fees,
57
+ unbilled_balance: unbilled_balance,
58
+ cash_advance_balance: cash_advance_balance,
59
+ number_of_days_past_due: number_of_days_past_due,
60
+ past_due_amount: past_due_amount,
61
+ installment_amount: installment_amount,
62
+ number_of_installments: number_of_installments,
63
+ payment_frequency: payment_frequency,
64
+ expiry_date: expiry_date,
65
+ consumer_or_commercial: consumer_or_commercial,
66
+ legal_action: legal_action,
67
+ partial_payment: partial_payment,
68
+ fresh_cash_advance: fresh_cash_advance,
69
+ )
70
+ ```
71
+
72
+ Get the transformed data
73
+
74
+ ```ruby
75
+ transformed_data_result[:transformed_data]
76
+ ```
77
+
78
+ ### Supported Data
79
+
80
+ | Segment | Field | Supported? |
81
+ | ------ | ------ | ------ |
82
+ | Header | MEMBER REFERENCE NUMBER | ✓ |
83
+ || PROCESSOR NAME | ✓ |
84
+ || USER ID | ✓ |
85
+ | Name | Multiple Entries | |
86
+ | | FIRST NAME | ✓ |
87
+ | | MIDDLE NAME ||
88
+ | | LAST NAME | ✓ |
89
+ | | MOTHER'S MAIDEN FULL NAME | |
90
+ | | CIVIL STATUS | ✓ |
91
+ | | DATE OF BIRTH | ✓ |
92
+ | | GENDER | ✓ |
93
+ | | NATIONALITY | |
94
+ | | NUMBER OF DEPENDENTS | |
95
+ | | HOME OWNERSHIP | |
96
+ | | CAR OWNERSHIP | |
97
+ | | A/C HOLDER TYPE | ✓ |
98
+ | | DISPUTE | |
99
+ | Id | Multiple Entries | |
100
+ | | ID NUMBER | ✓ |
101
+ | | ID TYPE | ✓ |
102
+ | Alias | Multiple Entries | |
103
+ | | FIRST NAME | |
104
+ | | MIDDLE NAME | |
105
+ | | LAST NAME | |
106
+ | | MOTHER'S MAIDEN FULL NAME | |
107
+ | Address | Multiple Entries | |
108
+ | | ADDRESS LINE 1 | ✓ |
109
+ | | ADDRESS LINE 2 | ✓ |
110
+ | | ZIP CODE | |
111
+ | | TYPE| ✓ |
112
+ | Contact Number | Multiple Entries | |
113
+ | | COUNTRY CODE | |
114
+ | | AREA CODE | |
115
+ | | CONTACT NUMBER | ✓ |
116
+ | | EXT/CALL | |
117
+ | | FORMAT | ✓ |
118
+ | Email Address | Multiple Entries | |
119
+ | | EMAIL ADDRESS | ✓ |
120
+ | Employment | COMPANY NAME ||
121
+ | | NATURE OF BUSINESS | |
122
+ | | EMPLOYMENT TYPE | |
123
+ | | OCCUPATION | |
124
+ | | LENGTH OF EMPLOYMENT IN YEARS | |
125
+ | | LENGTH OF EMPLOYMENT IN MONTHS | |
126
+ | | CURRENCY CODE | |
127
+ | | CONSUMER ANNUAL INCOME | |
128
+ | Education | EDUCATION LEVEL | |
129
+ | Account | ACCOUNT NUMBER | ✓ |
130
+ | | RESTRUCTURED ACCOUNT NUMBER | ✓ |
131
+ | | USER ID | ✓ |
132
+ | | ACCOUNT STATUS | ✓ |
133
+ | | ACCOUT TYPE | ✓ |
134
+ | | CURRENCY CODE | ✓ |
135
+ | | OPENED DATE | ✓ |
136
+ | | PAYMENT AMOUNT | ✓ |
137
+ | | CLOSED DATE | ✓ |
138
+ | | CREDIT LIMIT OR LOAN AMOUNT | ✓ |
139
+ | | SHARED BY | ✓ |
140
+ | | OUTSTANDING BALANCE | ✓ |
141
+ | | INTEREST AND FEES | ✓ |
142
+ | | UNBILLED BALANCE | ✓ |
143
+ | | CASH ADVANCE BALANCE | ✓ |
144
+ | | NUMBER OF DAYS PAST DUE | ✓ |
145
+ | | PAST DUE AMOUNT | ✓ |
146
+ | | INSTALLMENT AMOUNT | ✓ |
147
+ | | NUMBER OF INSTALLMENTS | ✓ |
148
+ | | PAYMENT FREQUENCY | ✓ |
149
+ | | EXPIRY DATE | ✓ |
150
+ | | CONSUMER OR COMMERCIAL | ✓ |
151
+ | | LEGAL ACTION | ✓ |
152
+ | | PARTIAL PAYMENT | ✓ |
153
+ | | FRESH CASH ADVANCE | ✓ |
154
+
155
+ ## License
156
+
157
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
158
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "tufy"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,21 @@
1
+ require "tufy/version"
2
+ require "light-service"
3
+ require "date"
4
+ require "tufy/format_strings"
5
+ require "tufy/errors/required_data_missing_error"
6
+ require "tufy/build_segment"
7
+ require "tufy/build_header_segment"
8
+ require "tufy/build_name_segment"
9
+ require "tufy/build_id_segment"
10
+ require "tufy/build_address_segment"
11
+ require "tufy/build_contact_number_segment"
12
+ require "tufy/build_email_address_segment"
13
+ require "tufy/build_account_segment"
14
+ require "tufy/build_end_of_subject_segment"
15
+ require "tufy/transform"
16
+
17
+ module Tufy
18
+ def self.transform(raw_data)
19
+ Transform.execute(raw_data: raw_data)
20
+ end
21
+ end
@@ -0,0 +1,160 @@
1
+ module Tufy
2
+ class BuildAccountSegment < BuildSegment
3
+ expects :raw_data
4
+ promises :transformed_data
5
+
6
+ REQUIRED_KEYS = [
7
+ :account_number,
8
+ :restructured_account_number,
9
+ :user_id,
10
+ :account_status,
11
+ :account_type,
12
+ :currency_code,
13
+ :opened_date,
14
+ :payment_amount,
15
+ :closed_date,
16
+ :credit_limit_or_loan_amount,
17
+ :shared_by,
18
+ :outstanding_balance,
19
+ :interest_and_fees,
20
+ :unbilled_balance,
21
+ :cash_advance_balance,
22
+ :number_of_days_past_due,
23
+ :past_due_amount,
24
+ :installment_amount,
25
+ :number_of_installments,
26
+ :payment_frequency,
27
+ :expiry_date,
28
+ :consumer_or_commercial,
29
+ :legal_action,
30
+ :partial_payment,
31
+ :fresh_cash_advance,
32
+ ]
33
+
34
+ executed do |ctx|
35
+ validate_presence_of_required_keys(ctx.raw_data, REQUIRED_KEYS)
36
+ ctx.transformed_data = ctx.transformed_data + transform(ctx).upcase
37
+ end
38
+
39
+ private
40
+
41
+ def self.transform(ctx)
42
+ raw_data = ctx[:raw_data]
43
+
44
+ Constants::SEGMENT_TAG +
45
+ Constants::ACCOUNT_NUMBER_TAG +
46
+ FormatStrings::F2TS % raw_data[:account_number].to_s.size + raw_data[:account_number].to_s +
47
+ Constants::RESTRUCTURED_ACCOUNT_NUMBER_TAG +
48
+ FormatStrings::F2TS % raw_data[:restructured_account_number].to_s.size + raw_data[:restructured_account_number].to_s +
49
+ Constants::USER_ID_TAG +
50
+ FormatStrings::F2TS % raw_data[:user_id].size + raw_data[:user_id] +
51
+ Constants::ACCOUNT_STATUS_TAG +
52
+ FormatStrings::F2TS % raw_data[:account_status].size + raw_data[:account_status] +
53
+ Constants::ACCOUNT_TYPE_TAG +
54
+ FormatStrings::F2TS % raw_data[:account_type].size + raw_data[:account_type] +
55
+ Constants::CURRENCY_CODE_TAG +
56
+ FormatStrings::F2TS % raw_data[:currency_code].size + raw_data[:currency_code] +
57
+ Constants::OPENED_DATE_TAG +
58
+ FormatStrings::F2TS % transform_date(raw_data[:opened_date]).size + transform_date(raw_data[:opened_date]) +
59
+ Constants::PAYMENT_AMOUNT_TAG +
60
+ FormatStrings::F2TS % raw_data[:payment_amount].to_i.to_s.size + raw_data[:payment_amount].to_i.to_s +
61
+ Constants::CLOSED_DATE_TAG +
62
+ FormatStrings::F2TS % transform_date(raw_data[:closed_date]).size + transform_date(raw_data[:closed_date]) +
63
+ Constants::REPORTED_DATE_TAG +
64
+ FormatStrings::F2TS % transform_date(DateTime.now).size + transform_date(DateTime.now) +
65
+ Constants::CREDIT_LIMIT_OR_LOAN_AMOUNT_TAG +
66
+ FormatStrings::F2TS % raw_data[:credit_limit_or_loan_amount].to_i.to_s.size + raw_data[:credit_limit_or_loan_amount].to_i.to_s +
67
+ Constants::SHARED_BY_TAG +
68
+ FormatStrings::F2TS % raw_data[:shared_by].size + raw_data[:shared_by] +
69
+ Constants::OUTSTANDING_BALANCE_TAG +
70
+ FormatStrings::F2TS % raw_data[:outstanding_balance].to_i.to_s.size + raw_data[:outstanding_balance].to_i.to_s +
71
+ Constants::INTEREST_AND_FEES_TAG +
72
+ FormatStrings::F2TS % raw_data[:interest_and_fees].to_i.to_s.size + raw_data[:interest_and_fees].to_i.to_s +
73
+ Constants::UNBILLED_BALANCE_TAG +
74
+ FormatStrings::F2TS % raw_data[:unbilled_balance].to_i.to_s.size + raw_data[:unbilled_balance].to_i.to_s +
75
+ Constants::CASH_ADVANCE_BALANCE_TAG +
76
+ FormatStrings::F2TS % raw_data[:cash_advance_balance].to_i.to_s.size + raw_data[:cash_advance_balance].to_i.to_s +
77
+ Constants::NUMBER_OF_DAYS_PAST_DUE_TAG +
78
+ FormatStrings::F2TS % (FormatStrings::F3TS % raw_data[:number_of_days_past_due]).size + FormatStrings::F3TS % raw_data[:number_of_days_past_due] +
79
+ Constants::PAST_DUE_AMOUNT_TAG +
80
+ FormatStrings::F2TS % raw_data[:past_due_amount].to_i.to_s.size + raw_data[:past_due_amount].to_i.to_s +
81
+ Constants::INSTALLMENT_AMOUNT_TAG +
82
+ FormatStrings::F2TS % raw_data[:installment_amount].to_i.to_s.size + raw_data[:installment_amount].to_i.to_s +
83
+ Constants::NUMBER_OF_INSTALLMENTS_TAG +
84
+ FormatStrings::F2TS % raw_data[:number_of_installments].to_i.to_s.size + raw_data[:number_of_installments].to_i.to_s +
85
+ Constants::PAYMENT_FREQUENCY_TAG +
86
+ FormatStrings::F2TS % raw_data[:payment_frequency].size + raw_data[:payment_frequency] +
87
+ Constants::EXPIRY_DATE_TAG +
88
+ FormatStrings::F2TS % transform_date(raw_data[:expiry_date]).size + transform_date(raw_data[:expiry_date]) +
89
+ Constants::CONSUMER_OR_COMMERCIAL_TAG +
90
+ FormatStrings::F2TS % raw_data[:consumer_or_commercial].size + raw_data[:consumer_or_commercial] +
91
+ Constants::LEGAL_ACTION_TAG +
92
+ FormatStrings::F2TS % raw_data[:legal_action].size + raw_data[:legal_action] +
93
+ Constants::PARTIAL_PAYMENT_TAG +
94
+ FormatStrings::F2TS % raw_data[:partial_payment].size + raw_data[:partial_payment] +
95
+ Constants::FRESH_CASH_ADVANCE_TAG +
96
+ FormatStrings::F2TS % raw_data[:fresh_cash_advance].size + raw_data[:fresh_cash_advance]
97
+ end
98
+
99
+ module Constants
100
+ # tags
101
+ SEGMENT_TAG = "AC04A001"
102
+ ACCOUNT_NUMBER_TAG = "01"
103
+ RESTRUCTURED_ACCOUNT_NUMBER_TAG = "02"
104
+ USER_ID_TAG = "03"
105
+ ACCOUNT_STATUS_TAG = "04"
106
+ ACCOUNT_TYPE_TAG = "05"
107
+ CURRENCY_CODE_TAG = "06"
108
+ OPENED_DATE_TAG = "07"
109
+ PAYMENT_AMOUNT_TAG = "08"
110
+ CLOSED_DATE_TAG = "09"
111
+ REPORTED_DATE_TAG = "10"
112
+ CREDIT_LIMIT_OR_LOAN_AMOUNT_TAG = "11"
113
+ SHARED_BY_TAG = "12"
114
+ OUTSTANDING_BALANCE_TAG = "13"
115
+ INTEREST_AND_FEES_TAG = "14"
116
+ UNBILLED_BALANCE_TAG = "15"
117
+ CASH_ADVANCE_BALANCE_TAG = "16"
118
+ NUMBER_OF_DAYS_PAST_DUE_TAG = "17"
119
+ PAST_DUE_AMOUNT_TAG = "18"
120
+ INSTALLMENT_AMOUNT_TAG = "19"
121
+ NUMBER_OF_INSTALLMENTS_TAG = "20"
122
+ PAYMENT_FREQUENCY_TAG = "21"
123
+ EXPIRY_DATE_TAG = "22"
124
+ CONSUMER_OR_COMMERCIAL_TAG = "23"
125
+ LEGAL_ACTION_TAG = "24"
126
+ PARTIAL_PAYMENT_TAG = "25"
127
+ FRESH_CASH_ADVANCE_TAG = "26"
128
+
129
+ # account status constants
130
+ ACTIVE_OR_OPEN = "A"
131
+
132
+ # account type constants
133
+ SECURED_PERSONAL_LOAN = "3100"
134
+
135
+ # currency code constants
136
+ PHP = "PHP"
137
+
138
+ # shared by constants
139
+ SHARED_BY_1 = "1"
140
+
141
+ # payment frequency constants
142
+ ANNUAL = "A"
143
+ BI_WEEKLY = "B"
144
+ MONTHLY = "M"
145
+ QUARTERLY = "Q"
146
+ SEMI_ANNUALLY = "S"
147
+ WEEKLY = "W"
148
+
149
+ # consumer or commercial constants
150
+ CONSUMER = "I"
151
+ COMMERCIAL = "C"
152
+
153
+ # legal action, partial payment,
154
+ # fresh cash advance constants
155
+ YES = "Y"
156
+ NO = "N"
157
+ NOT_APPLICABLE = "A"
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,49 @@
1
+ module Tufy
2
+ class BuildAddressSegment < BuildSegment
3
+ expects :raw_data
4
+ promises :transformed_data
5
+
6
+ REQUIRED_KEYS = [
7
+ :address_line_1,
8
+ :address_line_2,
9
+ :address_type,
10
+ ]
11
+
12
+ executed do |ctx|
13
+ validate_presence_of_required_keys(ctx.raw_data, REQUIRED_KEYS)
14
+ ctx.transformed_data = ctx.transformed_data + transform(ctx).upcase
15
+ end
16
+
17
+ private
18
+
19
+ def self.transform(ctx)
20
+ raw_data = ctx[:raw_data]
21
+
22
+ Constants::SEGMENT_TAG + # Segment Tag (Required)
23
+ Constants::ADDRESS_LINE_1_TAG +
24
+ FormatStrings::F2TS % remove_special_characters(raw_data[:address_line_1]).size +
25
+ remove_special_characters(raw_data[:address_line_1]) + # Address Line 1 (Required)
26
+ Constants::ADDRESS_LINE_2_TAG +
27
+ FormatStrings::F2TS % remove_special_characters(raw_data[:address_line_2]).size +
28
+ remove_special_characters(raw_data[:address_line_2]) + # Address Line 2 (Required)
29
+ Constants::ADDRESS_TYPE_TAG +
30
+ FormatStrings::F2TS % raw_data[:address_type].size +
31
+ raw_data[:address_type] # Address Type (Required)
32
+ end
33
+
34
+ module Constants
35
+ # tags
36
+ SEGMENT_TAG = "AL03A01"
37
+ ADDRESS_LINE_1_TAG = "01"
38
+ ADDRESS_LINE_2_TAG = "02"
39
+ ADDRESS_TYPE_TAG = "07"
40
+
41
+ # address type constants
42
+ RESIDENTIAL = "R"
43
+ OFFICE = "F"
44
+ BILLING_ADDRESS = "B"
45
+ OTHERS = "O"
46
+ UNKNOWN = "U"
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,41 @@
1
+ module Tufy
2
+ class BuildContactNumberSegment < BuildSegment
3
+ expects :raw_data
4
+ promises :transformed_data
5
+
6
+ REQUIRED_KEYS = [
7
+ :contact_number,
8
+ :contact_number_format,
9
+ ]
10
+
11
+ executed do |ctx|
12
+ validate_presence_of_required_keys(ctx.raw_data, REQUIRED_KEYS)
13
+ ctx.transformed_data = ctx.transformed_data + transform(ctx).upcase
14
+ end
15
+
16
+ private
17
+
18
+ def self.transform(ctx)
19
+ raw_data = ctx[:raw_data]
20
+
21
+ Constants::SEGMENT_TAG + # Segment Tag (Required)
22
+ Constants::CONTACT_NUMBER_TAG +
23
+ FormatStrings::F2TS % remove_special_characters(raw_data[:contact_number]).size +
24
+ remove_special_characters(raw_data[:contact_number]) + # Contact Number (Required)
25
+ Constants::CONTACT_NUMBER_FORMAT_TAG +
26
+ FormatStrings::F2TS % raw_data[:contact_number_format].size +
27
+ raw_data[:contact_number_format] # Contact Number Format (Required)
28
+ end
29
+
30
+ module Constants
31
+ # tags
32
+ SEGMENT_TAG = "PH03P01"
33
+ CONTACT_NUMBER_TAG = "03"
34
+ CONTACT_NUMBER_FORMAT_TAG = "05"
35
+
36
+ # contact number format constants
37
+ FREE_FORMAT = "F"
38
+ STRUCTURED_FORMAT = "S"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,32 @@
1
+ module Tufy
2
+ class BuildEmailAddressSegment < BuildSegment
3
+ expects :raw_data
4
+ promises :transformed_data
5
+
6
+ REQUIRED_KEYS = [
7
+ :email_address,
8
+ ]
9
+
10
+ executed do |ctx|
11
+ validate_presence_of_required_keys(ctx.raw_data, REQUIRED_KEYS)
12
+ ctx.transformed_data = ctx.transformed_data + transform(ctx).upcase
13
+ end
14
+
15
+ private
16
+
17
+ def self.transform(ctx)
18
+ raw_data = ctx[:raw_data]
19
+
20
+ Constants::SEGMENT_TAG + # Segment Tag (Required)
21
+ Constants::EMAIL_ADDRESS_TAG +
22
+ FormatStrings::F2TS % raw_data[:email_address].size +
23
+ raw_data[:email_address] # Email Address (Required)
24
+ end
25
+
26
+ module Constants
27
+ # tags
28
+ SEGMENT_TAG = "ID03I01"
29
+ EMAIL_ADDRESS_TAG = "01"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,27 @@
1
+ module Tufy
2
+ class BuildEndOfSubjectSegment < BuildSegment
3
+ expects :raw_data
4
+ promises :transformed_data
5
+
6
+ executed do |ctx|
7
+ ctx.transformed_data = ctx.transformed_data + transform(ctx).upcase
8
+ end
9
+
10
+ private
11
+
12
+ def self.transform(ctx)
13
+ raw_data = ctx[:raw_data]
14
+
15
+ Constants::SEGMENT_TAG + # Segment Tag (Required)
16
+ FormatStrings::F2TS % Constants::END_OF_SUBJECT.size +
17
+ Constants::END_OF_SUBJECT
18
+ end
19
+
20
+ module Constants
21
+ # tags
22
+ SEGMENT_TAG = "ES"
23
+
24
+ END_OF_SUBJECT = "**"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,35 @@
1
+ module Tufy
2
+ class BuildHeaderSegment < BuildSegment
3
+ expects :raw_data
4
+ promises :transformed_data
5
+
6
+ REQUIRED_KEYS = [
7
+ :member_reference_number,
8
+ :processor_name,
9
+ :user_id
10
+ ]
11
+
12
+ executed do |ctx|
13
+ validate_presence_of_required_keys(ctx.raw_data, REQUIRED_KEYS)
14
+ ctx.transformed_data = ctx.transformed_data + transform(ctx).upcase
15
+ end
16
+
17
+ private
18
+
19
+ def self.transform(ctx)
20
+ Constants::SEGMENT_TAG + # Segment Tag (Required)
21
+ Constants::TUDF_VERSION + # Version Tag (Required)
22
+ "#{FormatStrings::F25TS % ctx.raw_data[:member_reference_number]}" + # Member Reference Number (Required)
23
+ "#{FormatStrings::F26TS % ctx.raw_data[:processor_name].upcase}" + # Member Processor Name (Required)
24
+ "#{FormatStrings::F10TS % ctx.raw_data[:user_id].upcase}" + # User ID (Required)
25
+ "#{transform_date(Date.today)}" + # Reported Date (Required)
26
+ Constants::FILLER # Filler (Required)
27
+ end
28
+
29
+ module Constants
30
+ SEGMENT_TAG = "TUDF"
31
+ TUDF_VERSION = "11"
32
+ FILLER = "0000000000"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,57 @@
1
+ module Tufy
2
+ class BuildIdSegment < BuildSegment
3
+ expects :raw_data
4
+ promises :transformed_data
5
+
6
+ REQUIRED_KEYS = [
7
+ :id_number,
8
+ :id_type,
9
+ ]
10
+
11
+ executed do |ctx|
12
+ # ID Segment is not required.
13
+ # If ID type passed here does
14
+ # not exist, do not proceed.
15
+ # TODO: Testing
16
+ validate_presence_of_required_keys(ctx.raw_data, REQUIRED_KEYS)
17
+ if id_type_exists?(ctx.raw_data[:id_type])
18
+ ctx.transformed_data = ctx.transformed_data + transform(ctx).upcase
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def self.transform(ctx)
25
+ raw_data = ctx[:raw_data]
26
+
27
+ Constants::SEGMENT_TAG + # Segment Tag (Required)
28
+ Constants::ID_NUMBER_TAG +
29
+ FormatStrings::F2TS % remove_special_characters(raw_data[:id_number]).size +
30
+ remove_special_characters(raw_data[:id_number]) + # ID Number (Required)
31
+ Constants::ID_TYPE_TAG +
32
+ FormatStrings::F2TS % raw_data[:id_type].size +
33
+ raw_data[:id_type] # ID Type (Required)
34
+ end
35
+
36
+ def self.id_type_exists?(id_type)
37
+ Constants::ID_TYPES.include?(id_type)
38
+ end
39
+
40
+ module Constants
41
+ # tags
42
+ SEGMENT_TAG = "ID03I01"
43
+ ID_NUMBER_TAG = "01"
44
+ ID_TYPE_TAG = "02"
45
+
46
+ # id type constants
47
+ SSS = "SSS"
48
+ PP = "PP"
49
+ TIN = "TIN"
50
+ DL = "DL"
51
+ GSIS = "GSIS"
52
+ UMID = "UMID"
53
+
54
+ ID_TYPES = [SSS, PP, TIN, DL, GSIS, UMID]
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,75 @@
1
+ module Tufy
2
+ class BuildNameSegment < BuildSegment
3
+ expects :raw_data
4
+ promises :transformed_data
5
+
6
+ REQUIRED_KEYS = [
7
+ :first_name,
8
+ :last_name,
9
+ :civil_status,
10
+ :date_of_birth,
11
+ :gender,
12
+ :ac_holder_type,
13
+ ]
14
+
15
+ executed do |ctx|
16
+ validate_presence_of_required_keys(ctx.raw_data, REQUIRED_KEYS)
17
+ ctx.transformed_data = ctx.transformed_data + transform(ctx).upcase
18
+ end
19
+
20
+ private
21
+
22
+ def self.transform(ctx)
23
+ raw_data = ctx[:raw_data]
24
+
25
+ Constants::SEGMENT_TAG + # Segment Tag (Required)
26
+ Constants::FIRST_NAME_TAG +
27
+ FormatStrings::F2TS % raw_data[:first_name].size +
28
+ raw_data[:first_name] + # First Name (Required)
29
+ Constants::LAST_NAME_TAG +
30
+ FormatStrings::F2TS % raw_data[:last_name].size +
31
+ raw_data[:last_name] + # Last Name (Required)
32
+ Constants::CIVIL_STATUS_TAG +
33
+ FormatStrings::F2TS % raw_data[:civil_status].size +
34
+ raw_data[:civil_status] + # Civil Status (Required)
35
+ Constants::DATE_OF_BIRTH_TAG +
36
+ FormatStrings::F2TS % transform_date(raw_data[:date_of_birth]).size +
37
+ transform_date(raw_data[:date_of_birth]) + # Date of Birth (Required)
38
+ Constants::GENDER_TAG +
39
+ FormatStrings::F2TS % raw_data[:gender].size +
40
+ raw_data[:gender] + # Gender (Required)
41
+ Constants::AC_HOLDER_TYPE_TAG +
42
+ FormatStrings::F2TS % raw_data[:ac_holder_type].size +
43
+ raw_data[:ac_holder_type] # A/C Holder Type
44
+ end
45
+
46
+ module Constants
47
+ # tags
48
+ SEGMENT_TAG = "NA03N01"
49
+ FIRST_NAME_TAG = "01"
50
+ LAST_NAME_TAG = "03"
51
+ CIVIL_STATUS_TAG = "05"
52
+ DATE_OF_BIRTH_TAG = "06"
53
+ GENDER_TAG = "07"
54
+ AC_HOLDER_TYPE_TAG = "12"
55
+
56
+ # civil status constants
57
+ SINGLE = "S"
58
+ MARRIED = "M"
59
+ DIVORCED = "D"
60
+ WIDOWED = "W"
61
+ CIVIL_STATUS_UNKNOWN = "U"
62
+
63
+ # gender constants
64
+ FEMALE = "1"
65
+ MALE = "2"
66
+ GENDER_UNKNOWN = "3"
67
+
68
+ # a/c holder type constants
69
+ HI = "HI"
70
+ HPI = "HPI"
71
+ HJ = "HJ"
72
+ G = "G"
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,24 @@
1
+ module Tufy
2
+ class BuildSegment
3
+ include LightService::Action
4
+
5
+ protected
6
+
7
+ def self.validate_presence_of_required_keys(raw_data, required_keys)
8
+ required_keys.each do |required_key|
9
+ raise Tufy::Errors::RequiredDataMissing, required_key.to_s unless raw_data.key? required_key
10
+ end
11
+ end
12
+
13
+ def self.transform_date(date)
14
+ # TODO: Remove conditional
15
+ # after data-integrity issues
16
+ # have been resolved
17
+ date ? date.strftime("%d%m%Y") : "00000000"
18
+ end
19
+
20
+ def self.remove_special_characters(string)
21
+ string.gsub(/[^0-9A-Za-z]/, '')
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,6 @@
1
+ module Tufy
2
+ module Errors
3
+ class RequiredDataMissing < StandardError
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,10 @@
1
+ module Tufy
2
+ module FormatStrings
3
+ F25TS = "%-25.25s" # Fixed 25-character String with Trailing Spaces
4
+ F26TS = "%-26.26s" # Fixed 26-character String with Trailing Spaces
5
+ F10TS = "%-10.10s" # Fixed 10-character String with Trailing Spaces
6
+
7
+ F2TS = "%02d" # Fixed 2-character String with Leading Zeroes
8
+ F3TS = "%03d" # Fixed 3-character String with Leading Zeroes
9
+ end
10
+ end
@@ -0,0 +1,24 @@
1
+ module Tufy
2
+ class Transform
3
+ include LightService::Organizer
4
+ include LightService::Action
5
+
6
+ expects :raw_data
7
+
8
+ executed do |ctx|
9
+ ctx[:transformed_data] = ""
10
+
11
+ with(ctx).reduce(
12
+ BuildHeaderSegment,
13
+ BuildNameSegment,
14
+ BuildAddressSegment,
15
+ BuildContactNumberSegment,
16
+ BuildEmailAddressSegment,
17
+ BuildAccountSegment,
18
+ BuildEndOfSubjectSegment,
19
+ )
20
+
21
+ ctx[:transformed_data]
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module Tufy
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'tufy/version'
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "tufy"
7
+ spec.version = Tufy::VERSION
8
+ spec.authors = ["Neil Marion dela Cruz"]
9
+ spec.email = ["nmfdelacruz@gmail.com"]
10
+
11
+ spec.summary = %q{Parses data into Transunion-specific data format}
12
+ spec.description = %q{Parses data into Transunion-specific data format}
13
+ spec.homepage = "https://github.com/carabao-capital/tufy"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_dependency "light-service", "0.4.0"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.14"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "rspec", "~> 3.0"
28
+ spec.add_development_dependency "pry-nav"
29
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tufy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Neil Marion dela Cruz
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-05-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: light-service
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.4.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.4.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.14'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.14'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-nav
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Parses data into Transunion-specific data format
84
+ email:
85
+ - nmfdelacruz@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
93
+ - CHANGELOG.md
94
+ - CODE_OF_CONDUCT.md
95
+ - Gemfile
96
+ - LICENSE.txt
97
+ - README.md
98
+ - Rakefile
99
+ - bin/console
100
+ - bin/setup
101
+ - lib/tufy.rb
102
+ - lib/tufy/build_account_segment.rb
103
+ - lib/tufy/build_address_segment.rb
104
+ - lib/tufy/build_contact_number_segment.rb
105
+ - lib/tufy/build_email_address_segment.rb
106
+ - lib/tufy/build_end_of_subject_segment.rb
107
+ - lib/tufy/build_header_segment.rb
108
+ - lib/tufy/build_id_segment.rb
109
+ - lib/tufy/build_name_segment.rb
110
+ - lib/tufy/build_segment.rb
111
+ - lib/tufy/errors/required_data_missing_error.rb
112
+ - lib/tufy/format_strings.rb
113
+ - lib/tufy/transform.rb
114
+ - lib/tufy/version.rb
115
+ - tufy.gemspec
116
+ homepage: https://github.com/carabao-capital/tufy
117
+ licenses:
118
+ - MIT
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.6.12
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: Parses data into Transunion-specific data format
140
+ test_files: []