creditsafe 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +17 -17
  3. data/.gitignore +2 -2
  4. data/.rspec +1 -1
  5. data/.rubocop.yml +11 -11
  6. data/.ruby-version +1 -1
  7. data/CHANGELOG.md +49 -45
  8. data/Gemfile +5 -5
  9. data/Gemfile.lock +129 -129
  10. data/LICENSE.txt +22 -22
  11. data/README.md +175 -175
  12. data/creditsafe.gemspec +35 -35
  13. data/data/creditsafe-live.xml +342 -342
  14. data/data/creditsafe-test.xml +342 -342
  15. data/lib/creditsafe.rb +4 -4
  16. data/lib/creditsafe/client.rb +158 -158
  17. data/lib/creditsafe/constants.rb +49 -49
  18. data/lib/creditsafe/errors.rb +16 -16
  19. data/lib/creditsafe/match_type.rb +115 -115
  20. data/lib/creditsafe/messages.rb +97 -97
  21. data/lib/creditsafe/namespace.rb +20 -20
  22. data/lib/creditsafe/request/company_report.rb +42 -42
  23. data/lib/creditsafe/request/find_company.rb +120 -120
  24. data/lib/creditsafe/version.rb +5 -5
  25. data/spec/creditsafe/client_spec.rb +423 -423
  26. data/spec/creditsafe/messages_spec.rb +76 -76
  27. data/spec/fixtures/company-report-not-found.xml +13 -13
  28. data/spec/fixtures/company-report-request.xml +1 -1
  29. data/spec/fixtures/company-report-successful.xml +582 -582
  30. data/spec/fixtures/error-fault.xml +8 -8
  31. data/spec/fixtures/error-invalid-credentials.html +31 -31
  32. data/spec/fixtures/find-companies-error-no-text.xml +11 -11
  33. data/spec/fixtures/find-companies-error.xml +11 -11
  34. data/spec/fixtures/find-companies-none-found.xml +13 -13
  35. data/spec/fixtures/find-companies-request.xml +1 -1
  36. data/spec/fixtures/find-companies-successful-multi.xml +493 -493
  37. data/spec/fixtures/find-companies-successful.xml +29 -29
  38. data/spec/spec_helper.rb +14 -14
  39. metadata +3 -3
@@ -1,42 +1,42 @@
1
- # frozen_string_literal: true
2
-
3
- require "creditsafe/namespace"
4
-
5
- module Creditsafe
6
- module Request
7
- class CompanyReport
8
- def initialize(company_id, custom_data)
9
- @company_id = company_id
10
- @custom_data = custom_data
11
- end
12
-
13
- # rubocop:disable Metrics/MethodLength
14
- def message
15
- message = {
16
- "#{Creditsafe::Namespace::OPER}:companyId" => company_id.to_s,
17
- "#{Creditsafe::Namespace::OPER}:reportType" => "Full",
18
- "#{Creditsafe::Namespace::OPER}:language" => "EN",
19
- }
20
-
21
- unless custom_data.nil?
22
- message["#{Creditsafe::Namespace::OPER}:customData"] = {
23
- "#{Creditsafe::Namespace::DAT}:Entries" => {
24
- "#{Creditsafe::Namespace::DAT}:Entry" => custom_data_entries,
25
- },
26
- }
27
- end
28
-
29
- message
30
- end
31
- # rubocop:enable Metrics/MethodLength
32
-
33
- private
34
-
35
- def custom_data_entries
36
- custom_data.map { |key, value| { :@key => key, :content! => value } }
37
- end
38
-
39
- attr_reader :company_id, :custom_data
40
- end
41
- end
42
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "creditsafe/namespace"
4
+
5
+ module Creditsafe
6
+ module Request
7
+ class CompanyReport
8
+ def initialize(company_id, custom_data)
9
+ @company_id = company_id
10
+ @custom_data = custom_data
11
+ end
12
+
13
+ # rubocop:disable Metrics/MethodLength
14
+ def message
15
+ message = {
16
+ "#{Creditsafe::Namespace::OPER}:companyId" => company_id.to_s,
17
+ "#{Creditsafe::Namespace::OPER}:reportType" => "Full",
18
+ "#{Creditsafe::Namespace::OPER}:language" => "EN",
19
+ }
20
+
21
+ unless custom_data.nil?
22
+ message["#{Creditsafe::Namespace::OPER}:customData"] = {
23
+ "#{Creditsafe::Namespace::DAT}:Entries" => {
24
+ "#{Creditsafe::Namespace::DAT}:Entry" => custom_data_entries,
25
+ },
26
+ }
27
+ end
28
+
29
+ message
30
+ end
31
+ # rubocop:enable Metrics/MethodLength
32
+
33
+ private
34
+
35
+ def custom_data_entries
36
+ custom_data.map { |key, value| { :@key => key, :content! => value } }
37
+ end
38
+
39
+ attr_reader :company_id, :custom_data
40
+ end
41
+ end
42
+ end
@@ -1,120 +1,120 @@
1
- # frozen_string_literal: true
2
-
3
- require "creditsafe/match_type"
4
- require "creditsafe/namespace"
5
- require "creditsafe/constants"
6
-
7
- module Creditsafe
8
- module Request
9
- class FindCompany
10
- def initialize(search_criteria)
11
- check_search_criteria(search_criteria)
12
- @country_code = search_criteria[:country_code]
13
- @registration_number = search_criteria[:registration_number]
14
- @company_name = search_criteria[:company_name]
15
- @vat_number = search_criteria[:vat_number]
16
- @city = search_criteria[:city]
17
- @postal_code = search_criteria[:postal_code]
18
- end
19
-
20
- # rubocop:disable Metrics/MethodLength
21
- # rubocop:disable Metrics/AbcSize
22
- def message
23
- search_criteria = {}
24
-
25
- unless company_name.nil?
26
- search_criteria["#{Creditsafe::Namespace::DAT}:Name"] = {
27
- "@MatchType" => match_type,
28
- :content! => company_name,
29
- }
30
- end
31
-
32
- unless registration_number.nil?
33
- search_criteria["#{Creditsafe::Namespace::DAT}:RegistrationNumber"] =
34
- registration_number
35
- end
36
-
37
- unless vat_number.nil?
38
- search_criteria["#{Creditsafe::Namespace::DAT}:VatNumber"] =
39
- vat_number
40
- end
41
-
42
- unless city.nil?
43
- search_criteria["#{Creditsafe::Namespace::DAT}:Address"] = {
44
- "#{Creditsafe::Namespace::DAT}:City" => city,
45
- }
46
- end
47
-
48
- unless postal_code.nil?
49
- search_criteria["#{Creditsafe::Namespace::DAT}:Address"] = {
50
- "#{Creditsafe::Namespace::DAT}:PostalCode" => postal_code,
51
- }
52
- end
53
-
54
- build_message(search_criteria)
55
- end
56
- # rubocop:enable Metrics/AbcSize
57
- # rubocop:enable Metrics/MethodLength
58
-
59
- private
60
-
61
- attr_reader :country_code, :registration_number, :city, :company_name, :postal_code,
62
- :vat_number
63
-
64
- def match_type
65
- Creditsafe::MatchType::ALLOWED[country_code.upcase.to_sym]&.first ||
66
- Creditsafe::MatchType::MATCH_BLOCK
67
- end
68
-
69
- def build_message(search_criteria)
70
- {
71
- "#{Creditsafe::Namespace::OPER}:countries" => {
72
- "#{Creditsafe::Namespace::CRED}:CountryCode" => country_code,
73
- },
74
- "#{Creditsafe::Namespace::OPER}:searchCriteria" => search_criteria,
75
- }
76
- end
77
-
78
- # rubocop:disable Metrics/CyclomaticComplexity
79
- # rubocop:disable Metrics/MethodLength
80
- # rubocop:disable Metrics/PerceivedComplexity
81
- # rubocop:disable Metrics/AbcSize
82
- def check_search_criteria(search_criteria)
83
- if search_criteria[:country_code].nil?
84
- raise ArgumentError, "country_code is a required search criteria"
85
- end
86
-
87
- unless only_one_required_criteria?(search_criteria)
88
- raise ArgumentError, "only one of registration_number, company_name or " \
89
- "vat number is required search criteria"
90
- end
91
-
92
- if search_criteria[:city] && search_criteria[:country_code] != "DE"
93
- raise ArgumentError, "city is only supported for German searches"
94
- end
95
-
96
- if search_criteria[:postal_code] && search_criteria[:country_code] != "DE"
97
- raise ArgumentError, "Postal code is only supported for German searches"
98
- end
99
-
100
- if search_criteria[:vat_number] && !Constants::Country::VAT_NUMBER_SUPPORTED.
101
- include?(search_criteria[:country_code])
102
- raise ArgumentError, "VAT number is not supported in this country"
103
- end
104
- end
105
- # rubocop:enable Metrics/AbcSize
106
- # rubocop:enable Metrics/PerceivedComplexity
107
- # rubocop:enable Metrics/MethodLength
108
- # rubocop:enable Metrics/CyclomaticComplexity
109
-
110
- def only_one_required_criteria?(search_criteria)
111
- by_registration_number = !search_criteria[:registration_number].nil?
112
- by_company_name = !search_criteria[:company_name].nil?
113
- by_vat_number = !search_criteria[:vat_number].nil?
114
-
115
- (by_registration_number ^ by_company_name ^ by_vat_number) &&
116
- !(by_registration_number && by_company_name && by_vat_number)
117
- end
118
- end
119
- end
120
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "creditsafe/match_type"
4
+ require "creditsafe/namespace"
5
+ require "creditsafe/constants"
6
+
7
+ module Creditsafe
8
+ module Request
9
+ class FindCompany
10
+ def initialize(search_criteria)
11
+ check_search_criteria(search_criteria)
12
+ @country_code = search_criteria[:country_code]
13
+ @registration_number = search_criteria[:registration_number]
14
+ @company_name = search_criteria[:company_name]
15
+ @vat_number = search_criteria[:vat_number]
16
+ @city = search_criteria[:city]
17
+ @postal_code = search_criteria[:postal_code]
18
+ end
19
+
20
+ # rubocop:disable Metrics/MethodLength
21
+ # rubocop:disable Metrics/AbcSize
22
+ def message
23
+ search_criteria = {}
24
+
25
+ unless company_name.nil?
26
+ search_criteria["#{Creditsafe::Namespace::DAT}:Name"] = {
27
+ "@MatchType" => match_type,
28
+ :content! => company_name,
29
+ }
30
+ end
31
+
32
+ unless registration_number.nil?
33
+ search_criteria["#{Creditsafe::Namespace::DAT}:RegistrationNumber"] =
34
+ registration_number
35
+ end
36
+
37
+ unless vat_number.nil?
38
+ search_criteria["#{Creditsafe::Namespace::DAT}:VatNumber"] =
39
+ vat_number
40
+ end
41
+
42
+ unless city.nil?
43
+ search_criteria["#{Creditsafe::Namespace::DAT}:Address"] = {
44
+ "#{Creditsafe::Namespace::DAT}:City" => city,
45
+ }
46
+ end
47
+
48
+ unless postal_code.nil?
49
+ search_criteria["#{Creditsafe::Namespace::DAT}:Address"] = {
50
+ "#{Creditsafe::Namespace::DAT}:PostalCode" => postal_code,
51
+ }
52
+ end
53
+
54
+ build_message(search_criteria)
55
+ end
56
+ # rubocop:enable Metrics/AbcSize
57
+ # rubocop:enable Metrics/MethodLength
58
+
59
+ private
60
+
61
+ attr_reader :country_code, :registration_number, :city, :company_name, :postal_code,
62
+ :vat_number
63
+
64
+ def match_type
65
+ Creditsafe::MatchType::ALLOWED[country_code.upcase.to_sym]&.first ||
66
+ Creditsafe::MatchType::MATCH_BLOCK
67
+ end
68
+
69
+ def build_message(search_criteria)
70
+ {
71
+ "#{Creditsafe::Namespace::OPER}:countries" => {
72
+ "#{Creditsafe::Namespace::CRED}:CountryCode" => country_code,
73
+ },
74
+ "#{Creditsafe::Namespace::OPER}:searchCriteria" => search_criteria,
75
+ }
76
+ end
77
+
78
+ # rubocop:disable Metrics/CyclomaticComplexity
79
+ # rubocop:disable Metrics/MethodLength
80
+ # rubocop:disable Metrics/PerceivedComplexity
81
+ # rubocop:disable Metrics/AbcSize
82
+ def check_search_criteria(search_criteria)
83
+ if search_criteria[:country_code].nil?
84
+ raise ArgumentError, "country_code is a required search criteria"
85
+ end
86
+
87
+ unless only_one_required_criteria?(search_criteria)
88
+ raise ArgumentError, "only one of registration_number, company_name or " \
89
+ "vat number is required search criteria"
90
+ end
91
+
92
+ if search_criteria[:city] && search_criteria[:country_code] != "DE"
93
+ raise ArgumentError, "city is only supported for German searches"
94
+ end
95
+
96
+ if search_criteria[:postal_code] && search_criteria[:country_code] != "DE"
97
+ raise ArgumentError, "Postal code is only supported for German searches"
98
+ end
99
+
100
+ if search_criteria[:vat_number] && !Constants::Country::VAT_NUMBER_SUPPORTED.
101
+ include?(search_criteria[:country_code])
102
+ raise ArgumentError, "VAT number is not supported in this country"
103
+ end
104
+ end
105
+ # rubocop:enable Metrics/AbcSize
106
+ # rubocop:enable Metrics/PerceivedComplexity
107
+ # rubocop:enable Metrics/MethodLength
108
+ # rubocop:enable Metrics/CyclomaticComplexity
109
+
110
+ def only_one_required_criteria?(search_criteria)
111
+ by_registration_number = !search_criteria[:registration_number].nil?
112
+ by_company_name = !search_criteria[:company_name].nil?
113
+ by_vat_number = !search_criteria[:vat_number].nil?
114
+
115
+ (by_registration_number ^ by_company_name ^ by_vat_number) &&
116
+ !(by_registration_number && by_company_name && by_vat_number)
117
+ end
118
+ end
119
+ end
120
+ end
@@ -1,5 +1,5 @@
1
- # frozen_string_literal: true
2
-
3
- module Creditsafe
4
- VERSION = "0.6.0"
5
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Creditsafe
4
+ VERSION = "0.6.1"
5
+ end
@@ -1,423 +1,423 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
- require "creditsafe/client"
5
- require "timecop"
6
-
7
- URL = "https://webservices.creditsafe.com/GlobalData/1.3/"\
8
- "MainServiceBasic.svc"
9
-
10
- RSpec.describe(Creditsafe::Client) do
11
- notifications = []
12
- let(:username) { "AzureDiamond" }
13
- let(:password) { "hunter2" }
14
-
15
- # rubocop:disable RSpec/BeforeAfterAll
16
- before(:all) do
17
- ActiveSupport::Notifications.subscribe do |*args|
18
- notifications << ActiveSupport::Notifications::Event.new(*args)
19
- end
20
- end
21
- # rubocop:enable RSpec/BeforeAfterAll
22
-
23
- before { notifications = [] }
24
-
25
- shared_examples_for "sends notifications" do
26
- let(:time) { Time.local(1990) }
27
-
28
- it "records a SOAP event" do
29
- Timecop.freeze(time) { method_call }
30
-
31
- expect(notifications).to match(
32
- [
33
- have_attributes(
34
- name: "creditsafe.#{soap_verb}",
35
- transaction_id: match(/\A.{20}\Z/),
36
- time: time,
37
- end: time,
38
- payload: {
39
- request: be_truthy,
40
- response: be_truthy,
41
- },
42
- ),
43
- ],
44
- )
45
- end
46
- end
47
-
48
- shared_examples_for "handles api errors" do
49
- context "when an error occurs due to invalid credentials" do
50
- before do
51
- stub_request(:post, URL).to_return(
52
- body: load_fixture("error-invalid-credentials.html"),
53
- status: 401,
54
- )
55
- end
56
-
57
- it "raises an AccountError" do
58
- expect { method_call }.to raise_error(
59
- Creditsafe::AccountError, /invalid credentials/
60
- ) do |error|
61
- expect(notifications).to match(
62
- [
63
- have_attributes(
64
- name: "creditsafe.#{soap_verb}",
65
- payload: {
66
- request: be_truthy,
67
- error: error,
68
- },
69
- ),
70
- ],
71
- )
72
- end
73
- end
74
- end
75
-
76
- context "when an error occurs due to a fault" do
77
- before do
78
- stub_request(:post, URL).
79
- to_return(body: load_fixture("error-fault.xml"))
80
- end
81
-
82
- it "raises an UnknownApiError" do
83
- expect { method_call }.to raise_error(Creditsafe::UnknownApiError) do |error|
84
- expect(notifications).to match(
85
- [
86
- have_attributes(
87
- name: "creditsafe.#{soap_verb}",
88
- payload: {
89
- request: be_truthy,
90
- error: error,
91
- },
92
- ),
93
- ],
94
- )
95
- end
96
- end
97
- end
98
-
99
- context "when a timeout occurs" do
100
- before { stub_request(:post, URL).to_timeout }
101
-
102
- it "raises a TimeoutError" do
103
- expect { method_call }.to raise_error(Creditsafe::TimeoutError)
104
- end
105
- end
106
- end
107
-
108
- describe "#new" do
109
- subject do
110
- -> { described_class.new(username: username, password: password) }
111
- end
112
-
113
- it { is_expected.to_not raise_error }
114
-
115
- context "without a username" do
116
- let(:username) { nil }
117
-
118
- it { is_expected.to raise_error(ArgumentError) }
119
- end
120
- end
121
-
122
- describe "#inspect" do
123
- subject { client.inspect }
124
-
125
- let(:client) { described_class.new(username: username, password: password) }
126
-
127
- it { is_expected.to_not include(password) }
128
- end
129
-
130
- describe "#find_company" do
131
- subject { -> { method_call } }
132
-
133
- let(:soap_verb) { "find_companies" }
134
- let(:client) { described_class.new(username: username, password: password) }
135
- let(:country_code) { "GB" }
136
- let(:registration_number) { "RN123" }
137
- let(:city) { nil }
138
- let(:postal_code) { nil }
139
- let(:company_name) { nil }
140
- let(:vat_number) { nil }
141
- let(:search_criteria) do
142
- {
143
- country_code: country_code,
144
- registration_number: registration_number,
145
- company_name: company_name,
146
- vat_number: vat_number,
147
- city: city,
148
- postal_code: postal_code,
149
- }.reject { |_, v| v.nil? }
150
- end
151
-
152
- let(:find_company) { client.find_company(search_criteria) }
153
- let(:method_call) { find_company }
154
-
155
- before do
156
- stub_request(:post, URL).to_return(
157
- body: load_fixture("find-companies-successful.xml"),
158
- status: 200,
159
- )
160
- end
161
-
162
- it { is_expected.to_not raise_error }
163
-
164
- context "without a country_code" do
165
- let(:country_code) { nil }
166
-
167
- it { is_expected.to raise_error(ArgumentError) }
168
- end
169
-
170
- context "without a registration_number" do
171
- let(:registration_number) { nil }
172
-
173
- it { is_expected.to raise_error(ArgumentError) }
174
- end
175
-
176
- context "with a city" do
177
- let(:city) { "Berlin" }
178
-
179
- it { is_expected.to raise_error(ArgumentError) }
180
-
181
- context "in Germany" do
182
- let(:country_code) { "DE" }
183
-
184
- it { is_expected.to_not raise_error }
185
- end
186
- end
187
-
188
- context "with a postal_code" do
189
- let(:postal_code) { "41199" }
190
-
191
- it { is_expected.to raise_error(ArgumentError) }
192
-
193
- context "in Germany" do
194
- let(:country_code) { "DE" }
195
-
196
- it { is_expected.to_not raise_error }
197
- end
198
- end
199
-
200
- context "with a company name" do
201
- let(:country_code) { "FR" }
202
- let(:registration_number) { nil }
203
- let(:company_name) { "Mimes Inc" }
204
-
205
- it { is_expected.to_not raise_error }
206
-
207
- it "selects a valid match type for the country code" do
208
- find_company
209
-
210
- request = a_request(:post, URL).with do |req|
211
- body = Nokogiri::XML(req.body)
212
- expect(body.xpath("//dat:Name").first.attributes["MatchType"].value).
213
- to eq("MatchBeginning")
214
- end
215
-
216
- expect(request).to have_been_made
217
- end
218
- end
219
-
220
- context "with a vat_number" do
221
- let(:vat_number) { "942404110" }
222
- let(:registration_number) { nil }
223
-
224
- it { is_expected.to raise_error(ArgumentError) }
225
-
226
- context "in US" do
227
- let(:country_code) { "US" }
228
-
229
- it { is_expected.to_not raise_error }
230
- end
231
- end
232
-
233
- context "with different invalid required criteria combinations used" do
234
- context "with registration number and company name" do
235
- let(:company_name) { "Mimes Inc" }
236
-
237
- it { is_expected.to raise_error(ArgumentError) }
238
- end
239
-
240
- context "with registration number and vat_number" do
241
- let(:vat_number) { "942404110" }
242
-
243
- it { is_expected.to raise_error(ArgumentError) }
244
- end
245
-
246
- context "with company name and vat_number" do
247
- let(:registration_number) { nil }
248
- let(:company_name) { "Mimes Inc" }
249
- let(:vat_number) { "942404110" }
250
-
251
- it { is_expected.to raise_error(ArgumentError) }
252
- end
253
-
254
- context "with all three required criteria" do
255
- let(:company_name) { "Mimes Inc" }
256
- let(:vat_number) { "942404110" }
257
-
258
- it { is_expected.to raise_error(ArgumentError) }
259
- end
260
-
261
- context "with no required criteria" do
262
- let(:registration_number) { nil }
263
-
264
- it { is_expected.to raise_error(ArgumentError) }
265
- end
266
- end
267
-
268
- it "requests the company deatils" do
269
- find_company
270
- expect(a_request(:post, URL).with do |req|
271
- expect(CompareXML.equivalent?(
272
- Nokogiri::XML(req.body),
273
- load_xml_fixture("find-companies-request.xml"),
274
- verbose: true,
275
- )).to eq([])
276
- end).to have_been_made
277
- end
278
-
279
- it "returns the company details" do
280
- expect(find_company).
281
- to eq(:name => "GOCARDLESS LTD",
282
- :type => "Ltd",
283
- :status => "Active",
284
- :registration_number => "07495895",
285
- :address => {
286
- simple_value: "338-346, GOSWELL, LONDON",
287
- postal_code: "EC1V7LQ",
288
- },
289
- :available_report_types => { available_report_type: "Full" },
290
- :available_languages => { available_language: "EN" },
291
- :@date_of_latest_accounts => "2014-01-31T00:00:00Z",
292
- :@online_reports => "true",
293
- :@monitoring => "false",
294
- :@country => "GB",
295
- :@id => "GB003/0/07495895")
296
- end
297
-
298
- include_examples "sends notifications"
299
- include_examples "handles api errors"
300
-
301
- context "when no companies are found" do
302
- before do
303
- stub_request(:post, URL).to_return(
304
- body: load_fixture("find-companies-none-found.xml"),
305
- status: 200,
306
- )
307
- end
308
-
309
- it "returns nil" do
310
- expect(find_company).to be_nil
311
- end
312
-
313
- it "records a nil payload" do
314
- find_company
315
- expect(notifications).to match([have_attributes(
316
- payload: {
317
- request: be_truthy,
318
- response: {
319
- find_companies_response: include(
320
- find_companies_result: include(
321
- messages: {
322
- message: include(
323
- "There are no results matching specified criteria.",
324
- ),
325
- },
326
- companies: be_nil,
327
- ),
328
- ),
329
- },
330
- },
331
- )])
332
- end
333
- end
334
-
335
- context "when an error occurs with further details" do
336
- before do
337
- stub_request(:post, URL).to_return(
338
- body: load_fixture("find-companies-error.xml"),
339
- status: 200,
340
- )
341
- end
342
-
343
- it "gives a useful error, with the specific error in the response" do
344
- expect { method_call }.to raise_error(
345
- Creditsafe::RequestError,
346
- "Invalid operation parameters (Invalid countries list specified.)",
347
- )
348
- end
349
-
350
- context "with further details provided in the response" do
351
- before do
352
- stub_request(:post, URL).to_return(
353
- body: load_fixture("find-companies-error-no-text.xml"),
354
- status: 200,
355
- )
356
- end
357
-
358
- it "gives a useful error, with the specific error in the response" do
359
- expect { method_call }.to raise_error(
360
- Creditsafe::RequestError,
361
- "Invalid operation parameters",
362
- )
363
- end
364
- end
365
- end
366
- end
367
-
368
- describe "#company_report" do
369
- before do
370
- stub_request(:post, URL).to_return(
371
- body: load_fixture("company-report-successful.xml"),
372
- status: 200,
373
- )
374
- end
375
-
376
- let(:soap_verb) { "retrieve_company_online_report" }
377
- let(:client) { described_class.new(username: username, password: password) }
378
- let(:custom_data) { { foo: "bar", bar: "baz" } }
379
- let(:company_report) do
380
- client.company_report("GB003/0/07495895", custom_data: custom_data)
381
- end
382
- let(:method_call) { company_report }
383
-
384
- it "requests the company details" do
385
- company_report
386
- request = a_request(:post, URL).with do |req|
387
- expect(
388
- CompareXML.equivalent?(
389
- Nokogiri::XML(req.body),
390
- load_xml_fixture("company-report-request.xml"),
391
- verbose: true,
392
- ),
393
- ).to eq([])
394
- end
395
-
396
- expect(request).to have_been_made
397
- end
398
-
399
- it "returns the company details" do
400
- expect(company_report).to include(:company_summary)
401
- end
402
-
403
- include_examples "sends notifications"
404
- include_examples "handles api errors"
405
-
406
- context "when a report is unavailable" do
407
- before do
408
- stub_request(:post, URL).
409
- to_return(body: load_fixture("company-report-not-found.xml"))
410
- end
411
-
412
- it "raises an error" do
413
- expect { company_report }.to raise_error(Creditsafe::DataError)
414
- end
415
-
416
- it "gives a useful error message" do
417
- expect { company_report }.to raise_error(
418
- Creditsafe::DataError, /Report unavailable/
419
- )
420
- end
421
- end
422
- end
423
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "creditsafe/client"
5
+ require "timecop"
6
+
7
+ URL = "https://webservices.creditsafe.com/GlobalData/1.3/"\
8
+ "MainServiceBasic.svc"
9
+
10
+ RSpec.describe(Creditsafe::Client) do
11
+ notifications = []
12
+ let(:username) { "AzureDiamond" }
13
+ let(:password) { "hunter2" }
14
+
15
+ # rubocop:disable RSpec/BeforeAfterAll
16
+ before(:all) do
17
+ ActiveSupport::Notifications.subscribe do |*args|
18
+ notifications << ActiveSupport::Notifications::Event.new(*args)
19
+ end
20
+ end
21
+ # rubocop:enable RSpec/BeforeAfterAll
22
+
23
+ before { notifications = [] }
24
+
25
+ shared_examples_for "sends notifications" do
26
+ let(:time) { Time.local(1990) }
27
+
28
+ it "records a SOAP event" do
29
+ Timecop.freeze(time) { method_call }
30
+
31
+ expect(notifications).to match(
32
+ [
33
+ have_attributes(
34
+ name: "creditsafe.#{soap_verb}",
35
+ transaction_id: match(/\A.{20}\Z/),
36
+ time: time,
37
+ end: time,
38
+ payload: {
39
+ request: be_truthy,
40
+ response: be_truthy,
41
+ },
42
+ ),
43
+ ],
44
+ )
45
+ end
46
+ end
47
+
48
+ shared_examples_for "handles api errors" do
49
+ context "when an error occurs due to invalid credentials" do
50
+ before do
51
+ stub_request(:post, URL).to_return(
52
+ body: load_fixture("error-invalid-credentials.html"),
53
+ status: 401,
54
+ )
55
+ end
56
+
57
+ it "raises an AccountError" do
58
+ expect { method_call }.to raise_error(
59
+ Creditsafe::AccountError, /invalid credentials/
60
+ ) do |error|
61
+ expect(notifications).to match(
62
+ [
63
+ have_attributes(
64
+ name: "creditsafe.#{soap_verb}",
65
+ payload: {
66
+ request: be_truthy,
67
+ error: error,
68
+ },
69
+ ),
70
+ ],
71
+ )
72
+ end
73
+ end
74
+ end
75
+
76
+ context "when an error occurs due to a fault" do
77
+ before do
78
+ stub_request(:post, URL).
79
+ to_return(body: load_fixture("error-fault.xml"))
80
+ end
81
+
82
+ it "raises an UnknownApiError" do
83
+ expect { method_call }.to raise_error(Creditsafe::UnknownApiError) do |error|
84
+ expect(notifications).to match(
85
+ [
86
+ have_attributes(
87
+ name: "creditsafe.#{soap_verb}",
88
+ payload: {
89
+ request: be_truthy,
90
+ error: error,
91
+ },
92
+ ),
93
+ ],
94
+ )
95
+ end
96
+ end
97
+ end
98
+
99
+ context "when a timeout occurs" do
100
+ before { stub_request(:post, URL).to_timeout }
101
+
102
+ it "raises a TimeoutError" do
103
+ expect { method_call }.to raise_error(Creditsafe::TimeoutError)
104
+ end
105
+ end
106
+ end
107
+
108
+ describe "#new" do
109
+ subject do
110
+ -> { described_class.new(username: username, password: password) }
111
+ end
112
+
113
+ it { is_expected.to_not raise_error }
114
+
115
+ context "without a username" do
116
+ let(:username) { nil }
117
+
118
+ it { is_expected.to raise_error(ArgumentError) }
119
+ end
120
+ end
121
+
122
+ describe "#inspect" do
123
+ subject { client.inspect }
124
+
125
+ let(:client) { described_class.new(username: username, password: password) }
126
+
127
+ it { is_expected.to_not include(password) }
128
+ end
129
+
130
+ describe "#find_company" do
131
+ subject { -> { method_call } }
132
+
133
+ let(:soap_verb) { "find_companies" }
134
+ let(:client) { described_class.new(username: username, password: password) }
135
+ let(:country_code) { "GB" }
136
+ let(:registration_number) { "RN123" }
137
+ let(:city) { nil }
138
+ let(:postal_code) { nil }
139
+ let(:company_name) { nil }
140
+ let(:vat_number) { nil }
141
+ let(:search_criteria) do
142
+ {
143
+ country_code: country_code,
144
+ registration_number: registration_number,
145
+ company_name: company_name,
146
+ vat_number: vat_number,
147
+ city: city,
148
+ postal_code: postal_code,
149
+ }.reject { |_, v| v.nil? }
150
+ end
151
+
152
+ let(:find_company) { client.find_company(search_criteria) }
153
+ let(:method_call) { find_company }
154
+
155
+ before do
156
+ stub_request(:post, URL).to_return(
157
+ body: load_fixture("find-companies-successful.xml"),
158
+ status: 200,
159
+ )
160
+ end
161
+
162
+ it { is_expected.to_not raise_error }
163
+
164
+ context "without a country_code" do
165
+ let(:country_code) { nil }
166
+
167
+ it { is_expected.to raise_error(ArgumentError) }
168
+ end
169
+
170
+ context "without a registration_number" do
171
+ let(:registration_number) { nil }
172
+
173
+ it { is_expected.to raise_error(ArgumentError) }
174
+ end
175
+
176
+ context "with a city" do
177
+ let(:city) { "Berlin" }
178
+
179
+ it { is_expected.to raise_error(ArgumentError) }
180
+
181
+ context "in Germany" do
182
+ let(:country_code) { "DE" }
183
+
184
+ it { is_expected.to_not raise_error }
185
+ end
186
+ end
187
+
188
+ context "with a postal_code" do
189
+ let(:postal_code) { "41199" }
190
+
191
+ it { is_expected.to raise_error(ArgumentError) }
192
+
193
+ context "in Germany" do
194
+ let(:country_code) { "DE" }
195
+
196
+ it { is_expected.to_not raise_error }
197
+ end
198
+ end
199
+
200
+ context "with a company name" do
201
+ let(:country_code) { "FR" }
202
+ let(:registration_number) { nil }
203
+ let(:company_name) { "Mimes Inc" }
204
+
205
+ it { is_expected.to_not raise_error }
206
+
207
+ it "selects a valid match type for the country code" do
208
+ find_company
209
+
210
+ request = a_request(:post, URL).with do |req|
211
+ body = Nokogiri::XML(req.body)
212
+ expect(body.xpath("//dat:Name").first.attributes["MatchType"].value).
213
+ to eq("MatchBeginning")
214
+ end
215
+
216
+ expect(request).to have_been_made
217
+ end
218
+ end
219
+
220
+ context "with a vat_number" do
221
+ let(:vat_number) { "942404110" }
222
+ let(:registration_number) { nil }
223
+
224
+ it { is_expected.to raise_error(ArgumentError) }
225
+
226
+ context "in US" do
227
+ let(:country_code) { "US" }
228
+
229
+ it { is_expected.to_not raise_error }
230
+ end
231
+ end
232
+
233
+ context "with different invalid required criteria combinations used" do
234
+ context "with registration number and company name" do
235
+ let(:company_name) { "Mimes Inc" }
236
+
237
+ it { is_expected.to raise_error(ArgumentError) }
238
+ end
239
+
240
+ context "with registration number and vat_number" do
241
+ let(:vat_number) { "942404110" }
242
+
243
+ it { is_expected.to raise_error(ArgumentError) }
244
+ end
245
+
246
+ context "with company name and vat_number" do
247
+ let(:registration_number) { nil }
248
+ let(:company_name) { "Mimes Inc" }
249
+ let(:vat_number) { "942404110" }
250
+
251
+ it { is_expected.to raise_error(ArgumentError) }
252
+ end
253
+
254
+ context "with all three required criteria" do
255
+ let(:company_name) { "Mimes Inc" }
256
+ let(:vat_number) { "942404110" }
257
+
258
+ it { is_expected.to raise_error(ArgumentError) }
259
+ end
260
+
261
+ context "with no required criteria" do
262
+ let(:registration_number) { nil }
263
+
264
+ it { is_expected.to raise_error(ArgumentError) }
265
+ end
266
+ end
267
+
268
+ it "requests the company deatils" do
269
+ find_company
270
+ expect(a_request(:post, URL).with do |req|
271
+ expect(CompareXML.equivalent?(
272
+ Nokogiri::XML(req.body),
273
+ load_xml_fixture("find-companies-request.xml"),
274
+ verbose: true,
275
+ )).to eq([])
276
+ end).to have_been_made
277
+ end
278
+
279
+ it "returns the company details" do
280
+ expect(find_company).
281
+ to eq(:name => "GOCARDLESS LTD",
282
+ :type => "Ltd",
283
+ :status => "Active",
284
+ :registration_number => "07495895",
285
+ :address => {
286
+ simple_value: "338-346, GOSWELL, LONDON",
287
+ postal_code: "EC1V7LQ",
288
+ },
289
+ :available_report_types => { available_report_type: "Full" },
290
+ :available_languages => { available_language: "EN" },
291
+ :@date_of_latest_accounts => "2014-01-31T00:00:00Z",
292
+ :@online_reports => "true",
293
+ :@monitoring => "false",
294
+ :@country => "GB",
295
+ :@id => "GB003/0/07495895")
296
+ end
297
+
298
+ include_examples "sends notifications"
299
+ include_examples "handles api errors"
300
+
301
+ context "when no companies are found" do
302
+ before do
303
+ stub_request(:post, URL).to_return(
304
+ body: load_fixture("find-companies-none-found.xml"),
305
+ status: 200,
306
+ )
307
+ end
308
+
309
+ it "returns nil" do
310
+ expect(find_company).to be_nil
311
+ end
312
+
313
+ it "records a nil payload" do
314
+ find_company
315
+ expect(notifications).to match([have_attributes(
316
+ payload: {
317
+ request: be_truthy,
318
+ response: {
319
+ find_companies_response: include(
320
+ find_companies_result: include(
321
+ messages: {
322
+ message: include(
323
+ "There are no results matching specified criteria.",
324
+ ),
325
+ },
326
+ companies: be_nil,
327
+ ),
328
+ ),
329
+ },
330
+ },
331
+ )])
332
+ end
333
+ end
334
+
335
+ context "when an error occurs with further details" do
336
+ before do
337
+ stub_request(:post, URL).to_return(
338
+ body: load_fixture("find-companies-error.xml"),
339
+ status: 200,
340
+ )
341
+ end
342
+
343
+ it "gives a useful error, with the specific error in the response" do
344
+ expect { method_call }.to raise_error(
345
+ Creditsafe::RequestError,
346
+ "Invalid operation parameters (Invalid countries list specified.)",
347
+ )
348
+ end
349
+
350
+ context "with further details provided in the response" do
351
+ before do
352
+ stub_request(:post, URL).to_return(
353
+ body: load_fixture("find-companies-error-no-text.xml"),
354
+ status: 200,
355
+ )
356
+ end
357
+
358
+ it "gives a useful error, with the specific error in the response" do
359
+ expect { method_call }.to raise_error(
360
+ Creditsafe::RequestError,
361
+ "Invalid operation parameters",
362
+ )
363
+ end
364
+ end
365
+ end
366
+ end
367
+
368
+ describe "#company_report" do
369
+ before do
370
+ stub_request(:post, URL).to_return(
371
+ body: load_fixture("company-report-successful.xml"),
372
+ status: 200,
373
+ )
374
+ end
375
+
376
+ let(:soap_verb) { "retrieve_company_online_report" }
377
+ let(:client) { described_class.new(username: username, password: password) }
378
+ let(:custom_data) { { foo: "bar", bar: "baz" } }
379
+ let(:company_report) do
380
+ client.company_report("GB003/0/07495895", custom_data: custom_data)
381
+ end
382
+ let(:method_call) { company_report }
383
+
384
+ it "requests the company details" do
385
+ company_report
386
+ request = a_request(:post, URL).with do |req|
387
+ expect(
388
+ CompareXML.equivalent?(
389
+ Nokogiri::XML(req.body),
390
+ load_xml_fixture("company-report-request.xml"),
391
+ verbose: true,
392
+ ),
393
+ ).to eq([])
394
+ end
395
+
396
+ expect(request).to have_been_made
397
+ end
398
+
399
+ it "returns the company details" do
400
+ expect(company_report).to include(:company_summary)
401
+ end
402
+
403
+ include_examples "sends notifications"
404
+ include_examples "handles api errors"
405
+
406
+ context "when a report is unavailable" do
407
+ before do
408
+ stub_request(:post, URL).
409
+ to_return(body: load_fixture("company-report-not-found.xml"))
410
+ end
411
+
412
+ it "raises an error" do
413
+ expect { company_report }.to raise_error(Creditsafe::DataError)
414
+ end
415
+
416
+ it "gives a useful error message" do
417
+ expect { company_report }.to raise_error(
418
+ Creditsafe::DataError, /Report unavailable/
419
+ )
420
+ end
421
+ end
422
+ end
423
+ end