creditsafe 0.6.0 → 0.6.1

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 (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