instant_quote 1.7.3 → 1.7.8

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: 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.