callcredit 0.3.8 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1213865aa7687c9adfd222ffeed8c2e1e6a76ccd
4
- data.tar.gz: 2e1265299afc2b3198eb4c1c0c07da6e809dd6fe
3
+ metadata.gz: a36f71d745577cbb7014548b3bfb274aaf08daec
4
+ data.tar.gz: 54086f749c30f37c3055298450d4ec4988f5f1e2
5
5
  SHA512:
6
- metadata.gz: 88f56e2dce84202fdaed7891de549f8e6c4d89400c6c6b1718efe717fc50368f7ef990ccd9a066ff5568f69388db2a6e9020e38b0e06f732bc1d4cb0581f4259
7
- data.tar.gz: 321382da4b9e994eeb5c702c166ff78a8372e5bfb3d640b17a6d8dc596339427c1d507354f87e437bf0945b6021ea5f9cd53887762a2faf4e0bbd8f90e2ba80f
6
+ metadata.gz: adf512665d1906b25a37cb658b39875d680360a6465f9e7f256e4a7e6f6ec568ed2d7841734c0874db2ba355f3330f866aa7facdcb856382e08f6d291c9e535b
7
+ data.tar.gz: 8a597828c0501da6782c48813f59abaddf82f66da96d2897059fef7a640ebf01cb7354389f43feb1a1b5784d512e92466a50861ac2cd07ddde199a00f938f9f3
@@ -0,0 +1,41 @@
1
+ # For all options see https://github.com/bbatsov/rubocop/tree/master/config
2
+
3
+ inherit_from: .rubocop_todo.yml
4
+
5
+ AllCops:
6
+ Exclude:
7
+ - bin/*
8
+
9
+ LineLength:
10
+ Max: 80
11
+
12
+ ClassLength:
13
+ Enabled: false
14
+
15
+ # Avoid methods longer than 30 lines of code
16
+ MethodLength:
17
+ CountComments: false # count full line comments?
18
+ Max: 87
19
+
20
+ # Avoid single-line methods.
21
+ SingleLineMethods:
22
+ AllowIfMethodIsEmpty: true
23
+
24
+ StringLiterals:
25
+ Enabled: false
26
+
27
+ GlobalVars:
28
+ Enabled: false
29
+
30
+ # Wants underscores in all large numbers. Pain in the ass for things like
31
+ # unix timestamps.
32
+ NumericLiterals:
33
+ Enabled: false
34
+
35
+ # Wants you to use the same argument names for every reduce. This seems kinda
36
+ # naff compared to naming them semantically
37
+ SingleLineBlockParams:
38
+ Enabled: false
39
+
40
+ Style/SignalException:
41
+ EnforcedStyle: 'only_raise'
@@ -0,0 +1,154 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2014-10-30 22:45:17 +0000 using RuboCop version 0.27.0.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
7
+
8
+ # Offense count: 27
9
+ # Cop supports --auto-correct.
10
+ Lint/UnusedBlockArgument:
11
+ Enabled: false
12
+
13
+ # Offense count: 128
14
+ Metrics/AbcSize:
15
+ Max: 64
16
+
17
+ # Offense count: 9
18
+ Metrics/CyclomaticComplexity:
19
+ Max: 10
20
+
21
+ # Offense count: 5
22
+ Metrics/PerceivedComplexity:
23
+ Max: 10
24
+
25
+ # Offense count: 17
26
+ Style/AccessorMethodName:
27
+ Enabled: false
28
+
29
+ # Offense count: 64
30
+ # Cop supports --auto-correct.
31
+ # Configuration parameters: EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle, SupportedLastArgumentHashStyles.
32
+ Style/AlignHash:
33
+ Enabled: false
34
+
35
+ # Offense count: 72
36
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
37
+ Style/ClassAndModuleChildren:
38
+ Enabled: false
39
+
40
+ # Offense count: 16
41
+ # Configuration parameters: Keywords.
42
+ Style/CommentAnnotation:
43
+ Enabled: false
44
+
45
+ # Offense count: 336
46
+ Style/Documentation:
47
+ Enabled: false
48
+
49
+ # Offense count: 1285
50
+ # Cop supports --auto-correct.
51
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
52
+ Style/DotPosition:
53
+ Enabled: false
54
+
55
+ # Offense count: 6
56
+ Style/DoubleNegation:
57
+ Enabled: false
58
+
59
+ # Offense count: 11
60
+ Style/EachWithObject:
61
+ Enabled: false
62
+
63
+ # Offense count: 92
64
+ # Configuration parameters: MinBodyLength.
65
+ Style/GuardClause:
66
+ Enabled: false
67
+
68
+ # Offense count: 24
69
+ # Cop supports --auto-correct.
70
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
71
+ Style/IndentHash:
72
+ Enabled: false
73
+
74
+ # Offense count: 60
75
+ Style/Lambda:
76
+ Enabled: false
77
+
78
+ # Offense count: 141
79
+ # Cop supports --auto-correct.
80
+ Style/LineEndConcatenation:
81
+ Enabled: false
82
+
83
+ # Offense count: 3
84
+ # Cop supports --auto-correct.
85
+ Style/MethodCallParentheses:
86
+ Enabled: false
87
+
88
+ Style/ModuleFunction:
89
+ Enabled: false
90
+
91
+ # Offense count: 449
92
+ # Cop supports --auto-correct.
93
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
94
+ Style/MultilineOperationIndentation:
95
+ Enabled: false
96
+
97
+ # Offense count: 4
98
+ # Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
99
+ Style/Next:
100
+ Enabled: false
101
+
102
+ # Offense count: 11
103
+ # Configuration parameters: NamePrefix, NamePrefixBlacklist.
104
+ Style/PredicateName:
105
+ Enabled: false
106
+
107
+ # Offense count: 5
108
+ # Cop supports --auto-correct.
109
+ Style/Proc:
110
+ Enabled: false
111
+
112
+ # Offense count: 9
113
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
114
+ Style/RaiseArgs:
115
+ Enabled: false
116
+
117
+ # Offense count: 5
118
+ # Cop supports --auto-correct.
119
+ # Configuration parameters: AllowMultipleReturnValues.
120
+ Style/RedundantReturn:
121
+ Enabled: false
122
+
123
+ # Offense count: 177
124
+ # Cop supports --auto-correct.
125
+ Style/RedundantSelf:
126
+ Enabled: false
127
+
128
+ # Offense count: 17
129
+ # Cop supports --auto-correct.
130
+ Style/SingleSpaceBeforeFirstArg:
131
+ Enabled: false
132
+
133
+ # Offense count: 87
134
+ # Cop supports --auto-correct.
135
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
136
+ Style/StringLiteralsInInterpolation:
137
+ Enabled: false
138
+
139
+ # Offense count: 53
140
+ # Cop supports --auto-correct.
141
+ # Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
142
+ Style/TrailingComma:
143
+ Enabled: false
144
+
145
+ # Offense count: 8
146
+ # Cop supports --auto-correct.
147
+ # Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, Whitelist.
148
+ Style/TrivialAccessors:
149
+ Enabled: false
150
+
151
+ # Offense count: 1
152
+ # Cop supports --auto-correct.
153
+ Style/WhileUntilDo:
154
+ Enabled: false
@@ -1,6 +1,13 @@
1
+ ## 0.4.0 - December 31, 2014
2
+
3
+ - Add support for BankStandard and BankEnhanced checks
4
+ - Tweak `Callcredit::Response#result` to support multiple kinds of check (i.e. not just
5
+ identity checks)
6
+ - Enforce code style with Rubocop
7
+
1
8
  ## 0.3.8 - July 16, 2014
2
9
 
3
- - Include requiest ID (RID) on all requests
10
+ - Include request ID (RID) on all requests
4
11
 
5
12
  ## 0.3.7 - June 3, 2014
6
13
 
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Grey Baker
1
+ Copyright (c) 2014 GoCardless
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person
4
4
  obtaining a copy of this software and associated documentation
data/README.md CHANGED
@@ -45,7 +45,30 @@ The library will raise an error if you're missing any of the required
45
45
  parameters (first_name, last_name, date_of_birth, building_number and
46
46
  postcode).
47
47
 
48
+ #### BankStandard check
49
+
50
+ To perform a BankStandard check use:
51
+
52
+ ```ruby
53
+ Callcredit.bank_standard_check(account_number: "44779911", sort_code: "200000")
54
+ ```
55
+
56
+ The library will raise an error unless you provide both account_number and sort_code.
57
+
58
+ #### BankEnhanced check
59
+
60
+ To perform a BankEnhanced check use:
61
+
62
+ ```ruby
63
+ Callcredit.bank_enhanced_check(first_name: "Tim", last_name: "Rogers", postcode: "EC1V 7LQ", account_number: "44779911", sort_code: "200000", building_number: "338-346")
64
+ ```
65
+
66
+ The library will raise an error if you're missing any of the required
67
+ parameters (first_name, last_name, building_number, postcode, account_number
68
+ and sort_code).
69
+
48
70
  #### Other checks
71
+
49
72
  For any other check, simply pass the name of the check you'd like to perform
50
73
  into the `perform_check` method, along with details of the individual you're
51
74
  checking.
@@ -63,11 +86,6 @@ data_hash = { personal_data: { first_name: "Grey", last_name: "Baker" } }
63
86
  Callcredit.perform_check([:id_enhanced, :credit_score], data_hash)
64
87
  ```
65
88
 
66
- NOTE: Currently, this gem only supports checks on the payer's personal
67
- information (other information won't be passed through to Callcredit).
68
- Extending the gem should be trivial if Callcredit have given you access to
69
- other checks.
70
-
71
89
  ### Parsing responses
72
90
 
73
91
  Unless you've set the "raw" argument to true in your config, checks called by
@@ -80,7 +98,8 @@ Callcredit.id_enhanced_check(...) # => Callcredit::Response
80
98
  Callcredit.id_enhanced_check(...).input # => Hash of input params, as
81
99
  # returned by Callcredit
82
100
 
83
- Callcredit.id_enhanced_check(...).result # => Hash of results
101
+ Callcredit.id_enhanced_check(...).result # => Hash of results, mapping
102
+ # a check type to its results
84
103
 
85
104
  Callcredit.id_enhanced_check(...).full_result # => Hash of the full XML body
86
105
  # returned by Callcredit
@@ -10,13 +10,13 @@ Gem::Specification.new do |gem|
10
10
  gem.add_development_dependency 'webmock', '~> 1.18.0'
11
11
 
12
12
  gem.authors = ['Grey Baker']
13
- gem.description = %q{Ruby wrapper for Callcredit's CallValidate API}
13
+ gem.description = "Ruby wrapper for Callcredit's CallValidate API"
14
14
  gem.email = ['grey@gocardless.com']
15
15
  gem.files = `git ls-files`.split("\n")
16
16
  gem.homepage = 'https://github.com/gocardless/callcredit-ruby'
17
17
  gem.name = 'callcredit'
18
18
  gem.require_paths = ['lib']
19
- gem.summary = %q{Ruby wrapper for Callcredit's CallValidate API}
19
+ gem.summary = "Ruby wrapper for Callcredit's CallValidate API"
20
20
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
21
  gem.version = Callcredit::VERSION.dup
22
22
  end
@@ -11,6 +11,8 @@ require 'callcredit/validations'
11
11
  require 'callcredit/client'
12
12
  require 'callcredit/response'
13
13
  require 'callcredit/checks/id_enhanced'
14
+ require 'callcredit/checks/bank_standard'
15
+ require 'callcredit/checks/bank_enhanced'
14
16
  require 'callcredit/middleware/check_response'
15
17
 
16
18
  # Errors
@@ -28,6 +30,14 @@ module Callcredit
28
30
  client.id_enhanced_check(*args)
29
31
  end
30
32
 
33
+ def self.bank_standard_check(*args)
34
+ client.bank_standard_check(*args)
35
+ end
36
+
37
+ def self.bank_enhanced_check(*args)
38
+ client.bank_enhanced_check(*args)
39
+ end
40
+
31
41
  def self.perform_check(*args)
32
42
  client.perform_check(*args)
33
43
  end
@@ -49,4 +59,3 @@ module Callcredit
49
59
  end
50
60
  private_class_method :client
51
61
  end
52
-
@@ -0,0 +1,49 @@
1
+ module Callcredit
2
+ module Checks
3
+ class BankEnhanced
4
+ REQUIRED_INPUTS = [:first_name, :last_name, :postcode, :account_number,
5
+ :sort_code, :account_number, :sort_code]
6
+
7
+ PERSONAL_DATA_KEYS = [:first_name, :last_name, :postcode,
8
+ :building_name, :building_number]
9
+
10
+ BANK_DATA_KEYS = [:account_number, :sort_code]
11
+
12
+ def initialize(client)
13
+ @client = client
14
+ end
15
+
16
+ def perform(data = {})
17
+ check_params(data)
18
+ response = @client.perform_check([:bank_standard, :bank_enhanced],
19
+ build_params(data))
20
+
21
+ @client.config[:raw] ? response : Response.new(response)
22
+ end
23
+
24
+ private
25
+
26
+ def build_params(data)
27
+ {
28
+ personal_data: data.select { |k, v| PERSONAL_DATA_KEYS.include?(k) },
29
+ bank_data: data.select { |k, v| BANK_DATA_KEYS.include?(k) }
30
+ }
31
+ end
32
+
33
+ def check_params(data)
34
+ REQUIRED_INPUTS.each do |param|
35
+ if data[param].nil?
36
+ msg = "An BankEnhanced check requires a #{param}"
37
+ raise InvalidRequestError.new(msg, param)
38
+ end
39
+ end
40
+
41
+ # For a BankEnhanced check, we also need a building name or number
42
+ unless data[:building_number] || data[:building_name]
43
+ msg = "A BankEnhanced check requires a building number or name"
44
+ raise InvalidRequestError.new(msg, :building_number)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,28 @@
1
+ module Callcredit
2
+ module Checks
3
+ class BankStandard
4
+ REQUIRED_INPUTS = [:account_number, :sort_code]
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def perform(data = {})
11
+ check_params(data)
12
+ response = @client.perform_check(:bank_standard, bank_data: data)
13
+ @client.config[:raw] ? response : Response.new(response)
14
+ end
15
+
16
+ private
17
+
18
+ def check_params(data)
19
+ REQUIRED_INPUTS.each do |param|
20
+ if data[param].nil?
21
+ msg = "An BankStandard check requires a #{param}"
22
+ raise InvalidRequestError.new(msg, param)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -23,7 +23,7 @@ module Callcredit
23
23
  end
24
24
  end
25
25
 
26
- # For and ID Enhanced check, we also need a building name or number
26
+ # For an ID Enhanced check, we also need a building name or number
27
27
  unless data[:building_number] || data[:building_name]
28
28
  msg = "An IDEnhanced check requires a building number or name"
29
29
  raise InvalidRequestError.new(msg, :building_number)
@@ -1,9 +1,19 @@
1
1
  module Callcredit
2
2
  class Client
3
- def initialize(config=nil)
3
+ def initialize(config = nil)
4
4
  @config = (config || Callcredit.config).clone
5
5
  end
6
6
 
7
+ def bank_standard_check(check_data)
8
+ check = Checks::BankStandard.new(self)
9
+ check.perform(check_data)
10
+ end
11
+
12
+ def bank_enhanced_check(check_data)
13
+ check = Checks::BankEnhanced.new(self)
14
+ check.perform(check_data)
15
+ end
16
+
7
17
  def id_enhanced_check(check_data)
8
18
  check = Checks::IDEnhanced.new(self)
9
19
  check.perform(check_data)
@@ -7,7 +7,8 @@ module Callcredit
7
7
  password: nil,
8
8
  application_name: nil,
9
9
  raw: false,
10
- api_endpoint: "https://ct.callcreditsecure.co.uk/callvalidateapi/incomingserver.php",
10
+ api_endpoint: "https://ct.callcreditsecure.co.uk/callvalidateapi/" \
11
+ "incomingserver.php",
11
12
  user_agent: "Callcredit Ruby Gem #{Callcredit::VERSION}".freeze
12
13
  }.freeze
13
14
 
@@ -25,8 +26,7 @@ module Callcredit
25
26
  end
26
27
 
27
28
  def clone
28
- Config.new { |config| @config.each { |k,v| config[k] = v } }
29
+ Config.new { |config| @config.each { |k, v| config[k] = v } }
29
30
  end
30
31
  end
31
32
  end
32
-
@@ -47,5 +47,10 @@ module Callcredit
47
47
  delivery_town: "Deliverytown",
48
48
  delivery_postcode: "Deliverypostcode"
49
49
  }
50
+
51
+ BANK_DETAILS = {
52
+ account_number: "Bankaccountnumber",
53
+ sort_code: "Banksortcode"
54
+ }
50
55
  end
51
- end
56
+ end
@@ -2,12 +2,16 @@ module Callcredit
2
2
  class CallcreditError < StandardError
3
3
  attr_reader :message
4
4
  attr_reader :status
5
- attr_reader :response_body
5
+ attr_reader :response
6
6
 
7
- def initialize(message=nil, status=nil, response=nil)
7
+ def initialize(message = nil, status = nil, response = nil)
8
8
  @message = message
9
9
  @status = status
10
- @response_body = response_body
10
+ @response = response
11
+ end
12
+
13
+ def response_body
14
+ response.fetch(:body, nil) if response.responds_to?(:fetch)
11
15
  end
12
16
 
13
17
  def to_s
@@ -1,9 +1,9 @@
1
1
  module Callcredit
2
2
  class InvalidRequestError < CallcreditError
3
- attr_accessor :param
3
+ attr_reader :param
4
4
 
5
- def initialize(message, param, status=nil, response_body=nil)
6
- super(message, status, response_body)
5
+ def initialize(message, param, status = nil, response = nil)
6
+ super(message, status, response)
7
7
  @param = param
8
8
  end
9
9
  end
@@ -2,18 +2,22 @@ module Callcredit
2
2
  module Middleware
3
3
  class CheckResponse < Faraday::Middleware
4
4
  def call(env)
5
- @app.call(env).on_complete do |env|
6
- unless results = env[:body]["Results"]
5
+ @app.call(env).on_complete do |completed_env|
6
+ results = completed_env[:body]["Results"]
7
+
8
+ unless results
7
9
  raise InvalidResponseError.new(
8
- "Invalid response", env[:status], env)
10
+ "Invalid response", completed_env[:status], completed_env)
9
11
  end
10
12
 
11
13
  if results["Errors"]
12
14
  errors = results["Errors"].values.flatten
13
15
  messages = errors.map { |e| e.is_a?(Hash) ? e["__content__"] : e }
14
- raise APIError.new(messages.join(" | "), env[:status], env)
16
+
17
+ raise APIError.new(messages.join(" | "), completed_env[:status],
18
+ completed_env)
15
19
  end
16
- response_values(env)
20
+ response_values(completed_env)
17
21
  end
18
22
  end
19
23
 
@@ -22,7 +22,7 @@ module Callcredit
22
22
  end
23
23
 
24
24
  # Compile the complete XML request to send to Callcredit
25
- def build_request_xml(checks, check_data={})
25
+ def build_request_xml(checks, check_data = {})
26
26
  builder = Nokogiri::XML::Builder.new do |xml|
27
27
  xml.callvalidate do
28
28
  authentication(xml)
@@ -66,9 +66,11 @@ module Callcredit
66
66
  end
67
67
 
68
68
  def personal_data(xml, data)
69
+ return unless data
70
+
69
71
  unless data.is_a? Hash
70
72
  raise InvalidRequestError.new(
71
- "All checks require personal_data", :personal_data)
73
+ "Personal data must be a hash (if provided)", :personal_data)
72
74
  end
73
75
 
74
76
  xml.Personalinformation do
@@ -87,15 +89,27 @@ module Callcredit
87
89
  end
88
90
  end
89
91
 
90
- def card_data(xml, data)
92
+ def card_data(_xml, _data)
91
93
  # Not implemented
92
94
  end
93
95
 
94
96
  def bank_data(xml, data)
95
- # Not implemented
97
+ return unless data
98
+
99
+ unless data.is_a? Hash
100
+ raise InvalidRequestError.new(
101
+ "Bank data must be a hash (if provided)", :bank_data)
102
+ end
103
+
104
+ xml.Bankinformation do
105
+ Constants::BANK_DETAILS.each do |param, element_name|
106
+ value = Validations.clean_param(param, data[param])
107
+ xml.send(element_name, value) if value
108
+ end
109
+ end
96
110
  end
97
111
 
98
- def income_data(xml, data)
112
+ def income_data(_xml, _data)
99
113
  # Not implemented
100
114
  end
101
115
  end
@@ -17,7 +17,8 @@ module Callcredit
17
17
  end
18
18
 
19
19
  def result
20
- @response_data["Results"]["Result"]["Displays"]["IdentityCheck"]
20
+ @response_data["Results"]["Result"]["Displays"].
21
+ reject { |k, v| displays_excluded_from_results.include?(k) }
21
22
  end
22
23
 
23
24
  def warnings
@@ -27,5 +28,11 @@ module Callcredit
27
28
  def full_result
28
29
  @response_data
29
30
  end
31
+
32
+ private
33
+
34
+ def displays_excluded_from_results
35
+ %w(ChecksCompleted InputData Warnings InternalUse)
36
+ end
30
37
  end
31
38
  end
@@ -7,10 +7,10 @@ module Callcredit
7
7
  end
8
8
 
9
9
  def underscore(str)
10
- str.to_s.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
11
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
10
+ str.to_s.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
11
+ gsub(/([a-z\d])([A-Z])/, '\1_\2').
12
12
  tr("-", "_").
13
13
  downcase
14
14
  end
15
15
  end
16
- end
16
+ end
@@ -1,19 +1,19 @@
1
1
  module Callcredit
2
2
  module Validations
3
-
4
3
  VALIDATIONS = {
5
- date_of_birth: ->(value) { clean_date_of_birth(value) },
6
- title: ->(value) { value || "Unknown" },
7
- first_name: ->(value) { clean_name(value, :first_name) },
8
- last_name: ->(value) { clean_name(value, :last_name) },
9
- middle_names: ->(value) { clean_name(value, :middle_names) },
10
- postcode: ->(value) { clean_postcode(value, :postcode) },
11
- previous_postcode: ->(value) { clean_postcode(value, :previous_postcode) },
12
- delivery_postcode: ->(value) { clean_postcode(value, :delivery_postcode) }
4
+ date_of_birth: ->(val) { clean_date_of_birth(val) },
5
+ title: ->(val) { val || "Unknown" },
6
+ first_name: ->(val) { clean_name(val, :first_name) },
7
+ last_name: ->(val) { clean_name(val, :last_name) },
8
+ middle_names: ->(val) { clean_name(val, :middle_names) },
9
+ postcode: ->(val) { clean_postcode(val, :postcode) },
10
+ previous_postcode: ->(val) { clean_postcode(val, :previous_postcode) },
11
+ account_number: ->(val) { clean_account_number(val) },
12
+ sort_code: ->(val) { clean_sort_code(val) },
13
13
  }
14
14
 
15
15
  def self.clean_param(key, value)
16
- validator = VALIDATIONS.fetch(key, ->(value){ value })
16
+ validator = VALIDATIONS.fetch(key, ->(val) { val })
17
17
  validator.call(value)
18
18
  end
19
19
 
@@ -28,7 +28,7 @@ module Callcredit
28
28
  def self.clean_name(name, param)
29
29
  return unless name
30
30
  # Convert name to ASCII characters only
31
- name = UnicodeUtils.nfkd(name).gsub(/(\p{Letter})\p{Mark}+/,'\\1')
31
+ name = UnicodeUtils.nfkd(name).gsub(/(\p{Letter})\p{Mark}+/, '\\1')
32
32
  input_error(param, name) unless name =~ /\A[a-z A-Z'-]{1,30}\z/
33
33
  name
34
34
  end
@@ -40,13 +40,30 @@ module Callcredit
40
40
  postcode
41
41
  end
42
42
 
43
- def self.input_error(param, value=nil)
44
- msg = if value.nil?
45
- "#{param} is a required param"
46
- else
47
- %{Invalid value "#{value}" for #{param}}
43
+ def self.clean_account_number(account_number)
44
+ return unless account_number
45
+ cleaned_value = account_number.to_s.gsub(/[-\s]/, '')
46
+ unless cleaned_value =~ /\A\d{6,8}\z/
47
+ input_error(:account_number, account_number)
48
48
  end
49
+ cleaned_value
50
+ end
51
+
52
+ def self.clean_sort_code(sort_code)
53
+ return unless sort_code
54
+ cleaned_value = sort_code.to_s.gsub(/[-\s]/, '')
55
+ input_error(:sort_code, sort_code) unless cleaned_value =~ /\A\d{6}\z/
56
+ cleaned_value
57
+ end
58
+
59
+ def self.input_error(param, value = nil)
60
+ msg = if value.nil?
61
+ "#{param} is a required param"
62
+ else
63
+ "Invalid value \"#{value}\" for #{param}"
64
+ end
65
+
49
66
  raise InvalidRequestError.new(msg, param)
50
67
  end
51
68
  end
52
- end
69
+ end
@@ -1,3 +1,3 @@
1
1
  module Callcredit
2
- VERSION = '0.3.8'.freeze
2
+ VERSION = '0.4.0'.freeze
3
3
  end
@@ -10,7 +10,7 @@ describe Callcredit do
10
10
  before { Callcredit.configure { |config| config[key] = key } }
11
11
 
12
12
  describe [key] do
13
- subject { super()[key] }
13
+ subject { Callcredit.config[key] }
14
14
  it { should == key }
15
15
  end
16
16
  end
@@ -36,6 +36,28 @@ describe Callcredit do
36
36
  end
37
37
  end
38
38
 
39
+ describe '#bank_standard_check' do
40
+ before { configure_callcredit }
41
+ let(:data) { { account_number: "44779911", sort_code: "200000" } }
42
+
43
+ it "delegates to the client" do
44
+ expect_any_instance_of(Callcredit::Client).
45
+ to receive(:bank_standard_check).with(data)
46
+ Callcredit.bank_standard_check(data)
47
+ end
48
+ end
49
+
50
+ describe '#bank_enhanced_check' do
51
+ before { configure_callcredit }
52
+ let(:data) { { first_name: "Grey", last_name: "Baker" } }
53
+
54
+ it "delegates to the client" do
55
+ expect_any_instance_of(Callcredit::Client).
56
+ to receive(:bank_enhanced_check).with(data)
57
+ Callcredit.bank_enhanced_check(data)
58
+ end
59
+ end
60
+
39
61
  describe '#perform_check' do
40
62
  before { configure_callcredit }
41
63
  let(:data) do
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe Callcredit::Checks::BankEnhanced do
4
+ let(:bank_enhanced_check) { Callcredit::Checks::BankEnhanced.new(client) }
5
+ let(:client) { Callcredit::Client.new(config) }
6
+ let(:config) { Callcredit::Config.new }
7
+
8
+ let(:response_hash) { { status: status, body: body } }
9
+ let(:status) { 200 }
10
+ let(:body) { response_xml }
11
+ let(:response_xml) { load_fixture('response.xml') }
12
+ before { stub_request(:get, config[:api_endpoint]).to_return(response_hash) }
13
+
14
+ describe "#perform" do
15
+ subject(:perform_check) { bank_enhanced_check.perform(check_data) }
16
+
17
+ let(:check_data) do
18
+ { first_name: "Grey",
19
+ last_name: "Baker",
20
+ postcode: "EC2A 1DX",
21
+ building_number: "22-25",
22
+ sort_code: "200000",
23
+ account_number: "44779911" }
24
+ end
25
+
26
+ it "separates the supplied data into personal and bank details" do
27
+ expect(client).to receive(:perform_check) do |check_types, data|
28
+ expect(data[:personal_data][:postcode]).to eq(check_data[:postcode])
29
+ expect(data[:bank_data][:sort_code]).to eq(check_data[:sort_code])
30
+ end
31
+
32
+ perform_check
33
+ end
34
+
35
+ it "makes a get request" do
36
+ perform_check
37
+ expect(a_request(:get, config[:api_endpoint])).to have_been_made
38
+ end
39
+
40
+ it { is_expected.to be_a Callcredit::Response }
41
+
42
+ context "when the config[:raw] is true" do
43
+ before { config[:raw] = true }
44
+ it { is_expected.to be_a Faraday::Response }
45
+
46
+ describe '#body' do
47
+ subject { perform_check.body }
48
+ it { should be_a String }
49
+ end
50
+ end
51
+
52
+ describe "validates inputs" do
53
+ it_behaves_like "it validates presence", :first_name
54
+ it_behaves_like "it validates presence", :last_name
55
+ it_behaves_like "it validates presence", :postcode
56
+ it_behaves_like "it validates presence", :building_number
57
+ it_behaves_like "it validates presence", :account_number
58
+ it_behaves_like "it validates presence", :sort_code
59
+
60
+ context "with a building_name instead of building number" do
61
+ before { check_data.delete(:building_number) }
62
+ before { check_data[:building_name] = "The Mill" }
63
+
64
+ it "makes a get request" do
65
+ perform_check
66
+ expect(a_request(:get, config[:api_endpoint])).to have_been_made
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe Callcredit::Checks::BankStandard do
4
+ let(:bank_standard_check) { Callcredit::Checks::BankStandard.new(client) }
5
+ let(:client) { Callcredit::Client.new(config) }
6
+ let(:config) { Callcredit::Config.new }
7
+
8
+ let(:response_hash) { { status: status, body: body } }
9
+ let(:status) { 200 }
10
+ let(:body) { response_xml }
11
+ let(:response_xml) { load_fixture('response.xml') }
12
+ before { stub_request(:get, config[:api_endpoint]).to_return(response_hash) }
13
+
14
+ describe "#perform" do
15
+ subject(:perform_check) { bank_standard_check.perform(check_data) }
16
+
17
+ let(:check_data) do
18
+ { account_number: "44779911",
19
+ sort_code: "200000" }
20
+ end
21
+
22
+ it "makes a get request" do
23
+ perform_check
24
+ expect(a_request(:get, config[:api_endpoint])).to have_been_made
25
+ end
26
+
27
+ it { is_expected.to be_a Callcredit::Response }
28
+
29
+ context "when the config[:raw] is true" do
30
+ before { config[:raw] = true }
31
+ it { is_expected.to be_a Faraday::Response }
32
+
33
+ describe '#body' do
34
+ subject { perform_check.body }
35
+ it { should be_a String }
36
+ end
37
+ end
38
+
39
+ describe "validates inputs" do
40
+ it_behaves_like "it validates presence", :account_number
41
+ it_behaves_like "it validates presence", :sort_code
42
+ end
43
+ end
44
+ end
@@ -34,7 +34,7 @@ describe Callcredit::Checks::IDEnhanced do
34
34
  it { is_expected.to be_a Faraday::Response }
35
35
 
36
36
  describe '#body' do
37
- subject { super().body }
37
+ subject { perform_check.body }
38
38
  it { should be_a String }
39
39
  end
40
40
  end
@@ -11,7 +11,7 @@ describe Callcredit::Client do
11
11
  subject(:new_client) { Callcredit::Client.new }
12
12
 
13
13
  describe '#config' do
14
- subject { super().config }
14
+ subject { new_client.config }
15
15
  it { should_not == Callcredit.config }
16
16
  end
17
17
  it "has the attributes of the global config" do
@@ -24,7 +24,7 @@ describe Callcredit::Client do
24
24
  subject(:new_client) { Callcredit::Client.new(config) }
25
25
 
26
26
  describe '#config' do
27
- subject { super().config }
27
+ subject { new_client.config }
28
28
  it { should_not == config }
29
29
  end
30
30
  it "has the attributes of the passed in config" do
@@ -41,6 +41,22 @@ describe Callcredit::Client do
41
41
  end
42
42
  end
43
43
 
44
+ describe "#bank_standard_check" do
45
+ it "delegates to an instance of BankStandard" do
46
+ expect_any_instance_of(Callcredit::Checks::BankStandard).
47
+ to receive(:perform).once
48
+ client.bank_standard_check(check_data)
49
+ end
50
+ end
51
+
52
+ describe "#bank_enhanced_check" do
53
+ it "delegates to an instance of BankEnhanced" do
54
+ expect_any_instance_of(Callcredit::Checks::BankEnhanced).
55
+ to receive(:perform).once
56
+ client.bank_enhanced_check(check_data)
57
+ end
58
+ end
59
+
44
60
  describe "#perform_check" do
45
61
  subject(:perform_check) { client.perform_check(:check_type, check_data) }
46
62
 
@@ -41,6 +41,40 @@ describe Callcredit::Request do
41
41
  expect(xsd.validate(request_xml)).to eq([])
42
42
  end
43
43
  end
44
+
45
+ context "for a BankStandard check" do
46
+ before do
47
+ check_data.merge!(
48
+ bank_data: { account_number: 55779911, sort_code: 200000 }
49
+ )
50
+ end
51
+
52
+ subject(:request_xml) do
53
+ request.build_request_xml(:bank_standard, check_data)
54
+ end
55
+
56
+ it "generates a valid XML request" do
57
+ expect(xsd.validate(request_xml)).to eq([])
58
+ end
59
+ end
60
+
61
+ context "for a BankEnhanced check" do
62
+ before do
63
+ check_data.merge!(
64
+ bank_data: { account_number: 55779911, sort_code: 200000 },
65
+ personal_data: { first_name: "Tim", last_name: "Rogers",
66
+ postcode: "EC1V 7LQ", building_number: "338-346" }
67
+ )
68
+ end
69
+
70
+ subject(:request_xml) do
71
+ request.build_request_xml(:bank_enhanced, check_data)
72
+ end
73
+
74
+ it "generates a valid XML request" do
75
+ expect(xsd.validate(request_xml)).to eq([])
76
+ end
77
+ end
44
78
  end
45
79
 
46
80
  describe "#perform" do
@@ -56,7 +90,7 @@ describe Callcredit::Request do
56
90
  it { is_expected.to be_a Faraday::Response }
57
91
 
58
92
  describe '#body' do
59
- subject { super().body }
93
+ subject { perform_check.body }
60
94
  it { should be_a String }
61
95
  end
62
96
  end
@@ -85,4 +85,70 @@ describe Callcredit::Validations do
85
85
  end
86
86
  end
87
87
  end
88
+
89
+ describe '#clean_account_number' do
90
+ subject { Callcredit::Validations.clean_account_number(account_number) }
91
+
92
+ context "without an account_number" do
93
+ let(:account_number) { nil }
94
+ it { is_expected.to eq(nil) }
95
+ end
96
+
97
+ context "with a correct account_number" do
98
+ let(:account_number) { "12345678" }
99
+ it { is_expected.to eq(account_number) }
100
+ end
101
+
102
+ context "with a padded account_number" do
103
+ let(:account_number) { " 1234 5678 " }
104
+ it { is_expected.to eq("12345678") }
105
+ end
106
+
107
+ context "with an account_number with letters" do
108
+ let(:account_number) { "N1234567" }
109
+ it "raises an error" do
110
+ expect { subject }.to raise_error Callcredit::InvalidRequestError
111
+ end
112
+ end
113
+
114
+ context "with an account_number with too many numbers" do
115
+ let(:account_number) { "123456789" }
116
+ it "raises an error" do
117
+ expect { subject }.to raise_error Callcredit::InvalidRequestError
118
+ end
119
+ end
120
+ end
121
+
122
+ describe '#clean_sort_code' do
123
+ subject { Callcredit::Validations.clean_sort_code(sort_code) }
124
+
125
+ context "without a sort_code" do
126
+ let(:sort_code) { nil }
127
+ it { is_expected.to eq(nil) }
128
+ end
129
+
130
+ context "with a correct sort_code" do
131
+ let(:sort_code) { "123456" }
132
+ it { is_expected.to eq(sort_code) }
133
+ end
134
+
135
+ context "with a padded sort_code" do
136
+ let(:sort_code) { " 1234 56 " }
137
+ it { is_expected.to eq("123456") }
138
+ end
139
+
140
+ context "with a sort_code with letters" do
141
+ let(:sort_code) { "N12345" }
142
+ it "raises an error" do
143
+ expect { subject }.to raise_error Callcredit::InvalidRequestError
144
+ end
145
+ end
146
+
147
+ context "with a sort_code with too many numbers" do
148
+ let(:sort_code) { "1234567" }
149
+ it "raises an error" do
150
+ expect { subject }.to raise_error Callcredit::InvalidRequestError
151
+ end
152
+ end
153
+ end
88
154
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: callcredit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Grey Baker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-16 00:00:00.000000000 Z
11
+ date: 2014-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday_middleware
@@ -108,6 +108,8 @@ extensions: []
108
108
  extra_rdoc_files: []
109
109
  files:
110
110
  - .gitignore
111
+ - .rubocop.yml
112
+ - .rubocop_todo.yml
111
113
  - .travis.yml
112
114
  - CHANGELOG.md
113
115
  - Gemfile
@@ -115,6 +117,8 @@ files:
115
117
  - README.md
116
118
  - callcredit.gemspec
117
119
  - lib/callcredit.rb
120
+ - lib/callcredit/checks/bank_enhanced.rb
121
+ - lib/callcredit/checks/bank_standard.rb
118
122
  - lib/callcredit/checks/id_enhanced.rb
119
123
  - lib/callcredit/client.rb
120
124
  - lib/callcredit/config.rb
@@ -130,6 +134,8 @@ files:
130
134
  - lib/callcredit/validations.rb
131
135
  - lib/callcredit/version.rb
132
136
  - spec/callcredit_spec.rb
137
+ - spec/checks/bank_enhanced_spec.rb
138
+ - spec/checks/bank_standard_spec.rb
133
139
  - spec/checks/id_enhanced_spec.rb
134
140
  - spec/client_spec.rb
135
141
  - spec/fixtures/access_denied.xml
@@ -166,6 +172,8 @@ specification_version: 4
166
172
  summary: Ruby wrapper for Callcredit's CallValidate API
167
173
  test_files:
168
174
  - spec/callcredit_spec.rb
175
+ - spec/checks/bank_enhanced_spec.rb
176
+ - spec/checks/bank_standard_spec.rb
169
177
  - spec/checks/id_enhanced_spec.rb
170
178
  - spec/client_spec.rb
171
179
  - spec/fixtures/access_denied.xml