instant_quote 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4ef875cefed1539965a4ae7b1887b6f8566b59afa05645da6c4c870d21d47cdf
4
+ data.tar.gz: 6f6b168b51dd4c945f18772e2baf3ef1712af0a28737929d50f9abd9d9da5ec6
5
+ SHA512:
6
+ metadata.gz: 50be577e7e0c420de314a096d792462391bcb71d4d13e0bdaeb64db4611cd03231e2e394b7c50be6d9523344a9c86fdf174f0b04d45880238eaabfd452680627
7
+ data.tar.gz: 85d5e1ae438101c3e699e289632098ef9530efacae59a31d5f60d08db173d780a371573bb534f2fbb98de8918e6df509c7b161986e6c0907722ebe3a71e08573
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .DS_Store
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,17 @@
1
+ Layout/LineLength:
2
+ Max: 100
3
+
4
+ Style/Documentation:
5
+ Enabled: false
6
+
7
+ Metrics/ClassLength:
8
+ Max: 250
9
+
10
+ Metrics/MethodLength:
11
+ Max: 25
12
+
13
+ Metrics/BlockLength:
14
+ Max: 200
15
+
16
+ Naming/AccessorMethodName:
17
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.6.3
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.3
7
+ before_install: gem install bundler -v 2.0.2
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # When developing new features in the gems this might be handy
6
+ #
7
+ # gem 'capital_on_tap', path: '../capital-on-tap'
8
+ # gem 'iwoca', path: '../iwoca'
9
+
10
+ # Specify your gem's dependencies in instant-quotes.gemspec
11
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,110 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ instant_quote (1.0.5)
5
+ activesupport
6
+ capital_on_tap
7
+ iwoca
8
+ money
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ activesupport (6.0.2.1)
14
+ concurrent-ruby (~> 1.0, >= 1.0.2)
15
+ i18n (>= 0.7, < 2)
16
+ minitest (~> 5.1)
17
+ tzinfo (~> 1.1)
18
+ zeitwerk (~> 2.2)
19
+ addressable (2.7.0)
20
+ public_suffix (>= 2.0.2, < 5.0)
21
+ ast (2.4.0)
22
+ byebug (11.1.1)
23
+ capital_on_tap (1.0.0)
24
+ addressable
25
+ faraday
26
+ faraday_middleware
27
+ multi_json
28
+ rainbow
29
+ coderay (1.1.2)
30
+ concurrent-ruby (1.1.5)
31
+ diff-lcs (1.3)
32
+ docile (1.3.2)
33
+ dotenv (2.7.5)
34
+ faraday (0.17.3)
35
+ multipart-post (>= 1.2, < 3)
36
+ faraday_middleware (0.14.0)
37
+ faraday (>= 0.7.4, < 1.0)
38
+ i18n (1.8.2)
39
+ concurrent-ruby (~> 1.0)
40
+ iwoca (1.0.0)
41
+ addressable
42
+ faraday
43
+ faraday_middleware
44
+ multi_json
45
+ rainbow
46
+ jaro_winkler (1.5.4)
47
+ method_source (0.9.2)
48
+ minitest (5.14.0)
49
+ money (6.13.7)
50
+ i18n (>= 0.6.4, <= 2)
51
+ multi_json (1.14.1)
52
+ multipart-post (2.1.1)
53
+ parallel (1.19.1)
54
+ parser (2.7.0.2)
55
+ ast (~> 2.4.0)
56
+ pry (0.12.2)
57
+ coderay (~> 1.1.0)
58
+ method_source (~> 0.9.0)
59
+ pry-byebug (3.8.0)
60
+ byebug (~> 11.0)
61
+ pry (~> 0.10)
62
+ public_suffix (4.0.3)
63
+ rainbow (3.0.0)
64
+ rake (10.5.0)
65
+ rspec (3.9.0)
66
+ rspec-core (~> 3.9.0)
67
+ rspec-expectations (~> 3.9.0)
68
+ rspec-mocks (~> 3.9.0)
69
+ rspec-core (3.9.1)
70
+ rspec-support (~> 3.9.1)
71
+ rspec-expectations (3.9.0)
72
+ diff-lcs (>= 1.2.0, < 2.0)
73
+ rspec-support (~> 3.9.0)
74
+ rspec-mocks (3.9.1)
75
+ diff-lcs (>= 1.2.0, < 2.0)
76
+ rspec-support (~> 3.9.0)
77
+ rspec-support (3.9.2)
78
+ rubocop (0.79.0)
79
+ jaro_winkler (~> 1.5.1)
80
+ parallel (~> 1.10)
81
+ parser (>= 2.7.0.1)
82
+ rainbow (>= 2.2.2, < 4.0)
83
+ ruby-progressbar (~> 1.7)
84
+ unicode-display_width (>= 1.4.0, < 1.7)
85
+ ruby-progressbar (1.10.1)
86
+ simplecov (0.18.1)
87
+ docile (~> 1.1)
88
+ simplecov-html (~> 0.11.0)
89
+ simplecov-html (0.11.0)
90
+ thread_safe (0.3.6)
91
+ tzinfo (1.2.6)
92
+ thread_safe (~> 0.1)
93
+ unicode-display_width (1.6.1)
94
+ zeitwerk (2.2.2)
95
+
96
+ PLATFORMS
97
+ ruby
98
+
99
+ DEPENDENCIES
100
+ bundler (~> 2.0)
101
+ dotenv
102
+ instant_quote!
103
+ pry-byebug
104
+ rake (~> 10.0)
105
+ rspec (~> 3.0)
106
+ rubocop
107
+ simplecov
108
+
109
+ BUNDLED WITH
110
+ 2.0.2
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # Instant Quote
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/instant/quotes`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'instant_quote'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install instant-quotes
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require 'bundler/setup'
6
+ require 'instant_quote'
7
+ require 'dotenv'
8
+
9
+ Dotenv.load
10
+
11
+ require 'capital_on_tap'
12
+ require 'iwoca'
13
+
14
+ CapitalOnTap.configure do |config|
15
+ config.client_id = ENV['CAPITAL_ON_TAP_CLIENT_ID']
16
+ config.client_secret = ENV['CAPITAL_ON_TAP_CLIENT_SECRET']
17
+ config.username = ENV['CAPITAL_ON_TAP_USERNAME']
18
+ config.password = ENV['CAPITAL_ON_TAP_PASSWORD']
19
+ config.debug = true
20
+ end
21
+
22
+ Iwoca.configure do |config|
23
+ config.api_key = ENV['IWOCA_API_KEY']
24
+ config.webhook_signature = ENV['IWOCA_WEBHOOK_SIGNATURE']
25
+ end
26
+
27
+ send(:include, InstantQuote)
28
+
29
+ require 'pry'
30
+ Pry.start
data/bin/setup ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # frozen_string_literal: true
4
+
5
+ set -euo pipefail
6
+ IFS=$'\n\t'
7
+ set -vx
8
+
9
+ bundle install
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'instant_quote/version'
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = 'instant_quote'
10
+ spec.version = InstantQuote::VERSION
11
+ spec.authors = ['rikas']
12
+ spec.email = ['oterosantos@gmail.com']
13
+
14
+ spec.summary = 'Instant quote providers gem.'
15
+ spec.description = spec.summary
16
+ spec.homepage = 'https://finpoint.co.uk'
17
+
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^((test|spec|features)/|.env)}) }
24
+ end
25
+ spec.bindir = 'exe'
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ['lib']
28
+
29
+ spec.add_development_dependency 'bundler', '~> 2.0'
30
+ spec.add_development_dependency 'dotenv'
31
+ spec.add_development_dependency 'pry-byebug'
32
+ spec.add_development_dependency 'rake', '~> 10.0'
33
+ spec.add_development_dependency 'rspec', '~> 3.0'
34
+ spec.add_development_dependency 'rubocop'
35
+ spec.add_development_dependency 'simplecov'
36
+
37
+ spec.add_dependency 'activesupport'
38
+ spec.add_dependency 'capital_on_tap'
39
+ spec.add_dependency 'iwoca'
40
+ spec.add_dependency 'money'
41
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InstantQuote
4
+ class Adapter
5
+ def self.additional_fields(fields = [])
6
+ return (@additional_fields || []) if fields.empty?
7
+
8
+ @additional_fields = fields
9
+ end
10
+
11
+ def self.get_link(application_id)
12
+ new.get_link(application_id)
13
+ end
14
+
15
+ def self.get_quote(params)
16
+ new.get_quote(params)
17
+ end
18
+
19
+ def self.get_status(application_id)
20
+ new.get_status(application_id)
21
+ end
22
+
23
+ def self.get_approval(application_id)
24
+ new.get_approval(application_id)
25
+ end
26
+
27
+ def get_link(_application_id)
28
+ raise NotImplementedError, "You must implement '#{self.class.name}#get_link'"
29
+ end
30
+
31
+ def get_quote(_params)
32
+ raise NotImplementedError, "You must implement '#{self.class.name}#get_quote'"
33
+ end
34
+
35
+ def get_status(_application_id)
36
+ raise NotImplementedError, "You must implement '#{self.class.name}#get_status'"
37
+ end
38
+
39
+ def get_approval(_application_id)
40
+ raise NotImplementedError, "You must implement '#{self.class.name}#get_approval"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Require all the connection translators
4
+ translators = Dir.children(File.expand_path('connection_translators', __dir__))
5
+ translators.each { |translator| require "instant_quote/connection_translators/#{translator}" }
6
+
7
+ # Require all the decision parsers
8
+ parsers = Dir.children(File.expand_path('decision_parsers', __dir__))
9
+ parsers.each { |parser| require "instant_quote/decision_parsers/#{parser}" }
10
+
11
+ # Require all the adapters
12
+ adapters = Dir.children(File.expand_path('adapters', __dir__))
13
+ adapters.each { |adapter| require "instant_quote/adapters/#{adapter}" }
14
+
15
+ module InstantQuote
16
+ class AdapterFinder
17
+ attr_reader :connection, :adapter, :translator, :decision_parser
18
+
19
+ def initialize(connection)
20
+ @connection = connection
21
+ @adapter_name = connection.adapter
22
+
23
+ validate_adapter_name!
24
+
25
+ @adapter = Object.const_get("InstantQuote::Adapters::#{adapter_class}")
26
+ @translator = Object.const_get("InstantQuote::ConnectionTranslators::#{adapter_class}")
27
+ @decision_parser = Object.const_get("InstantQuote::DecisionParsers::#{adapter_class}")
28
+ end
29
+
30
+ def get_link
31
+ adapter.get_link(connection.external_id)
32
+ end
33
+
34
+ def get_quote
35
+ params = translator.translate(connection)
36
+
37
+ adapter.get_quote(params)
38
+ end
39
+
40
+ def get_status
41
+ adapter.get_status(connection.external_id)
42
+ end
43
+
44
+ def get_approval
45
+ adapter.get_approval(connection.external_id)
46
+ end
47
+
48
+ def additional_fields
49
+ adapter.additional_fields
50
+ end
51
+
52
+ def parse_decision
53
+ decision_parser.new(connection.approval_decision_info)
54
+ end
55
+
56
+ private
57
+
58
+ def adapter_class
59
+ @adapter_name.to_s.split('_').map(&:capitalize).join
60
+ end
61
+
62
+ def available_adapters
63
+ adapters = Dir.children(File.expand_path('adapters', __dir__))
64
+ adapters.map { |adapter| adapter.tr('.rb', '') }
65
+ end
66
+
67
+ def validate_adapter_name!
68
+ return true if available_adapters.include?(@adapter_name)
69
+
70
+ message = "Unknown adapter '#{@adapter_name}'. Available names: #{available_adapters}"
71
+
72
+ raise InstantQuote::AdapterError, message
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'capital_on_tap'
4
+ require 'instant_quote/decision_parsers/capital_on_tap'
5
+
6
+ module InstantQuote
7
+ module Adapters
8
+ class CapitalOnTap < Adapter
9
+ additional_fields [
10
+ {
11
+ name: 'date_of_birth',
12
+ label: 'Date of birth',
13
+ type: 'date',
14
+ required: true
15
+ },
16
+ {
17
+ name: 'business_landline',
18
+ label: 'Business landline',
19
+ required: true
20
+ },
21
+ {
22
+ name: 'applicant_phone_number',
23
+ label: 'Applicant mobile phone',
24
+ required: true
25
+ },
26
+ {
27
+ name: 'applicant_consent',
28
+ label: 'Yes, I give my consent for my data to be shared',
29
+ required: true,
30
+ type: 'checkbox'
31
+ }
32
+ ]
33
+
34
+ # Creates the quote with the information from instant connection
35
+ def get_quote(params)
36
+ response = ::CapitalOnTap::Application.create(params)
37
+
38
+ # CoT responses can be 200 OK but still have an error!
39
+ unless response.success? && !response.error
40
+ raise ApiError.new(data: response.body, error: response.error || 'Unknown API error')
41
+ end
42
+
43
+ response.body.dig(:result)
44
+ end
45
+
46
+ # Get the status for a given application ID
47
+ # {:applicationStatus=>
48
+ # {:locatorId=>"B247T62",
49
+ # :applicationStage=>"AppSubmitted",
50
+ # :creditDecision=>
51
+ # {:status=>"Pending",
52
+ # :starRating=>0.0,
53
+ # :approvalAmount=>0.0,
54
+ # :monthlyInterestRate=>0.0,
55
+ # :monthlyCardInterestRate=>0.0,
56
+ # :decisionDate=>"2020-01-28T01:44:29.241",
57
+ # :creditDecisionReason=>"None"}},
58
+ # :links=>{:self=>"/api/v1/Applications/B247T62", :parent=>nil},
59
+ # :metaData=>{}
60
+ # }
61
+ def get_status(application_id)
62
+ response = ::CapitalOnTap::Application.status(application_id)
63
+
64
+ raise ApiError.new(data: response.body, error: response.error) unless response.success?
65
+
66
+ DecisionParsers::CapitalOnTap.new(response.body[:applicationStatus])
67
+ end
68
+
69
+ # The link is always the same for Capital On Tap
70
+ def get_link(_application_id)
71
+ 'https://account.capitalontap.com/apps/portal/login/'
72
+ end
73
+
74
+ # Capital On Tap doesn't need an approval request
75
+ def get_approval(_application_id)
76
+ true
77
+ end
78
+ end
79
+ end
80
+ end