killbill-stripe 0.1.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 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