instant_quote 1.7.3 → 1.7.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f9a1202f635271c79343dd62421fb3b5e25c070fb6c9946e4a6b576a7924edc3
4
- data.tar.gz: 39d9952984651ed93a4fed738be8bafbebe0529a3c271eaa349a8c744eae30de
3
+ metadata.gz: a68d10d20e17f32e18921fae70cd7dfeb606e71e2801e809269c148bfe35c513
4
+ data.tar.gz: fbe659e1e32f5cbc7fd98ab6db37601fd3215b6c866f23119588e4a83d604509
5
5
  SHA512:
6
- metadata.gz: a637cffbc3e704ea920c76bc8ef4a0beccfde26dee3380537f4e19aee9df8c385e90db683d950f1e82751622a13e6bb98eb742614299e9a6e6f8ae079b694aae
7
- data.tar.gz: 6db6c7751b03f95e2ff1045e5cf8c309490d9d169fd472cb665b6a549659b19e4f59e1981f8ff1be2469b67108698ec240ff1241db977cd02ed8c59daa15063d
6
+ metadata.gz: e5f3a8834baabc3c81107e5c31a982b761ac0af4fe9e07149c1cfa2c494060dbed29a42de225dabe0072867f2782efac2e10521a97ef7f89f19c19c7859845c1
7
+ data.tar.gz: 06f335e1b72643023c5673a0bc7d0542ff8b03e32dda660db4d49a673933c3ccbef9cd9f3b05ef6100c68552797ffb27ec15953b4418678167b1ee1c008b6ce6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- instant_quote (1.7.3)
4
+ instant_quote (1.7.8)
5
5
  activesupport
6
6
  capital_on_tap
7
7
  iwoca
@@ -13,7 +13,7 @@ PATH
13
13
  GEM
14
14
  remote: https://rubygems.org/
15
15
  specs:
16
- activesupport (6.1.3)
16
+ activesupport (6.1.3.1)
17
17
  concurrent-ruby (~> 1.0, >= 1.0.2)
18
18
  i18n (>= 1.6, < 2)
19
19
  minitest (>= 5.1)
@@ -36,15 +36,19 @@ GEM
36
36
  diff-lcs (1.4.4)
37
37
  docile (1.3.5)
38
38
  dotenv (2.7.6)
39
- faraday (1.3.0)
39
+ faraday (1.4.1)
40
+ faraday-excon (~> 1.1)
40
41
  faraday-net_http (~> 1.0)
42
+ faraday-net_http_persistent (~> 1.1)
41
43
  multipart-post (>= 1.2, < 3)
42
- ruby2_keywords
44
+ ruby2_keywords (>= 0.0.4)
45
+ faraday-excon (1.1.0)
43
46
  faraday-net_http (1.0.1)
47
+ faraday-net_http_persistent (1.1.0)
44
48
  faraday_middleware (1.0.0)
45
49
  faraday (~> 1.0)
46
50
  hashdiff (1.0.1)
47
- i18n (1.8.9)
51
+ i18n (1.8.10)
48
52
  concurrent-ruby (~> 1.0)
49
53
  iwoca (1.0.0)
50
54
  addressable
@@ -53,8 +57,8 @@ GEM
53
57
  multi_json
54
58
  rainbow
55
59
  method_source (1.0.0)
56
- minitest (5.14.3)
57
- money (6.14.0)
60
+ minitest (5.14.4)
61
+ money (6.14.1)
58
62
  i18n (>= 0.6.4, <= 2)
59
63
  multi_json (1.15.0)
60
64
  multipart-post (2.1.1)
@@ -67,7 +71,7 @@ GEM
67
71
  parallel (1.20.1)
68
72
  parser (3.0.0.0)
69
73
  ast (~> 2.4.1)
70
- phonelib (0.6.48)
74
+ phonelib (0.6.49)
71
75
  pry (0.13.1)
72
76
  coderay (~> 1.1)
73
77
  method_source (~> 1.0)
@@ -77,7 +81,7 @@ GEM
77
81
  public_suffix (4.0.6)
78
82
  rainbow (3.0.0)
79
83
  rake (10.5.0)
80
- regexp_parser (2.0.3)
84
+ regexp_parser (2.1.1)
81
85
  rexml (3.2.4)
82
86
  rspec (3.10.0)
83
87
  rspec-core (~> 3.10.0)
@@ -92,7 +96,7 @@ GEM
92
96
  diff-lcs (>= 1.2.0, < 2.0)
93
97
  rspec-support (~> 3.10.0)
94
98
  rspec-support (3.10.2)
95
- rubocop (1.9.1)
99
+ rubocop (1.11.0)
96
100
  parallel (~> 1.10)
97
101
  parser (>= 3.0.0.0)
98
102
  rainbow (>= 2.2.2, < 4.0)
@@ -119,7 +123,7 @@ GEM
119
123
  tzinfo (2.0.4)
120
124
  concurrent-ruby (~> 1.0)
121
125
  unicode-display_width (2.0.0)
122
- webmock (3.11.2)
126
+ webmock (3.12.1)
123
127
  addressable (>= 2.3.6)
124
128
  crack (>= 0.3.2)
125
129
  hashdiff (>= 0.4.0, < 2.0.0)
@@ -148,4 +152,4 @@ DEPENDENCIES
148
152
  webmock
149
153
 
150
154
  BUNDLED WITH
151
- 2.2.5
155
+ 2.2.11
@@ -51,14 +51,14 @@ module InstantQuote
51
51
  raise NotImplementedError, "You must implement '#{self.class.name}#get_status'"
52
52
  end
53
53
 
54
- # Default for pre approval will be true, override it in the adapter class if needed.
54
+ # Default for pre approval will be success, override it in the adapter class if needed.
55
55
  def get_preapproval(_params, _connection)
56
- true
56
+ OpenStruct.new(success?: true)
57
57
  end
58
58
 
59
- # Default for approval will be true, override it in the adapter class if needed.
59
+ # Default for approval will be success, override it in the adapter class if needed.
60
60
  def get_approval(_application_id, _connection)
61
- true
61
+ OpenStruct.new(success?: true)
62
62
  end
63
63
  end
64
64
  end
@@ -28,18 +28,6 @@ module InstantQuote
28
28
  required: true,
29
29
  if: ->(app) { app.borrower_organisation.sole_trader? }
30
30
  },
31
- {
32
- name: 'turnover_percentage_after_feb_2020',
33
- label: 'What is your current turnover as a percentage of your turnover prior to February 2020?',
34
- required: true,
35
- choices: [
36
- 'My turnover had increased since covid',
37
- 'My turnover is about the same as it was pre-covid (within 20%)',
38
- 'My turnover has fallen materially as a result of covid (20%-60% reduction in turnover)',
39
- 'My turnover has fallen significantly as a result of covid (more than a 60% reduction in turnover)'
40
- ],
41
- type: 'select'
42
- },
43
31
  {
44
32
  name: 'preferred_monthly_repayment_option',
45
33
  label: 'How do you want to set up your direct debit for monthly repayment?',
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+ require 'instant_quote/decision_parsers/fake'
5
+
6
+ module InstantQuote
7
+ module Adapters
8
+ class Fake < 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: 'desired_status',
18
+ label: 'What status do you want to get back?',
19
+ required: true,
20
+ choices: {
21
+ 'Pending' => 'pending',
22
+ 'Approved' => 'approved',
23
+ 'Declined' => 'declined',
24
+ 'No decision possible' => 'no_decision_possible',
25
+ 'Error on get_quote' => 'error_on_get_quote',
26
+ 'Error on get_status' => 'error_on_get_status'
27
+ },
28
+ type: 'select'
29
+ },
30
+ {
31
+ name: 'decision_info_html',
32
+ label: 'What html you want to render for decision info?',
33
+ required: true,
34
+ choices: {
35
+ 'Iwoca' => 'iwoca',
36
+ 'Iwoca CBILS' => 'iwoca_cbils',
37
+ 'Capital on tap' => 'capital_on_tap',
38
+ 'Optimum' => 'optimum',
39
+ 'Youlend' => 'youlend'
40
+ },
41
+ type: 'select'
42
+ },
43
+ {
44
+ name: 'with_preapproval',
45
+ label: 'Preapproval?',
46
+ choices: {
47
+ 'No' => 'no',
48
+ 'Yes (success)' => 'yes_success',
49
+ 'Yes (decline)' => 'yes_decline'
50
+ },
51
+ type: 'select'
52
+ },
53
+ {
54
+ name: 'with_approval',
55
+ label: 'With approval?',
56
+ choices: {
57
+ 'No' => 'no',
58
+ 'Yes' => 'yes'
59
+ },
60
+ type: 'select'
61
+ },
62
+ {
63
+ name: 'applicant_consent',
64
+ label: 'Yes, I give my consent for my data to be shared',
65
+ required: true,
66
+ type: 'checkbox'
67
+ }
68
+ ]
69
+
70
+ # TODO: what should we do here?
71
+ def get_approval(_state_key, _connection)
72
+ true
73
+ end
74
+
75
+ def get_preapproval(params, _connection)
76
+ response = OpenStruct.new(success?: true, error_description: '')
77
+
78
+ return response if params[:with_preapproval] == 'no'
79
+
80
+ if params[:with_preapproval] == 'yes_decline'
81
+ response[:success?] = false
82
+ response.error_description = 'preapproval is declined'
83
+ end
84
+
85
+ response
86
+ end
87
+
88
+ def get_quote(params, _connection)
89
+ if params[:desired_status] == 'error_on_get_quote'
90
+ response = OpenStruct.new(
91
+ body: { errorMessage: 'Error on get_quote that raises an exception' },
92
+ error: '501 error_on_get_quote'
93
+ )
94
+ raise_error(response)
95
+ end
96
+
97
+ # Returns a random identifier
98
+ SecureRandom.hex(3)
99
+ end
100
+
101
+ # Get the status for a given application ID
102
+ # rubocop:disable Metrics/AbcSize
103
+ # rubocop:disable Metrics/MethodLength
104
+ def get_status(_application_id, connection)
105
+ status = connection.extra_info['desired_status']
106
+
107
+ if status == 'error_on_get_status'
108
+ response = OpenStruct.new(
109
+ body: { errorMessage: 'Error on get_status that raises an exception' },
110
+ error: '502 error_on_get_status'
111
+ )
112
+ raise_error(response) unless response.success?
113
+ end
114
+
115
+ response = OpenStruct.new(
116
+ body: {
117
+ latest_approval_request: {
118
+ status: status,
119
+ approved: {
120
+ interval: rand(10..30),
121
+ duration: rand(10..30),
122
+ max_credit: rand(1000..8000),
123
+ monthly_interest_rate: rand(0..1.0).round(2)
124
+ }
125
+ },
126
+ credit_decision: {
127
+ status: status,
128
+ sweep: 10,
129
+ loan_amount: rand(1000..8000),
130
+ funded_amount: rand(1000..8000),
131
+ fee: rand(100..800),
132
+ monthly_interest_rate: rand(0..1.0).round(2),
133
+ monthly_card_interest_rate: rand(0..1.0).round(2),
134
+ amount: rand(1000..8000)
135
+ }
136
+ }
137
+ )
138
+
139
+ DecisionParsers::Fake.new(response.body)
140
+ end
141
+ # rubocop:enable Metrics/AbcSize
142
+ # rubocop:enable Metrics/MethodLength
143
+
144
+ # The link is always the same
145
+ def get_link(connection)
146
+ id = connection.external_id
147
+
148
+ "https://fake.com/link/#{id}"
149
+ end
150
+
151
+ private
152
+
153
+ def raise_error(response)
154
+ raise ApiError.new(
155
+ adapter: 'fake',
156
+ data: response.body,
157
+ error: response.error || 'Unknown API error'
158
+ )
159
+ end
160
+ end
161
+ end
162
+ end
@@ -75,7 +75,7 @@ module InstantQuote
75
75
  raise ApiError.new(
76
76
  adapter: 'youlend',
77
77
  data: response.body,
78
- error: response.error || '[Youlend] API error'
78
+ error: response.errors.first || '[Youlend] API error'
79
79
  )
80
80
  end
81
81
  end
@@ -72,9 +72,12 @@ module InstantQuote
72
72
  }
73
73
  end
74
74
 
75
+ # TODO: this is no longer true, but we are still keeping the range for legacy reasons.
75
76
  # Since in Finpoint the user selects an intervel (i.e. '500,000 - 999,999'). We get the avg
76
77
  # on this interval and use that number as the monthly turnover.
77
78
  def translate_turnover
79
+ return app_org.turnover_pennies.to_i if app_org.turnover_pennies
80
+
78
81
  turnover = app_org.turnover_range
79
82
 
80
83
  ((turnover.from + turnover.to) / 2 / 100).ceil
@@ -98,7 +101,6 @@ module InstantQuote
98
101
  def additional_questions
99
102
  [
100
103
  preferred_monthly_repayment_option_question,
101
- turnover_percentage_question,
102
104
  send_cash_from_credit_facility_to_bank_question
103
105
  ]
104
106
  end
@@ -107,10 +109,6 @@ module InstantQuote
107
109
  question_from_extra_info('preferred_monthly_repayment_option', '17')
108
110
  end
109
111
 
110
- def turnover_percentage_question
111
- question_from_extra_info('turnover_percentage_after_feb_2020', '20')
112
- end
113
-
114
112
  def send_cash_from_credit_facility_to_bank_question
115
113
  question_from_extra_info('send_cash_from_credit_facility_to_bank', '23')
116
114
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InstantQuote
4
+ module ConnectionTranslators
5
+ class Fake < ConnectionTranslator
6
+ def translate
7
+ {
8
+ salutation: app_user.salutation,
9
+ first_name: app_user.first_name,
10
+ last_name: app_user.last_name,
11
+ date_of_birth: extra_info['date_of_birth'],
12
+ registration_number: app_org.company_number,
13
+ desired_status: extra_info['desired_status']
14
+ }
15
+ end
16
+
17
+ private
18
+
19
+ def app_user
20
+ application.primary_user
21
+ end
22
+
23
+ def app_org
24
+ application.borrower_organisation
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'money'
4
+
5
+ module InstantQuote
6
+ module DecisionParsers
7
+ class Fake < DecisionParser
8
+ STATUSES = {
9
+ pending: 'pending',
10
+ approved: 'approved',
11
+ declined: 'declined',
12
+ could_not_submit: 'CouldNotSubmit',
13
+ no_decision: 'no_decision_possible'
14
+ }.freeze
15
+
16
+ def pending?
17
+ status == STATUSES[:pending]
18
+ end
19
+
20
+ def approved?
21
+ status == STATUSES[:approved]
22
+ end
23
+
24
+ def declined?
25
+ status == STATUSES[:declined]
26
+ end
27
+
28
+ def credit_duration
29
+ credit_decision.dig(:approved, :duration)
30
+ end
31
+
32
+ def credit_interval
33
+ credit_decision.dig(:approved, :interval)
34
+ end
35
+
36
+ def sweep
37
+ credit_decision[:sweep]
38
+ end
39
+
40
+ def fee
41
+ fee = credit_decision[:fee].to_f
42
+
43
+ Money.new(fee * 100).format
44
+ end
45
+
46
+ def amount
47
+ Money.new(credit_decision[:amount].to_f * 100).format
48
+ end
49
+
50
+ def loan_amount
51
+ amount = credit_decision[:loan_amount].to_f
52
+
53
+ Money.new(amount * 100).format
54
+ end
55
+
56
+ def funded_amount
57
+ amount = credit_decision[:funded_amount].to_f
58
+
59
+ Money.new(amount * 100).format
60
+ end
61
+
62
+ def monthly_interest_rate
63
+ credit_decision[:monthly_interes_rate] ||
64
+ credit_decision.dig(:approved, :monthly_interest_rate) || 0.0
65
+ end
66
+
67
+ def monthly_card_interest_rate
68
+ credit_decision[:monthly_card_interes_rate] || 0.0
69
+ end
70
+
71
+ def status
72
+ credit_decision[:status] || STATUSES[:could_not_submit]
73
+ end
74
+
75
+ private
76
+
77
+ def credit_decision
78
+ data[:credit_decision] || data[:latest_approval_request] || {}
79
+ end
80
+ end
81
+ end
82
+ end
@@ -18,7 +18,7 @@ module InstantQuote
18
18
  # }
19
19
  class Youlend < DecisionParser
20
20
  def approved?
21
- status_hash[:loanOptions].any? && first_option
21
+ status_hash[:loanOptions].any? && !funded_option.empty?
22
22
  end
23
23
 
24
24
  def declined?
@@ -26,7 +26,7 @@ module InstantQuote
26
26
  end
27
27
 
28
28
  def sweep
29
- first_option[:sweep]
29
+ funded_option[:sweep]
30
30
  end
31
31
 
32
32
  def status
@@ -34,21 +34,19 @@ module InstantQuote
34
34
  end
35
35
 
36
36
  def fee
37
- return 0.0 unless first_option
38
-
39
- fee = first_option[:fee].to_f
37
+ fee = funded_option[:fee].to_f
40
38
 
41
39
  Money.new(fee * 100).format
42
40
  end
43
41
 
44
42
  def loan_amount
45
- amount = first_option[:loanAmount].to_f
43
+ amount = funded_option[:loanAmount].to_f
46
44
 
47
45
  Money.new(amount * 100).format
48
46
  end
49
47
 
50
48
  def funded_amount
51
- amount = first_option[:fundedAmount].to_f
49
+ amount = funded_option[:fundedAmount].to_f
52
50
 
53
51
  Money.new(amount * 100).format
54
52
  end
@@ -57,8 +55,10 @@ module InstantQuote
57
55
 
58
56
  private
59
57
 
60
- def first_option
61
- @first_option ||= status_hash[:loanOptions].find { |opt| opt[:fundedAmount].positive? }
58
+ def funded_option
59
+ @funded_option ||= status_hash[:loanOptions].find(-> { {} }) do |opt|
60
+ opt[:fundedAmount].positive?
61
+ end
62
62
  end
63
63
 
64
64
  def status_hash
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module InstantQuote
4
- VERSION = '1.7.3'
4
+ VERSION = '1.7.8'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: instant_quote
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.3
4
+ version: 1.7.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - rikas
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-20 00:00:00.000000000 Z
11
+ date: 2021-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -271,6 +271,7 @@ files:
271
271
  - lib/instant_quote/adapter.rb
272
272
  - lib/instant_quote/adapter_finder.rb
273
273
  - lib/instant_quote/adapters/capital_on_tap.rb
274
+ - lib/instant_quote/adapters/fake.rb
274
275
  - lib/instant_quote/adapters/iwoca.rb
275
276
  - lib/instant_quote/adapters/iwoca_cbils.rb
276
277
  - lib/instant_quote/adapters/optimum.rb
@@ -278,12 +279,14 @@ files:
278
279
  - lib/instant_quote/api_error.rb
279
280
  - lib/instant_quote/connection_translator.rb
280
281
  - lib/instant_quote/connection_translators/capital_on_tap.rb
282
+ - lib/instant_quote/connection_translators/fake.rb
281
283
  - lib/instant_quote/connection_translators/iwoca.rb
282
284
  - lib/instant_quote/connection_translators/iwoca_cbils.rb
283
285
  - lib/instant_quote/connection_translators/optimum.rb
284
286
  - lib/instant_quote/connection_translators/youlend.rb
285
287
  - lib/instant_quote/decision_parser.rb
286
288
  - lib/instant_quote/decision_parsers/capital_on_tap.rb
289
+ - lib/instant_quote/decision_parsers/fake.rb
287
290
  - lib/instant_quote/decision_parsers/iwoca.rb
288
291
  - lib/instant_quote/decision_parsers/iwoca_cbils.rb
289
292
  - lib/instant_quote/decision_parsers/optimum.rb
@@ -309,7 +312,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
309
312
  - !ruby/object:Gem::Version
310
313
  version: '0'
311
314
  requirements: []
312
- rubygems_version: 3.0.3
315
+ rubygems_version: 3.2.11
313
316
  signing_key:
314
317
  specification_version: 4
315
318
  summary: Instant quote providers gem.