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,52 @@
1
+ require 'yaml'
2
+
3
+ module GiactVerification
4
+ class Configuration
5
+
6
+ attr_accessor :api_username
7
+ attr_accessor :api_password
8
+ attr_accessor :giact_endpoint
9
+
10
+ def initialize(args = {})
11
+ @giact_endpoint = :production
12
+ end
13
+
14
+ def invalid?
15
+ api_username.nil? || api_password.nil?
16
+ end
17
+
18
+ def servicing?(state)
19
+ serviced_states.include?(state)
20
+ end
21
+
22
+ def servicing_country?(country)
23
+ serviced_countries.include?(country)
24
+ end
25
+
26
+ def accepts_id_type?(id_type)
27
+ valid_alternative_id_types.include?(id_type)
28
+ end
29
+
30
+ def valid_account_type?(account_type)
31
+ valid_account_types.include?(account_type)
32
+ end
33
+
34
+ private
35
+
36
+ def valid_account_types
37
+ @valid_account_types ||= YAML.load_file(GiactVerification.config_directory + '/valid_account_types.yml')
38
+ end
39
+
40
+ def valid_alternative_id_types
41
+ @valid_alternative_id_types ||= YAML.load_file(GiactVerification.config_directory + '/alternative_id_types.yml')
42
+ end
43
+
44
+ def serviced_states
45
+ @serviced_states ||= YAML.load_file(GiactVerification.config_directory + '/serviced_states.yml')
46
+ end
47
+
48
+ def serviced_countries
49
+ @serviced_countries ||= YAML.load_file(GiactVerification.config_directory + '/serviced_countries.yml')
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,22 @@
1
+ module GiactVerification
2
+ class DecorateHash
3
+
4
+ def self.call(args)
5
+ new(args).call
6
+ end
7
+
8
+ def initialize(args)
9
+ @input = args[:hashable].to_h
10
+ @decorator = args.fetch(:decorator, GiactVerification::GiactSoapDecorator)
11
+ end
12
+
13
+ def call
14
+ input.map do |key, value|
15
+ decorator.call(key: key, value: value)
16
+ end.to_h
17
+ end
18
+
19
+ private
20
+ attr_reader :input, :decorator
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+ module GiactVerification
2
+ class GiactSoapDecorator
3
+
4
+ KEYS_TO_UPCASE = [:state, :drivers_license_state, :country]
5
+
6
+ def self.call(args)
7
+ new(args).call
8
+ end
9
+
10
+ def initialize(args)
11
+ @key = args[:key]
12
+ @value = args[:value]
13
+ end
14
+
15
+ def call
16
+ [key, modified_value]
17
+ end
18
+
19
+ private
20
+ attr_reader :key, :value
21
+
22
+ def modified_value
23
+ if value.methods.include?(:strftime)
24
+ value.strftime('%Y-%m-%d')
25
+ elsif KEYS_TO_UPCASE.include?(key)
26
+ value.upcase
27
+ else
28
+ value.to_s
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,7 @@
1
+ module GiactVerification
2
+ class ArgumentError < RuntimeError; end
3
+ class ConfigurationError < RuntimeError; end
4
+ class HTTPError < StandardError;end;
5
+ class MalformedXmlError < StandardError;end;
6
+ class GiactXmlError < StandardError;end;
7
+ end
@@ -0,0 +1,10 @@
1
+ - UsaMilitaryId
2
+ - UsaStateId
3
+ - PassportUsa
4
+ - PassportForeign
5
+ - UsaResidentAlienId
6
+ - StudentId
7
+ - TribalId
8
+ - DlCanada
9
+ - DlMexico
10
+ - OtherForeignId
@@ -0,0 +1,11 @@
1
+ en:
2
+ errors:
3
+ valid_account_type?:
4
+ arg:
5
+ default: 'Must be a valid account type (Checking, Savings or Other)'
6
+ routing_number_length?:
7
+ arg:
8
+ default: 'length must be 9 digits with no dashes or whitespace'
9
+ account_number_length?:
10
+ arg:
11
+ default: 'length must be between 4 and 17 digits with no dashes or whitespace'
@@ -0,0 +1,35 @@
1
+ en:
2
+ errors:
3
+ serviced_state?:
4
+ arg:
5
+ default: 'must be a serviced US state or Canadian province (this includes all US states or CA provinces)'
6
+ serviced_country?:
7
+ arg:
8
+ default: 'must be a serviced country (US or CA)'
9
+ postal_code?:
10
+ arg:
11
+ default: 'must be a valid US (5 or 10 digit) or Canadian (7 digit) zip/postal code with no dashes or white space'
12
+ phone_number_length?:
13
+ arg:
14
+ default: 'length must be 10 digits with no dashes or whitespace'
15
+ phone_number_format?:
16
+ arg:
17
+ default: 'length must be 10 digits with 1-9 as the first digit (matching this regex: /[1-9][0-9]{9}/)'
18
+ last_four_ssn_length?:
19
+ arg:
20
+ default: 'length must be 4 digits with no dashes or white space'
21
+ ssn_or_ein_length?:
22
+ arg:
23
+ default: 'length must be 9 digits with no dashes or white space'
24
+ respond_to_strftime?:
25
+ arg:
26
+ default: "must be an object that responds to the method ':strftime'"
27
+ drivers_license_length?:
28
+ arg:
29
+ default: "length must be between 1-28 characters"
30
+ accepted_alternative_id?:
31
+ arg:
32
+ default: "id type must be one of the accepted alternative ids (UsaMilitaryId, UsaStateId, PassportUsa, PassportForeign, UsaResidentAlienId, StudentId, TribalId, DlCanada, DlMexico, or OtherForeignId)"
33
+ alternative_id_number_length?:
34
+ arg:
35
+ default: "length must be between 1 and 50 digits"
@@ -0,0 +1,2 @@
1
+ - US
2
+ - CA
@@ -0,0 +1,78 @@
1
+ # CANADA
2
+ - 'AB'
3
+ - 'BC'
4
+ - 'MB'
5
+ - 'NB'
6
+ - 'NL'
7
+ - 'NS'
8
+ - 'NU'
9
+ - 'ON'
10
+ - 'PE'
11
+ - 'QC'
12
+ - 'SK'
13
+ - 'NT'
14
+ - 'YT'
15
+
16
+ #UNITED STATES
17
+ - 'AA'
18
+ - 'AE'
19
+ - 'AK'
20
+ - 'AL'
21
+ - 'AP'
22
+ - 'AR'
23
+ - 'AS'
24
+ - 'AZ'
25
+ - 'CA'
26
+ - 'CO'
27
+ - 'CT'
28
+ - 'DC'
29
+ - 'DE'
30
+ - 'FL'
31
+ - 'FM'
32
+ - 'GA'
33
+ - 'GU'
34
+ - 'HI'
35
+ - 'IA'
36
+ - 'ID'
37
+ - 'IL'
38
+ - 'IN'
39
+ - 'KS'
40
+ - 'KY'
41
+ - 'LA'
42
+ - 'MA'
43
+ - 'MD'
44
+ - 'ME'
45
+ - 'MH'
46
+ - 'MI'
47
+ - 'MN'
48
+ - 'MO'
49
+ - 'MP'
50
+ - 'MS'
51
+ - 'MT'
52
+ - 'NC'
53
+ - 'ND'
54
+ - 'NE'
55
+ - 'NH'
56
+ - 'NJ'
57
+ - 'NM'
58
+ - 'NV'
59
+ - 'NY'
60
+ - 'OH'
61
+ - 'OK'
62
+ - 'OR'
63
+ - 'PA'
64
+ - 'PR'
65
+ - 'PW'
66
+ - 'RI'
67
+ - 'SC'
68
+ - 'SD'
69
+ - 'TN'
70
+ - 'TX'
71
+ - 'UT'
72
+ - 'VA'
73
+ - 'VI'
74
+ - 'VT'
75
+ - 'WA'
76
+ - 'WV'
77
+ - 'WI'
78
+ - 'WY'
@@ -0,0 +1,4 @@
1
+ - Checking
2
+ - Savings
3
+ - Other
4
+
@@ -0,0 +1,26 @@
1
+ module GiactVerification
2
+ class ExtractInquiryResult
3
+
4
+ def self.call(args)
5
+ new(args).call
6
+ end
7
+
8
+ def initialize(args)
9
+ @xml = args[:xml]
10
+ @hash = GiactVerification::XmlToHash.call(xml: xml)
11
+ end
12
+
13
+ def call
14
+ @inquiry_result = hash.dig(:'soap:envelope', :'soap:body', :post_inquiry_response, :post_inquiry_result)
15
+
16
+ if inquiry_result == nil
17
+ raise MalformedXmlError, xml
18
+ end
19
+
20
+ inquiry_result
21
+ end
22
+
23
+ private
24
+ attr_reader :xml, :hash, :inquiry_result
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ require 'erb'
2
+
3
+ module GiactVerification
4
+ class InquiryTemplateRenderer
5
+
6
+ def self.call(args)
7
+ new(args).call
8
+ end
9
+
10
+ def initialize(args)
11
+ @substitutions = args[:substitutions]
12
+ @filepath = GiactVerification.inquiry_template_directory
13
+ end
14
+
15
+ def call
16
+ ERB.new(template_contents, nil, '>').result(binding)
17
+ end
18
+
19
+ private
20
+ attr_reader :substitutions, :filepath, :rendered_template
21
+
22
+ def template_contents
23
+ File.read(filepath)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ require 'ostruct'
2
+
3
+ module GiactVerification
4
+ class Check < OpenStruct
5
+
6
+ def initialize(args)
7
+ @attributes = args[:attributes]
8
+ @validation_class = args[:validation_class] || CheckValidator
9
+
10
+ super(attributes)
11
+ end
12
+
13
+ def invalid?
14
+ validator.failure?
15
+ end
16
+
17
+ def errors
18
+ validator.messages
19
+ end
20
+
21
+ def decorate_for_xml
22
+ GiactVerification::DecorateHash.call(hashable: self)
23
+ end
24
+
25
+ private
26
+ attr_reader :validation_class, :attributes
27
+
28
+ def validator
29
+ @validator ||= validation_class.call(self.to_h)
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,33 @@
1
+ require 'ostruct'
2
+
3
+ module GiactVerification
4
+ class Customer < OpenStruct
5
+
6
+ def initialize(args)
7
+ @attributes = args[:attributes]
8
+ @validation_class = args[:validation_class] || CustomerValidator
9
+
10
+ super(attributes)
11
+ end
12
+
13
+ def invalid?
14
+ validator.failure?
15
+ end
16
+
17
+ def errors
18
+ validator.messages
19
+ end
20
+
21
+ def decorate_for_xml
22
+ GiactVerification::DecorateHash.call(hashable: self)
23
+ end
24
+
25
+ private
26
+ attr_reader :validation_class, :attributes
27
+
28
+ def validator
29
+ @validator ||= validation_class.call(self.to_h)
30
+ end
31
+ end
32
+ end
33
+
@@ -0,0 +1,28 @@
1
+ module GiactVerification
2
+ class GiactXml
3
+
4
+ def initialize(args)
5
+ @xml = args[:xml]
6
+ @validator = args[:validator] || GiactVerification::GiactXmlValidator
7
+ end
8
+
9
+ def valid?
10
+ @valid ||= validator.call(xml: xml)
11
+ end
12
+
13
+ def inquiry_result
14
+ if invalid?
15
+ raise GiactVerification::GiactXmlError, 'Cannot retrieve inquiry result from invalid xml'
16
+ else
17
+ @inquiry_result ||= GiactVerification::ExtractInquiryResult.call(xml: xml)
18
+ end
19
+ end
20
+
21
+ private
22
+ attr_reader :xml, :validator
23
+
24
+ def invalid?
25
+ !valid?
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+
4
+ module GiactVerification
5
+ class ProductionRequester
6
+
7
+ PRODUCTION_URI = URI.parse('https://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 = PRODUCTION_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