giact_verification 0.1.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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +143 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/giact_verification.gemspec +42 -0
  13. data/lib/giact_verification.rb +67 -0
  14. data/lib/giact_verification/authenticate.rb +44 -0
  15. data/lib/giact_verification/configuration.rb +52 -0
  16. data/lib/giact_verification/decorators/decorate_hash.rb +22 -0
  17. data/lib/giact_verification/decorators/giact_soap_decorator.rb +32 -0
  18. data/lib/giact_verification/errors.rb +7 -0
  19. data/lib/giact_verification/etc/alternative_id_types.yml +10 -0
  20. data/lib/giact_verification/etc/check_validator_errors.yml +11 -0
  21. data/lib/giact_verification/etc/customer_validator_errors.yml +35 -0
  22. data/lib/giact_verification/etc/serviced_countries.yml +2 -0
  23. data/lib/giact_verification/etc/serviced_states.yml +78 -0
  24. data/lib/giact_verification/etc/valid_account_types.yml +4 -0
  25. data/lib/giact_verification/extract_inquiry_result.rb +26 -0
  26. data/lib/giact_verification/inquiry_template_renderer.rb +26 -0
  27. data/lib/giact_verification/models/check.rb +33 -0
  28. data/lib/giact_verification/models/customer.rb +33 -0
  29. data/lib/giact_verification/models/giact_xml.rb +28 -0
  30. data/lib/giact_verification/requests/production_requester.rb +28 -0
  31. data/lib/giact_verification/requests/request_coordinator.rb +30 -0
  32. data/lib/giact_verification/requests/requester_factory.rb +25 -0
  33. data/lib/giact_verification/requests/sandbox_requester.rb +28 -0
  34. data/lib/giact_verification/requests/stubbed_requester.rb +38 -0
  35. data/lib/giact_verification/requests/support/declined_response.xml +17 -0
  36. data/lib/giact_verification/requests/support/error_response.xml +19 -0
  37. data/lib/giact_verification/requests/support/pass_response.xml +20 -0
  38. data/lib/giact_verification/response.rb +16 -0
  39. data/lib/giact_verification/response_parser.rb +35 -0
  40. data/lib/giact_verification/templates/inquiry.xml.erb +146 -0
  41. data/lib/giact_verification/validators/check_validator.rb +27 -0
  42. data/lib/giact_verification/validators/customer_validator.rb +77 -0
  43. data/lib/giact_verification/validators/giact_xml_validator.rb +25 -0
  44. data/lib/giact_verification/version.rb +3 -0
  45. data/lib/giact_verification/xml_to_hash.rb +22 -0
  46. metadata +214 -0
@@ -0,0 +1,30 @@
1
+ module GiactVerification
2
+ class RequestCoordinator
3
+
4
+ def self.call(args)
5
+ new(args).call
6
+ end
7
+
8
+ def initialize(args)
9
+ @body = args[:body]
10
+ @requester = args[:requester] || GiactVerification::RequesterFactory.call
11
+ @parser = args[:parser] || GiactVerification::ResponseParser
12
+ end
13
+
14
+ def call
15
+ response = requester.call(body: body)
16
+
17
+ parsed_response = parser.call(response: response)
18
+
19
+ GiactVerification::Response.new(
20
+ raw_request: body,
21
+ raw_response: response.body,
22
+ success: parsed_response.success,
23
+ parsed_response: parsed_response.body
24
+ )
25
+ end
26
+
27
+ private
28
+ attr_reader :body, :parser, :requester
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ module GiactVerification
2
+ class RequesterFactory
3
+ def self.call
4
+ new.call
5
+ end
6
+
7
+ def initialize
8
+ @endpoint_set_to = GiactVerification.giact_endpoint
9
+ end
10
+
11
+ def call
12
+ case endpoint_set_to
13
+ when :production
14
+ GiactVerification::ProductionRequester
15
+ when :sandbox
16
+ GiactVerification::SandboxRequester
17
+ when :stubbed
18
+ GiactVerification::StubbedRequester
19
+ end
20
+ end
21
+
22
+ private
23
+ attr_reader :endpoint_set_to
24
+ end
25
+ end
@@ -0,0 +1,28 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+
4
+ module GiactVerification
5
+ class SandboxRequester
6
+
7
+ SANDBOX_URI = URI.parse('https://sandbox.api.giact.com/verificationservices/v5/InquiriesWS-5-8.asmx').freeze
8
+
9
+ def self.call(args)
10
+ new(args).call
11
+ end
12
+
13
+ def initialize(args)
14
+ @endpointable = SANDBOX_URI
15
+ @body = args[:body]
16
+ end
17
+
18
+ def call
19
+ http = Net::HTTP.new(endpointable.host, endpointable.port)
20
+ http.use_ssl = true
21
+
22
+ response = http.post(endpointable.path, body, 'Content-Type' => 'text/xml')
23
+ end
24
+
25
+ private
26
+ attr_reader :endpointable, :body
27
+ end
28
+ end
@@ -0,0 +1,38 @@
1
+ require 'ostruct'
2
+
3
+ module GiactVerification
4
+ class StubbedRequester
5
+
6
+ def self.call(args)
7
+ new(args).call
8
+ end
9
+
10
+ def initialize(args)
11
+ @body = args[:body]
12
+ end
13
+
14
+ def call
15
+ hashed_request_body = XmlToHash.call(xml: body)
16
+
17
+ response_body = response_for(hashed_request_body)
18
+
19
+ response = OpenStruct.new({code: '200', body: response_body})
20
+ end
21
+
22
+ private
23
+ attr_reader :body
24
+
25
+ def response_for(hashed_body)
26
+ last_name = hashed_body.dig(:'soap:envelope', :'soap:body', :post_inquiry, :inquiry, :customer, :last_name)
27
+
28
+ case last_name
29
+ when 'GiactDeclined'
30
+ File.read(File.join(GiactVerification.root, 'lib', 'giact_verification', 'requests', 'support', 'declined_response.xml'))
31
+ when 'GiactError'
32
+ File.read(File.join(GiactVerification.root, 'lib', 'giact_verification', 'requests', 'support', 'error_response.xml'))
33
+ else
34
+ File.read(File.join(GiactVerification.root, 'lib', 'giact_verification', 'requests', 'support', 'pass_response.xml'))
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema">
4
+ <soap:Body>
5
+ <PostInquiryResponse xmlns="http://api.giact.com/verificationservices/v5">
6
+ <PostInquiryResult>
7
+ <ItemReferenceId>5000001888</ItemReferenceId>
8
+ <CreatedDate>2017-02-03T11:35:43.242182-06:00</CreatedDate>
9
+ <VerificationResponse>Declined</VerificationResponse>
10
+ <AccountResponseCode>GN05</AccountResponseCode>
11
+ <AccountClosedDate xsi:nil="true" />
12
+ <FundsConfirmationResult xsi:nil="true" />
13
+ <CustomerResponseCode>CA01</CustomerResponseCode>
14
+ </PostInquiryResult>
15
+ </PostInquiryResponse>
16
+ </soap:Body>
17
+ </soap:Envelope>
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
3
+ <soap:Body>
4
+ <PostInquiryResponse xmlns="http://api.giact.com/verificationservices/v5">
5
+ <PostInquiryResult>
6
+ <ItemReferenceId>218958</ItemReferenceId>
7
+ <CreatedDate>2018-01-31T14:22:25.6344486-06:00</CreatedDate>
8
+ <ErrorMessage>If gAuthenticate, gIdentify, CustomerID, OFAC List Scanning, or gMobile is enabled, then either both FirstName and LastName or BusinessName is required.</ErrorMessage>
9
+ <VerificationResponse>Error</VerificationResponse>
10
+ <AccountResponseCode xsi:nil="true" />
11
+ <AccountAddedDate xsi:nil="true" />
12
+ <AccountLastUpdatedDate xsi:nil="true" />
13
+ <AccountClosedDate xsi:nil="true" />
14
+ <FundsConfirmationResult xsi:nil="true" />
15
+ <CustomerResponseCode xsi:nil="true" />
16
+ </PostInquiryResult>
17
+ </PostInquiryResponse>
18
+ </soap:Body>
19
+ </soap:Envelope>
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema">
4
+ <soap:Body>
5
+ <PostInquiryResponse xmlns="http://api.giact.com/verificationservices/v5">
6
+ <PostInquiryResult>
7
+ <ItemReferenceId>5000001888</ItemReferenceId>
8
+ <CreatedDate>2017-02-03T11:35:43.242182-06:00</CreatedDate>
9
+ <VerificationResponse>Pass</VerificationResponse>
10
+ <AccountResponseCode>_1111</AccountResponseCode>
11
+ <BankName>WELLS FARGO BANK NA (ARIZONA)</BankName>
12
+ <AccountAddedDate>2008-04-09T00:00:00</AccountAddedDate>
13
+ <AccountLastUpdatedDate>2010-06-23T00:00:00</AccountLastUpdatedDate>
14
+ <AccountClosedDate xsi:nil="true" />
15
+ <FundsConfirmationResult xsi:nil="true" />
16
+ <CustomerResponseCode>CA11</CustomerResponseCode>
17
+ </PostInquiryResult>
18
+ </PostInquiryResponse>
19
+ </soap:Body>
20
+ </soap:Envelope>
@@ -0,0 +1,16 @@
1
+ module GiactVerification
2
+ class Response
3
+ attr_reader :raw_request, :raw_response, :parsed_response, :success
4
+
5
+ def initialize(args)
6
+ @raw_request = args[:raw_request]
7
+ @raw_response = args[:raw_response]
8
+ @parsed_response = args[:parsed_response]
9
+ @success = args[:success]
10
+ end
11
+
12
+ def success?
13
+ success
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ require 'ostruct'
2
+
3
+ module GiactVerification
4
+ class ResponseParser
5
+
6
+ def self.call(args)
7
+ new(args).call
8
+ end
9
+
10
+ def initialize(args)
11
+ @response = args[:response]
12
+ end
13
+
14
+ def call
15
+ if successful_request?
16
+ OpenStruct.new({ body: giact_xml.inquiry_result, success: true })
17
+ else
18
+ OpenStruct.new({ body: {}, success: false })
19
+ end
20
+ end
21
+
22
+ private
23
+ attr_reader :response
24
+
25
+ def successful_request?
26
+ response.code == "200" && giact_xml.valid?
27
+ end
28
+
29
+ def giact_xml
30
+ @giact_xml ||= GiactVerification::GiactXml.new(xml: response.body)
31
+ end
32
+ end
33
+ end
34
+
35
+
@@ -0,0 +1,146 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
3
+ <soap:Header>
4
+ <AuthenticationHeader xmlns="http://api.giact.com/verificationservices/v5">
5
+ <ApiUsername><%= GiactVerification.configuration.api_username %></ApiUsername>
6
+ <ApiPassword><%= GiactVerification.configuration.api_password %></ApiPassword>
7
+ </AuthenticationHeader>
8
+ </soap:Header>
9
+ <soap:Body>
10
+ <PostInquiry xmlns="http://api.giact.com/verificationservices/v5">
11
+ <Inquiry>
12
+ <% if @substitutions[:unique_id] %>
13
+ <UniqueId><%= @substitutions[:unique_id] %></UniqueId>
14
+ <% end %>
15
+ <% if @substitutions[:g_verify_enabled] %>
16
+ <GVerifyEnabled><%= @substitutions[:g_verify_enabled] %></GVerifyEnabled>
17
+ <% end %>
18
+ <% if @substitutions[:funds_confirmation_enabled] %>
19
+ <FundsConfirmationEnabled><%= @substitutions[:funds_confirmation_enabled] %></FundsConfirmationEnabled>
20
+ <% end %>
21
+ <% if @substitutions[:g_authenticate_enabled] %>
22
+ <GAuthenticateEnabled><%= @substitutions[:g_authenticate_enabled] %></GAuthenticateEnabled>
23
+ <% end %>
24
+ <% if @substitutions[:voided_check_image_enabled] %>
25
+ <VoidedCheckImageEnabled><%= @substitutions[:voided_check_image_enabled] %></VoidedCheckImageEnabled>
26
+ <% end %>
27
+ <% if @substitutions[:g_identify_enabled] %>
28
+ <GIdentifyEnabled><%= @substitutions[:g_identify_enabled] %></GIdentifyEnabled>
29
+ <% end %>
30
+ <% if @substitutions[:customer_id_enabled] %>
31
+ <CustomerIdEnabled><%= @substitutions[:customer_id_enabled] %></CustomerIdEnabled>
32
+ <% end %>
33
+ <% if @substitutions[:ofac_scan_enabled] %>
34
+ <OfacScanEnabled><%= @substitutions[:ofac_scan_enabled] %></OfacScanEnabled>
35
+ <% end %>
36
+ <% if @substitutions[:g_identify_esi_enabled] %>
37
+ <GIdentifyEsiEnabled><%= @substitutions[:g_identify_esi_enabled] %></GIdentifyEsiEnabled>
38
+ <% end %>
39
+ <% if @substitutions[:ip_address_information_enabled] %>
40
+ <IpAddressInformationEnabled><%= @substitutions[:ip_address_information_enabled] %></IpAddressInformationEnabled>
41
+ <% end %>
42
+ <% if @substitutions[:domain_whois_enabled] %>
43
+ <DomainWhoisEnabled><%= @substitutions[:domain_whois_enabled] %></DomainWhoisEnabled>
44
+ <% end %>
45
+ <% if @substitutions[:mobile_verify_enabled] %>
46
+ <MobileVerifyEnabled><%= @substitutions[:mobile_verify_enabled] %></MobileVerifyEnabled>
47
+ <% end %>
48
+ <% if @substitutions[:mobile_identify_enabled] %>
49
+ <MobileIdentifyEnabled><%= @substitutions[:mobile_identify_enabled] %></MobileIdentifyEnabled>
50
+ <% end %>
51
+ <% if @substitutions[:check] %>
52
+ <Check>
53
+ <% if @substitutions[:check][:routing_number] %>
54
+ <RoutingNumber><%= @substitutions[:check][:routing_number] %></RoutingNumber>
55
+ <% end %>
56
+ <% if @substitutions[:check][:account_number] %>
57
+ <AccountNumber><%= @substitutions[:check][:account_number] %></AccountNumber>
58
+ <% end %>
59
+ <% if @substitutions[:check][:account_type] %>
60
+ <AccountType><%= @substitutions[:check][:account_type] %></AccountType>
61
+ <% end %>
62
+ <% if @substitutions[:check][:check_number] %>
63
+ <CheckNumber><%= @substitutions[:check][:check_number] %></CheckNumber>
64
+ <% end %>
65
+ <% if @substitutions[:check][:check_amount] %>
66
+ <CheckAmount><%= @substitutions[:check][:check_amount] %></CheckAmount>
67
+ <% end %>
68
+ </Check>
69
+ <% end %>
70
+ <% if @substitutions[:customer] %>
71
+ <Customer>
72
+ <% if @substitutions[:customer][:name_prefix] %>
73
+ <NamePrefix><%= @substitutions[:customer][:name_prefix] %></NamePrefix>
74
+ <% end %>
75
+ <% if @substitutions[:customer][:first_name] %>
76
+ <FirstName><%= @substitutions[:customer][:first_name] %></FirstName>
77
+ <% end %>
78
+ <% if @substitutions[:customer][:middle_name] %>
79
+ <MiddleName><%= @substitutions[:customer][:middle_name] %></MiddleName>
80
+ <% end %>
81
+ <% if @substitutions[:customer][:last_name] %>
82
+ <LastName><%= @substitutions[:customer][:last_name] %></LastName>
83
+ <% end %>
84
+ <% if @substitutions[:customer][:name_suffix] %>
85
+ <NameSuffix><%= @substitutions[:customer][:name_suffix] %></NameSuffix>
86
+ <% end %>
87
+ <% if @substitutions[:customer][:address_line1] %>
88
+ <AddressLine1><%= @substitutions[:customer][:address_line1] %></AddressLine1>
89
+ <% end %>
90
+ <% if @substitutions[:customer][:address_line2] %>
91
+ <AddressLine2><%= @substitutions[:customer][:address_line2] %></AddressLine2>
92
+ <% end %>
93
+ <% if @substitutions[:customer][:city] %>
94
+ <City><%= @substitutions[:customer][:city] %></City>
95
+ <% end %>
96
+ <% if @substitutions[:customer][:state] %>
97
+ <State><%= @substitutions[:customer][:state] %></State>
98
+ <% end %>
99
+ <% if @substitutions[:customer][:zip_code] %>
100
+ <ZipCode><%= @substitutions[:customer][:zip_code] %></ZipCode>
101
+ <% end %>
102
+ <% if @substitutions[:customer][:country] %>
103
+ <Country><%= @substitutions[:customer][:country] %></Country>
104
+ <% end %>
105
+ <% if @substitutions[:customer][:phone_number] %>
106
+ <PhoneNumber><%= @substitutions[:customer][:phone_number] %></PhoneNumber>
107
+ <% end %>
108
+ <% if @substitutions[:customer][:tax_id] %>
109
+ <TaxId><%= @substitutions[:customer][:tax_id] %></TaxId>
110
+ <% end %>
111
+ <% if @substitutions[:customer][:date_of_birth] %>
112
+ <DateOfBirth><%= @substitutions[:customer][:date_of_birth] %></DateOfBirth>
113
+ <% end %>
114
+ <% if @substitutions[:customer][:drivers_license_number] %>
115
+ <DlNumber><%= @substitutions[:customer][:drivers_license_number] %></DlNumber>
116
+ <% end %>
117
+ <% if @substitutions[:customer][:drivers_license_state] %>
118
+ <DlState><%= @substitutions[:customer][:drivers_license_state] %></DlState>
119
+ <% end %>
120
+ <% if @substitutions[:customer][:email_address] %>
121
+ <EmailAddress><%= @substitutions[:customer][:email_address] %></EmailAddress>
122
+ <% end %>
123
+ <% if @substitutions[:customer][:current_ip_address] %>
124
+ <CurrentIpAddress><%= @substitutions[:customer][:current_ip_address] %></CurrentIpAddress>
125
+ <% end %>
126
+ <% if @substitutions[:customer][:mobile_consent_record_id] %>
127
+ <MobileConsentRecordId><%= @substitutions[:customer][:mobile_consent_record_id] %></MobileConsentRecordId>
128
+ <% end %>
129
+ <% if @substitutions[:customer][:alternative_id_type] %>
130
+ <AltIdType><%= @substitutions[:customer][:alternative_id_type] %></AltIdType>
131
+ <% end %>
132
+ <% if @substitutions[:customer][:alternative_id_issuer] %>
133
+ <AltIdIssuer><%= @substitutions[:customer][:alternative_id_issuer] %></AltIdIssuer>
134
+ <% end %>
135
+ <% if @substitutions[:customer][:alternative_id_number] %>
136
+ <AltIdNumber><%= @substitutions[:customer][:alternative_id_number] %></AltIdNumber>
137
+ <% end %>
138
+ <% if @substitutions[:customer][:domain] %>
139
+ <Domain><%= @substitutions[:customer][:domain] %></Domain>
140
+ <% end %>
141
+ </Customer>
142
+ <% end %>
143
+ </Inquiry>
144
+ </PostInquiry>
145
+ </soap:Body>
146
+ </soap:Envelope>
@@ -0,0 +1,27 @@
1
+ require 'dry-validation'
2
+
3
+ CheckValidator = Dry::Validation.Schema do
4
+
5
+ configure do
6
+ config.messages_file = File.join(GiactVerification.config_directory, 'check_validator_errors.yml')
7
+
8
+ def valid_account_type?(account_type)
9
+ GiactVerification.valid_account_type?(account_type)
10
+ end
11
+
12
+ def routing_number_length?(routing_number)
13
+ routing_number.to_s.size == 9
14
+ end
15
+
16
+ def account_number_length?(account_number)
17
+ (4..17).include?(account_number.to_s.size)
18
+ end
19
+ end
20
+
21
+ required(:routing_number) { filled? & number? & routing_number_length? }
22
+ required(:account_number) { filled? & number? & account_number_length? }
23
+
24
+ optional(:check_number) { none? | (filled? & number?) }
25
+ optional(:check_amount) { none? | (filled? & number?) }
26
+ optional(:account_type) { none? | (filled? & str? & valid_account_type? ) }
27
+ end
@@ -0,0 +1,77 @@
1
+ require 'dry-validation'
2
+
3
+ CustomerValidator = Dry::Validation.Schema do
4
+
5
+ configure do
6
+ config.messages_file = File.join(GiactVerification.config_directory, 'customer_validator_errors.yml')
7
+
8
+ def serviced_state?(state)
9
+ GiactVerification.servicing?(state.upcase)
10
+ end
11
+
12
+ def serviced_country?(country)
13
+ GiactVerification.servicing_country?(country.upcase)
14
+ end
15
+
16
+ def postal_code?(value)
17
+ [5, 7, 10].include?(value.to_s.length)
18
+ end
19
+
20
+ def phone_number_format?(value)
21
+ value.to_s =~ /[1-9][0-9]{9}/
22
+ end
23
+
24
+ def phone_number_length?(value)
25
+ value.to_s.length == 10
26
+ end
27
+
28
+ def last_four_ssn_length?(value)
29
+ value.to_s.length == 4
30
+ end
31
+
32
+ def ssn_or_ein_length?(value)
33
+ value.to_s.length == 9
34
+ end
35
+
36
+ def respond_to_strftime?(value)
37
+ value.respond_to?(:strftime)
38
+ end
39
+
40
+ def drivers_license_length?(value)
41
+ (1..28).include?(value.to_s.length)
42
+ end
43
+
44
+ def accepted_alternative_id?(id_type)
45
+ GiactVerification.accepts_id_type?(id_type)
46
+ end
47
+
48
+ def alternative_id_number_length?(alternative_id_number)
49
+ (1..50).include?(alternative_id_number.to_s.length)
50
+ end
51
+ end
52
+
53
+ optional(:name_prefix) { none? | size?(1..4) }
54
+ required(:first_name) { filled? & size?(2..40) }
55
+ optional(:middle_name) { none? | size?(1..40) }
56
+ required(:last_name) { filled? & size?(2..40) }
57
+ optional(:name_suffix) { none? | size?(1..4) }
58
+
59
+ required(:address_line1) { filled? & size?(2..40) }
60
+ optional(:address_line2) { none? | empty? | size?(1..40) }
61
+ required(:city) { filled? & size?(2..25) }
62
+ required(:state) { filled? & size?(2) & serviced_state? }
63
+ required(:zip_code) { filled? & number? & postal_code? }
64
+ optional(:country) { none? | (filled? & serviced_country?) }
65
+ optional(:phone_number) { none? | (number? & phone_number_length? & phone_number_format?) }
66
+ required(:tax_id) { filled? & number? & (last_four_ssn_length? | ssn_or_ein_length?) }
67
+ required(:date_of_birth) { filled? & (date? | date_time? | respond_to_strftime?) }
68
+ optional(:drivers_license_number) { none? | drivers_license_length? }
69
+ optional(:drivers_license_state) { none? | (filled? & serviced_state?) }
70
+ optional(:email_address) { none? | size?(1..100) }
71
+ optional(:current_ip_address) { none? | size?(1..15) }
72
+ optional(:mobile_consent_record_id) { none? | number? }
73
+ optional(:alternative_id_type) { none? | accepted_alternative_id? }
74
+ optional(:alternative_id_issuer) { none? | (str? & size?(1..50)) }
75
+ optional(:alternative_id_number) { none? | (number? & alternative_id_number_length?) }
76
+ optional(:domain) { none? | (str? & size?(1..100)) }
77
+ end