killbill 3.2.4 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|