killbill-stripe 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -18,24 +18,31 @@ Gem::Specification.new do |s|
18
18
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
19
  s.bindir = 'bin'
20
20
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
- s.require_paths = ["lib"]
21
+ s.require_paths = ['lib']
22
22
 
23
23
  s.rdoc_options << '--exclude' << '.'
24
24
 
25
- s.add_dependency 'killbill', '~> 3.0.0'
26
- s.add_dependency 'activemerchant', '~> 1.42.3'
27
- s.add_dependency 'activerecord', '~> 3.2.1'
28
- s.add_dependency 'money', '~> 6.0.0'
25
+ s.add_dependency 'killbill', '~> 3.1.12'
26
+ s.add_dependency 'activemerchant', '~> 1.44.1'
27
+ s.add_dependency 'offsite_payments', '~> 2.0.1'
28
+ s.add_dependency 'activerecord', '~> 4.1.0'
29
+ s.add_dependency 'actionpack', '~> 4.1.0'
30
+ s.add_dependency 'actionview', '~> 4.1.0'
31
+ s.add_dependency 'activesupport', '~> 4.1.0'
32
+ s.add_dependency 'money', '~> 6.1.1'
33
+ s.add_dependency 'monetize', '~> 0.3.0'
29
34
  s.add_dependency 'sinatra', '~> 1.3.4'
30
35
  if defined?(JRUBY_VERSION)
31
- s.add_dependency 'activerecord-jdbcmysql-adapter', '~> 1.2.9'
36
+ s.add_dependency 'activerecord-jdbcmysql-adapter', '~> 1.3.7'
37
+ # Required to avoid errors like java.lang.NoClassDefFoundError: org/bouncycastle/asn1/DERBoolean
38
+ s.add_dependency 'jruby-openssl', '~> 0.9.4'
32
39
  end
33
40
 
34
41
  s.add_development_dependency 'jbundler', '~> 0.4.1'
35
42
  s.add_development_dependency 'rake', '>= 10.0.0'
36
43
  s.add_development_dependency 'rspec', '~> 2.12.0'
37
44
  if defined?(JRUBY_VERSION)
38
- s.add_development_dependency 'activerecord-jdbcsqlite3-adapter', '~> 1.2.6'
45
+ s.add_development_dependency 'activerecord-jdbcsqlite3-adapter', '~> 1.3.7'
39
46
  else
40
47
  s.add_development_dependency 'sqlite3', '~> 1.3.7'
41
48
  end
data/lib/stripe.rb CHANGED
@@ -1,30 +1,24 @@
1
+ require 'action_controller'
1
2
  require 'active_record'
2
- require 'activemerchant'
3
+ require 'action_view'
4
+ require 'active_merchant'
5
+ require 'active_support'
3
6
  require 'bigdecimal'
4
7
  require 'money'
8
+ require 'monetize'
9
+ require 'offsite_payments'
5
10
  require 'pathname'
6
- require 'set'
7
11
  require 'sinatra'
8
12
  require 'singleton'
9
13
  require 'yaml'
10
14
 
11
15
  require 'killbill'
12
-
13
- require 'stripe/config/configuration'
14
- require 'stripe/config/properties'
16
+ require 'killbill/helpers/active_merchant'
15
17
 
16
18
  require 'stripe/api'
17
19
  require 'stripe/private_api'
18
20
 
19
- require 'stripe/models/stripe_payment_method'
20
- require 'stripe/models/stripe_response'
21
- require 'stripe/models/stripe_transaction'
22
-
23
- require 'stripe/stripe_utils'
24
- require 'stripe/stripe/gateway'
21
+ require 'stripe/models/payment_method'
22
+ require 'stripe/models/response'
23
+ require 'stripe/models/transaction'
25
24
 
26
- class Object
27
- def blank?
28
- respond_to?(:empty?) ? empty? : !self
29
- end
30
- end
data/lib/stripe/api.rb CHANGED
@@ -1,248 +1,188 @@
1
- module Killbill::Stripe
2
- class PaymentPlugin < Killbill::Plugin::Payment
3
- def start_plugin
4
- Killbill::Stripe.initialize! @logger, @conf_dir, @kb_apis
1
+ module Killbill #:nodoc:
2
+ module Stripe #:nodoc:
3
+ class PaymentPlugin < ::Killbill::Plugin::ActiveMerchant::PaymentPlugin
5
4
 
6
- super
5
+ def initialize
6
+ gateway_builder = Proc.new do |config|
7
+ ::ActiveMerchant::Billing::StripeGateway.new :login => config[:api_secret_key]
8
+ end
7
9
 
8
- @logger.info 'Killbill::Stripe::PaymentPlugin started'
9
- end
10
+ super(gateway_builder,
11
+ :stripe,
12
+ ::Killbill::Stripe::StripePaymentMethod,
13
+ ::Killbill::Stripe::StripeTransaction,
14
+ ::Killbill::Stripe::StripeResponse)
15
+ end
10
16
 
11
- # return DB connections to the Pool if required
12
- def after_request
13
- ActiveRecord::Base.connection.close
14
- end
17
+ def authorize_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
18
+ pm = @payment_method_model.from_kb_payment_method_id(kb_payment_method_id, context.tenant_id)
19
+
20
+ # Pass extra parameters for the gateway here
21
+ options = {
22
+ :customer => pm.stripe_customer_id
23
+ }
15
24
 
16
- def process_payment(kb_account_id, kb_payment_id, kb_payment_method_id, amount, currency, call_context = nil, options = {})
17
- # Use Money to compute the amount in cents, as it depends on the currency (1 cent of BTC is 1 Satoshi, not 0.01 BTC)
18
- amount_in_cents = Money.new_with_amount(amount, currency).cents.to_i
25
+ properties = merge_properties(properties, options)
26
+ super(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
27
+ end
19
28
 
20
- # If the payment was already made, just return the status
21
- stripe_transaction = StripeTransaction.from_kb_payment_id(kb_payment_id) rescue nil
22
- return stripe_transaction.stripe_response.to_payment_response unless stripe_transaction.nil?
29
+ def capture_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
30
+ # Pass extra parameters for the gateway here
31
+ options = {}
23
32
 
24
- options[:order_id] ||= kb_payment_id
25
- options[:currency] ||= currency.to_s.upcase
26
- options[:description] ||= Killbill::Stripe.stripe_payment_description || "Kill Bill payment for #{kb_payment_id}"
33
+ properties = merge_properties(properties, options)
34
+ super(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
35
+ end
27
36
 
28
- # Retrieve the Stripe payment method
29
- pm = StripePaymentMethod.from_kb_payment_method_id(kb_payment_method_id)
30
- options[:customer] ||= pm.stripe_customer_id
37
+ def purchase_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
38
+ pm = @payment_method_model.from_kb_payment_method_id(kb_payment_method_id, context.tenant_id)
31
39
 
32
- # Go to Stripe
33
- stripe_response = Killbill::Stripe.gateway.purchase amount_in_cents, pm.stripe_card_id_or_token, options
34
- response = save_response_and_transaction stripe_response, :charge, kb_payment_id, amount_in_cents, currency
40
+ # Pass extra parameters for the gateway here
41
+ options = {
42
+ :customer => pm.stripe_customer_id
43
+ }
35
44
 
36
- response.to_payment_response
37
- end
45
+ properties = merge_properties(properties, options)
46
+ super(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
47
+ end
38
48
 
39
- def get_payment_info(kb_account_id, kb_payment_id, tenant_context = nil, options = {})
40
- # We assume the payment is immutable in Stripe and only look at our tables
41
- stripe_transaction = StripeTransaction.from_kb_payment_id(kb_payment_id)
42
- stripe_transaction.stripe_response.to_payment_response
43
- end
49
+ def void_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, properties, context)
50
+ # Pass extra parameters for the gateway here
51
+ options = {}
44
52
 
45
- def process_refund(kb_account_id, kb_payment_id, amount, currency, call_context = nil, options = {})
46
- # Use Money to compute the amount in cents, as it depends on the currency (1 cent of BTC is 1 Satoshi, not 0.01 BTC)
47
- amount_in_cents = Money.new_with_amount(amount, currency).cents.to_i
53
+ properties = merge_properties(properties, options)
54
+ super(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, properties, context)
55
+ end
48
56
 
49
- stripe_transaction = StripeTransaction.find_candidate_transaction_for_refund(kb_payment_id, amount_in_cents)
57
+ def credit_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
58
+ # Pass extra parameters for the gateway here
59
+ options = {}
50
60
 
51
- # Go to Stripe
52
- stripe_response = Killbill::Stripe.gateway.refund amount_in_cents, stripe_transaction.stripe_txn_id, options
53
- response = save_response_and_transaction stripe_response, :refund, kb_payment_id, amount_in_cents, currency
61
+ properties = merge_properties(properties, options)
62
+ super(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
63
+ end
54
64
 
55
- response.to_refund_response
56
- end
65
+ def refund_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
66
+ # Pass extra parameters for the gateway here
67
+ options = {}
57
68
 
58
- def get_refund_info(kb_account_id, kb_payment_id, tenant_context = nil, options = {})
59
- # We assume the refund is immutable in Stripe and only look at our tables
60
- stripe_transactions = StripeTransaction.refunds_from_kb_payment_id(kb_payment_id)
69
+ properties = merge_properties(properties, options)
70
+ super(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
71
+ end
61
72
 
62
- stripe_transactions.map { |t| t.stripe_response.to_refund_response }
63
- end
73
+ def get_payment_info(kb_account_id, kb_payment_id, properties, context)
74
+ # Pass extra parameters for the gateway here
75
+ options = {}
64
76
 
65
- def add_payment_method(kb_account_id, kb_payment_method_id, payment_method_props, set_default, call_context = nil, options = {})
66
- # Do we have a customer for that account already?
67
- stripe_customer_id = StripePaymentMethod.stripe_customer_id_from_kb_account_id(kb_account_id)
68
-
69
- # This will either update the current customer if present, or create a new one
70
- options[:customer] ||= stripe_customer_id
71
- options[:set_default] ||= set_default
72
-
73
- # Magic field, see also private_api.rb (works only when creating an account)
74
- if options[:customer].blank?
75
- options[:description] ||= kb_account_id
76
- else
77
- options[:description] = nil
78
- end
79
-
80
- # Registering a card or a token from Stripe.js?
81
- cc_or_token = find_value_from_payment_method_props(payment_method_props, 'token') || find_value_from_payment_method_props(payment_method_props, 'cardId')
82
- if cc_or_token.blank?
83
- # Nope - real credit card
84
- cc_or_token = ActiveMerchant::Billing::CreditCard.new(
85
- :number => find_value_from_payment_method_props(payment_method_props, 'ccNumber'),
86
- :month => find_value_from_payment_method_props(payment_method_props, 'ccExpirationMonth'),
87
- :year => find_value_from_payment_method_props(payment_method_props, 'ccExpirationYear'),
88
- :verification_value => find_value_from_payment_method_props(payment_method_props, 'ccVerificationValue'),
89
- :first_name => find_value_from_payment_method_props(payment_method_props, 'ccFirstName'),
90
- :last_name => find_value_from_payment_method_props(payment_method_props, 'ccLastName')
91
- )
92
- end
93
-
94
- options[:billing_address] ||= {
95
- :address1 => find_value_from_payment_method_props(payment_method_props, 'address1'),
96
- :address2 => find_value_from_payment_method_props(payment_method_props, 'address2'),
97
- :city => find_value_from_payment_method_props(payment_method_props, 'city'),
98
- :zip => find_value_from_payment_method_props(payment_method_props, 'zip'),
99
- :state => find_value_from_payment_method_props(payment_method_props, 'state'),
100
- :country => find_value_from_payment_method_props(payment_method_props, 'country')
101
- }
102
-
103
- # Go to Stripe
104
- stripe_response = Killbill::Stripe.gateway.store cc_or_token, options
105
- response = save_response_and_transaction stripe_response, :add_payment_method
106
-
107
- if response.success
108
- unless stripe_customer_id.blank?
109
- card_response = stripe_response.responses.first.params
110
- customer_response = stripe_response.responses.last.params
111
- else
112
- card_response = stripe_response.params['cards']['data'][0]
113
- customer_response = stripe_response.params
114
- end
77
+ properties = merge_properties(properties, options)
78
+ super(kb_account_id, kb_payment_id, properties, context)
79
+ end
115
80
 
116
- StripePaymentMethod.create :kb_account_id => kb_account_id,
117
- :kb_payment_method_id => kb_payment_method_id,
118
- :stripe_customer_id => customer_response['id'],
119
- :stripe_card_id_or_token => card_response['id'],
120
- :cc_first_name => card_response['name'],
121
- :cc_last_name => nil,
122
- :cc_type => card_response['type'],
123
- :cc_exp_month => card_response['exp_month'],
124
- :cc_exp_year => card_response['exp_year'],
125
- :cc_last_4 => card_response['last4'],
126
- :address1 => card_response['address_line1'],
127
- :address2 => card_response['address_line2'],
128
- :city => card_response['address_city'],
129
- :state => card_response['address_state'],
130
- :zip => card_response['address_zip'],
131
- :country => card_response['address_country']
132
- else
133
- raise response.message
81
+ def search_payments(search_key, offset, limit, properties, context)
82
+ # Pass extra parameters for the gateway here
83
+ options = {}
84
+
85
+ properties = merge_properties(properties, options)
86
+ super(search_key, offset, limit, properties, context)
134
87
  end
135
- end
136
88
 
137
- def delete_payment_method(kb_account_id, kb_payment_method_id, call_context = nil, options = {})
138
- pm = StripePaymentMethod.from_kb_payment_method_id(kb_payment_method_id)
89
+ def add_payment_method(kb_account_id, kb_payment_method_id, payment_method_props, set_default, properties, context)
90
+ # Do we have a customer for that account already?
91
+ stripe_customer_id = StripePaymentMethod.stripe_customer_id_from_kb_account_id(kb_account_id, context.tenant_id)
139
92
 
140
- # Delete the card on the customer object
141
- stripe_response = Killbill::Stripe.gateway.unstore(pm.stripe_customer_id, pm.stripe_card_id_or_token)
142
- response = save_response_and_transaction stripe_response, :delete_payment_method
93
+ # Pass extra parameters for the gateway here
94
+ options = {
95
+ # This will either update the current customer if present, or create a new one
96
+ :customer => stripe_customer_id,
97
+ # Magic field, see also private_api.rb (works only when creating an account)
98
+ :description => kb_account_id
99
+ }
143
100
 
144
- if response.success
145
- StripePaymentMethod.mark_as_deleted! kb_payment_method_id
146
- else
147
- raise response.message
101
+ properties = merge_properties(properties, options)
102
+ super(kb_account_id, kb_payment_method_id, payment_method_props, set_default, properties, context)
148
103
  end
149
- end
150
104
 
151
- def get_payment_method_detail(kb_account_id, kb_payment_method_id, tenant_context = nil, options = {})
152
- StripePaymentMethod.from_kb_payment_method_id(kb_payment_method_id).to_payment_method_response
153
- end
105
+ def delete_payment_method(kb_account_id, kb_payment_method_id, properties, context)
106
+ pm = StripePaymentMethod.from_kb_payment_method_id(kb_payment_method_id, context.tenant_id)
154
107
 
155
- def set_default_payment_method(kb_account_id, kb_payment_method_id, call_context = nil, options = {})
156
- pm = StripePaymentMethod.from_kb_payment_method_id(kb_payment_method_id)
108
+ # Pass extra parameters for the gateway here
109
+ options = {
110
+ :customer_id => pm.stripe_customer_id
111
+ }
157
112
 
158
- # Update the default payment method on the customer object
159
- stripe_response = Killbill::Stripe.gateway.update_customer(pm.stripe_customer_id, :default_card => pm.stripe_card_id_or_token)
160
- response = save_response_and_transaction stripe_response, :set_default_payment_method
113
+ properties = merge_properties(properties, options)
114
+ super(kb_account_id, kb_payment_method_id, properties, context)
115
+ end
161
116
 
162
- if response.success
163
- # TODO Update our records
164
- else
165
- raise response.message
117
+ def get_payment_method_detail(kb_account_id, kb_payment_method_id, properties, context)
118
+ # Pass extra parameters for the gateway here
119
+ options = {}
120
+
121
+ properties = merge_properties(properties, options)
122
+ super(kb_account_id, kb_payment_method_id, properties, context)
166
123
  end
167
- end
168
124
 
169
- def get_payment_methods(kb_account_id, refresh_from_gateway = false, call_context = nil, options = {})
170
- StripePaymentMethod.from_kb_account_id(kb_account_id).collect { |pm| pm.to_payment_method_info_response }
171
- end
125
+ def set_default_payment_method(kb_account_id, kb_payment_method_id, properties, context)
126
+ pm = StripePaymentMethod.from_kb_payment_method_id(kb_payment_method_id, context.tenant_id)
172
127
 
173
- def reset_payment_methods(kb_account_id, payment_methods)
174
- return if payment_methods.nil?
175
-
176
- stripe_pms = StripePaymentMethod.from_kb_account_id(kb_account_id)
177
-
178
- payment_methods.delete_if do |payment_method_info_plugin|
179
- should_be_deleted = false
180
- stripe_pms.each do |stripe_pm|
181
- # Do stripe_pm and payment_method_info_plugin represent the same Stripe payment method?
182
- if stripe_pm.external_payment_method_id == payment_method_info_plugin.external_payment_method_id
183
- # Do we already have a kb_payment_method_id?
184
- if stripe_pm.kb_payment_method_id == payment_method_info_plugin.payment_method_id
185
- should_be_deleted = true
186
- break
187
- elsif stripe_pm.kb_payment_method_id.nil?
188
- # We didn't have the kb_payment_method_id - update it
189
- stripe_pm.kb_payment_method_id = payment_method_info_plugin.payment_method_id
190
- should_be_deleted = stripe_pm.save
191
- break
192
- # Otherwise the same card points to 2 different kb_payment_method_id. This should never happen,
193
- # but we cowardly will insert a second row below
194
- end
195
- end
196
- end
128
+ # Update the default payment method on the customer object
129
+ stripe_response = gateway.update_customer(pm.stripe_customer_id, :default_card => pm.token)
130
+ response, transaction = save_response_and_transaction stripe_response, :set_default_payment_method, kb_account_id, context.tenant_id
197
131
 
198
- should_be_deleted
132
+ if response.success
133
+ # TODO Update our records
134
+ else
135
+ raise response.message
136
+ end
199
137
  end
200
138
 
201
- # The remaining elements in payment_methods are not in our table (this should never happen?!)
202
- payment_methods.each do |payment_method_info_plugin|
203
- StripePaymentMethod.create :kb_account_id => kb_account_id,
204
- :kb_payment_method_id => payment_method_info_plugin.payment_method_id,
205
- :stripe_card_id_or_token => payment_method_info_plugin.external_payment_method_id
206
- end
207
- end
139
+ def get_payment_methods(kb_account_id, refresh_from_gateway, properties, context)
140
+ # Pass extra parameters for the gateway here
141
+ options = {}
208
142
 
209
- def search_payments(search_key, offset = 0, limit = 100, call_context = nil, options = {})
210
- StripeResponse.search(search_key, offset, limit, :payment)
211
- end
143
+ properties = merge_properties(properties, options)
144
+ super(kb_account_id, refresh_from_gateway, properties, context)
145
+ end
212
146
 
213
- def search_refunds(search_key, offset = 0, limit = 100, call_context = nil, options = {})
214
- StripeResponse.search(search_key, offset, limit, :refund)
215
- end
147
+ def search_payment_methods(search_key, offset, limit, properties, context)
148
+ # Pass extra parameters for the gateway here
149
+ options = {}
216
150
 
217
- def search_payment_methods(search_key, offset = 0, limit = 100, call_context = nil, options = {})
218
- StripePaymentMethod.search(search_key, offset, limit)
219
- end
151
+ properties = merge_properties(properties, options)
152
+ super(search_key, offset, limit, properties, context)
153
+ end
220
154
 
221
- private
155
+ def reset_payment_methods(kb_account_id, payment_methods, properties, context)
156
+ super
157
+ end
222
158
 
223
- def find_value_from_payment_method_props(payment_method_props, key)
224
- return payment_method_props[key] if payment_method_props.is_a? Hash
225
- prop = (payment_method_props.properties.find { |kv| kv.key == key })
226
- prop.nil? ? nil : prop.value
227
- end
159
+ def build_form_descriptor(kb_account_id, descriptor_fields, properties, context)
160
+ # Pass extra parameters for the gateway here
161
+ options = {}
162
+ properties = merge_properties(properties, options)
228
163
 
229
- def save_response_and_transaction(stripe_response, api_call, kb_payment_id=nil, amount_in_cents=0, currency=nil)
230
- @logger.warn "Unsuccessful #{api_call}: #{stripe_response.message}" unless stripe_response.success?
164
+ # Add your custom static hidden tags here
165
+ options = {
166
+ #:token => config[:stripe][:token]
167
+ }
168
+ descriptor_fields = merge_properties(descriptor_fields, options)
231
169
 
232
- # Save the response to our logs
233
- response = StripeResponse.from_response(api_call, kb_payment_id, stripe_response)
234
- response.save!
170
+ super(kb_account_id, descriptor_fields, properties, context)
171
+ end
235
172
 
236
- if response.success and !kb_payment_id.blank? and !response.stripe_txn_id.blank?
237
- # Record the transaction
238
- transaction = response.create_stripe_transaction!(:amount_in_cents => amount_in_cents,
239
- :currency => currency,
240
- :api_call => api_call,
241
- :kb_payment_id => kb_payment_id,
242
- :stripe_txn_id => response.stripe_txn_id)
243
- @logger.debug "Recorded transaction: #{transaction.inspect}"
173
+ def process_notification(notification, properties, context)
174
+ # Pass extra parameters for the gateway here
175
+ options = {}
176
+ properties = merge_properties(properties, options)
177
+
178
+ super(notification, properties, context) do |gw_notification, service|
179
+ # Retrieve the payment
180
+ # gw_notification.kb_payment_id =
181
+ #
182
+ # Set the response body
183
+ # gw_notification.entity =
184
+ end
244
185
  end
245
- response
246
186
  end
247
187
  end
248
188
  end