instant_quote 1.1.6 → 1.4.0

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: e4ef4d0ea8516cb2964a5ffb767aab8312c50e4a1a0b00b6d4f93a3621e2018a
4
- data.tar.gz: 6d2e7d83712d2f16cf3366642e5ff315adcac56b6d9a1d16479ff3e66ad68a9f
3
+ metadata.gz: 40981c76f383ff34163f212e6b9f32a58d2281426ee40fc872b1f38102e24754
4
+ data.tar.gz: 227f3b25eec82494a383ad796f09b0dda5ad9b1472d93c1ba6e2728855529c59
5
5
  SHA512:
6
- metadata.gz: 71993a58586581d1fcdcc722fc89d418b00a78f27eb252f49e94626e3aea56d8089a22c5a4b5b4b20d0e1fea6cad4275e6f9f7c132e19de932c779572bd31f7b
7
- data.tar.gz: 4b31a45177b8dda43fb31ec9d852ab16a4cc99a5c9cc22e0a40f335d6c463cddec2e6d3f242b4d7c023a61984d9b060fbd5a09f7d4dc18c50b7f0c2000845d19
6
+ metadata.gz: 860eb841f3405a3bf62c614551d0f663de38451956321ca2998d790381a365f42067f85d48bc32c90a689ed579e69d9167dbe32d9f2220292ad79a119227d730
7
+ data.tar.gz: f767ccde890f42dfc727e230c0fc02479d81bcf0e911a1b00d33e12ac7679edd244cfe41be7e6dc7c5ad292796dae85379962b5b0643b1aa646817c19499ec14
@@ -1 +1 @@
1
- 2.6.3
1
+ 2.6.6
data/Gemfile CHANGED
@@ -6,6 +6,7 @@ source 'https://rubygems.org'
6
6
  #
7
7
  # gem 'capital_on_tap', path: '../capital-on-tap'
8
8
  # gem 'iwoca', path: '../iwoca'
9
+ # gem 'optimum', path: '../optimum'
9
10
 
10
11
  # Specify your gem's dependencies in instant-quotes.gemspec
11
12
  gemspec
@@ -1,22 +1,23 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- instant_quote (1.1.6)
4
+ instant_quote (1.4.0)
5
5
  activesupport
6
6
  capital_on_tap
7
7
  iwoca
8
8
  money
9
+ optimum
9
10
  phonelib
10
11
 
11
12
  GEM
12
13
  remote: https://rubygems.org/
13
14
  specs:
14
- activesupport (6.0.2.2)
15
+ activesupport (6.0.3.3)
15
16
  concurrent-ruby (~> 1.0, >= 1.0.2)
16
17
  i18n (>= 0.7, < 2)
17
18
  minitest (~> 5.1)
18
19
  tzinfo (~> 1.1)
19
- zeitwerk (~> 2.2)
20
+ zeitwerk (~> 2.2, >= 2.2.2)
20
21
  addressable (2.7.0)
21
22
  public_suffix (>= 2.0.2, < 5.0)
22
23
  ast (2.4.0)
@@ -28,7 +29,7 @@ GEM
28
29
  multi_json
29
30
  rainbow
30
31
  coderay (1.1.2)
31
- concurrent-ruby (1.1.6)
32
+ concurrent-ruby (1.1.7)
32
33
  crack (0.4.3)
33
34
  safe_yaml (~> 1.0.0)
34
35
  diff-lcs (1.3)
@@ -39,7 +40,7 @@ GEM
39
40
  faraday_middleware (1.0.0)
40
41
  faraday (~> 1.0)
41
42
  hashdiff (1.0.1)
42
- i18n (1.8.2)
43
+ i18n (1.8.5)
43
44
  concurrent-ruby (~> 1.0)
44
45
  iwoca (1.0.0)
45
46
  addressable
@@ -49,15 +50,21 @@ GEM
49
50
  rainbow
50
51
  jaro_winkler (1.5.4)
51
52
  method_source (1.0.0)
52
- minitest (5.14.0)
53
- money (6.13.7)
53
+ minitest (5.14.2)
54
+ money (6.13.8)
54
55
  i18n (>= 0.6.4, <= 2)
55
- multi_json (1.14.1)
56
+ multi_json (1.15.0)
56
57
  multipart-post (2.1.1)
58
+ optimum (1.0.0)
59
+ addressable
60
+ faraday
61
+ faraday_middleware
62
+ multi_json
63
+ rainbow
57
64
  parallel (1.19.1)
58
65
  parser (2.7.0.5)
59
66
  ast (~> 2.4.0)
60
- phonelib (0.6.42)
67
+ phonelib (0.6.45)
61
68
  pry (0.13.0)
62
69
  coderay (~> 1.1)
63
70
  method_source (~> 1.0)
@@ -103,7 +110,7 @@ GEM
103
110
  addressable (>= 2.3.6)
104
111
  crack (>= 0.3.2)
105
112
  hashdiff (>= 0.4.0, < 2.0.0)
106
- zeitwerk (2.3.0)
113
+ zeitwerk (2.4.0)
107
114
 
108
115
  PLATFORMS
109
116
  ruby
@@ -120,4 +127,4 @@ DEPENDENCIES
120
127
  webmock
121
128
 
122
129
  BUNDLED WITH
123
- 2.0.2
130
+ 2.1.4
@@ -38,6 +38,7 @@ Gem::Specification.new do |spec|
38
38
  spec.add_dependency 'activesupport'
39
39
  spec.add_dependency 'capital_on_tap'
40
40
  spec.add_dependency 'iwoca'
41
+ spec.add_dependency 'optimum'
41
42
  spec.add_dependency 'money'
42
43
  spec.add_dependency 'phonelib'
43
44
  end
@@ -1,16 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
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}" }
4
+ Dir.glob('*.rb', base: File.expand_path('connection_translators', __dir__)) do |translator|
5
+ require "instant_quote/connection_translators/#{translator}"
6
+ end
6
7
 
7
8
  # 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}" }
9
+ Dir.glob('*.rb', base: File.expand_path('decision_parsers', __dir__)) do |parser|
10
+ require "instant_quote/decision_parsers/#{parser}"
11
+ end
10
12
 
11
13
  # Require all the adapters
12
- adapters = Dir.children(File.expand_path('adapters', __dir__))
13
- adapters.each { |adapter| require "instant_quote/adapters/#{adapter}" }
14
+ Dir.glob('*.rb', base: File.expand_path('adapters', __dir__)) do |adapter|
15
+ require "instant_quote/adapters/#{adapter}"
16
+ end
14
17
 
15
18
  module InstantQuote
16
19
  class AdapterFinder
@@ -28,8 +31,8 @@ module InstantQuote
28
31
  end
29
32
 
30
33
  def self.available_adapters
31
- adapters = Dir.children(File.expand_path('adapters', __dir__))
32
- adapters.map { |adapter| adapter.tr('.rb', '') }
34
+ Dir.glob('*.rb', base: File.expand_path('adapters', __dir__))
35
+ .map { |adapter| adapter.sub('.rb', '') }
33
36
  end
34
37
 
35
38
  def get_link
@@ -25,7 +25,7 @@ module InstantQuote
25
25
  },
26
26
  {
27
27
  name: 'monthly_income',
28
- label: 'Applicat monthly income',
28
+ label: 'Applicant monthly income',
29
29
  type: 'number',
30
30
  required: true,
31
31
  if: ->(app) { app.borrower_organisation.sole_trader? }
@@ -37,6 +37,31 @@ module InstantQuote
37
37
  required: true,
38
38
  if: ->(app) { app.borrower_organisation.sole_trader? }
39
39
  },
40
+ {
41
+ name: 'turnover_percentage_after_feb_2020',
42
+ label: 'When compared to before COVID-19, what is your current turnover level?',
43
+ required: true,
44
+ choices: {
45
+ 'Greater than before (>100%)' => 'GreaterThanHundredPercentage',
46
+ 'Marginally reduced (80-100%)' => 'LessThanOrEqualToHunderdPercentage',
47
+ 'Reduced (60-79%)' => 'LessThanSeventyNinePercentage',
48
+ 'Halved (40-59%)' => 'LessThanFiftyNinePercentage',
49
+ 'Less than half (20-39%)' => 'LessThanThirtyNinePercentage',
50
+ 'Severely reduced or no turnover (<20%)' => 'LessThanTwentyPercentage'
51
+ },
52
+ type: 'select'
53
+ },
54
+ {
55
+ name: 'preferred_monthly_repayment_option',
56
+ label: 'What is your preferred monthly repayment option?',
57
+ required: true,
58
+ choices: [
59
+ 'Minimum Amount Required',
60
+ 'Full Balance',
61
+ 'Fixed Amount'
62
+ ],
63
+ type: 'select'
64
+ },
40
65
  {
41
66
  name: 'applicant_consent',
42
67
  label: 'Yes, I give my consent for my data to be shared',
@@ -57,17 +82,17 @@ module InstantQuote
57
82
 
58
83
  # Get the status for a given application ID
59
84
  # {:applicationStatus=>
60
- # {:locatorId=>"B247T62",
61
- # :applicationStage=>"AppSubmitted",
85
+ # {:locatorId=>'B247T62',
86
+ # :applicationStage=>'AppSubmitted',
62
87
  # :creditDecision=>
63
- # {:status=>"Pending",
88
+ # {:status=>'Pending',
64
89
  # :starRating=>0.0,
65
90
  # :approvalAmount=>0.0,
66
91
  # :monthlyInterestRate=>0.0,
67
92
  # :monthlyCardInterestRate=>0.0,
68
- # :decisionDate=>"2020-01-28T01:44:29.241",
69
- # :creditDecisionReason=>"None"}},
70
- # :links=>{:self=>"/api/v1/Applications/B247T62", :parent=>nil},
93
+ # :decisionDate=>'2020-01-28T01:44:29.241',
94
+ # :creditDecisionReason=>'None'}},
95
+ # :links=>{:self=>'/api/v1/Applications/B247T62', :parent=>nil},
71
96
  # :metaData=>{}
72
97
  # }
73
98
  def get_status(application_id)
@@ -77,7 +77,7 @@ module InstantQuote
77
77
 
78
78
  raise_error(response) unless response.success?
79
79
 
80
- DecisionParsers::Iwoca.new(response.body)
80
+ decision_parser.new(response.body)
81
81
  end
82
82
 
83
83
  # Gets the URL for the given state key.
@@ -96,6 +96,10 @@ module InstantQuote
96
96
 
97
97
  private
98
98
 
99
+ def decision_parser
100
+ DecisionParsers::Iwoca
101
+ end
102
+
99
103
  def raise_error(response)
100
104
  raise ApiError.new(
101
105
  adapter: 'iwoca',
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'iwoca'
4
+ require 'instant_quote/adapters/iwoca'
5
+ require 'instant_quote/decision_parsers/iwoca_cbils'
6
+
7
+ module InstantQuote
8
+ module Adapters
9
+ class IwocaCbils < Iwoca
10
+ additional_fields Iwoca.additional_fields
11
+
12
+ private
13
+
14
+ def decision_parser
15
+ DecisionParsers::IwocaCbils
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optimum'
4
+ require 'instant_quote/decision_parsers/optimum'
5
+
6
+ module InstantQuote
7
+ module Adapters
8
+ class Optimum < Adapter
9
+ additional_fields [
10
+ {
11
+ name: 'applicant_phone_number',
12
+ label: 'Applicant mobile phone',
13
+ required: true
14
+ },
15
+ {
16
+ name: 'expected_turnover_next_12_months',
17
+ label: 'Expected turnover next 12 months',
18
+ required: true,
19
+ type: 'money'
20
+ },
21
+ {
22
+ name: 'expected_customers',
23
+ label: 'Number of expected customers with a balance in 6 months',
24
+ required: true,
25
+ type: 'number'
26
+ },
27
+ {
28
+ name: 'industry_sector',
29
+ label: 'Industry sector',
30
+ required: true,
31
+ type: 'select',
32
+ choices: [
33
+ 'Advertising / Marketing',
34
+ 'Beer / Wine Merchant',
35
+ 'Builders Merchant',
36
+ 'Clothing & Fashion',
37
+ 'Computer Hardware',
38
+ 'Computer Software',
39
+ 'Construction',
40
+ 'Consultancy',
41
+ 'Contract Cleaning',
42
+ 'Courier',
43
+ 'Distribution',
44
+ 'Driving Agency',
45
+ 'Electrical Contracting',
46
+ 'Electrical Wholesaler',
47
+ 'Engineering - Heavy',
48
+ 'Engineering - Light',
49
+ 'Engineering - Precision',
50
+ 'Fabrication',
51
+ 'Flooring Contractor',
52
+ 'Food Manufacture',
53
+ 'Franchise',
54
+ 'Free Newspaper',
55
+ 'Freight Forwarding',
56
+ 'Fruit Importer',
57
+ 'Furniture Manufacture',
58
+ 'Garden Equipment',
59
+ 'Haulage',
60
+ 'IT Contracting',
61
+ 'Jewellery',
62
+ 'Maintenance',
63
+ 'Manufacturing',
64
+ 'Meat Trade',
65
+ 'Other Services',
66
+ 'Permanent Recruitment',
67
+ 'Plant Hire',
68
+ 'Plastic Injection Moulding',
69
+ 'Plumbers Merchant',
70
+ 'Printing',
71
+ 'Publishing',
72
+ 'Recycling',
73
+ 'Security Guards',
74
+ 'Shopfitting',
75
+ 'Stationery',
76
+ 'Steel Stockholding',
77
+ 'Telecoms',
78
+ 'Temporary Recruitment',
79
+ 'Timber Merchant',
80
+ 'Tooling Manufacture',
81
+ 'Toys & Fancy Goods',
82
+ 'Warehousing & Storage',
83
+ 'Wholesale'
84
+ ]
85
+ },
86
+ {
87
+ name: 'credit_control',
88
+ label: 'Do you require credit control?',
89
+ required: false,
90
+ choices: {
91
+ 'Yes' => '1',
92
+ 'No' => '0'
93
+ },
94
+ type: 'radio'
95
+ },
96
+ {
97
+ name: 'applicant_consent',
98
+ label: 'Yes, I give my consent for my data to be shared',
99
+ required: true,
100
+ type: 'checkbox'
101
+ }
102
+ ]
103
+
104
+ def get_quote(params)
105
+ response = ::Optimum::Decision.create(params)
106
+
107
+ return response.data[:opportunityId] if response.success?
108
+
109
+ raise_error(response)
110
+ end
111
+
112
+ def get_status(application_id)
113
+ response = ::Optimum::Decision.update(application_id)
114
+
115
+ raise_error(response) unless response.success?
116
+
117
+ decision_parser.new(response.body)
118
+ end
119
+
120
+ # Gets the URL for the given state key.
121
+ def get_link(_)
122
+ ''
123
+ end
124
+
125
+ def get_approval(_)
126
+ true
127
+ end
128
+
129
+ private
130
+
131
+ def decision_parser
132
+ DecisionParsers::Optimum
133
+ end
134
+
135
+ def raise_error(response)
136
+ raise ApiError.new(
137
+ adapter: 'optimum',
138
+ data: response.body,
139
+ error: response.error || 'Unknown API error'
140
+ )
141
+ end
142
+ end
143
+ end
144
+ end
@@ -14,7 +14,7 @@ module InstantQuote
14
14
  @code = params[:code]
15
15
 
16
16
  # Delete the metaData key, because it's irrelevant and has long strings
17
- @data.delete(:metaData) if @data.key?(:metaData)
17
+ @data.delete(:metaData) if @data.respond_to?(:key?) && @data.key?(:metaData)
18
18
  end
19
19
  end
20
20
  end
@@ -6,6 +6,60 @@ module InstantQuote
6
6
  module ConnectionTranslators
7
7
  class CapitalOnTap < ConnectionTranslator
8
8
  DEFAULT_SALUTATION = 'Mr'
9
+ LOAN_PURPOSE_MAPPING = {
10
+ 'Apply for COVID-19 support/for other reasons' => 'General working capital requirements',
11
+ 'Apply for COVID-19 support/to pay existing loans' => 'Repay Finances with another lender',
12
+ 'Apply for COVID-19 support/to pay suppliers' => 'General working capital requirements',
13
+ 'Apply for COVID-19 support/to protect jobs' => 'Payment of wages or rent',
14
+ 'Apply for COVID-19 support/to refinance existing loans' => 'Repay Finances with another lender',
15
+ 'Buy or develop property/buy the property my business already occupies' => '',
16
+ 'Buy or develop property/buying a business that includes premises' => 'Acquisition of another business in the UK',
17
+ 'Buy or develop property/buying a property for my business to move into' => '',
18
+ 'Buy or develop property/develop residential or commercial premises' => 'Bridging loan',
19
+ 'Buy or develop property/invest in a foreign property to rent it out' => '',
20
+ 'Buy or develop property/invest in a holiday let' => '',
21
+ 'Buy or develop property/invest in UK property' => 'Bridging loan',
22
+ 'Buy or develop property/other property finance needs' => 'Bridging loan',
23
+ 'Buy or refinance vehicle(s)/agricultural vehicle(s)' => 'General working capital requirements',
24
+ 'Buy or refinance vehicle(s)/car(s)' => 'General working capital requirements',
25
+ 'Buy or refinance vehicle(s)/caravan(s) & mobile home(s)' => 'General working capital requirements',
26
+ 'Buy or refinance vehicle(s)/commercial vehicle(s)' => 'General working capital requirements',
27
+ 'Buy or refinance vehicle(s)/fork lift truck(s)' => 'General working capital requirements',
28
+ 'Buy or refinance vehicle(s)/other vehicle finance requirements' => 'General working capital requirements',
29
+ 'Help with grants, tax credits and pension finance/for a research & development project' => 'Research and development activities',
30
+ 'Help with grants, tax credits and pension finance/for green energy projects' => 'General working capital requirements',
31
+ 'Help with grants, tax credits and pension finance/for projects with social impact' => 'General working capital requirements',
32
+ 'Help with grants, tax credits and pension finance/other grant funding needs' => '',
33
+ 'Help with grants, tax credits and pension finance/starting a business, incl. accelerator and incubator programs' => 'Start up costs',
34
+ 'Help with grants, tax credits and pension finance/to fund skills and training initiatives' => 'General working capital requirements',
35
+ 'Help with grants, tax credits and pension finance/utilise pensions to lend to a business' => '',
36
+ 'Improve cashflow/borrow against monthly income from a credit card terminal' => '',
37
+ 'Improve cashflow/finance overseas trading and exporting' => 'General working capital requirements',
38
+ 'Improve cashflow/other cashflow requirements' => 'General working capital requirements',
39
+ 'Improve cashflow/raise credit against agreed purchase orders' => 'General working capital requirements',
40
+ 'Improve cashflow/release capital from pension fund(s)' => '',
41
+ 'Improve cashflow/release cash from one unpaid invoice to another business' => 'General working capital requirements',
42
+ 'Improve cashflow/release cash from several invoices to other businesses' => 'General working capital requirements',
43
+ 'Improve cashflow/spread the cost of a large bill' => 'General working capital requirements',
44
+ 'Invest in equipment or machinery/computers (hardware, software)' => 'Purchase of equipment/machinery/stock',
45
+ 'Invest in equipment or machinery/equipment (office, printing, medical, etc.)' => 'Purchase of equipment/machinery/stock',
46
+ 'Invest in equipment or machinery/furniture & furnishings' => 'Purchase of equipment/machinery/stock',
47
+ 'Invest in equipment or machinery/machinery & tools' => 'Purchase of equipment/machinery/stock',
48
+ 'Invest in equipment or machinery/other investment needs' => 'Purchase of licences,quotas or other entitlements to trade',
49
+ 'Invest in equipment or machinery/phone & telecom systems' => 'Purchase of equipment/machinery/stock',
50
+ 'Refinance an existing.../asset' => 'Repay Finances with another lender',
51
+ 'Refinance an existing.../business loan' => 'Repay Finances with another lender',
52
+ 'Refinance an existing.../commercial mortgage' => '',
53
+ 'Refinance an existing.../other refinancing needs' => 'Repay Finances with another lender',
54
+ 'Seeking investment/for a management buy-out' => 'Acquisition of another business in the UK',
55
+ 'Seeking investment/other funding requirements' => 'General working capital requirements',
56
+ 'Seeking investment/to launch a new B2B product or service' => 'Start up costs',
57
+ 'Seeking investment/to launch a new consumer product or service' => 'Start up costs',
58
+ 'Seeking investment/to purchase another business' => 'Acquisition of another business in the UK',
59
+ 'Seeking investment/to reach more consumers with a proven product or service' => 'Expansion Activities in the UK',
60
+ 'Seeking investment/to win more business clients with a proven product or service' => 'Expansion Activities in the UK',
61
+ 'Seeking investment/venture builder, accelerator and incubator programs' => ''
62
+ }.freeze
9
63
 
10
64
  # rubocop:disable Metrics/AbcSize
11
65
  def translate
@@ -24,7 +78,8 @@ module InstantQuote
24
78
  MonthlyTurnOver: translate_turnover,
25
79
  BusinessType: translate_business_type,
26
80
  BusinessAddress: translate_address,
27
- RegistrationNumber: app_org.company_number
81
+ RegistrationNumber: app_org.company_number,
82
+ additionalQuestions: additional_questions
28
83
  }
29
84
 
30
85
  # If the borrower organisation is Sole Trader we need to merge two additional fields.
@@ -61,7 +116,7 @@ module InstantQuote
61
116
 
62
117
  return '' unless addr && addr != ''
63
118
 
64
- street_parts = [addr.line_1, addr.line_2, addr.line_3, addr.line_4]
119
+ street_parts = [addr.line_1, addr.line_2]
65
120
 
66
121
  {
67
122
  CountryCode: 'UK',
@@ -71,7 +126,7 @@ module InstantQuote
71
126
  }
72
127
  end
73
128
 
74
- # Since in Finpoint the user selects an intervel (i.e. "500,000 - 999,999"). We get the avg
129
+ # Since in Finpoint the user selects an intervel (i.e. '500,000 - 999,999'). We get the avg
75
130
  # on this interval and use that number as the monthly turnover.
76
131
  def translate_turnover
77
132
  turnover = app_org.turnover_range
@@ -93,6 +148,47 @@ module InstantQuote
93
148
  'Partnership'
94
149
  end
95
150
  end
151
+
152
+ def additional_questions
153
+ [
154
+ loan_purpose_question,
155
+ preferred_monthly_repayment_option_question,
156
+ turnover_percentage_question
157
+ ]
158
+ end
159
+
160
+ def loan_purpose_question
161
+ {
162
+ question: 'What is the purpose of the loan?',
163
+ answer: translate_loan_purpose,
164
+ questionType: '16'
165
+ }
166
+ end
167
+
168
+ def preferred_monthly_repayment_option_question
169
+ question_from_extra_info('preferred_monthly_repayment_option', '17')
170
+ end
171
+
172
+ def turnover_percentage_question
173
+ question_from_extra_info('turnover_percentage_after_feb_2020', '20')
174
+ end
175
+
176
+ def question_from_extra_info(name, question_type)
177
+ field = Adapters::CapitalOnTap.additional_fields.find do |f|
178
+ f[:name] == name
179
+ end
180
+
181
+ { question: field[:label], answer: extra_info[field[:name]], questionType: question_type }
182
+ end
183
+
184
+ def translate_loan_purpose
185
+ proceeds_purpose = [
186
+ application.proceeds_purpose&.overview&.name,
187
+ application.proceeds_purpose&.name
188
+ ].join('/')
189
+
190
+ LOAN_PURPOSE_MAPPING[proceeds_purpose]
191
+ end
96
192
  end
97
193
  end
98
194
  end
@@ -10,7 +10,7 @@ module InstantQuote
10
10
  company: company_information,
11
11
  people: [person_information],
12
12
  requested_products: {
13
- credit_facility: {
13
+ product_name => {
14
14
  approval: {
15
15
  amount: (application.amount_pennies / 100),
16
16
  duration: 12,
@@ -25,6 +25,10 @@ module InstantQuote
25
25
 
26
26
  private
27
27
 
28
+ def product_name
29
+ :credit_facility
30
+ end
31
+
28
32
  # rubocop:disable Metrics/AbcSize
29
33
  def company_information
30
34
  information = {
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'instant_quote/connection_translators/iwoca'
4
+
5
+ module InstantQuote
6
+ module ConnectionTranslators
7
+ class IwocaCbils < Iwoca
8
+ private
9
+
10
+ def product_name
11
+ :cbils
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InstantQuote
4
+ module ConnectionTranslators
5
+ class Optimum < ConnectionTranslator
6
+ def translate
7
+ {
8
+ companyNumber: company&.company_number.to_s,
9
+ sector: extra_info['industry_sector'],
10
+ turnover: extra_info['expected_turnover_next_12_months'].to_f,
11
+ homeowners: homeowners?,
12
+ yearsTrading: company&.years_in_business,
13
+ expectedCustomers: extra_info['expected_customers'].to_i,
14
+ contactName: application&.primary_user&.name,
15
+ contactNumber: extra_info['applicant_phone_number'],
16
+ contactEmail: application&.primary_user&.email,
17
+ creditControl: extra_info['credit_control'] == '1',
18
+ phoenix: false,
19
+ quotationOnly: false
20
+ }
21
+ end
22
+
23
+ private
24
+
25
+ def company
26
+ application.borrower_organisation
27
+ end
28
+
29
+ def homeowners?
30
+ case company&.directors_home_owning&.name
31
+ when 'Home owner without mortgage', 'Home owner with mortgage'
32
+ true
33
+ else
34
+ false
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'instant_quote/decision_parsers/iwoca'
4
+
5
+ module InstantQuote
6
+ module DecisionParsers
7
+ class IwocaCbils < Iwoca
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InstantQuote
4
+ module DecisionParsers
5
+ # Example response:
6
+ #
7
+ # {
8
+ # decision: {
9
+ # decision: "approved",
10
+ # trialPeriodMonths: 4, # trial period length
11
+ # fundingLimit: 745000,
12
+ # annualRenewalFee: 0,
13
+ # badDebtProtection: 0.85,
14
+ # cashAvailableWithinHours: 48,
15
+ # discountFee: 3.35,
16
+ # facility: "Factoring", # Factoring or Invoice Discounting or Confidential Invoice Discounting
17
+ # prepayment: 80,
18
+ # serviceFee: 1.14
19
+ # },
20
+ # opportunityId: "01234567ABCDEFGH", # the Optimum Finance opportunity ID (only supplied for successful applications that are not 'quotation only')
21
+ # companyName: "COMPANY NAME LTD" # company name from the given company number - use this to verify correct company
22
+ # }
23
+
24
+ class Optimum < DecisionParser
25
+ STATUSES = {
26
+ approved: 'approved',
27
+ declined: 'declined',
28
+ referred: 'referred',
29
+ }.freeze
30
+
31
+ LOAN_STATES = {
32
+ started: 'Closed Won'
33
+ }.freeze
34
+
35
+ def initialize(data = {})
36
+ super
37
+ end
38
+
39
+ def pending?
40
+ !STATUSES.value?(status)
41
+ end
42
+
43
+ def approved?
44
+ status == STATUSES[:approved]
45
+ end
46
+
47
+ def declined?
48
+ status == STATUSES[:declined]
49
+ end
50
+
51
+ def manual_review?
52
+ status == STATUSES[:referred]
53
+ end
54
+
55
+ def loan_started?
56
+ data[:status] == LOAN_STATES[:started]
57
+ end
58
+
59
+ def amount
60
+ amount_approved = decision[:fundingLimit] || 0
61
+
62
+ Money.new(amount_approved * 100).format
63
+ end
64
+
65
+ def credit_duration
66
+ 0
67
+ end
68
+
69
+ def credit_interval
70
+ decision[:trialPeriodMonths]
71
+ end
72
+
73
+ def monthly_interest_rate
74
+ 0
75
+ end
76
+
77
+ def status
78
+ decision[:decision]
79
+ end
80
+
81
+ private
82
+
83
+ def decision
84
+ data[:decision] || data[:originalDecision] || {}
85
+ end
86
+ end
87
+ end
88
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module InstantQuote
4
- VERSION = '1.1.6'
4
+ VERSION = '1.4.0'
5
5
  end
@@ -16,31 +16,15 @@ module InstantQuote
16
16
  class SignatureVerifyError < StandardError
17
17
  end
18
18
 
19
- def iwoca_event
20
- # Dynamically calls the following methods:
21
- # * handle_approval_status_changed
22
- # * handle_instruct_payments
23
- # * handle_customer_funded
24
- if iwoca_verify_signature
25
- return send("handle_#{iwoca_event_type}") if respond_to?("handle_#{iwoca_event_type}")
26
-
27
- render json: iwoca_payload, status: 200
28
- else
29
- iwoca_verify_signature_error
30
- end
31
- rescue SignatureVerifyError => e
32
- iwoca_verify_signature_error(e.message)
33
- end
34
-
35
19
  private
36
20
 
37
21
  def iwoca_verify_signature
38
- unless webhook_signature && iwoca_payload && iwoca_signature
22
+ unless webhook_signature && payload && iwoca_signature
39
23
  raise SignatureVerifyError, "#{SIGNATURE_HEADER} header missing"
40
24
  end
41
25
 
42
26
  digest = OpenSSL::Digest.new('sha1')
43
- hmac_digest = OpenSSL::HMAC.digest(digest, webhook_signature, iwoca_payload)
27
+ hmac_digest = OpenSSL::HMAC.digest(digest, webhook_signature, payload)
44
28
  signature = "sha1=#{Base64.strict_encode64(hmac_digest)}"
45
29
 
46
30
  Rack::Utils.secure_compare(signature, iwoca_signature)
@@ -50,8 +34,8 @@ module InstantQuote
50
34
  @webhook_signature ||= ::Iwoca.configuration.webhook_signature
51
35
  end
52
36
 
53
- def iwoca_payload
54
- @iwoca_payload ||= request.body.read
37
+ def payload
38
+ @payload ||= request.body.read
55
39
  end
56
40
 
57
41
  def iwoca_signature
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.1.6
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - rikas
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-04-06 00:00:00.000000000 Z
11
+ date: 2020-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: optimum
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
167
181
  - !ruby/object:Gem::Dependency
168
182
  name: money
169
183
  requirement: !ruby/object:Gem::Requirement
@@ -216,13 +230,19 @@ files:
216
230
  - lib/instant_quote/adapter_finder.rb
217
231
  - lib/instant_quote/adapters/capital_on_tap.rb
218
232
  - lib/instant_quote/adapters/iwoca.rb
233
+ - lib/instant_quote/adapters/iwoca_cbils.rb
234
+ - lib/instant_quote/adapters/optimum.rb
219
235
  - lib/instant_quote/api_error.rb
220
236
  - lib/instant_quote/connection_translator.rb
221
237
  - lib/instant_quote/connection_translators/capital_on_tap.rb
222
238
  - lib/instant_quote/connection_translators/iwoca.rb
239
+ - lib/instant_quote/connection_translators/iwoca_cbils.rb
240
+ - lib/instant_quote/connection_translators/optimum.rb
223
241
  - lib/instant_quote/decision_parser.rb
224
242
  - lib/instant_quote/decision_parsers/capital_on_tap.rb
225
243
  - lib/instant_quote/decision_parsers/iwoca.rb
244
+ - lib/instant_quote/decision_parsers/iwoca_cbils.rb
245
+ - lib/instant_quote/decision_parsers/optimum.rb
226
246
  - lib/instant_quote/version.rb
227
247
  - lib/instant_quote/webhooks/iwoca.rb
228
248
  homepage: https://finpoint.co.uk