killbill-stripe 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 70736e813db9a21f0144ef12503a5e257978d083
4
+ data.tar.gz: f620f84e2a4da96f51fbb70a0b1c5c2b39a42303
5
+ SHA512:
6
+ metadata.gz: 5991a3693fdfb78f398bcde89f8113fed5ad72fe6d58d17ea8bd887a4cc570fafab74d1d43014ef1b16af26732c967a6d3fb9a5992c70d0c9bc206210f49173a
7
+ data.tar.gz: 8ed1cc06a9801512930f089a1d9e90143c224272c411cea8ff043c93cd90cc89e79d715a498eabf4eac63af6de3a9bae3a16ee904f88ca24e4f3713ed23e0958
data/.gitignore ADDED
@@ -0,0 +1,39 @@
1
+ *.gem
2
+ *.rbc
3
+ *.swp
4
+ .bundle
5
+ .config
6
+ coverage
7
+ InstalledFiles
8
+ lib/bundler/man
9
+ pkg
10
+ rdoc
11
+ spec/reports
12
+ test/tmp
13
+ test/version_tmp
14
+ tmp
15
+
16
+ # YARD artifacts
17
+ .yardoc
18
+ _yardoc
19
+ doc/
20
+
21
+ .jbundler
22
+ Jarfile.lock
23
+ Gemfile.lock
24
+
25
+ .DS_Store
26
+
27
+ # Build directory
28
+ killbill-stripe/
29
+
30
+ # Config file
31
+ stripe.yml
32
+
33
+ # Testing database
34
+ test.db
35
+
36
+ target
37
+ pom.xml.asc
38
+
39
+ .idea/
data/.travis.yml ADDED
@@ -0,0 +1,19 @@
1
+ language: ruby
2
+
3
+ notifications:
4
+ email:
5
+ - kill-bill-commits@googlegroups.com
6
+
7
+ rvm:
8
+ - jruby-19mode
9
+ - jruby-20mode
10
+ - jruby-head
11
+
12
+ jdk:
13
+ - openjdk6
14
+ - openjdk7
15
+ - oraclejdk7
16
+
17
+ matrix:
18
+ allow_failures:
19
+ - rvm: jruby-head
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Jarfile ADDED
@@ -0,0 +1,6 @@
1
+ jar 'org.kill-bill.billing:killbill-api', '0.8.2'
2
+ jar 'org.kill-bill.billing.plugin:killbill-plugin-api-notification', '0.6.4'
3
+ jar 'org.kill-bill.billing.plugin:killbill-plugin-api-payment', '0.6.4'
4
+ jar 'org.kill-bill.billing.plugin:killbill-plugin-api-currency', '0.6.4'
5
+ jar 'org.kill-bill.billing:killbill-util:tests', '0.9.1'
6
+ jar 'javax.servlet:javax.servlet-api', '3.0.1'
data/NEWS ADDED
@@ -0,0 +1,2 @@
1
+ 0.1.0
2
+ Initial release
data/README.md ADDED
@@ -0,0 +1,21 @@
1
+ killbill-stripe-plugin
2
+ ======================
3
+
4
+ Killbill payment plugin for Stripe.
5
+
6
+ Getting started
7
+ ---------------
8
+
9
+ 1. Make sure you can build the project by running the smoke tests: `mvn clean test`
10
+ 2. Go to [stripe.com](http://stripe.com/) and create an account. This account will be used as a sandbox environment for testing.
11
+ 3. In your Stripe account, click on **Your Account** (top right), then click on **Account Settings** and then on the **API Keys** tab. Write down your Test Secret Key.
12
+ 4. Verify the setup by running the killbill-stripe-plugin integration tests (make sure to update your API Key): `mvn clean test -Pintegration -Dkillbill.payment.stripe.apiKey=1234567689abcdef`
13
+ 5. Go to your Stripe account, you should see some data (e.g. account created).
14
+ 6. Congrats! You're all set!
15
+
16
+ Build
17
+ -----
18
+
19
+ To build the project, use maven:
20
+
21
+ mvn clean install
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env rake
2
+
3
+ # Install tasks to build and release the plugin
4
+ require 'bundler/setup'
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ # Install test tasks
8
+ require 'rspec/core/rake_task'
9
+ namespace :test do
10
+ desc "Run RSpec tests"
11
+ RSpec::Core::RakeTask.new do |task|
12
+ task.name = 'spec'
13
+ task.pattern = './spec/*/*_spec.rb'
14
+ end
15
+
16
+ namespace :remote do
17
+ desc "Run RSpec remote tests"
18
+ RSpec::Core::RakeTask.new do |task|
19
+ task.name = 'spec'
20
+ task.pattern = './spec/*/remote/*_spec.rb'
21
+ end
22
+ end
23
+ end
24
+
25
+ # Install tasks to package the plugin for Killbill
26
+ require 'killbill/rake_task'
27
+ Killbill::PluginHelper.install_tasks
28
+
29
+ # Run tests by default
30
+ task :default => 'test:spec'
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/config.ru ADDED
@@ -0,0 +1,4 @@
1
+ require 'stripe'
2
+ require 'stripe/config/application'
3
+
4
+ run Sinatra::Application
data/db/ddl.sql ADDED
@@ -0,0 +1,99 @@
1
+ CREATE TABLE `stripe_payment_methods` (
2
+ `id` int(11) NOT NULL AUTO_INCREMENT,
3
+ `kb_account_id` varchar(255) NOT NULL,
4
+ `kb_payment_method_id` varchar(255) DEFAULT NULL,
5
+ `stripe_customer_id` varchar(255) DEFAULT NULL,
6
+ `stripe_card_id_or_token` varchar(255) NOT NULL,
7
+ `cc_first_name` varchar(255) DEFAULT NULL,
8
+ `cc_last_name` varchar(255) DEFAULT NULL,
9
+ `cc_type` varchar(255) DEFAULT NULL,
10
+ `cc_exp_month` int(11) DEFAULT NULL,
11
+ `cc_exp_year` int(11) DEFAULT NULL,
12
+ `cc_last_4` int(11) DEFAULT NULL,
13
+ `address1` varchar(255) DEFAULT NULL,
14
+ `address2` varchar(255) DEFAULT NULL,
15
+ `city` varchar(255) DEFAULT NULL,
16
+ `state` varchar(255) DEFAULT NULL,
17
+ `zip` varchar(255) DEFAULT NULL,
18
+ `country` varchar(255) DEFAULT NULL,
19
+ `is_deleted` tinyint(1) NOT NULL DEFAULT '0',
20
+ `created_at` datetime NOT NULL,
21
+ `updated_at` datetime NOT NULL,
22
+ PRIMARY KEY (`id`),
23
+ KEY `index_stripe_payment_methods_on_kb_account_id` (`kb_account_id`),
24
+ KEY `index_stripe_payment_methods_on_kb_payment_method_id` (`kb_payment_method_id`)
25
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
26
+
27
+ CREATE TABLE `stripe_transactions` (
28
+ `id` int(11) NOT NULL AUTO_INCREMENT,
29
+ `stripe_response_id` int(11) NOT NULL,
30
+ `api_call` varchar(255) NOT NULL,
31
+ `kb_payment_id` varchar(255) NOT NULL,
32
+ `stripe_txn_id` varchar(255) NOT NULL,
33
+ `amount_in_cents` int(11) NOT NULL,
34
+ `currency` char(3) NOT NULL,
35
+ `created_at` datetime NOT NULL,
36
+ `updated_at` datetime NOT NULL,
37
+ PRIMARY KEY (`id`),
38
+ KEY `index_stripe_transactions_on_kb_payment_id` (`kb_payment_id`)
39
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
40
+
41
+ CREATE TABLE `stripe_responses` (
42
+ `id` int(11) NOT NULL AUTO_INCREMENT,
43
+ `api_call` varchar(255) NOT NULL,
44
+ `kb_payment_id` varchar(255) DEFAULT NULL,
45
+ `message` varchar(255) DEFAULT NULL,
46
+ `authorization` varchar(255) DEFAULT NULL,
47
+ `fraud_review` tinyint(1) DEFAULT NULL,
48
+ `test` tinyint(1) DEFAULT NULL,
49
+ `params_id` varchar(255) DEFAULT NULL,
50
+ `params_object` varchar(255) DEFAULT NULL,
51
+ `params_created` varchar(255) DEFAULT NULL,
52
+ `params_livemode` varchar(255) DEFAULT NULL,
53
+ `params_paid` varchar(255) DEFAULT NULL,
54
+ `params_amount` varchar(255) DEFAULT NULL,
55
+ `params_currency` varchar(255) DEFAULT NULL,
56
+ `params_refunded` varchar(255) DEFAULT NULL,
57
+ `params_card_id` varchar(255) DEFAULT NULL,
58
+ `params_card_object` varchar(255) DEFAULT NULL,
59
+ `params_card_last4` varchar(255) DEFAULT NULL,
60
+ `params_card_type` varchar(255) DEFAULT NULL,
61
+ `params_card_exp_month` varchar(255) DEFAULT NULL,
62
+ `params_card_exp_year` varchar(255) DEFAULT NULL,
63
+ `params_card_fingerprint` varchar(255) DEFAULT NULL,
64
+ `params_card_customer` varchar(255) DEFAULT NULL,
65
+ `params_card_country` varchar(255) DEFAULT NULL,
66
+ `params_card_name` varchar(255) DEFAULT NULL,
67
+ `params_card_address_line1` varchar(255) DEFAULT NULL,
68
+ `params_card_address_line2` varchar(255) DEFAULT NULL,
69
+ `params_card_address_city` varchar(255) DEFAULT NULL,
70
+ `params_card_address_state` varchar(255) DEFAULT NULL,
71
+ `params_card_address_zip` varchar(255) DEFAULT NULL,
72
+ `params_card_address_country` varchar(255) DEFAULT NULL,
73
+ `params_card_cvc_check` varchar(255) DEFAULT NULL,
74
+ `params_card_address_line1_check` varchar(255) DEFAULT NULL,
75
+ `params_card_address_zip_check` varchar(255) DEFAULT NULL,
76
+ `params_captured` varchar(255) DEFAULT NULL,
77
+ `params_refunds` varchar(255) DEFAULT NULL,
78
+ `params_balance_transaction` varchar(255) DEFAULT NULL,
79
+ `params_failure_message` varchar(255) DEFAULT NULL,
80
+ `params_failure_code` varchar(255) DEFAULT NULL,
81
+ `params_amount_refunded` varchar(255) DEFAULT NULL,
82
+ `params_customer` varchar(255) DEFAULT NULL,
83
+ `params_invoice` varchar(255) DEFAULT NULL,
84
+ `params_description` varchar(255) DEFAULT NULL,
85
+ `params_dispute` varchar(255) DEFAULT NULL,
86
+ `params_metadata` varchar(255) DEFAULT NULL,
87
+ `params_error_type` varchar(255) DEFAULT NULL,
88
+ `params_error_message` varchar(255) DEFAULT NULL,
89
+ `avs_result_code` varchar(255) DEFAULT NULL,
90
+ `avs_result_message` varchar(255) DEFAULT NULL,
91
+ `avs_result_street_match` varchar(255) DEFAULT NULL,
92
+ `avs_result_postal_match` varchar(255) DEFAULT NULL,
93
+ `cvv_result_code` varchar(255) DEFAULT NULL,
94
+ `cvv_result_message` varchar(255) DEFAULT NULL,
95
+ `success` tinyint(1) DEFAULT NULL,
96
+ `created_at` datetime NOT NULL,
97
+ `updated_at` datetime NOT NULL,
98
+ PRIMARY KEY (`id`)
99
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
data/db/schema.rb ADDED
@@ -0,0 +1,99 @@
1
+ require 'active_record'
2
+
3
+ ActiveRecord::Schema.define(:version => 20130311153635) do
4
+ create_table "stripe_payment_methods", :force => true do |t|
5
+ t.string "kb_account_id", :null => false
6
+ t.string "kb_payment_method_id" # NULL before Killbill knows about it
7
+ t.string "stripe_customer_id"
8
+ t.string "stripe_card_id_or_token",:null => false
9
+ t.string "cc_first_name"
10
+ t.string "cc_last_name"
11
+ t.string "cc_type"
12
+ t.integer "cc_exp_month"
13
+ t.integer "cc_exp_year"
14
+ t.integer "cc_last_4"
15
+ t.string "address1"
16
+ t.string "address2"
17
+ t.string "city"
18
+ t.string "state"
19
+ t.string "zip"
20
+ t.string "country"
21
+ t.boolean "is_deleted", :null => false, :default => false
22
+ t.datetime "created_at", :null => false
23
+ t.datetime "updated_at", :null => false
24
+ end
25
+
26
+ add_index(:stripe_payment_methods, :kb_account_id)
27
+ add_index(:stripe_payment_methods, :kb_payment_method_id)
28
+
29
+ create_table "stripe_transactions", :force => true do |t|
30
+ t.integer "stripe_response_id", :null => false
31
+ t.string "api_call", :null => false
32
+ t.string "kb_payment_id", :null => false
33
+ t.string "stripe_txn_id", :null => false
34
+ t.integer "amount_in_cents", :null => false
35
+ t.string "currency", :null => false
36
+ t.datetime "created_at", :null => false
37
+ t.datetime "updated_at", :null => false
38
+ end
39
+
40
+ add_index(:stripe_transactions, :kb_payment_id)
41
+
42
+ create_table "stripe_responses", :force => true do |t|
43
+ t.string "api_call", :null => false
44
+ t.string "kb_payment_id"
45
+ t.string "message"
46
+ t.string "authorization"
47
+ t.boolean "fraud_review"
48
+ t.boolean "test"
49
+ t.string "params_id"
50
+ t.string "params_object"
51
+ t.string "params_created"
52
+ t.string "params_livemode"
53
+ t.string "params_paid"
54
+ t.string "params_amount"
55
+ t.string "params_currency"
56
+ t.string "params_refunded"
57
+ t.string "params_card_id"
58
+ t.string "params_card_object"
59
+ t.string "params_card_last4"
60
+ t.string "params_card_type"
61
+ t.string "params_card_exp_month"
62
+ t.string "params_card_exp_year"
63
+ t.string "params_card_fingerprint"
64
+ t.string "params_card_customer"
65
+ t.string "params_card_country"
66
+ t.string "params_card_name"
67
+ t.string "params_card_address_line1"
68
+ t.string "params_card_address_line2"
69
+ t.string "params_card_address_city"
70
+ t.string "params_card_address_state"
71
+ t.string "params_card_address_zip"
72
+ t.string "params_card_address_country"
73
+ t.string "params_card_cvc_check"
74
+ t.string "params_card_address_line1_check"
75
+ t.string "params_card_address_zip_check"
76
+ t.string "params_captured"
77
+ t.string "params_refunds"
78
+ t.string "params_balance_transaction"
79
+ t.string "params_failure_message"
80
+ t.string "params_failure_code"
81
+ t.string "params_amount_refunded"
82
+ t.string "params_customer"
83
+ t.string "params_invoice"
84
+ t.string "params_description"
85
+ t.string "params_dispute"
86
+ t.string "params_metadata"
87
+ t.string "params_error_type"
88
+ t.string "params_error_message"
89
+ t.string "avs_result_code"
90
+ t.string "avs_result_message"
91
+ t.string "avs_result_street_match"
92
+ t.string "avs_result_postal_match"
93
+ t.string "cvv_result_code"
94
+ t.string "cvv_result_message"
95
+ t.boolean "success"
96
+ t.datetime "created_at", :null => false
97
+ t.datetime "updated_at", :null => false
98
+ end
99
+ end
@@ -0,0 +1,42 @@
1
+ version = File.read(File.expand_path('../VERSION', __FILE__)).strip
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'killbill-stripe'
5
+ s.version = version
6
+ s.summary = 'Plugin to use Stripe as a gateway.'
7
+ s.description = 'Kill Bill payment plugin for Stripe.'
8
+
9
+ s.required_ruby_version = '>= 1.9.3'
10
+
11
+ s.license = 'Apache License (2.0)'
12
+
13
+ s.author = 'Kill Bill core team'
14
+ s.email = 'killbilling-users@googlegroups.com'
15
+ s.homepage = 'http://kill-bill.org'
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.bindir = 'bin'
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+
23
+ s.rdoc_options << '--exclude' << '.'
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'
29
+ s.add_dependency 'sinatra', '~> 1.3.4'
30
+ if defined?(JRUBY_VERSION)
31
+ s.add_dependency 'activerecord-jdbcmysql-adapter', '~> 1.2.9'
32
+ end
33
+
34
+ s.add_development_dependency 'jbundler', '~> 0.4.1'
35
+ s.add_development_dependency 'rake', '>= 10.0.0'
36
+ s.add_development_dependency 'rspec', '~> 2.12.0'
37
+ if defined?(JRUBY_VERSION)
38
+ s.add_development_dependency 'activerecord-jdbcsqlite3-adapter', '~> 1.2.6'
39
+ else
40
+ s.add_development_dependency 'sqlite3', '~> 1.3.7'
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ mainClass=Killbill::Stripe::PaymentPlugin
2
+ require=stripe
3
+ pluginType=PAYMENT
data/lib/stripe/api.rb ADDED
@@ -0,0 +1,248 @@
1
+ module Killbill::Stripe
2
+ class PaymentPlugin < Killbill::Plugin::Payment
3
+ def start_plugin
4
+ Killbill::Stripe.initialize! @logger, @conf_dir, @kb_apis
5
+
6
+ super
7
+
8
+ @logger.info 'Killbill::Stripe::PaymentPlugin started'
9
+ end
10
+
11
+ # return DB connections to the Pool if required
12
+ def after_request
13
+ ActiveRecord::Base.connection.close
14
+ end
15
+
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
19
+
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?
23
+
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}"
27
+
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
31
+
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
35
+
36
+ response.to_payment_response
37
+ end
38
+
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
44
+
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
48
+
49
+ stripe_transaction = StripeTransaction.find_candidate_transaction_for_refund(kb_payment_id, amount_in_cents)
50
+
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
54
+
55
+ response.to_refund_response
56
+ end
57
+
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)
61
+
62
+ stripe_transactions.map { |t| t.stripe_response.to_refund_response }
63
+ end
64
+
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
115
+
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
134
+ end
135
+ end
136
+
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)
139
+
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
143
+
144
+ if response.success
145
+ StripePaymentMethod.mark_as_deleted! kb_payment_method_id
146
+ else
147
+ raise response.message
148
+ end
149
+ end
150
+
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
154
+
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)
157
+
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
161
+
162
+ if response.success
163
+ # TODO Update our records
164
+ else
165
+ raise response.message
166
+ end
167
+ end
168
+
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
172
+
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
197
+
198
+ should_be_deleted
199
+ end
200
+
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
208
+
209
+ def search_payments(search_key, offset = 0, limit = 100, call_context = nil, options = {})
210
+ StripeResponse.search(search_key, offset, limit, :payment)
211
+ end
212
+
213
+ def search_refunds(search_key, offset = 0, limit = 100, call_context = nil, options = {})
214
+ StripeResponse.search(search_key, offset, limit, :refund)
215
+ end
216
+
217
+ def search_payment_methods(search_key, offset = 0, limit = 100, call_context = nil, options = {})
218
+ StripePaymentMethod.search(search_key, offset, limit)
219
+ end
220
+
221
+ private
222
+
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
228
+
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?
231
+
232
+ # Save the response to our logs
233
+ response = StripeResponse.from_response(api_call, kb_payment_id, stripe_response)
234
+ response.save!
235
+
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}"
244
+ end
245
+ response
246
+ end
247
+ end
248
+ end