optimum 1.0.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 +7 -0
- data/.gitignore +13 -0
- data/.rspec +4 -0
- data/.rubocop.yml +31 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +105 -0
- data/README.md +74 -0
- data/Rakefile +8 -0
- data/bin/console +18 -0
- data/bin/setup +8 -0
- data/lib/optimum.rb +23 -0
- data/lib/optimum/configuration.rb +28 -0
- data/lib/optimum/connection.rb +68 -0
- data/lib/optimum/customer_generator.rb +130 -0
- data/lib/optimum/decision.rb +17 -0
- data/lib/optimum/path_sanitizer.rb +11 -0
- data/lib/optimum/response.rb +25 -0
- data/lib/optimum/version.rb +5 -0
- data/optimum.gemspec +46 -0
- data/vcr_cassettes/decide_invalid.yml +53 -0
- data/vcr_cassettes/decide_no_auth.yml +52 -0
- data/vcr_cassettes/decide_valid.yml +54 -0
- data/vcr_cassettes/update_approved.yml +53 -0
- data/vcr_cassettes/update_declined.yml +53 -0
- data/vcr_cassettes/update_invalid.yml +53 -0
- data/vcr_cassettes/update_no_auth.yml +52 -0
- data/vcr_cassettes/update_no_decision_possible.yml +53 -0
- metadata +295 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3534d5d95a086cfb762786c9f275b468c819f490c33d04a1b4d5479eaa2d7600
|
4
|
+
data.tar.gz: aff2d7e31171732f026966d41b6e65466f73ee3c3e5aa9b81e33dfabc5e5cae0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ff410a48fc4f8fc417ffbddd931603901566cb13bed126e33f2420f178920105f43358c8c640c7dd3f3159f4e66ef1ad0519105f4c9825c8308ecbdf5885e6f0
|
7
|
+
data.tar.gz: 4443d5f791fb50599012110c9aa7d5a4faf4898073838dbf815be8485ecce1c35a799f4c29dc15378ad4aebbd3e389b50e57c632ab976bc947e543a19203b182
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require: rubocop-rspec
|
2
|
+
|
3
|
+
AllCops:
|
4
|
+
TargetRubyVersion: 2.5.1
|
5
|
+
|
6
|
+
# Don't force top level comments in every class
|
7
|
+
Style/Documentation:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
# A good line length is 100 chars
|
11
|
+
Layout/LineLength:
|
12
|
+
Max: 100
|
13
|
+
AllowURI: true
|
14
|
+
|
15
|
+
Metrics/BlockLength:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
Metrics/ClassLength:
|
19
|
+
Max: 300
|
20
|
+
|
21
|
+
Metrics/MethodLength:
|
22
|
+
Max: 20
|
23
|
+
|
24
|
+
Metrics/AbcSize:
|
25
|
+
Max: 30
|
26
|
+
|
27
|
+
RSpec/ExampleLength:
|
28
|
+
Enabled: false
|
29
|
+
|
30
|
+
RSpec/MultipleExpectations:
|
31
|
+
Max: 10
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.6.6
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
optimum (1.0.0)
|
5
|
+
addressable
|
6
|
+
faraday
|
7
|
+
faraday_middleware
|
8
|
+
multi_json
|
9
|
+
rainbow
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
addressable (2.7.0)
|
15
|
+
public_suffix (>= 2.0.2, < 5.0)
|
16
|
+
ast (2.4.0)
|
17
|
+
byebug (11.1.0)
|
18
|
+
coderay (1.1.2)
|
19
|
+
concurrent-ruby (1.1.5)
|
20
|
+
crack (0.4.3)
|
21
|
+
safe_yaml (~> 1.0.0)
|
22
|
+
diff-lcs (1.3)
|
23
|
+
docile (1.3.2)
|
24
|
+
dotenv (2.7.5)
|
25
|
+
faker (2.10.1)
|
26
|
+
i18n (>= 1.6, < 2)
|
27
|
+
faraday (1.0.1)
|
28
|
+
multipart-post (>= 1.2, < 3)
|
29
|
+
faraday_middleware (1.0.0)
|
30
|
+
faraday (~> 1.0)
|
31
|
+
hashdiff (1.0.0)
|
32
|
+
i18n (1.8.2)
|
33
|
+
concurrent-ruby (~> 1.0)
|
34
|
+
jaro_winkler (1.5.4)
|
35
|
+
json (2.3.0)
|
36
|
+
method_source (0.9.2)
|
37
|
+
multi_json (1.15.0)
|
38
|
+
multipart-post (2.1.1)
|
39
|
+
parallel (1.19.1)
|
40
|
+
parser (2.7.0.2)
|
41
|
+
ast (~> 2.4.0)
|
42
|
+
pry (0.12.2)
|
43
|
+
coderay (~> 1.1.0)
|
44
|
+
method_source (~> 0.9.0)
|
45
|
+
pry-byebug (3.7.0)
|
46
|
+
byebug (~> 11.0)
|
47
|
+
pry (~> 0.10)
|
48
|
+
public_suffix (4.0.3)
|
49
|
+
rainbow (3.0.0)
|
50
|
+
rake (10.5.0)
|
51
|
+
rspec (3.9.0)
|
52
|
+
rspec-core (~> 3.9.0)
|
53
|
+
rspec-expectations (~> 3.9.0)
|
54
|
+
rspec-mocks (~> 3.9.0)
|
55
|
+
rspec-core (3.9.1)
|
56
|
+
rspec-support (~> 3.9.1)
|
57
|
+
rspec-expectations (3.9.0)
|
58
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
59
|
+
rspec-support (~> 3.9.0)
|
60
|
+
rspec-mocks (3.9.1)
|
61
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
62
|
+
rspec-support (~> 3.9.0)
|
63
|
+
rspec-support (3.9.2)
|
64
|
+
rubocop (0.79.0)
|
65
|
+
jaro_winkler (~> 1.5.1)
|
66
|
+
parallel (~> 1.10)
|
67
|
+
parser (>= 2.7.0.1)
|
68
|
+
rainbow (>= 2.2.2, < 4.0)
|
69
|
+
ruby-progressbar (~> 1.7)
|
70
|
+
unicode-display_width (>= 1.4.0, < 1.7)
|
71
|
+
rubocop-rspec (1.37.1)
|
72
|
+
rubocop (>= 0.68.1)
|
73
|
+
ruby-progressbar (1.10.1)
|
74
|
+
safe_yaml (1.0.5)
|
75
|
+
simplecov (0.17.1)
|
76
|
+
docile (~> 1.1)
|
77
|
+
json (>= 1.8, < 3)
|
78
|
+
simplecov-html (~> 0.10.0)
|
79
|
+
simplecov-html (0.10.2)
|
80
|
+
unicode-display_width (1.6.1)
|
81
|
+
vcr (5.0.0)
|
82
|
+
webmock (3.8.0)
|
83
|
+
addressable (>= 2.3.6)
|
84
|
+
crack (>= 0.3.2)
|
85
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
86
|
+
|
87
|
+
PLATFORMS
|
88
|
+
ruby
|
89
|
+
|
90
|
+
DEPENDENCIES
|
91
|
+
bundler
|
92
|
+
dotenv
|
93
|
+
faker
|
94
|
+
optimum!
|
95
|
+
pry-byebug
|
96
|
+
rake (~> 10.0)
|
97
|
+
rspec (~> 3.0)
|
98
|
+
rubocop
|
99
|
+
rubocop-rspec
|
100
|
+
simplecov
|
101
|
+
vcr
|
102
|
+
webmock
|
103
|
+
|
104
|
+
BUNDLED WITH
|
105
|
+
2.1.4
|
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# optimum API wrapper
|
2
|
+
|
3
|
+
This is a simple gem to interact with [optimum's](https://www.optimumfinance.co.uk/) Instant Decision API.
|
4
|
+
|
5
|
+
The API documentation can be found here: https://optimum-core-staging.herokuapp.com/api/v1/instant-decision/docs
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'optimum'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install optimum
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
You need to have an introducerId to use the API. Every request will be authenticated with that id in the params.
|
26
|
+
|
27
|
+
### Configuration
|
28
|
+
|
29
|
+
You can configure Optimum by providing a configuration block, before you do any call:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
Optimum.configure do |config|
|
33
|
+
config.introducer_id = YOUR_ID_HERE
|
34
|
+
# config.debug = true # This is false by default, keep in mind it will ve VERY verbose
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
### Quote
|
39
|
+
|
40
|
+
All the available methods are encapsulated in the `Decision` class. The available methods are:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
Optimum::Decision.create(PARAMS)
|
44
|
+
# => This will return a decision, along with opportunityId, which will be used in subsequent calls.
|
45
|
+
|
46
|
+
Optimum::Decision.update(PARAMS)
|
47
|
+
```
|
48
|
+
|
49
|
+
Every call will return a `Optimum::Response` instance, that you can use to get all the information
|
50
|
+
you need:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
response = Optimum::Decision.update(PARAMS)
|
54
|
+
|
55
|
+
response.status #=> 200
|
56
|
+
response.success? #=> true
|
57
|
+
response.errors #=> []
|
58
|
+
response.data #=> { ... }
|
59
|
+
```
|
60
|
+
|
61
|
+
## Development
|
62
|
+
|
63
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run
|
64
|
+
the tests. You can also run `bin/console` for an interactive prompt that will allow you to
|
65
|
+
experiment.
|
66
|
+
|
67
|
+
Please refer to optimum's documentation on how to test different states (we do have recorded VCR
|
68
|
+
responses, but if something changes on their side we need to update). The documentation is here:
|
69
|
+
https://optimum-core-staging.herokuapp.com/api/v1/instant-decision/docs
|
70
|
+
|
71
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new
|
72
|
+
version, update the version number in `version.rb`, and then run `bundle exec rake release`, which
|
73
|
+
will create a git tag for the version, push git commits and tags, and push the `.gem` file
|
74
|
+
to [rubygems.org](https://rubygems.org).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'optimum'
|
6
|
+
require 'date'
|
7
|
+
|
8
|
+
require 'dotenv'
|
9
|
+
Dotenv.load
|
10
|
+
|
11
|
+
Optimum.configure do |config|
|
12
|
+
config.introducer_id = ENV['OPTIMUM_INTRODUCER_ID']
|
13
|
+
end
|
14
|
+
|
15
|
+
send(:include, Optimum)
|
16
|
+
|
17
|
+
require 'pry'
|
18
|
+
Pry.start
|
data/bin/setup
ADDED
data/lib/optimum.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'optimum/version'
|
4
|
+
require 'optimum/path_sanitizer'
|
5
|
+
require 'optimum/configuration'
|
6
|
+
require 'optimum/connection'
|
7
|
+
require 'optimum/decision'
|
8
|
+
|
9
|
+
module Optimum
|
10
|
+
module_function
|
11
|
+
|
12
|
+
def configuration
|
13
|
+
@configuration ||= Configuration.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def connection
|
17
|
+
@connection ||= Connection.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def configure
|
21
|
+
yield(configuration)
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Optimum
|
4
|
+
class Configuration
|
5
|
+
attr_accessor :env, :introducer_id
|
6
|
+
attr_writer :debug
|
7
|
+
|
8
|
+
API_DOMAINS = {
|
9
|
+
production: 'https://www.optimum.localhost',
|
10
|
+
development: 'https://optimum-core-staging.herokuapp.com'
|
11
|
+
}.freeze
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@introducer_id = ''
|
15
|
+
@webhook_signature = ''
|
16
|
+
@env = defined?(Rails) ? Rails.env : :development
|
17
|
+
@debug = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def debug?
|
21
|
+
@debug
|
22
|
+
end
|
23
|
+
|
24
|
+
def api_domain
|
25
|
+
API_DOMAINS[@env.to_sym] || API_DOMAINS[:development]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'faraday'
|
4
|
+
require 'faraday_middleware'
|
5
|
+
require 'rainbow'
|
6
|
+
require 'addressable'
|
7
|
+
|
8
|
+
require 'optimum/response'
|
9
|
+
|
10
|
+
module Optimum
|
11
|
+
class Connection
|
12
|
+
BASE_PATH = '/api/v1/instant-decision'
|
13
|
+
|
14
|
+
def get(path, params = {})
|
15
|
+
log "GET #{path} with #{params}"
|
16
|
+
|
17
|
+
http_response = adapter.get(PathSanitizer.sanitize(path)) do |req|
|
18
|
+
req.body = params.to_json
|
19
|
+
end
|
20
|
+
|
21
|
+
log "Response: #{http_response.body}"
|
22
|
+
|
23
|
+
Response.new(http_response)
|
24
|
+
end
|
25
|
+
|
26
|
+
def post(path, params = {})
|
27
|
+
log "POST #{path} with #{params}"
|
28
|
+
|
29
|
+
http_response = adapter.post(PathSanitizer.sanitize(path), params.to_json)
|
30
|
+
|
31
|
+
log "Response: #{http_response.body}"
|
32
|
+
|
33
|
+
Response.new(http_response)
|
34
|
+
end
|
35
|
+
|
36
|
+
def put(path, params = {})
|
37
|
+
log "PUT #{path} with #{params}"
|
38
|
+
|
39
|
+
http_response = adapter.put(PathSanitizer.sanitize(path), params.to_json)
|
40
|
+
|
41
|
+
log "Response: #{http_response.body}"
|
42
|
+
|
43
|
+
Response.new(http_response)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def log(text)
|
49
|
+
return unless Optimum.configuration.debug?
|
50
|
+
|
51
|
+
puts Rainbow("[Optimum] #{text}").magenta.bright
|
52
|
+
end
|
53
|
+
|
54
|
+
def base_url
|
55
|
+
Addressable::URI.join(Optimum.configuration.api_domain, BASE_PATH).to_s
|
56
|
+
end
|
57
|
+
|
58
|
+
def adapter
|
59
|
+
Faraday.new(url: base_url) do |conn|
|
60
|
+
conn.headers['Content-Type'] = 'application/json'
|
61
|
+
conn.headers['User-Agent'] = "ruby-optimum-#{VERSION}"
|
62
|
+
conn.response :json, parser_options: { symbolize_names: true }, content_type: /\bjson$/
|
63
|
+
conn.response :logger if Optimum.configuration.debug?
|
64
|
+
conn.adapter Faraday.default_adapter
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'faker'
|
4
|
+
|
5
|
+
module Optimum
|
6
|
+
# This class can be used to generate fake customers for test purposes
|
7
|
+
class CustomerGenerator
|
8
|
+
attr_accessor :id, :first_name, :last_name, :email, :phone, :address, :date_of_birth, :city
|
9
|
+
attr_accessor :postcode
|
10
|
+
|
11
|
+
DEFAULTS = {
|
12
|
+
id: SecureRandom.hex(4),
|
13
|
+
first_name: Faker::Name.first_name,
|
14
|
+
last_name: Faker::Name.last_name,
|
15
|
+
email: Faker::Internet.email,
|
16
|
+
phone: Faker::PhoneNumber.phone_number,
|
17
|
+
address: Faker::Address.street_address,
|
18
|
+
date_of_birth: Faker::Date.birthday(min_age: 23, max_age: 65),
|
19
|
+
city: Faker::Address.city,
|
20
|
+
postcode: Faker::Address.postcode
|
21
|
+
}.freeze
|
22
|
+
|
23
|
+
def self.generate(params = {})
|
24
|
+
new(params).generate
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(params = {})
|
28
|
+
Faker::Config.locale = 'en-GB'
|
29
|
+
|
30
|
+
DEFAULTS.each do |key, default_value|
|
31
|
+
send("#{key}=", params[key] || default_value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def generate
|
36
|
+
{
|
37
|
+
data: {
|
38
|
+
application: {
|
39
|
+
company: company_information,
|
40
|
+
people: [user_information],
|
41
|
+
requested_products: {
|
42
|
+
credit_facility: {
|
43
|
+
approval: {
|
44
|
+
amount: 123_123,
|
45
|
+
duration: 12,
|
46
|
+
detailed_purpose: 'business loan'
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def company_information
|
56
|
+
{
|
57
|
+
last_12_months_turnover: {
|
58
|
+
amount: 0.0
|
59
|
+
},
|
60
|
+
registered_company_name: 'HOKO LTD',
|
61
|
+
industry: 'B | Mining and Quarrying',
|
62
|
+
company_number: '09525857',
|
63
|
+
type: 'limited_liability_company',
|
64
|
+
trading_from_date: '2015-05-22',
|
65
|
+
registered_address: {
|
66
|
+
postcode: 'W1T 3NF',
|
67
|
+
street_line_1: 'Berners House',
|
68
|
+
street_line_2: '47-48 Berners Street',
|
69
|
+
town: 'London',
|
70
|
+
country: 'GB'
|
71
|
+
},
|
72
|
+
vat_status: {
|
73
|
+
is_vat_registered: true
|
74
|
+
}
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def user_information
|
79
|
+
{
|
80
|
+
uid: SecureRandom.uuid,
|
81
|
+
first_name: first_name,
|
82
|
+
last_name: last_name,
|
83
|
+
date_of_birth: date_of_birth,
|
84
|
+
roles: %w[applicant shareholder guarantor director],
|
85
|
+
phones: phones,
|
86
|
+
emails: emails,
|
87
|
+
residential_addresses: residential_addresses,
|
88
|
+
privacy_policy: {
|
89
|
+
agreed: true,
|
90
|
+
datetime: DateTime.now
|
91
|
+
}
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
def phones
|
96
|
+
[
|
97
|
+
{
|
98
|
+
uid: SecureRandom.uuid,
|
99
|
+
number: phone,
|
100
|
+
type: 'primary'
|
101
|
+
}
|
102
|
+
]
|
103
|
+
end
|
104
|
+
|
105
|
+
def emails
|
106
|
+
[
|
107
|
+
{
|
108
|
+
uid: SecureRandom.uuid,
|
109
|
+
email: email,
|
110
|
+
type: 'primary'
|
111
|
+
}
|
112
|
+
]
|
113
|
+
end
|
114
|
+
|
115
|
+
def residential_addresses
|
116
|
+
[
|
117
|
+
{
|
118
|
+
uid: SecureRandom.uuid,
|
119
|
+
town: city,
|
120
|
+
street_line_1: address,
|
121
|
+
street_line_2: '',
|
122
|
+
country: 'GB',
|
123
|
+
postcode: postcode,
|
124
|
+
house_number: '10',
|
125
|
+
residential_status: 'owner_no_mortgage'
|
126
|
+
}
|
127
|
+
]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|