killbill 3.2.4 → 4.0.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 +4 -4
- data/.gitignore +0 -2
- data/.travis.yml +26 -5
- data/Gemfile +1 -1
- data/Gemfile.head +5 -0
- data/Gemfile.lock +125 -0
- data/Jarfile +9 -9
- data/Jarfile.lock +54 -0
- data/NEWS +3 -0
- data/README.md +13 -0
- data/VERSION +1 -1
- data/generators/active_merchant/templates/.gitignore.rb +2 -3
- data/generators/active_merchant/templates/.travis.yml.rb +22 -3
- data/generators/active_merchant/templates/Gemfile.head.rb +5 -0
- data/generators/active_merchant/templates/Gemfile.rb +1 -1
- data/generators/active_merchant/templates/Jarfile.rb +9 -8
- data/generators/active_merchant/templates/LICENSE.rb +2 -2
- data/generators/active_merchant/templates/config.yml.rb +16 -6
- data/generators/active_merchant/templates/lib/plugin.rb +0 -1
- data/generators/active_merchant/templates/plugin.gemspec.rb +17 -15
- data/generators/active_merchant/templates/pom.xml.rb +1 -1
- data/generators/active_merchant/templates/release.sh.rb +34 -14
- data/generators/active_merchant/templates/spec/base_plugin_spec.rb +5 -7
- data/generators/active_merchant/templates/spec/integration_spec.rb +7 -18
- data/killbill.gemspec +21 -15
- data/lib/killbill/ext/active_merchant/typhoeus_connection.rb +3 -4
- data/lib/killbill/gen/api/account.rb +1 -1
- data/lib/killbill/gen/api/account_data.rb +1 -1
- data/lib/killbill/gen/api/audit_log.rb +2 -2
- data/lib/killbill/gen/api/audit_user_api.rb +3 -3
- data/lib/killbill/gen/api/block.rb +1 -1
- data/lib/killbill/gen/api/blocking_state.rb +1 -1
- data/lib/killbill/gen/api/call_context.rb +2 -2
- data/lib/killbill/gen/api/control_tag.rb +2 -2
- data/lib/killbill/gen/api/currency_conversion.rb +1 -1
- data/lib/killbill/gen/api/currency_conversion_api.rb +2 -2
- data/lib/killbill/gen/api/custom_field.rb +1 -1
- data/lib/killbill/gen/api/custom_field_user_api.rb +2 -2
- data/lib/killbill/gen/api/dry_run_arguments.rb +22 -3
- data/lib/killbill/gen/api/duration.rb +1 -1
- data/lib/killbill/gen/api/entitlement.rb +3 -3
- data/lib/killbill/gen/api/entitlement_ao_status_dry_run.rb +3 -3
- data/lib/killbill/gen/api/entitlement_api.rb +25 -7
- data/lib/killbill/gen/api/fixed.rb +1 -1
- data/lib/killbill/gen/api/invoice.rb +1 -1
- data/lib/killbill/gen/api/invoice_formatter.rb +2 -2
- data/lib/killbill/gen/api/invoice_item.rb +2 -2
- data/lib/killbill/gen/api/invoice_item_formatter.rb +2 -2
- data/lib/killbill/gen/api/invoice_payment.rb +3 -3
- data/lib/killbill/gen/api/invoice_user_api.rb +2 -2
- data/lib/killbill/gen/api/migration_plan.rb +1 -1
- data/lib/killbill/gen/api/mutable_account_data.rb +1 -1
- data/lib/killbill/gen/api/payment.rb +1 -1
- data/lib/killbill/gen/api/payment_api.rb +11 -11
- data/lib/killbill/gen/api/payment_transaction.rb +4 -4
- data/lib/killbill/gen/api/plan.rb +1 -1
- data/lib/killbill/gen/api/plan_change_result.rb +2 -2
- data/lib/killbill/gen/api/plan_phase.rb +1 -1
- data/lib/killbill/gen/api/plan_phase_price_override.rb +93 -0
- data/lib/killbill/gen/api/plan_phase_price_overrides_with_call_context.rb +77 -0
- data/lib/killbill/gen/api/plan_phase_specifier.rb +3 -3
- data/lib/killbill/gen/api/plan_specifier.rb +2 -2
- data/lib/killbill/gen/api/price.rb +1 -1
- data/lib/killbill/gen/api/product.rb +1 -1
- data/lib/killbill/gen/api/rate.rb +2 -2
- data/lib/killbill/gen/api/record_id_api.rb +1 -1
- data/lib/killbill/gen/api/recurring.rb +1 -1
- data/lib/killbill/gen/api/refund.rb +2 -2
- data/lib/killbill/gen/api/require_gen.rb +2 -0
- data/lib/killbill/gen/api/static_catalog.rb +2 -2
- data/lib/killbill/gen/api/subscription.rb +3 -3
- data/lib/killbill/gen/api/subscription_event.rb +3 -3
- data/lib/killbill/gen/api/tag.rb +1 -1
- data/lib/killbill/gen/api/tag_definition.rb +1 -1
- data/lib/killbill/gen/api/tag_user_api.rb +6 -6
- data/lib/killbill/gen/api/tiered_block.rb +1 -1
- data/lib/killbill/gen/api/usage.rb +3 -3
- data/lib/killbill/gen/plugin-api/currency_plugin_api.rb +1 -1
- data/lib/killbill/gen/plugin-api/ext_bus_event.rb +2 -2
- data/lib/killbill/gen/plugin-api/payment_transaction_info_plugin.rb +3 -3
- data/lib/killbill/helpers/active_merchant.rb +2 -2
- data/lib/killbill/helpers/active_merchant/active_record.rb +1 -1
- data/lib/killbill/helpers/active_merchant/active_record/active_record_helper.rb +14 -0
- data/lib/killbill/helpers/active_merchant/active_record/models/helpers.rb +8 -0
- data/lib/killbill/helpers/active_merchant/active_record/models/payment_method.rb +10 -8
- data/lib/killbill/helpers/active_merchant/active_record/models/response.rb +16 -3
- data/lib/killbill/helpers/active_merchant/active_record/models/streamy_result_set.rb +1 -3
- data/lib/killbill/helpers/active_merchant/active_record/models/transaction.rb +2 -0
- data/lib/killbill/helpers/active_merchant/configuration.rb +119 -27
- data/lib/killbill/helpers/active_merchant/gateway.rb +40 -27
- data/lib/killbill/helpers/active_merchant/killbill_spec_helper.rb +63 -45
- data/lib/killbill/helpers/active_merchant/payment_plugin.rb +121 -95
- data/lib/killbill/helpers/active_merchant/private_payment_plugin.rb +1 -1
- data/lib/killbill/helpers/active_merchant/properties.rb +9 -2
- data/lib/killbill/helpers/active_merchant/sinatra.rb +4 -8
- data/lib/killbill/helpers/active_merchant/utils.rb +44 -0
- data/lib/killbill/helpers/properties_helper.rb +41 -0
- data/lib/killbill/http_servlet.rb +11 -4
- data/lib/killbill/killbill_api.rb +6 -4
- data/lib/killbill/rake_task.rb +542 -102
- data/spec/killbill/helpers/configuration_spec.rb +117 -33
- data/spec/killbill/helpers/payment_method_spec.rb +20 -17
- data/spec/killbill/helpers/payment_plugin_spec.rb +401 -201
- data/spec/killbill/helpers/private_payment_plugin_spec.rb +3 -16
- data/spec/killbill/helpers/response_spec.rb +92 -22
- data/spec/killbill/helpers/streamy_result_set_spec.rb +3 -2
- data/spec/killbill/helpers/test_payment_method.rb +9 -0
- data/spec/killbill/helpers/test_response.rb +11 -0
- data/spec/killbill/helpers/test_schema.rb +6 -6
- data/spec/killbill/helpers/test_transaction.rb +11 -0
- data/spec/killbill/helpers/transaction_spec.rb +3 -13
- data/spec/killbill/helpers/utils_spec.rb +127 -69
- data/spec/spec_helper.rb +69 -18
- metadata +77 -71
- data/lib/killbill/ext/active_merchant/jdbc_connection.rb +0 -92
- data/lib/killbill/ext/active_merchant/proxy_support.rb +0 -58
- data/spec/killbill/helpers/gateway_spec.rb +0 -36
|
@@ -4,30 +4,7 @@ module Killbill
|
|
|
4
4
|
require 'active_merchant'
|
|
5
5
|
|
|
6
6
|
class Gateway
|
|
7
|
-
def self.wrap(gateway_builder,
|
|
8
|
-
::ActiveMerchant::Billing::Gateway.logger = logger
|
|
9
|
-
|
|
10
|
-
if config[:test]
|
|
11
|
-
::ActiveMerchant::Billing::Base.mode = :test
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
if config[:log_file]
|
|
15
|
-
::ActiveMerchant::Billing::Gateway.wiredump_device = File.open(config[:log_file], 'w')
|
|
16
|
-
else
|
|
17
|
-
log_method = config[:quiet] ? :debug : :info
|
|
18
|
-
::ActiveMerchant::Billing::Gateway.wiredump_device = ::Killbill::Plugin::ActiveMerchant::Utils::KBWiredumpDevice.new(logger, log_method)
|
|
19
|
-
end
|
|
20
|
-
::ActiveMerchant::Billing::Gateway.wiredump_device.sync = true
|
|
21
|
-
|
|
22
|
-
::ActiveMerchant::Billing::Gateway.open_timeout = config[:open_timeout] unless config[:open_timeout].nil?
|
|
23
|
-
::ActiveMerchant::Billing::Gateway.read_timeout = config[:read_timeout] unless config[:read_timeout].nil?
|
|
24
|
-
::ActiveMerchant::Billing::Gateway.retry_safe = config[:retry_safe] unless config[:retry_safe].nil?
|
|
25
|
-
::ActiveMerchant::Billing::Gateway.ssl_strict = config[:ssl_strict] unless config[:ssl_strict].nil?
|
|
26
|
-
::ActiveMerchant::Billing::Gateway.ssl_version = config[:ssl_version] unless config[:ssl_version].nil?
|
|
27
|
-
::ActiveMerchant::Billing::Gateway.max_retries = config[:max_retries] unless config[:max_retries].nil?
|
|
28
|
-
::ActiveMerchant::Billing::Gateway.proxy_address = config[:proxy_address] unless config[:proxy_address].nil?
|
|
29
|
-
::ActiveMerchant::Billing::Gateway.proxy_port = config[:proxy_port] unless config[:proxy_port].nil?
|
|
30
|
-
|
|
7
|
+
def self.wrap(gateway_builder, config)
|
|
31
8
|
Gateway.new(config, gateway_builder.call(config))
|
|
32
9
|
end
|
|
33
10
|
|
|
@@ -36,17 +13,53 @@ module Killbill
|
|
|
36
13
|
def initialize(config, am_gateway)
|
|
37
14
|
@config = config
|
|
38
15
|
@gateway = am_gateway
|
|
16
|
+
|
|
17
|
+
# Override urls if needed (there is no easy way to do it earlier, because AM uses class_attribute)
|
|
18
|
+
@gateway.class.test_url = @config[:test_url] unless @config[:test_url].nil?
|
|
19
|
+
@gateway.class.live_url = @config[:live_url] unless @config[:live_url].nil?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
# Materialize the most common operations - this is for performance reasons
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
def store(*args, &block)
|
|
27
|
+
method_missing(:store, *args, &block)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def unstore(*args, &block)
|
|
31
|
+
method_missing(:unstore, *args, &block)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def authorize(*args, &block)
|
|
35
|
+
method_missing(:authorize, *args, &block)
|
|
39
36
|
end
|
|
40
37
|
|
|
41
38
|
# Unfortunate name...
|
|
42
|
-
def capture(
|
|
43
|
-
method_missing(:capture,
|
|
39
|
+
def capture(*args, &block)
|
|
40
|
+
method_missing(:capture, *args, &block)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def purchase(*args, &block)
|
|
44
|
+
method_missing(:purchase, *args, &block)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def void(*args, &block)
|
|
48
|
+
method_missing(:void, *args, &block)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def credit(*args, &block)
|
|
52
|
+
method_missing(:credit, *args, &block)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def refund(*args, &block)
|
|
56
|
+
method_missing(:refund, *args, &block)
|
|
44
57
|
end
|
|
45
58
|
|
|
46
59
|
def method_missing(m, *args, &block)
|
|
47
60
|
# The options hash should be the last argument, iterate through all to be safe
|
|
48
61
|
args.reverse.each do |arg|
|
|
49
|
-
if arg.respond_to?(:has_key?) &&
|
|
62
|
+
if arg.respond_to?(:has_key?) && Utils.normalized(arg, :skip_gw)
|
|
50
63
|
return ::ActiveMerchant::Billing::Response.new(true, 'Skipped Gateway call')
|
|
51
64
|
end
|
|
52
65
|
end
|
|
@@ -2,29 +2,30 @@ module Killbill
|
|
|
2
2
|
module Plugin
|
|
3
3
|
module ActiveMerchant
|
|
4
4
|
module RSpec
|
|
5
|
+
include ::Killbill::Plugin::PropertiesHelper
|
|
5
6
|
|
|
6
|
-
def create_payment_method(payment_method_model=::Killbill::Plugin::ActiveMerchant::ActiveRecord::PaymentMethod, kb_account_id=nil, kb_tenant_id=nil, properties = [], options = {})
|
|
7
|
+
def create_payment_method(payment_method_model=::Killbill::Plugin::ActiveMerchant::ActiveRecord::PaymentMethod, kb_account_id=nil, kb_tenant_id=nil, properties = [], options = {}, set_default = true, plugin = @plugin)
|
|
7
8
|
kb_payment_method_id = SecureRandom.uuid
|
|
8
9
|
|
|
9
10
|
if kb_account_id.nil?
|
|
10
11
|
kb_account_id = SecureRandom.uuid
|
|
11
12
|
|
|
12
13
|
# Create a new account
|
|
13
|
-
create_kb_account
|
|
14
|
+
create_kb_account(kb_account_id, plugin.kb_apis.proxied_services[:account_user_api])
|
|
14
15
|
end
|
|
15
16
|
|
|
16
|
-
context =
|
|
17
|
-
account =
|
|
17
|
+
context = plugin.kb_apis.create_context(kb_tenant_id)
|
|
18
|
+
account = plugin.kb_apis.account_user_api.get_account_by_id(kb_account_id, context)
|
|
18
19
|
|
|
19
20
|
# The rest is pure Ruby
|
|
20
21
|
context = context.to_ruby(context)
|
|
21
22
|
|
|
22
23
|
# Generate a token
|
|
23
|
-
pm_properties = build_pm_properties(account, options)
|
|
24
|
+
pm_properties = build_pm_properties(account, options, set_default)
|
|
24
25
|
|
|
25
26
|
info = Killbill::Plugin::Model::PaymentMethodPlugin.new
|
|
26
27
|
info.properties = pm_properties
|
|
27
|
-
payment_method =
|
|
28
|
+
payment_method = plugin.add_payment_method(kb_account_id, kb_payment_method_id, info, true, properties, context)
|
|
28
29
|
|
|
29
30
|
pm = payment_method_model.from_kb_payment_method_id(kb_payment_method_id, context.tenant_id)
|
|
30
31
|
pm.should == payment_method
|
|
@@ -34,47 +35,47 @@ module Killbill
|
|
|
34
35
|
pm
|
|
35
36
|
end
|
|
36
37
|
|
|
37
|
-
def build_pm_properties(account = nil, overrides = {})
|
|
38
|
-
cc_number = (overrides.delete(:cc_number) || '4242424242424242')
|
|
39
|
-
cc_first_name = (overrides.delete(:cc_first_name) || 'John')
|
|
40
|
-
cc_last_name = (overrides.delete(:cc_last_name) || 'Doe')
|
|
41
|
-
cc_type = (overrides.delete(:cc_type) || 'Visa')
|
|
42
|
-
cc_exp_month = (overrides.delete(:cc_exp_month) || 12)
|
|
43
|
-
cc_exp_year = (overrides.delete(:cc_exp_year) || 2017)
|
|
44
|
-
cc_last_4 = (overrides.delete(:cc_last_4) || 4242)
|
|
45
|
-
address1 = (overrides.delete(:address1) || '5, oakriu road')
|
|
46
|
-
address2 = (overrides.delete(:address2) || 'apt. 298')
|
|
47
|
-
city = (overrides.delete(:city) || 'Gdio Foia')
|
|
48
|
-
state = (overrides.delete(:state) || 'FL')
|
|
49
|
-
zip = (overrides.delete(:zip) || 49302)
|
|
50
|
-
country = (overrides.delete(:country) || 'US')
|
|
51
|
-
cc_verification_value = (overrides.delete(:cc_verification_value) || 1234)
|
|
38
|
+
def build_pm_properties(account = nil, overrides = {}, set_defaults = true)
|
|
39
|
+
cc_number = (overrides.delete(:cc_number) || (set_defaults ? '4242424242424242' : nil))
|
|
40
|
+
cc_first_name = (overrides.delete(:cc_first_name) || (set_defaults ? 'John' : nil))
|
|
41
|
+
cc_last_name = (overrides.delete(:cc_last_name) || (set_defaults ? 'Doe' : nil))
|
|
42
|
+
cc_type = (overrides.delete(:cc_type) || (set_defaults ? 'Visa' : nil))
|
|
43
|
+
cc_exp_month = (overrides.delete(:cc_exp_month) || (set_defaults ? 12 : nil))
|
|
44
|
+
cc_exp_year = (overrides.delete(:cc_exp_year) || (set_defaults ? 2017 : nil))
|
|
45
|
+
cc_last_4 = (overrides.delete(:cc_last_4) || (set_defaults ? 4242 : nil))
|
|
46
|
+
address1 = (overrides.delete(:address1) || (set_defaults ? '5, oakriu road' : nil))
|
|
47
|
+
address2 = (overrides.delete(:address2) || (set_defaults ? 'apt. 298' : nil))
|
|
48
|
+
city = (overrides.delete(:city) || (set_defaults ? 'Gdio Foia' : nil))
|
|
49
|
+
state = (overrides.delete(:state) || (set_defaults ? 'FL' : nil))
|
|
50
|
+
zip = (overrides.delete(:zip) || (set_defaults ? 49302 : nil))
|
|
51
|
+
country = (overrides.delete(:country) || (set_defaults ? 'US' : nil))
|
|
52
|
+
cc_verification_value = (overrides.delete(:cc_verification_value) || (set_defaults ? 1234 : nil))
|
|
52
53
|
|
|
53
54
|
properties = []
|
|
54
|
-
properties <<
|
|
55
|
-
properties <<
|
|
56
|
-
properties <<
|
|
57
|
-
properties <<
|
|
58
|
-
properties <<
|
|
59
|
-
properties <<
|
|
60
|
-
properties <<
|
|
61
|
-
properties <<
|
|
62
|
-
properties <<
|
|
63
|
-
properties <<
|
|
64
|
-
properties <<
|
|
65
|
-
properties <<
|
|
66
|
-
properties <<
|
|
67
|
-
properties <<
|
|
68
|
-
properties <<
|
|
55
|
+
properties << build_property('ccNumber', cc_number)
|
|
56
|
+
properties << build_property('ccFirstName', cc_first_name)
|
|
57
|
+
properties << build_property('ccLastName', cc_last_name)
|
|
58
|
+
properties << build_property('ccType', cc_type)
|
|
59
|
+
properties << build_property('ccExpirationMonth', cc_exp_month)
|
|
60
|
+
properties << build_property('ccExpirationYear', cc_exp_year)
|
|
61
|
+
properties << build_property('ccLast4', cc_last_4)
|
|
62
|
+
properties << build_property('email', account.nil? ? Time.now.to_i.to_s + '-test@tester.com' : account.email) # Required by e.g. CyberSource
|
|
63
|
+
properties << build_property('address1', address1)
|
|
64
|
+
properties << build_property('address2', address2)
|
|
65
|
+
properties << build_property('city', city)
|
|
66
|
+
properties << build_property('state', state)
|
|
67
|
+
properties << build_property('zip', zip)
|
|
68
|
+
properties << build_property('country', country)
|
|
69
|
+
properties << build_property('ccVerificationValue', cc_verification_value)
|
|
69
70
|
|
|
70
71
|
overrides.each do |key, value|
|
|
71
|
-
properties <<
|
|
72
|
+
properties << build_property(key, value)
|
|
72
73
|
end
|
|
73
74
|
|
|
74
75
|
properties
|
|
75
76
|
end
|
|
76
77
|
|
|
77
|
-
def create_kb_account(kb_account_id)
|
|
78
|
+
def create_kb_account(kb_account_id, account_api = @account_api)
|
|
78
79
|
external_key = Time.now.to_i.to_s + '-test'
|
|
79
80
|
email = external_key + '@tester.com'
|
|
80
81
|
|
|
@@ -85,16 +86,33 @@ module Killbill
|
|
|
85
86
|
account.name = 'Integration spec'
|
|
86
87
|
account.currency = :USD
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
account_api.accounts << account
|
|
89
90
|
|
|
90
91
|
return external_key, kb_account_id
|
|
91
92
|
end
|
|
92
93
|
|
|
93
|
-
def
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
def build_call_context(tenant_id = '00000011-0022-0033-0044-000000000055')
|
|
95
|
+
call_context = ::Killbill::Plugin::Model::CallContext.new
|
|
96
|
+
call_context.tenant_id = tenant_id
|
|
97
|
+
call_context.to_ruby(call_context)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def build_plugin(model, name, conf_dir = '.')
|
|
101
|
+
plugin = model.new
|
|
102
|
+
|
|
103
|
+
svcs = {
|
|
104
|
+
:account_user_api => ::Killbill::Plugin::ActiveMerchant::RSpec::FakeJavaUserAccountApi.new,
|
|
105
|
+
:payment_api => ::Killbill::Plugin::ActiveMerchant::RSpec::FakeJavaPaymentApi.new,
|
|
106
|
+
:tenant_user_api => ::Killbill::Plugin::ActiveMerchant::RSpec::FakeJavaTenantUserApi.new
|
|
107
|
+
}
|
|
108
|
+
plugin.kb_apis = ::Killbill::Plugin::KillbillApi.new(name, svcs)
|
|
109
|
+
|
|
110
|
+
plugin.logger = ::Logger.new(STDOUT)
|
|
111
|
+
plugin.logger.level = ::Logger::INFO
|
|
112
|
+
plugin.conf_dir = File.expand_path(conf_dir)
|
|
113
|
+
plugin.root = "/foo/killbill-#{name}/0.0.1"
|
|
114
|
+
|
|
115
|
+
plugin
|
|
98
116
|
end
|
|
99
117
|
|
|
100
118
|
class FakeJavaUserAccountApi
|
|
@@ -149,7 +167,7 @@ module Killbill
|
|
|
149
167
|
|
|
150
168
|
attr_accessor :per_tenant_config
|
|
151
169
|
|
|
152
|
-
def initialize(per_tenant_config)
|
|
170
|
+
def initialize(per_tenant_config = {})
|
|
153
171
|
@per_tenant_config = per_tenant_config
|
|
154
172
|
end
|
|
155
173
|
|
|
@@ -8,6 +8,8 @@ module Killbill
|
|
|
8
8
|
require 'offsite_payments'
|
|
9
9
|
|
|
10
10
|
class PaymentPlugin < ::Killbill::Plugin::Payment
|
|
11
|
+
include ::Killbill::Plugin::ActiveMerchant::ActiveRecordHelper
|
|
12
|
+
include ::Killbill::Plugin::PropertiesHelper
|
|
11
13
|
|
|
12
14
|
def initialize(gateway_builder, identifier, payment_method_model, transaction_model, response_model)
|
|
13
15
|
super()
|
|
@@ -17,11 +19,9 @@ module Killbill
|
|
|
17
19
|
@payment_method_model = payment_method_model
|
|
18
20
|
@transaction_model = transaction_model
|
|
19
21
|
@response_model = response_model
|
|
20
|
-
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def start_plugin
|
|
24
|
-
|
|
25
25
|
@logger.progname = "#{@identifier.to_s}-plugin"
|
|
26
26
|
|
|
27
27
|
@config_key_name = "PLUGIN_CONFIG_#{@plugin_name}".to_sym
|
|
@@ -37,19 +37,11 @@ module Killbill
|
|
|
37
37
|
@logger.info "#{@identifier} payment plugin started"
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
# return DB connections to the Pool if required
|
|
41
40
|
def after_request
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
connection = ::ActiveRecord::Base.connection
|
|
46
|
-
pool.remove(connection)
|
|
47
|
-
connection.disconnect!
|
|
48
|
-
|
|
49
|
-
@logger.debug { "after_request: pool.active_connection? = #{pool.active_connection?}, connection.active? = #{connection.active?}, pool.connections.size = #{pool.connections.size}, connections = #{pool.connections.inspect}" }
|
|
41
|
+
# return DB connections to the Pool if required
|
|
42
|
+
close_connection(@logger)
|
|
50
43
|
end
|
|
51
44
|
|
|
52
|
-
|
|
53
45
|
def on_event(event)
|
|
54
46
|
if (event.event_type == :TENANT_CONFIG_CHANGE || event.event_type == :TENANT_CONFIG_DELETION) &&
|
|
55
47
|
event.meta_data.to_sym == @config_key_name
|
|
@@ -147,8 +139,8 @@ module Killbill
|
|
|
147
139
|
|
|
148
140
|
def get_payment_info(kb_account_id, kb_payment_id, properties, context)
|
|
149
141
|
# We assume the payment is immutable in the Gateway and only look at our tables
|
|
150
|
-
@
|
|
151
|
-
|
|
142
|
+
@response_model.from_kb_payment_id(@transaction_model, kb_payment_id, context.tenant_id).collect do |response|
|
|
143
|
+
response.to_transaction_info_plugin(response.send("#{@identifier}_transaction"))
|
|
152
144
|
end
|
|
153
145
|
end
|
|
154
146
|
|
|
@@ -163,8 +155,10 @@ module Killbill
|
|
|
163
155
|
options[:set_default] ||= set_default
|
|
164
156
|
options[:order_id] ||= kb_payment_method_id
|
|
165
157
|
|
|
158
|
+
should_skip_gw = Utils.normalized(options, :skip_gw)
|
|
159
|
+
|
|
166
160
|
# Registering a card or a token
|
|
167
|
-
if
|
|
161
|
+
if should_skip_gw
|
|
168
162
|
# If nothing is passed, that's fine - we probably just want a placeholder row in the plugin
|
|
169
163
|
payment_source = get_payment_source(nil, all_properties, options, context) rescue nil
|
|
170
164
|
else
|
|
@@ -172,21 +166,31 @@ module Killbill
|
|
|
172
166
|
end
|
|
173
167
|
|
|
174
168
|
# Go to the gateway
|
|
175
|
-
payment_processor_account_id = options
|
|
169
|
+
payment_processor_account_id = Utils.normalized(options, :payment_processor_account_id) || :default
|
|
176
170
|
gateway = lookup_gateway(payment_processor_account_id, context.tenant_id)
|
|
177
171
|
gw_response = gateway.store(payment_source, options)
|
|
178
172
|
response, transaction = save_response_and_transaction(gw_response, :add_payment_method, kb_account_id, context.tenant_id, payment_processor_account_id)
|
|
179
173
|
|
|
180
174
|
if response.success
|
|
181
175
|
# If we have skipped the call to the gateway, we still need to store the payment method (either a token or the full credit card)
|
|
182
|
-
if
|
|
176
|
+
if should_skip_gw
|
|
183
177
|
cc_or_token = payment_source
|
|
184
178
|
else
|
|
185
179
|
# response.authorization may be a String combination separated by ; - don't split it! Some plugins expect it as-is (they split it themselves)
|
|
186
180
|
cc_or_token = response.authorization
|
|
187
181
|
end
|
|
188
182
|
|
|
189
|
-
|
|
183
|
+
attributes = properties_to_hash(all_properties)
|
|
184
|
+
# Note: keep the same keys as in build_am_credit_card below
|
|
185
|
+
extra_params = {
|
|
186
|
+
:cc_first_name => Utils.normalized(attributes, :cc_first_name),
|
|
187
|
+
:cc_last_name => Utils.normalized(attributes, :cc_last_name),
|
|
188
|
+
:cc_type => Utils.normalized(attributes, :cc_type),
|
|
189
|
+
:cc_exp_month => Utils.normalized(attributes, :cc_expiration_month),
|
|
190
|
+
:cc_exp_year => Utils.normalized(attributes, :cc_expiration_year),
|
|
191
|
+
:cc_last_4 => Utils.normalized(attributes, :cc_last_4)
|
|
192
|
+
}
|
|
193
|
+
payment_method = @payment_method_model.from_response(kb_account_id, kb_payment_method_id, context.tenant_id, cc_or_token, gw_response, options, extra_params, @payment_method_model)
|
|
190
194
|
payment_method.save!
|
|
191
195
|
payment_method
|
|
192
196
|
else
|
|
@@ -200,10 +204,12 @@ module Killbill
|
|
|
200
204
|
pm = @payment_method_model.from_kb_payment_method_id(kb_payment_method_id, context.tenant_id)
|
|
201
205
|
|
|
202
206
|
# Delete the card
|
|
203
|
-
payment_processor_account_id = options
|
|
207
|
+
payment_processor_account_id = Utils.normalized(options, :payment_processor_account_id) || :default
|
|
204
208
|
gateway = lookup_gateway(payment_processor_account_id, context.tenant_id)
|
|
205
|
-
|
|
206
|
-
|
|
209
|
+
|
|
210
|
+
customer_id = Utils.normalized(options, :customer_id)
|
|
211
|
+
if customer_id
|
|
212
|
+
gw_response = gateway.unstore(customer_id, pm.token, options)
|
|
207
213
|
else
|
|
208
214
|
gw_response = gateway.unstore(pm.token, options)
|
|
209
215
|
end
|
|
@@ -266,10 +272,12 @@ module Killbill
|
|
|
266
272
|
|
|
267
273
|
# The remaining elements in payment_methods are not in our table (this should never happen?!)
|
|
268
274
|
payment_methods.each do |payment_method_info_plugin|
|
|
269
|
-
pm = @payment_method_model.create
|
|
275
|
+
pm = @payment_method_model.create(:kb_account_id => kb_account_id,
|
|
270
276
|
:kb_payment_method_id => payment_method_info_plugin.payment_method_id,
|
|
271
277
|
:kb_tenant_id => context.tenant_id,
|
|
272
|
-
:token => payment_method_info_plugin.external_payment_method_id
|
|
278
|
+
:token => payment_method_info_plugin.external_payment_method_id,
|
|
279
|
+
:created_at => Time.now.utc,
|
|
280
|
+
:updated_at => Time.now.utc)
|
|
273
281
|
end
|
|
274
282
|
end
|
|
275
283
|
|
|
@@ -370,12 +378,12 @@ module Killbill
|
|
|
370
378
|
# * payment_source should probably be retrieved per gateway
|
|
371
379
|
# * amount per gateway should be retrieved from the options
|
|
372
380
|
def dispatch_to_gateways(operation, kb_account_id, kb_payment_id, kb_payment_transaction_id, kb_payment_method_id, amount, currency, properties, context, gateway_call_proc, linked_transaction_proc=nil)
|
|
373
|
-
kb_transaction = get_kb_transaction(kb_payment_id, kb_payment_transaction_id, context.tenant_id)
|
|
381
|
+
kb_transaction = Utils::LazyEvaluator.new { get_kb_transaction(kb_payment_id, kb_payment_transaction_id, context.tenant_id) }
|
|
374
382
|
amount_in_cents = amount.nil? ? nil : to_cents(amount, currency)
|
|
375
383
|
|
|
376
384
|
# Setup options for ActiveMerchant
|
|
377
385
|
options = properties_to_hash(properties)
|
|
378
|
-
options[:order_id] ||= kb_transaction.external_key
|
|
386
|
+
options[:order_id] ||= (Utils.normalized(options, :external_key_as_order_id) ? kb_transaction.external_key : kb_payment_transaction_id)
|
|
379
387
|
options[:currency] ||= currency.to_s.upcase unless currency.nil?
|
|
380
388
|
options[:description] ||= "Kill Bill #{operation.to_s} for #{kb_payment_transaction_id}"
|
|
381
389
|
|
|
@@ -388,7 +396,7 @@ module Killbill
|
|
|
388
396
|
end
|
|
389
397
|
|
|
390
398
|
# Retrieve the previous transaction for the same operation and payment id - this is useful to detect dups for example
|
|
391
|
-
last_transaction = @transaction_model.send("#{operation.to_s}s_from_kb_payment_id", kb_payment_id, context.tenant_id).last
|
|
399
|
+
last_transaction = Utils::LazyEvaluator.new { @transaction_model.send("#{operation.to_s}s_from_kb_payment_id", kb_payment_id, context.tenant_id).last }
|
|
392
400
|
|
|
393
401
|
# Retrieve the linked transaction (authorization to capture, purchase to refund, etc.)
|
|
394
402
|
linked_transaction = nil
|
|
@@ -404,7 +412,13 @@ module Killbill
|
|
|
404
412
|
gw_responses = []
|
|
405
413
|
responses = []
|
|
406
414
|
transactions = []
|
|
407
|
-
|
|
415
|
+
|
|
416
|
+
payment_processor_account_ids = Utils.normalized(options, :payment_processor_account_ids)
|
|
417
|
+
if !payment_processor_account_ids
|
|
418
|
+
payment_processor_account_ids = [Utils.normalized(options, :payment_processor_account_id) || :default]
|
|
419
|
+
else
|
|
420
|
+
payment_processor_account_ids = payment_processor_account_ids.split(',')
|
|
421
|
+
end
|
|
408
422
|
payment_processor_account_ids.each do |payment_processor_account_id|
|
|
409
423
|
# Find the gateway
|
|
410
424
|
gateway = lookup_gateway(payment_processor_account_id, context.tenant_id)
|
|
@@ -459,53 +473,51 @@ module Killbill
|
|
|
459
473
|
end
|
|
460
474
|
|
|
461
475
|
def get_payment_source(kb_payment_method_id, properties, options, context)
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
476
|
+
attributes = properties_to_hash(properties, options)
|
|
477
|
+
|
|
478
|
+
# Use ccNumber for:
|
|
479
|
+
# * the real number
|
|
480
|
+
# * in-house token (e.g. proxy tokenization)
|
|
481
|
+
# * token from a token service provider (e.g. ApplePay)
|
|
482
|
+
# If not specified, the rest of the card details will be retrieved from the locally stored payment method (if available)
|
|
483
|
+
cc_number = Utils.normalized(attributes, :cc_number)
|
|
465
484
|
# Use token for the token stored in an external vault. The token itself should be enough to process payments.
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
if
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
485
|
+
token = Utils.normalized(attributes, :token) || Utils.normalized(attributes, :card_id) || Utils.normalized(attributes, :payment_data)
|
|
486
|
+
|
|
487
|
+
if token.blank?
|
|
488
|
+
pm = nil
|
|
489
|
+
begin
|
|
490
|
+
pm = @payment_method_model.from_kb_payment_method_id(kb_payment_method_id, context.tenant_id)
|
|
491
|
+
rescue => e
|
|
492
|
+
raise e if cc_number.blank?
|
|
493
|
+
end unless kb_payment_method_id.nil?
|
|
494
|
+
|
|
495
|
+
if cc_number.blank? && !pm.nil?
|
|
496
|
+
# Lookup existing token
|
|
497
|
+
if pm.token.nil?
|
|
498
|
+
# Real credit card
|
|
499
|
+
cc_or_token = build_am_credit_card(pm.cc_number, attributes, pm)
|
|
500
|
+
else
|
|
501
|
+
# Tokenized card
|
|
502
|
+
cc_or_token = pm.token
|
|
503
|
+
end
|
|
482
504
|
else
|
|
483
|
-
#
|
|
484
|
-
cc_or_token = pm
|
|
505
|
+
# Real credit card or network tokenization
|
|
506
|
+
cc_or_token = build_am_credit_card(cc_number, attributes, pm)
|
|
485
507
|
end
|
|
486
|
-
elsif !cc_number.blank? and cc_or_token.blank?
|
|
487
|
-
# Real credit card
|
|
488
|
-
cc_or_token = ::ActiveMerchant::Billing::CreditCard.new(
|
|
489
|
-
:number => cc_number,
|
|
490
|
-
:brand => find_value_from_properties(properties, 'ccType'),
|
|
491
|
-
:month => find_value_from_properties(properties, 'ccExpirationMonth'),
|
|
492
|
-
:year => find_value_from_properties(properties, 'ccExpirationYear'),
|
|
493
|
-
:verification_value => find_value_from_properties(properties, 'ccVerificationValue'),
|
|
494
|
-
:first_name => find_value_from_properties(properties, 'ccFirstName'),
|
|
495
|
-
:last_name => find_value_from_properties(properties, 'ccLastName')
|
|
496
|
-
)
|
|
497
508
|
else
|
|
498
509
|
# Use specified token
|
|
510
|
+
cc_or_token = build_am_token(token, attributes)
|
|
499
511
|
end
|
|
500
512
|
|
|
501
513
|
options[:billing_address] ||= {
|
|
502
|
-
:email
|
|
503
|
-
:address1 =>
|
|
504
|
-
:address2 =>
|
|
505
|
-
:city
|
|
506
|
-
:zip
|
|
507
|
-
:state
|
|
508
|
-
:country
|
|
514
|
+
:email => Utils.normalized(attributes, :email),
|
|
515
|
+
:address1 => Utils.normalized(attributes, :address1) || (pm.nil? ? nil : pm.address1),
|
|
516
|
+
:address2 => Utils.normalized(attributes, :address2) || (pm.nil? ? nil : pm.address2),
|
|
517
|
+
:city => Utils.normalized(attributes, :city) || (pm.nil? ? nil : pm.city),
|
|
518
|
+
:zip => Utils.normalized(attributes, :zip) || (pm.nil? ? nil : pm.zip),
|
|
519
|
+
:state => Utils.normalized(attributes, :state) || (pm.nil? ? nil : pm.state),
|
|
520
|
+
:country => Utils.normalized(attributes, :country) || (pm.nil? ? nil : pm.country)
|
|
509
521
|
}
|
|
510
522
|
|
|
511
523
|
# To make various gateway implementations happy...
|
|
@@ -514,10 +526,49 @@ module Killbill
|
|
|
514
526
|
cc_or_token
|
|
515
527
|
end
|
|
516
528
|
|
|
517
|
-
def
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
529
|
+
def build_am_credit_card(cc_number, attributes, pm=nil)
|
|
530
|
+
card_attributes = {
|
|
531
|
+
:number => cc_number,
|
|
532
|
+
:brand => Utils.normalized(attributes, :cc_type) || (pm.nil? ? nil : pm.cc_type),
|
|
533
|
+
:month => Utils.normalized(attributes, :cc_expiration_month) || (pm.nil? ? nil : pm.cc_exp_month),
|
|
534
|
+
:year => Utils.normalized(attributes, :cc_expiration_year) || (pm.nil? ? nil : pm.cc_exp_year),
|
|
535
|
+
:verification_value => Utils.normalized(attributes, :cc_verification_value) || (pm.nil? ? nil : pm.cc_verification_value),
|
|
536
|
+
:first_name => Utils.normalized(attributes, :cc_first_name) || (pm.nil? ? nil : pm.cc_first_name),
|
|
537
|
+
:last_name => Utils.normalized(attributes, :cc_last_name) || (pm.nil? ? nil : pm.cc_last_name)
|
|
538
|
+
}
|
|
539
|
+
tokenization_attributes = {
|
|
540
|
+
:eci => Utils.normalized(attributes, :eci),
|
|
541
|
+
:payment_cryptogram => Utils.normalized(attributes, :payment_cryptogram),
|
|
542
|
+
:transaction_id => Utils.normalized(attributes, :transaction_id)
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if tokenization_attributes[:eci].nil? &&
|
|
546
|
+
tokenization_attributes[:payment_cryptogram].nil? &&
|
|
547
|
+
tokenization_attributes[:transaction_id].nil?
|
|
548
|
+
::ActiveMerchant::Billing::CreditCard.new(card_attributes)
|
|
549
|
+
else
|
|
550
|
+
# NetworkTokenizationCreditCard is exactly like a credit card but with EMV/3DS standard payment network tokenization data
|
|
551
|
+
::ActiveMerchant::Billing::NetworkTokenizationCreditCard.new(card_attributes.merge(tokenization_attributes))
|
|
552
|
+
end
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
def build_am_token(token, attributes)
|
|
556
|
+
token_attributes = {
|
|
557
|
+
:payment_instrument_name => Utils.normalized(attributes, :payment_instrument_name),
|
|
558
|
+
:payment_network => Utils.normalized(attributes, :payment_network),
|
|
559
|
+
:transaction_identifier => Utils.normalized(attributes, :transaction_identifier)
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
if token_attributes[:payment_instrument_name].nil? &&
|
|
563
|
+
token_attributes[:payment_network].nil? &&
|
|
564
|
+
token_attributes[:transaction_identifier].nil?
|
|
565
|
+
token
|
|
566
|
+
else
|
|
567
|
+
# Use ActiveSupport since ActiveMerchant does the same
|
|
568
|
+
payment_data = ::ActiveSupport::JSON.decode(token) rescue token
|
|
569
|
+
# PaymentToken is meant for modeling proprietary payment token structures (like stripe and apple_pay)
|
|
570
|
+
::ActiveMerchant::Billing::ApplePayPaymentToken.new(payment_data, token_attributes)
|
|
571
|
+
end
|
|
521
572
|
end
|
|
522
573
|
|
|
523
574
|
def account_currency(kb_account_id, kb_tenant_id)
|
|
@@ -545,31 +596,6 @@ module Killbill
|
|
|
545
596
|
::Killbill::Plugin::ActiveMerchant.config
|
|
546
597
|
end
|
|
547
598
|
|
|
548
|
-
def hash_to_properties(options)
|
|
549
|
-
merge_properties([], options)
|
|
550
|
-
end
|
|
551
|
-
|
|
552
|
-
def properties_to_hash(properties, options = {})
|
|
553
|
-
merged = {}
|
|
554
|
-
(properties || []).each do |p|
|
|
555
|
-
merged[p.key.to_sym] = p.value
|
|
556
|
-
end
|
|
557
|
-
merged.merge(options)
|
|
558
|
-
end
|
|
559
|
-
|
|
560
|
-
def merge_properties(properties, options)
|
|
561
|
-
merged = properties_to_hash(properties, options)
|
|
562
|
-
|
|
563
|
-
properties = []
|
|
564
|
-
merged.each do |k, v|
|
|
565
|
-
p = ::Killbill::Plugin::Model::PluginProperty.new
|
|
566
|
-
p.key = k
|
|
567
|
-
p.value = v
|
|
568
|
-
properties << p
|
|
569
|
-
end
|
|
570
|
-
properties
|
|
571
|
-
end
|
|
572
|
-
|
|
573
599
|
def get_active_merchant_module
|
|
574
600
|
::OffsitePayments.integration(@identifier.to_s.camelize)
|
|
575
601
|
end
|