killbill-stripe 0.1.0 → 0.2.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.
@@ -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