killbill-stripe 4.1.1 → 5.0.0

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
  SHA1:
3
- metadata.gz: bbdc020a826585e1d723991b963ea2cc0b9866a6
4
- data.tar.gz: 2140de112d1665611c8535bde2084bfa731b8f85
3
+ metadata.gz: 2b3fd774290b63212046cc65ae4d9e597feecdcf
4
+ data.tar.gz: 3f76e5e8fa7b0c3541d010588be12b36546d1a37
5
5
  SHA512:
6
- metadata.gz: 4a58e78693d70c2504d8ff46e9263325b301927424899875e7fb84dc353c751230732543cba821de087b52134111ca941d15e351b573f6c775ec143c2608cf9a
7
- data.tar.gz: 688c6b82d49c17c34551d6daca4a9d20d7dda4d1ca6257f70ab90860570dd924cf2d40a781eb70be3dd275cf013ed8caf23b077c19d43e92b42c8503a3c5deea
6
+ metadata.gz: 58f9df996d008f919c4de81efef0024f6f3579691985e0643e75a0c6636bb712e9da1db2029c74b8151a5d1f2152b61d323ff97d16ad4dde6cada95a51583c44
7
+ data.tar.gz: 63a9d8bce5a5fcbec1690433ea13e47262691747c4d14f0733b4a6e6b4efd11eaa7f3d10cf62c517a24e4d8c6faaffed823162a4378afc3b7388149dfa21f71f
@@ -2,7 +2,6 @@ include Killbill::Plugin::ActiveMerchant
2
2
  module Killbill #:nodoc:
3
3
  module Stripe #:nodoc:
4
4
  class PaymentPlugin < ::Killbill::Plugin::ActiveMerchant::PaymentPlugin
5
-
6
5
  def initialize
7
6
  gateway_builder = Proc.new do |config|
8
7
  ::ActiveMerchant::Billing::StripeGateway.new :login => config[:api_secret_key]
@@ -207,8 +206,18 @@ module Killbill #:nodoc:
207
206
  gw_notification
208
207
  end
209
208
 
209
+ def verify_bank_account(stripe_customer_id, stripe_bank_account_id, amounts, kb_tenant_id)
210
+ gateway = lookup_gateway(:default, kb_tenant_id)
211
+ url = "customers/#{CGI.escape(stripe_customer_id)}/sources/#{CGI.escape(stripe_bank_account_id)}/verify?#{amounts_to_uri(amounts)}"
212
+ gateway.api_request(:post, url)
213
+ end
214
+
210
215
  private
211
216
 
217
+ def amounts_to_uri(amounts)
218
+ amounts.map {|v| "amounts[]=#{v.to_s}" }.join("&")
219
+ end
220
+
212
221
  def before_gateways(kb_transaction, last_transaction, payment_source, amount_in_cents, currency, options, context)
213
222
  super(kb_transaction, last_transaction, payment_source, amount_in_cents, currency, options, context)
214
223
  options[:idempotency_key] ||= kb_transaction.external_key
@@ -216,7 +225,16 @@ module Killbill #:nodoc:
216
225
 
217
226
  def get_payment_source(kb_payment_method_id, properties, options, context)
218
227
  return nil if options[:customer_id]
219
- super(kb_payment_method_id, properties, options, context)
228
+ if is_bank_account?(properties)
229
+ ActiveMerchant::Billing::StripeGateway::BankAccount.new({
230
+ :bank_name => find_value_from_properties(properties, :bank_name),
231
+ :routing_number => find_value_from_properties(properties, :routing_number),
232
+ :account_number => find_value_from_properties(properties, :account_number),
233
+ :type => find_value_from_properties(properties, :type) || "personal",
234
+ })
235
+ else
236
+ super(kb_payment_method_id, properties, options, context)
237
+ end
220
238
  end
221
239
 
222
240
  def populate_defaults(pm, amount, properties, context, options)
@@ -246,6 +264,11 @@ module Killbill #:nodoc:
246
264
 
247
265
  config(context.tenant_id)[:stripe][:fees_amount] || (config(context.tenant_id)[:stripe][:fees_percent].to_f * amount * 100)
248
266
  end
267
+
268
+ def is_bank_account?(properties)
269
+ find_value_from_properties(properties, :routing_number) &&
270
+ find_value_from_properties(properties, :account_number)
271
+ end
249
272
  end
250
273
  end
251
274
  end
@@ -72,6 +72,16 @@ post '/plugins/killbill-stripe', :provides => 'json' do
72
72
  response.to_json
73
73
  end
74
74
 
75
+ post '/plugins/killbill-stripe/verify', :provides => 'json' do
76
+ return params.to_json if development? or test?
77
+
78
+ stripe_response = plugin(session).verify_bank_account(params)
79
+
80
+ response = params.dup
81
+ response['stripe_response'] = stripe_response
82
+ response.to_json
83
+ end
84
+
75
85
  # Create managed account
76
86
  post '/plugins/killbill-stripe/accounts', :provides => 'json' do
77
87
  kb_account_id = params.delete('kb_account_id')
@@ -4,6 +4,10 @@ module ActiveMerchant
4
4
  KB_PLUGIN_VERSION = Gem.loaded_specs['killbill-stripe'].version.version rescue nil
5
5
 
6
6
  class StripeGateway
7
+ BANK_ACCOUNT_HOLDER_TYPE_MAPPING = {
8
+ "personal" => "individual",
9
+ "business" => "company",
10
+ }
7
11
 
8
12
  def get_balance(options = {})
9
13
  commit(:get, 'balance', nil, options)
@@ -37,6 +41,137 @@ module ActiveMerchant
37
41
 
38
42
  headers
39
43
  end
44
+
45
+ # To create a charge on a card or a token, call
46
+ #
47
+ # purchase(money, card_hash_or_token, { ... })
48
+ #
49
+ # To create a charge on a customer, call
50
+ #
51
+ # purchase(money, nil, { :customer => id, ... })
52
+ def purchase(money, payment, options = {})
53
+ responses = MultiResponse.run do |r|
54
+ if payment.is_a?(ApplePayPaymentToken)
55
+ r.process { tokenize_apple_pay_token(payment) }
56
+ payment = StripePaymentToken.new(r.params["token"]) if r.success?
57
+ end
58
+ r.process do
59
+ post = create_post_for_auth_or_purchase(money, payment, options)
60
+ commit(:post, 'charges', post, options)
61
+ end
62
+ end.responses.last
63
+ end
64
+
65
+ def store(payment, options = {})
66
+ params = {}
67
+ post = {}
68
+
69
+ if payment.is_a?(ApplePayPaymentToken)
70
+ token_exchange_response = tokenize_apple_pay_token(payment)
71
+ params = { :card => token_exchange_response.params["token"]["id"] } if token_exchange_response.success?
72
+ elsif payment.is_a?(BankAccount)
73
+ post.merge!(bank_account_params(payment, options))
74
+ else
75
+ add_creditcard(params, payment, options)
76
+ end
77
+
78
+ unless payment.is_a?(BankAccount)
79
+ post[:validate] = options[:validate] unless options[:validate].nil?
80
+ post[:description] = options[:description] if options[:description]
81
+ post[:email] = options[:email] if options[:email]
82
+ end
83
+
84
+ if post[:bank_account]
85
+ customer_url = "customers"
86
+ if options[:customer]
87
+ customer_url += "/#{CGI.escape(options[:customer])}/sources"
88
+ end
89
+ responses = MultiResponse.run do |r|
90
+ # get token and associate it with the customer
91
+ r.process { commit(:post, "tokens?#{post_data(post)}", nil, { bank_account: true }) }
92
+
93
+ if r.success?
94
+ r.process { commit(:post, customer_url, { source: r.params["id"] } ) }
95
+ end
96
+ end.responses
97
+ if options[:customer]
98
+ return responses.first
99
+ else
100
+ return responses.last
101
+ end
102
+ elsif options[:account]
103
+ add_external_account(post, params, payment)
104
+ commit(:post, "accounts/#{CGI.escape(options[:account])}/external_accounts", post, options)
105
+ elsif options[:customer]
106
+ MultiResponse.run(:first) do |r|
107
+ # The /cards endpoint does not update other customer parameters.
108
+ r.process { commit(:post, "customers/#{CGI.escape(options[:customer])}/cards", params, options) }
109
+
110
+ if options[:set_default] and r.success? and !r.params['id'].blank?
111
+ post[:default_card] = r.params['id']
112
+ end
113
+
114
+ if post.count > 0
115
+ r.process { update_customer(options[:customer], post) }
116
+ end
117
+ end
118
+ else
119
+ commit(:post, 'customers', post.merge(params), options)
120
+ end
121
+ end
122
+
123
+ def commit(method, url, parameters = nil, options = {})
124
+ if options[:bank_account]
125
+ response = api_request(:post, url)
126
+ success = response["error"].nil?
127
+
128
+ Response.new(success, nil, response)
129
+ else
130
+ add_expand_parameters(parameters, options) if parameters
131
+ response = api_request(method, url, parameters, options)
132
+
133
+ success = !response.key?("error")
134
+
135
+ card = card_from_response(response)
136
+ avs_code = AVS_CODE_TRANSLATOR["line1: #{card["address_line1_check"]}, zip: #{card["address_zip_check"]}"]
137
+ cvc_code = CVC_CODE_TRANSLATOR[card["cvc_check"]]
138
+ Response.new(success,
139
+ success ? "Transaction approved" : response["error"]["message"],
140
+ response,
141
+ :test => response.has_key?("livemode") ? !response["livemode"] : false,
142
+ :authorization => authorization_from(success, url, method, response),
143
+ :avs_result => { :code => avs_code },
144
+ :cvv_result => cvc_code,
145
+ :emv_authorization => emv_authorization_from_response(response),
146
+ :error_code => success ? nil : error_code_from(response)
147
+ )
148
+ end
149
+ end
150
+
151
+ def bank_account_params(bank_account, options = {})
152
+ account_holder_type = BANK_ACCOUNT_HOLDER_TYPE_MAPPING[bank_account.type]
153
+
154
+ post = {
155
+ bank_account: {
156
+ account_number: bank_account.account_number,
157
+ country: 'US',
158
+ currency: 'usd',
159
+ routing_number: bank_account.routing_number,
160
+ name: bank_account.bank_name,
161
+ account_holder_type: account_holder_type,
162
+ }
163
+ }
164
+ end
165
+
166
+ class BankAccount
167
+ attr_accessor :bank_name, :account_number, :routing_number, :type
168
+
169
+ def initialize(args)
170
+ args.each do |k,v|
171
+ instance_variable_set("@#{k}", v) unless v.nil?
172
+ end
173
+ end
174
+ end
40
175
  end
41
176
  end
42
177
  end
@@ -4,16 +4,32 @@ module Killbill #:nodoc:
4
4
 
5
5
  self.table_name = 'stripe_payment_methods'
6
6
 
7
- def self.from_response(kb_account_id, kb_payment_method_id, kb_tenant_id, cc_or_token, response, options, extra_params = {}, model = ::Killbill::Stripe::StripePaymentMethod)
7
+ def self.from_response(kb_account_id, kb_payment_method_id, kb_tenant_id, cc_or_token, response, options, extra_params = {:source_type => "cc"}, model = ::Killbill::Stripe::StripePaymentMethod)
8
8
  stripe_customer_id = options[:customer] || self.stripe_customer_id_from_kb_account_id(kb_account_id, kb_tenant_id)
9
- if !stripe_customer_id.blank? && response.respond_to?(:responses)
10
- card_response = response.responses.first.params
9
+ if response.params["bank_account"]
10
+ extra_params = {} #overwrite extra params because they will be passed with assumption of CC
11
+ payment_response = {
12
+ "token" => response.params["bank_account"]["id"],
13
+ "address_country" => response.params["bank_account"]["country"],
14
+ }
15
+ customer_response = { "id" => stripe_customer_id }
16
+ extra_params[:bank_name] = response.params["bank_account"]["bank_name"]
17
+ extra_params[:bank_routing_number] = response.params["bank_account"]["routing_number"]
18
+ extra_params[:source_type] = "bank_account"
19
+ cc_or_token ||= response.params["bank_account"]["id"]
20
+ elsif !stripe_customer_id.blank? && response.respond_to?(:responses)
21
+ payment_response = response.responses.first.params
11
22
  customer_response = response.responses.last.params
12
23
  elsif response.params['sources']
13
- card_response = response.params['sources']['data'][0]
24
+ payment_response = response.params['sources']['data'][0]
14
25
  customer_response = response.params
26
+ if response.params['sources']['data'][0]["object"] == "bank_account"
27
+ extra_params[:bank_name] = response.params["sources"]["data"][0]["bank_name"]
28
+ extra_params[:bank_routing_number] = response.params["sources"]["data"][0]["routing_number"]
29
+ extra_params[:source_type] = "bank_account"
30
+ end
15
31
  else
16
- card_response = {}
32
+ payment_response = {}
17
33
  customer_response = { 'id' => stripe_customer_id }
18
34
  end
19
35
 
@@ -25,19 +41,19 @@ module Killbill #:nodoc:
25
41
  options,
26
42
  {
27
43
  :stripe_customer_id => customer_response['id'],
28
- :token => card_response['id'],
29
- :cc_first_name => card_response['name'],
44
+ :token => payment_response['id'],
45
+ :cc_first_name => payment_response['name'],
30
46
  :cc_last_name => nil,
31
- :cc_type => card_response['brand'],
32
- :cc_exp_month => card_response['exp_month'],
33
- :cc_exp_year => card_response['exp_year'],
34
- :cc_last_4 => card_response['last4'],
35
- :address1 => card_response['address_line1'],
36
- :address2 => card_response['address_line2'],
37
- :city => card_response['address_city'],
38
- :state => card_response['address_state'],
39
- :zip => card_response['address_zip'],
40
- :country => card_response['address_country']
47
+ :cc_type => payment_response['brand'],
48
+ :cc_exp_month => payment_response['exp_month'],
49
+ :cc_exp_year => payment_response['exp_year'],
50
+ :cc_last_4 => payment_response['last4'],
51
+ :address1 => payment_response['address_line1'],
52
+ :address2 => payment_response['address_line2'],
53
+ :city => payment_response['address_city'],
54
+ :state => payment_response['address_state'],
55
+ :zip => payment_response['address_zip'],
56
+ :country => payment_response['address_country']
41
57
  }.merge!(extra_params.compact), # Don't override with nil values
42
58
  model)
43
59
  end
metadata CHANGED
@@ -1,21 +1,21 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: killbill-stripe
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.1
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kill Bill core team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-03 00:00:00.000000000 Z
11
+ date: 2018-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '8.0'
18
+ version: 9.3.0
19
19
  name: killbill
20
20
  prerelease: false
21
21
  type: :runtime
@@ -23,7 +23,7 @@ dependencies:
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '8.0'
26
+ version: 9.3.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
@@ -218,6 +218,9 @@ dependencies:
218
218
  - - ">="
219
219
  - !ruby/object:Gem::Version
220
220
  version: 10.0.0
221
+ - - "<"
222
+ - !ruby/object:Gem::Version
223
+ version: 11.0.0
221
224
  name: rake
222
225
  prerelease: false
223
226
  type: :development
@@ -226,6 +229,9 @@ dependencies:
226
229
  - - ">="
227
230
  - !ruby/object:Gem::Version
228
231
  version: 10.0.0
232
+ - - "<"
233
+ - !ruby/object:Gem::Version
234
+ version: 11.0.0
229
235
  - !ruby/object:Gem::Dependency
230
236
  requirement: !ruby/object:Gem::Requirement
231
237
  requirements: