instant_quote 1.7.2 → 1.7.7

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: fd282d49087da4618690e4ce31b277d7ef3ebacb9c1ee08e7140f6e36b068dbe
4
- data.tar.gz: fa1f1c9fd0a4ca9f89ae4f2a97b9d121b9be2988e7802fd02e4fb084d56a4052
3
+ metadata.gz: c6ca7c25677c925b0b637a2ac22052acf1e0969228fce0a2acd5d3916ea4bcf1
4
+ data.tar.gz: df855495089300f19461a6fdc50784987305a4064d4919b0426a7e330c9bf67b
5
5
  SHA512:
6
- metadata.gz: f6eaccc382934116cf76da77089286a4ffc0b24d64592000828c2668fe5eaa9286a6f2a5b49ddad2f258c0b9de97d352ff6073990293b12be9592bf1108f5cab
7
- data.tar.gz: 68b0407dee94857c6e1da32819dbafcffbd3a0ea278a58b1cb54d1ef4e1b75024deaf81914cb2bd4254c25477f63e5f6ce929e5d3d586dc2da77b93fd9a35f9d
6
+ metadata.gz: 0b4449520408ce3c7ea5ecadda96213fee6ae6ffde6476f1ad3cd13f46fa296612e29001ed9cd66e1f836fc32c29f3ed882bd4de88e386855adc511503a4edc0
7
+ data.tar.gz: dda46d5ba775f70e21319df87dd9e69033188f37f6ffffa59b0e85736179ade50b9ab1b34b0e906e18b5952fcdb814b4627ac0108c99c3b42afc24b0a8be6d5b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- instant_quote (1.7.2)
4
+ instant_quote (1.7.7)
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)
@@ -44,7 +44,7 @@ GEM
44
44
  faraday_middleware (1.0.0)
45
45
  faraday (~> 1.0)
46
46
  hashdiff (1.0.1)
47
- i18n (1.8.9)
47
+ i18n (1.8.10)
48
48
  concurrent-ruby (~> 1.0)
49
49
  iwoca (1.0.0)
50
50
  addressable
@@ -53,8 +53,8 @@ GEM
53
53
  multi_json
54
54
  rainbow
55
55
  method_source (1.0.0)
56
- minitest (5.14.3)
57
- money (6.14.0)
56
+ minitest (5.14.4)
57
+ money (6.14.1)
58
58
  i18n (>= 0.6.4, <= 2)
59
59
  multi_json (1.15.0)
60
60
  multipart-post (2.1.1)
@@ -67,7 +67,7 @@ GEM
67
67
  parallel (1.20.1)
68
68
  parser (3.0.0.0)
69
69
  ast (~> 2.4.1)
70
- phonelib (0.6.48)
70
+ phonelib (0.6.49)
71
71
  pry (0.13.1)
72
72
  coderay (~> 1.1)
73
73
  method_source (~> 1.0)
@@ -77,7 +77,7 @@ GEM
77
77
  public_suffix (4.0.6)
78
78
  rainbow (3.0.0)
79
79
  rake (10.5.0)
80
- regexp_parser (2.0.3)
80
+ regexp_parser (2.1.1)
81
81
  rexml (3.2.4)
82
82
  rspec (3.10.0)
83
83
  rspec-core (~> 3.10.0)
@@ -92,7 +92,7 @@ GEM
92
92
  diff-lcs (>= 1.2.0, < 2.0)
93
93
  rspec-support (~> 3.10.0)
94
94
  rspec-support (3.10.2)
95
- rubocop (1.9.1)
95
+ rubocop (1.11.0)
96
96
  parallel (~> 1.10)
97
97
  parser (>= 3.0.0.0)
98
98
  rainbow (>= 2.2.2, < 4.0)
@@ -119,7 +119,7 @@ GEM
119
119
  tzinfo (2.0.4)
120
120
  concurrent-ruby (~> 1.0)
121
121
  unicode-display_width (2.0.0)
122
- webmock (3.11.2)
122
+ webmock (3.12.1)
123
123
  addressable (>= 2.3.6)
124
124
  crack (>= 0.3.2)
125
125
  hashdiff (>= 0.4.0, < 2.0.0)
@@ -148,4 +148,4 @@ DEPENDENCIES
148
148
  webmock
149
149
 
150
150
  BUNDLED WITH
151
- 2.2.5
151
+ 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
@@ -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,43 +18,55 @@ module InstantQuote
18
18
  # }
19
19
  class Youlend < DecisionParser
20
20
  def approved?
21
- status_hash[:loanOptions].any?
21
+ status_hash[:loanOptions].any? && !funded_option.empty?
22
22
  end
23
23
 
24
24
  def declined?
25
- status_hash[:loanOptions].empty?
25
+ !approved?
26
26
  end
27
27
 
28
28
  def sweep
29
- first_option[:sweep]
29
+ funded_option[:sweep]
30
+ end
31
+
32
+ def status
33
+ approved? ? 'approved' : 'declined'
30
34
  end
31
35
 
32
36
  def fee
33
- fee = first_option[:fee].to_f
37
+ fee = funded_option[:fee].to_f
34
38
 
35
39
  Money.new(fee * 100).format
36
40
  end
37
41
 
38
42
  def loan_amount
39
- amount = first_option[:loanAmount].to_f
43
+ amount = funded_option[:loanAmount].to_f
40
44
 
41
45
  Money.new(amount * 100).format
42
46
  end
43
47
 
44
48
  def funded_amount
45
- amount = first_option[:fundedAmount].to_f
49
+ amount = funded_option[:fundedAmount].to_f
46
50
 
47
51
  Money.new(amount * 100).format
48
52
  end
49
53
 
54
+ alias amount funded_amount
55
+
50
56
  private
51
57
 
52
- def first_option
53
- @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
54
62
  end
55
63
 
56
64
  def status_hash
57
- data.presence || { loanOptions: [] }
65
+ default = { loanOptions: [] }
66
+
67
+ return default unless data && !data.empty?
68
+
69
+ data
58
70
  end
59
71
  end
60
72
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module InstantQuote
4
- VERSION = '1.7.2'
4
+ VERSION = '1.7.7'
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.2
4
+ version: 1.7.7
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-14 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.