killbill-bitpay 0.0.1

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.
@@ -0,0 +1,75 @@
1
+ CREATE TABLE `bitpay_payment_methods` (
2
+ `id` int(11) NOT NULL AUTO_INCREMENT,
3
+ `kb_payment_method_id` varchar(255) DEFAULT NULL,
4
+ `token` varchar(255) DEFAULT NULL,
5
+ `cc_first_name` varchar(255) DEFAULT NULL,
6
+ `cc_last_name` varchar(255) DEFAULT NULL,
7
+ `cc_type` varchar(255) DEFAULT NULL,
8
+ `cc_exp_month` varchar(255) DEFAULT NULL,
9
+ `cc_exp_year` varchar(255) DEFAULT NULL,
10
+ `cc_number` varchar(255) DEFAULT NULL,
11
+ `cc_last_4` varchar(255) DEFAULT NULL,
12
+ `cc_start_month` varchar(255) DEFAULT NULL,
13
+ `cc_start_year` varchar(255) DEFAULT NULL,
14
+ `cc_issue_number` varchar(255) DEFAULT NULL,
15
+ `cc_verification_value` varchar(255) DEFAULT NULL,
16
+ `cc_track_data` varchar(255) DEFAULT NULL,
17
+ `address1` varchar(255) DEFAULT NULL,
18
+ `address2` varchar(255) DEFAULT NULL,
19
+ `city` varchar(255) DEFAULT NULL,
20
+ `state` varchar(255) DEFAULT NULL,
21
+ `zip` varchar(255) DEFAULT NULL,
22
+ `country` varchar(255) DEFAULT NULL,
23
+ `is_deleted` tinyint(1) NOT NULL DEFAULT '0',
24
+ `created_at` datetime NOT NULL,
25
+ `updated_at` datetime NOT NULL,
26
+ `kb_account_id` varchar(255) DEFAULT NULL,
27
+ `kb_tenant_id` varchar(255) DEFAULT NULL,
28
+ PRIMARY KEY (`id`),
29
+ KEY `index_bitpay_payment_methods_on_kb_account_id` (`kb_account_id`),
30
+ KEY `index_bitpay_payment_methods_on_kb_payment_method_id` (`kb_payment_method_id`)
31
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
32
+
33
+ CREATE TABLE `bitpay_transactions` (
34
+ `id` int(11) NOT NULL AUTO_INCREMENT,
35
+ `bitpay_response_id` int(11) NOT NULL,
36
+ `api_call` varchar(255) NOT NULL,
37
+ `kb_payment_id` varchar(255) NOT NULL,
38
+ `kb_payment_transaction_id` varchar(255) NOT NULL,
39
+ `transaction_type` varchar(255) NOT NULL,
40
+ `payment_processor_account_id` varchar(255) DEFAULT NULL,
41
+ `txn_id` varchar(255) DEFAULT NULL,
42
+ `amount_in_cents` int(11) DEFAULT NULL,
43
+ `currency` varchar(255) DEFAULT NULL,
44
+ `created_at` datetime NOT NULL,
45
+ `updated_at` datetime NOT NULL,
46
+ `kb_account_id` varchar(255) NOT NULL,
47
+ `kb_tenant_id` varchar(255) NOT NULL,
48
+ PRIMARY KEY (`id`),
49
+ KEY `index_bitpay_transactions_on_kb_payment_id` (`kb_payment_id`)
50
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
51
+
52
+ CREATE TABLE `bitpay_responses` (
53
+ `id` int(11) NOT NULL AUTO_INCREMENT,
54
+ `api_call` varchar(255) NOT NULL,
55
+ `kb_payment_id` varchar(255) DEFAULT NULL,
56
+ `kb_payment_transaction_id` varchar(255) DEFAULT NULL,
57
+ `transaction_type` varchar(255) DEFAULT NULL,
58
+ `payment_processor_account_id` varchar(255) DEFAULT NULL,
59
+ `message` varchar(255) DEFAULT NULL,
60
+ `authorization` varchar(255) DEFAULT NULL,
61
+ `fraud_review` tinyint(1) DEFAULT NULL,
62
+ `test` tinyint(1) DEFAULT NULL,
63
+ `avs_result_code` varchar(255) DEFAULT NULL,
64
+ `avs_result_message` varchar(255) DEFAULT NULL,
65
+ `avs_result_street_match` varchar(255) DEFAULT NULL,
66
+ `avs_result_postal_match` varchar(255) DEFAULT NULL,
67
+ `cvv_result_code` varchar(255) DEFAULT NULL,
68
+ `cvv_result_message` varchar(255) DEFAULT NULL,
69
+ `success` tinyint(1) DEFAULT NULL,
70
+ `created_at` datetime NOT NULL,
71
+ `updated_at` datetime NOT NULL,
72
+ `kb_account_id` varchar(255) DEFAULT NULL,
73
+ `kb_tenant_id` varchar(255) DEFAULT NULL,
74
+ PRIMARY KEY (`id`)
75
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
@@ -0,0 +1,76 @@
1
+ require 'active_record'
2
+
3
+ ActiveRecord::Schema.define(:version => 20140410153635) do
4
+ create_table "bitpay_payment_methods", :force => true do |t|
5
+ t.string "kb_payment_method_id" # NULL before Kill Bill knows about it
6
+ t.string "token" # bitpay id
7
+ t.string "cc_first_name"
8
+ t.string "cc_last_name"
9
+ t.string "cc_type"
10
+ t.string "cc_exp_month"
11
+ t.string "cc_exp_year"
12
+ t.string "cc_number"
13
+ t.string "cc_last_4"
14
+ t.string "cc_start_month"
15
+ t.string "cc_start_year"
16
+ t.string "cc_issue_number"
17
+ t.string "cc_verification_value"
18
+ t.string "cc_track_data"
19
+ t.string "address1"
20
+ t.string "address2"
21
+ t.string "city"
22
+ t.string "state"
23
+ t.string "zip"
24
+ t.string "country"
25
+ t.boolean "is_deleted", :null => false, :default => false
26
+ t.datetime "created_at", :null => false
27
+ t.datetime "updated_at", :null => false
28
+ t.string "kb_account_id"
29
+ t.string "kb_tenant_id"
30
+ end
31
+
32
+ add_index(:bitpay_payment_methods, :kb_account_id)
33
+ add_index(:bitpay_payment_methods, :kb_payment_method_id)
34
+
35
+ create_table "bitpay_transactions", :force => true do |t|
36
+ t.integer "bitpay_response_id", :null => false
37
+ t.string "api_call", :null => false
38
+ t.string "kb_payment_id", :null => false
39
+ t.string "kb_payment_transaction_id", :null => false
40
+ t.string "transaction_type", :null => false
41
+ t.string "payment_processor_account_id"
42
+ t.string "txn_id" # bitpay transaction id
43
+ # Both null for void
44
+ t.integer "amount_in_cents"
45
+ t.string "currency"
46
+ t.datetime "created_at", :null => false
47
+ t.datetime "updated_at", :null => false
48
+ t.string "kb_account_id", :null => false
49
+ t.string "kb_tenant_id", :null => false
50
+ end
51
+
52
+ add_index(:bitpay_transactions, :kb_payment_id)
53
+
54
+ create_table "bitpay_responses", :force => true do |t|
55
+ t.string "api_call", :null => false
56
+ t.string "kb_payment_id"
57
+ t.string "kb_payment_transaction_id"
58
+ t.string "transaction_type"
59
+ t.string "payment_processor_account_id"
60
+ t.string "message"
61
+ t.string "authorization"
62
+ t.boolean "fraud_review"
63
+ t.boolean "test"
64
+ t.string "avs_result_code"
65
+ t.string "avs_result_message"
66
+ t.string "avs_result_street_match"
67
+ t.string "avs_result_postal_match"
68
+ t.string "cvv_result_code"
69
+ t.string "cvv_result_message"
70
+ t.boolean "success"
71
+ t.datetime "created_at", :null => false
72
+ t.datetime "updated_at", :null => false
73
+ t.string "kb_account_id"
74
+ t.string "kb_tenant_id"
75
+ end
76
+ end
@@ -0,0 +1,49 @@
1
+ version = File.read(File.expand_path('../VERSION', __FILE__)).strip
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'killbill-bitpay'
5
+ s.version = version
6
+ s.summary = 'Plugin to use Bitpay as a gateway.'
7
+ s.description = 'Kill Bill payment plugin for Bitpay.'
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.2.0'
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'
34
+ s.add_dependency 'sinatra', '~> 1.3.4'
35
+ if defined?(JRUBY_VERSION)
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'
39
+ end
40
+
41
+ s.add_development_dependency 'jbundler', '~> 0.4.1'
42
+ s.add_development_dependency 'rake', '>= 10.0.0'
43
+ s.add_development_dependency 'rspec', '~> 2.12.0'
44
+ if defined?(JRUBY_VERSION)
45
+ s.add_development_dependency 'activerecord-jdbcsqlite3-adapter', '~> 1.3.7'
46
+ else
47
+ s.add_development_dependency 'sqlite3', '~> 1.3.7'
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ mainClass=Killbill::Bitpay::PaymentPlugin
2
+ require=bitpay
3
+ pluginType=PAYMENT
@@ -0,0 +1,25 @@
1
+ require 'openssl'
2
+ require 'action_controller'
3
+ require 'active_record'
4
+ require 'action_view'
5
+ require 'active_merchant'
6
+ require 'active_support'
7
+ require 'bigdecimal'
8
+ require 'money'
9
+ require 'monetize'
10
+ require 'offsite_payments'
11
+ require 'pathname'
12
+ require 'sinatra'
13
+ require 'singleton'
14
+ require 'yaml'
15
+
16
+ require 'killbill'
17
+ require 'killbill/helpers/active_merchant'
18
+
19
+ require 'bitpay/api'
20
+ require 'bitpay/private_api'
21
+
22
+ require 'bitpay/models/payment_method'
23
+ require 'bitpay/models/response'
24
+ require 'bitpay/models/transaction'
25
+
@@ -0,0 +1,228 @@
1
+ module Killbill #:nodoc:
2
+ module Bitpay #:nodoc:
3
+ class PaymentPlugin < ::Killbill::Plugin::ActiveMerchant::PaymentPlugin
4
+
5
+ def initialize
6
+ gateway_builder = Proc.new do |config|
7
+ nil
8
+ end
9
+
10
+ super(gateway_builder,
11
+ :bitpay,
12
+ ::Killbill::Bitpay::BitpayPaymentMethod,
13
+ ::Killbill::Bitpay::BitpayTransaction,
14
+ ::Killbill::Bitpay::BitpayResponse)
15
+ end
16
+
17
+ def authorize_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
18
+ # Pass extra parameters for the gateway here
19
+ options = {}
20
+
21
+ properties = merge_properties(properties, options)
22
+ super(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
23
+ end
24
+
25
+ def capture_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
26
+ # Pass extra parameters for the gateway here
27
+ options = {}
28
+
29
+ properties = merge_properties(properties, options)
30
+ super(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
31
+ end
32
+
33
+ def purchase_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
34
+ kb_tenant_id = context.tenant_id
35
+ kb_payment_transaction = get_kb_transaction(kb_payment_id, kb_payment_transaction_id, kb_tenant_id)
36
+ payment_transaction_external_key = kb_payment_transaction.external_key
37
+
38
+ response = @response_model.where("transaction_type = 'PURCHASE' AND kb_tenant_id = '#{kb_tenant_id}' AND authorization = '#{payment_transaction_external_key}'")
39
+ .order(:created_at)[0]
40
+
41
+ transaction = response.create_bitpay_transaction(:kb_account_id => kb_account_id,
42
+ :kb_tenant_id => kb_tenant_id,
43
+ :amount_in_cents => amount.nil? ? nil : to_cents(amount, currency),
44
+ :currency => currency,
45
+ :api_call => :purchase,
46
+ :kb_payment_id => kb_payment_id,
47
+ :kb_payment_transaction_id => kb_payment_transaction_id,
48
+ :transaction_type => response.transaction_type,
49
+ :payment_processor_account_id => response.payment_processor_account_id,
50
+ :txn_id => response.txn_id,
51
+ :bitpay_response_id => response.id)
52
+
53
+ response.to_transaction_info_plugin(transaction)
54
+ end
55
+
56
+ def void_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, properties, context)
57
+ # Pass extra parameters for the gateway here
58
+ options = {}
59
+
60
+ properties = merge_properties(properties, options)
61
+ super(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, properties, context)
62
+ end
63
+
64
+ def credit_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
65
+ # Pass extra parameters for the gateway here
66
+ options = {}
67
+
68
+ properties = merge_properties(properties, options)
69
+ super(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
70
+ end
71
+
72
+ def refund_payment(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
73
+ # Pass extra parameters for the gateway here
74
+ options = {}
75
+
76
+ properties = merge_properties(properties, options)
77
+ super(kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context)
78
+ end
79
+
80
+ def get_payment_info(kb_account_id, kb_payment_id, properties, context)
81
+ # Pass extra parameters for the gateway here
82
+ options = {}
83
+
84
+ properties = merge_properties(properties, options)
85
+ super(kb_account_id, kb_payment_id, properties, context)
86
+ end
87
+
88
+ def search_payments(search_key, offset, limit, properties, context)
89
+ # Pass extra parameters for the gateway here
90
+ options = {}
91
+
92
+ properties = merge_properties(properties, options)
93
+ super(search_key, offset, limit, properties, context)
94
+ end
95
+
96
+ def add_payment_method(kb_account_id, kb_payment_method_id, payment_method_props, set_default, properties, context)
97
+ # Pass extra parameters for the gateway here
98
+ options = {}
99
+
100
+ properties = merge_properties(properties, options)
101
+ super(kb_account_id, kb_payment_method_id, payment_method_props, set_default, properties, context)
102
+ end
103
+
104
+ def delete_payment_method(kb_account_id, kb_payment_method_id, properties, context)
105
+ # Pass extra parameters for the gateway here
106
+ options = {}
107
+
108
+ properties = merge_properties(properties, options)
109
+ super(kb_account_id, kb_payment_method_id, properties, context)
110
+ end
111
+
112
+ def get_payment_method_detail(kb_account_id, kb_payment_method_id, properties, context)
113
+ # Pass extra parameters for the gateway here
114
+ options = {}
115
+
116
+ properties = merge_properties(properties, options)
117
+ super(kb_account_id, kb_payment_method_id, properties, context)
118
+ end
119
+
120
+ def set_default_payment_method(kb_account_id, kb_payment_method_id, properties, context)
121
+ # TODO
122
+ end
123
+
124
+ def get_payment_methods(kb_account_id, refresh_from_gateway, properties, context)
125
+ # Pass extra parameters for the gateway here
126
+ options = {}
127
+
128
+ properties = merge_properties(properties, options)
129
+ super(kb_account_id, refresh_from_gateway, properties, context)
130
+ end
131
+
132
+ def search_payment_methods(search_key, offset, limit, properties, context)
133
+ # Pass extra parameters for the gateway here
134
+ options = {}
135
+
136
+ properties = merge_properties(properties, options)
137
+ super(search_key, offset, limit, properties, context)
138
+ end
139
+
140
+ def reset_payment_methods(kb_account_id, payment_methods, properties, context)
141
+ super
142
+ end
143
+
144
+ def build_form_descriptor(kb_account_id, descriptor_fields, properties, context)
145
+ # Pass extra parameters for the gateway here
146
+ options = {}
147
+ properties = merge_properties(properties, options)
148
+
149
+ # Add the BitPay API key to generate the invoice id
150
+ options = {
151
+ :account_id => config[:bitpay][:api_key],
152
+ # Overload the order_id (passed as posData) (TODO fix OffsitePayments implementation)
153
+ :order_id => "#{kb_account_id};#{context.tenant_id}"
154
+ }
155
+ descriptor_fields = merge_properties(descriptor_fields, options)
156
+
157
+ super(kb_account_id, descriptor_fields, properties, context)
158
+ end
159
+
160
+ def process_notification(notification, properties, context)
161
+ # Add the BitPay API key to retrieve the invoice
162
+ options = {
163
+ :credential1 => config[:bitpay][:api_key]
164
+ }
165
+ properties = merge_properties(properties, options)
166
+
167
+ super(notification, properties, context) do |gw_notification, service|
168
+ is_success = nil
169
+ if service.status == 'Completed'
170
+ is_success = true
171
+ elsif service.status == 'Failed'
172
+ is_success = false
173
+ end
174
+
175
+ if is_success.nil?
176
+ # Either the invoice was never paid (expired) or hasn't been confirmed yet
177
+ logger.info "Ignoring BitPay IPN #{service.raw}"
178
+ else
179
+ # See above (parsed from posData)
180
+ kb_account_id, kb_tenant_id = service.item_id.nil? ? nil : service.item_id.split(';')
181
+ amount = service.params['price']
182
+ currency = service.currency
183
+ payment_external_key = service.transaction_id
184
+ payment_transaction_external_key = service.transaction_id
185
+
186
+ payment = record_payment(kb_account_id, kb_tenant_id, amount, currency, is_success, payment_external_key, payment_transaction_external_key)
187
+ gw_notification.kb_payment_id = payment.id unless payment.nil?
188
+ end
189
+ end
190
+ end
191
+
192
+ def record_payment(kb_account_id, kb_tenant_id, amount, currency, is_success, payment_external_key, payment_transaction_external_key, kb_payment_method_id=nil)
193
+ if kb_account_id.nil? || kb_tenant_id.nil? || amount.nil? || currency.nil? || payment_transaction_external_key.nil?
194
+ @logger.warn "Invalid notification: kb_account_id=#{kb_account_id}, kb_tenant_id=#{kb_tenant_id}, amount=#{amount}, currency=#{currency}, payment_external_key=#{payment_external_key}, payment_transaction_external_key=#{payment_transaction_external_key}, kb_payment_method_id=#{kb_payment_method_id}"
195
+ return nil
196
+ else
197
+ @logger.info "Recording payment: kb_account_id=#{kb_account_id}, amount=#{amount}, currency=#{currency}, payment_external_key=#{payment_external_key}, payment_transaction_external_key=#{payment_transaction_external_key}, kb_payment_method_id=#{kb_payment_method_id}"
198
+ end
199
+
200
+ @response_model.create(:api_call => :purchase,
201
+ :kb_account_id => kb_account_id,
202
+ :transaction_type => :PURCHASE,
203
+ :authorization => payment_transaction_external_key,
204
+ :kb_tenant_id => kb_tenant_id,
205
+ :success => is_success)
206
+
207
+ context = @kb_apis.create_context(kb_tenant_id)
208
+ kb_account = @kb_apis.account_user_api.get_account_by_id(kb_account_id, context)
209
+ kb_payment_method_id = kb_payment_method_id.nil? ? kb_account.payment_method_id : kb_payment_method_id
210
+ kb_payment_id = nil
211
+ properties = {}
212
+ @kb_apis.payment_api.create_purchase(kb_account,
213
+ kb_payment_method_id,
214
+ kb_payment_id,
215
+ amount,
216
+ currency,
217
+ payment_external_key,
218
+ payment_transaction_external_key,
219
+ properties,
220
+ context)
221
+ end
222
+
223
+ def get_active_merchant_module
224
+ ::OffsitePayments.integration(:bit_pay)
225
+ end
226
+ end
227
+ end
228
+ end