instant_quote 1.7.2 → 1.7.7

Sign up to get free protection for your applications and to get access to all the features.
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.