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 +4 -4
- data/lib/stripe/api.rb +25 -2
- data/lib/stripe/application.rb +10 -0
- data/lib/stripe/ext/active_merchant/active_merchant.rb +135 -0
- data/lib/stripe/models/payment_method.rb +33 -17
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b3fd774290b63212046cc65ae4d9e597feecdcf
|
4
|
+
data.tar.gz: 3f76e5e8fa7b0c3541d010588be12b36546d1a37
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58f9df996d008f919c4de81efef0024f6f3579691985e0643e75a0c6636bb712e9da1db2029c74b8151a5d1f2152b61d323ff97d16ad4dde6cada95a51583c44
|
7
|
+
data.tar.gz: 63a9d8bce5a5fcbec1690433ea13e47262691747c4d14f0733b4a6e6b4efd11eaa7f3d10cf62c517a24e4d8c6faaffed823162a4378afc3b7388149dfa21f71f
|
data/lib/stripe/api.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/stripe/application.rb
CHANGED
@@ -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
|
10
|
-
|
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
|
-
|
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
|
-
|
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 =>
|
29
|
-
:cc_first_name =>
|
44
|
+
:token => payment_response['id'],
|
45
|
+
:cc_first_name => payment_response['name'],
|
30
46
|
:cc_last_name => nil,
|
31
|
-
:cc_type =>
|
32
|
-
:cc_exp_month =>
|
33
|
-
:cc_exp_year =>
|
34
|
-
:cc_last_4 =>
|
35
|
-
:address1 =>
|
36
|
-
:address2 =>
|
37
|
-
:city =>
|
38
|
-
:state =>
|
39
|
-
:zip =>
|
40
|
-
: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
|
+
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:
|
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:
|
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:
|
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:
|