require 'spec_helper' describe Killbill::Plugin::ActiveMerchant::PaymentPlugin do include Killbill::Plugin::ActiveMerchant::RSpec let(:payment_api) { ::Killbill::Plugin::ActiveMerchant::RSpec::FakeJavaPaymentApi.new } let(:tenant_api) { ::Killbill::Plugin::ActiveMerchant::RSpec::FakeJavaTenantUserApi.new } let(:kb_apis) { ::Killbill::Plugin::KillbillApi.new('test', {:payment_api => payment_api, :tenant_user_api => tenant_api}) } let(:logger) do logger = Logger.new(STDOUT) logger.level = Logger::INFO logger end before(:each) do @kb_account_id = SecureRandom.uuid @kb_payment_id = SecureRandom.uuid @kb_payment_method_id = SecureRandom.uuid @amount_in_cents = rand(100000) @currency = 'USD' @call_context = Killbill::Plugin::Model::CallContext.new @call_context.tenant_id = SecureRandom.uuid token = ::Killbill::Plugin::Model::PluginProperty.new token.key = 'token' token.value = SecureRandom.uuid @payment_method_props = ::Killbill::Plugin::Model::PaymentMethodPlugin.new @payment_method_props.properties = [token] end context 'when skipping the gateway' do let(:plugin) do plugin = ::Killbill::Plugin::ActiveMerchant::PaymentPlugin.new(Proc.new { |config| nil }, :test, ::Killbill::Test::TestPaymentMethod, ::Killbill::Test::TestTransaction, ::Killbill::Test::TestResponse) plugin.kb_apis = kb_apis plugin.logger = logger plugin_config = { :test => [ {:account_id => 'default', :test => true}, {:account_id => 'something_non_standard', :test => true} ] } with_plugin_yaml_config('test.yml', plugin_config) do |file| plugin.conf_dir = File.dirname(file) plugin.root = File.dirname(file) # Start the plugin here - since the config file will be deleted plugin.start_plugin end plugin end before(:each) do property = ::Killbill::Plugin::Model::PluginProperty.new property.key = 'skip_gw' property.value = 'true' @properties = [property] @ppai = ::Killbill::Plugin::Model::PluginProperty.new @ppai.key = 'payment_processor_account_id' @ppai.value = 'something_non_standard' @properties_with_ppai = @properties.dup @properties_with_ppai << @ppai end after(:all) do plugin.stop_plugin end it 'should implement payment plugin API calls' do plugin.get_payment_methods(@kb_account_id, true, @properties, @call_context).size.should == 0 plugin.add_payment_method(@kb_account_id, @kb_payment_method_id, @payment_method_props, true, @properties, @call_context) plugin.get_payment_methods(@kb_account_id, true, @properties, @call_context).size.should == 1 ::Killbill::Test::TestPaymentMethod.where(:kb_payment_method_id => @kb_payment_method_id).first.token.should == @payment_method_props.properties[0].value authorization_id = SecureRandom.uuid payment_api.add_payment(@kb_payment_id, authorization_id, SecureRandom.uuid, :AUTHORIZE) authorization = plugin.authorize_payment(@kb_account_id, @kb_payment_id, authorization_id, @kb_payment_method_id, @amount_in_cents, @currency, @properties, @call_context) verify_transaction_info_plugin(authorization, authorization_id, :AUTHORIZE, 1) capture_id = SecureRandom.uuid payment_api.add_payment(@kb_payment_id, capture_id, SecureRandom.uuid, :CAPTURE) capture = plugin.capture_payment(@kb_account_id, @kb_payment_id, capture_id, @kb_payment_method_id, @amount_in_cents, @currency, @properties, @call_context) verify_transaction_info_plugin(capture, capture_id, :CAPTURE, 2) purchase_id = SecureRandom.uuid payment_api.add_payment(@kb_payment_id, purchase_id, SecureRandom.uuid, :PURCHASE) purchase = plugin.purchase_payment(@kb_account_id, @kb_payment_id, purchase_id, @kb_payment_method_id, @amount_in_cents, @currency, @properties, @call_context) verify_transaction_info_plugin(purchase, purchase_id, :PURCHASE, 3) void_id = SecureRandom.uuid payment_api.add_payment(@kb_payment_id, void_id, SecureRandom.uuid, :VOID) void = plugin.void_payment(@kb_account_id, @kb_payment_id, void_id, @kb_payment_method_id, @properties, @call_context) verify_transaction_info_plugin(void, void_id, :VOID, 4) credit_id = SecureRandom.uuid payment_api.add_payment(@kb_payment_id, credit_id, SecureRandom.uuid, :CREDIT) credit = plugin.credit_payment(@kb_account_id, @kb_payment_id, credit_id, @kb_payment_method_id, @amount_in_cents, @currency, @properties, @call_context) verify_transaction_info_plugin(credit, credit_id, :CREDIT, 5) refund_id = SecureRandom.uuid payment_api.add_payment(@kb_payment_id, refund_id, SecureRandom.uuid, :REFUND) refund = plugin.refund_payment(@kb_account_id, @kb_payment_id, refund_id, @kb_payment_method_id, @amount_in_cents, @currency, @properties, @call_context) verify_transaction_info_plugin(refund, refund_id, :REFUND, 6) plugin.delete_payment_method(@kb_account_id, @kb_payment_method_id, @properties, @call_context) plugin.get_payment_methods(@kb_account_id, true, @properties, @call_context).size.should == 0 end it 'should support different payment_processor_account_ids' do plugin.get_payment_methods(@kb_account_id, true, @properties, @call_context).size.should == 0 plugin.add_payment_method(@kb_account_id, @kb_payment_method_id, @payment_method_props, true, @properties, @call_context) plugin.get_payment_methods(@kb_account_id, true, @properties, @call_context).size.should == 1 ::Killbill::Test::TestPaymentMethod.where(:kb_payment_method_id => @kb_payment_method_id).first.token.should == @payment_method_props.properties[0].value authorization_id = SecureRandom.uuid payment_api.add_payment(@kb_payment_id, authorization_id, SecureRandom.uuid, :AUTHORIZE) authorization = plugin.authorize_payment(@kb_account_id, @kb_payment_id, authorization_id, @kb_payment_method_id, @amount_in_cents, @currency, @properties_with_ppai, @call_context) verify_transaction_info_plugin(authorization, authorization_id, :AUTHORIZE, 1, @ppai.value) capture_id = SecureRandom.uuid payment_api.add_payment(@kb_payment_id, capture_id, SecureRandom.uuid, :CAPTURE) # We omit the payment_processor_account_id to verify we can retrieve it capture = plugin.capture_payment(@kb_account_id, @kb_payment_id, capture_id, @kb_payment_method_id, @amount_in_cents, @currency, @properties, @call_context) verify_transaction_info_plugin(capture, capture_id, :CAPTURE, 2, @ppai.value) end it 'should support storing a credit card' do plugin.get_payment_methods(@kb_account_id, true, @properties, @call_context).size.should == 0 properties = [] properties << build_property('ccNumber', '41111111111111111') properties << build_property('ccFirstName', 'Paul') properties << build_property('ccLastName', 'Dupond') properties << build_property('ccType', 'visa') properties << build_property('ccExpirationMonth', '12') properties << build_property('ccExpirationYear', '17') payment_method_props = ::Killbill::Plugin::Model::PaymentMethodPlugin.new payment_method_props.properties = properties plugin.add_payment_method(@kb_account_id, SecureRandom.uuid, payment_method_props, true, @properties, @call_context) pms = plugin.get_payment_methods(@kb_account_id, true, @properties, @call_context) pms.size.should == 1 pm = plugin.get_payment_method_detail(@kb_account_id, pms[0].payment_method_id, @properties, @call_context) plugin.find_value_from_properties(pm.properties, 'token').should be_nil plugin.find_value_from_properties(pm.properties, 'ccFirstName').should == 'Paul' plugin.find_value_from_properties(pm.properties, 'ccLastName').should == 'Dupond' plugin.find_value_from_properties(pm.properties, 'ccType').should == 'visa' plugin.find_value_from_properties(pm.properties, 'ccExpirationMonth').should == '12' plugin.find_value_from_properties(pm.properties, 'ccExpirationYear').should == '17' plugin.find_value_from_properties(pm.properties, 'ccLast4').should == '1111' plugin.find_value_from_properties(pm.properties, 'ccNumber').should == '41111111111111111' # Verify we can retrieve the payment source, during the payment call source = plugin.get_payment_source(pm.kb_payment_method_id, [], {}, @call_context) source.is_a?(::ActiveMerchant::Billing::CreditCard).should be_true source.first_name.should == 'Paul' source.last_name.should == 'Dupond' source.brand.should == 'visa' source.month.should == 12 source.year.should == 17 source.number.should == '41111111111111111' end it 'should support storing a token' do plugin.get_payment_methods(@kb_account_id, true, @properties, @call_context).size.should == 0 properties = [] properties << build_property('token', 'ABCDEF') payment_method_props = ::Killbill::Plugin::Model::PaymentMethodPlugin.new payment_method_props.properties = properties plugin.add_payment_method(@kb_account_id, SecureRandom.uuid, payment_method_props, true, @properties, @call_context) pms = plugin.get_payment_methods(@kb_account_id, true, @properties, @call_context) pms.size.should == 1 pm = plugin.get_payment_method_detail(@kb_account_id, pms[0].payment_method_id, @properties, @call_context) plugin.find_value_from_properties(pm.properties, 'token').should == 'ABCDEF' plugin.find_value_from_properties(pm.properties, 'ccFirstName').should be_nil plugin.find_value_from_properties(pm.properties, 'ccLastName').should be_nil plugin.find_value_from_properties(pm.properties, 'ccType').should be_nil plugin.find_value_from_properties(pm.properties, 'ccExpirationMonth').should be_nil plugin.find_value_from_properties(pm.properties, 'ccExpirationYear').should be_nil plugin.find_value_from_properties(pm.properties, 'ccLast4').should be_nil plugin.find_value_from_properties(pm.properties, 'ccNumber').should be_nil # Verify we can retrieve the payment source, during the payment call source = plugin.get_payment_source(pm.kb_payment_method_id, [], {}, @call_context) source.should == 'ABCDEF' end it 'should support storing a placeholder row' do plugin.get_payment_methods(@kb_account_id, true, @properties, @call_context).size.should == 0 plugin.add_payment_method(@kb_account_id, SecureRandom.uuid, ::Killbill::Plugin::Model::PaymentMethodPlugin.new, true, @properties, @call_context) pms = plugin.get_payment_methods(@kb_account_id, true, @properties, @call_context) pms.size.should == 1 pm = plugin.get_payment_method_detail(@kb_account_id, pms[0].payment_method_id, @properties, @call_context) plugin.find_value_from_properties(pm.properties, 'token').should be_nil plugin.find_value_from_properties(pm.properties, 'ccFirstName').should be_nil plugin.find_value_from_properties(pm.properties, 'ccLastName').should be_nil plugin.find_value_from_properties(pm.properties, 'ccType').should be_nil plugin.find_value_from_properties(pm.properties, 'ccExpirationMonth').should be_nil plugin.find_value_from_properties(pm.properties, 'ccExpirationYear').should be_nil plugin.find_value_from_properties(pm.properties, 'ccLast4').should be_nil plugin.find_value_from_properties(pm.properties, 'ccNumber').should be_nil # Verify we can retrieve the payment source, during the payment call source = plugin.get_payment_source(pm.kb_payment_method_id, [], {}, @call_context) source.is_a?(::ActiveMerchant::Billing::CreditCard).should be_true source.first_name.should be_nil source.last_name.should be_nil source.brand.should be_nil source.month.should be_nil source.year.should be_nil source.number.should be_nil end it 'recognizes a tokenized card by the network' do options = { :cc_number => '4242424242424242', :cc_type => 'visa', :cc_expiration_month => 12, :cc_expiration_year => 2019, :payment_cryptogram => 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', :eci => '05' } source = plugin.get_payment_source(nil, [], options, @call_context) source.is_a?(::ActiveMerchant::Billing::NetworkTokenizationCreditCard).should be_true source.type.should == 'network_tokenization' source.number.should == '4242424242424242' source.brand.should == 'visa' source.month.should == 12 source.year.should == 2019 source.payment_cryptogram.should == 'EHuWW9PiBkWvqE5juRwDzAUFBAk=' source.eci.should == '05' end it 'recognizes an ApplePay token' do options = { :token => '{"data":"BDPNWStMmGewQUWGg4o7E/j+1cq1T78qyU84b67itjcYI8wPYAOhshjhZPrqdUr4XwPMbj4zcGMdy++1H2VkPOY+BOMF25ub19cX4nCvkXUUOTjDllB1TgSr8JHZxgp9rCgsSUgbBgKf60XKutXf6aj/o8ZIbKnrKQ8Sh0ouLAKloUMn+vPu4+A7WKrqrauz9JvOQp6vhIq+HKjUcUNCITPyFhmOEtq+H+w0vRa1CE6WhFBNnCHqzzWKckB/0nqLZRTYbF0p+vyBiVaWHeghERfHxRtbzpeczRPPuFsfpHVs48oPLC/k/1MNd47kz/pHDcR/Dy6aUM+lNfoily/QJN+tS3m0HfOtISAPqOmXemvr6xJCjCZlCuw0C9mXz/obHpofuIES8r9cqGGsUAPDpw7g642m4PzwKF+HBuYUneWDBNSD2u6jbAG3","version":"EC_v1","header":{"applicationData":"94ee059335e587e501cc4bf90613e0814f00a7b08bc7c648fd865a2af6a22cc2","transactionId":"c1caf5ae72f0039a82bad92b828363734f85bf2f9cadf193d1bad9ddcb60a795","ephemeralPublicKey":"MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABGm+gsl0PZFT/kDdUSkxwyfo8JpwTQQzBm9lJJnmTl4DGUvAD4GseGj/pshBZ0K3TeuqDt/tDLbE+8/m0yCmoxw=","publicKeyHash":"/bb9CNC36uBheHFPbmohB7Oo1OsX2J+kJqv48zOVViQ="},"signature":"MIIDQgYJKoZIhvcNAQcCoIIDMzCCAy8CAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCAiswggInMIIBlKADAgECAhBcl+Pf3+U4pk13nVD9nwQQMAkGBSsOAwIdBQAwJzElMCMGA1UEAx4cAGMAaABtAGEAaQBAAHYAaQBzAGEALgBjAG8AbTAeFw0xNDAxMDEwNjAwMDBaFw0yNDAxMDEwNjAwMDBaMCcxJTAjBgNVBAMeHABjAGgAbQBhAGkAQAB2AGkAcwBhAC4AYwBvAG0wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANC8+kgtgmvWF1OzjgDNrjTEBRuo/5MKvlM146pAf7Gx41blE9w4fIXJAD7FfO7QKjIXYNt39rLyy7xDwb/5IkZM60TZ2iI1pj55Uc8fd4fzOpk3ftZaQGXNLYptG1d9V7IS82Oup9MMo1BPVrXTPHNcsM99EPUnPqdbeGc87m0rAgMBAAGjXDBaMFgGA1UdAQRRME+AEHZWPrWtJd7YZ431hCg7YFShKTAnMSUwIwYDVQQDHhwAYwBoAG0AYQBpAEAAdgBpAHMAYQAuAGMAbwBtghBcl+Pf3+U4pk13nVD9nwQQMAkGBSsOAwIdBQADgYEAbUKYCkuIKS9QQ2mFcMYREIm2l+Xg8/JXv+GBVQJkOKoscY4iNDFA/bQlogf9LLU84THwNRnsvV3Prv7RTY81gq0dtC8zYcAaAkCHII3yqMnJ4AOu6EOW9kJk232gSE7WlCtHbfLSKfuSgQX8KXQYuZLk2Rr63N8ApXsXwBL3cJ0xgeAwgd0CAQEwOzAnMSUwIwYDVQQDHhwAYwBoAG0AYQBpAEAAdgBpAHMAYQAuAGMAbwBtAhBcl+Pf3+U4pk13nVD9nwQQMAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEgYBaK3ElOstbH8WooseDABf+Jg/129JcIawm7c6Vxn7ZasNbAq3tAt8Pty+uQCgssXqZkLA7kz2GzMolNtv9wYmu9Ujwar1PHYS+B/oGnoz591wjagXWRz0nMo5y3O1KzX0d8CRHAVa88SrV1a5JIiRev3oStIqwv5xuZldag6Tr8w=="}', :payment_instrument_name => 'SomeBank Points Card', :payment_network => 'MasterCard', :transaction_identifier => 'uniqueidentifier123' } source = plugin.get_payment_source(nil, [], options, @call_context) source.is_a?(::ActiveMerchant::Billing::ApplePayPaymentToken).should be_true source.type.should == 'apple_pay' source.payment_instrument_name.should == 'SomeBank Points Card' source.payment_network.should == 'MasterCard' # Not set in ApplePayPaymentToken? #source.transaction_identifier.should == 'uniqueidentifier123' source.payment_data.should == { 'data' => 'BDPNWStMmGewQUWGg4o7E/j+1cq1T78qyU84b67itjcYI8wPYAOhshjhZPrqdUr4XwPMbj4zcGMdy++1H2VkPOY+BOMF25ub19cX4nCvkXUUOTjDllB1TgSr8JHZxgp9rCgsSUgbBgKf60XKutXf6aj/o8ZIbKnrKQ8Sh0ouLAKloUMn+vPu4+A7WKrqrauz9JvOQp6vhIq+HKjUcUNCITPyFhmOEtq+H+w0vRa1CE6WhFBNnCHqzzWKckB/0nqLZRTYbF0p+vyBiVaWHeghERfHxRtbzpeczRPPuFsfpHVs48oPLC/k/1MNd47kz/pHDcR/Dy6aUM+lNfoily/QJN+tS3m0HfOtISAPqOmXemvr6xJCjCZlCuw0C9mXz/obHpofuIES8r9cqGGsUAPDpw7g642m4PzwKF+HBuYUneWDBNSD2u6jbAG3', 'version' => 'EC_v1', 'header' => { 'applicationData' => '94ee059335e587e501cc4bf90613e0814f00a7b08bc7c648fd865a2af6a22cc2', 'transactionId' => 'c1caf5ae72f0039a82bad92b828363734f85bf2f9cadf193d1bad9ddcb60a795', 'ephemeralPublicKey' => 'MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAAAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA///////////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABGm+gsl0PZFT/kDdUSkxwyfo8JpwTQQzBm9lJJnmTl4DGUvAD4GseGj/pshBZ0K3TeuqDt/tDLbE+8/m0yCmoxw=', 'publicKeyHash' => '/bb9CNC36uBheHFPbmohB7Oo1OsX2J+kJqv48zOVViQ=' }, 'signature' => 'MIIDQgYJKoZIhvcNAQcCoIIDMzCCAy8CAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3DQEHAaCCAiswggInMIIBlKADAgECAhBcl+Pf3+U4pk13nVD9nwQQMAkGBSsOAwIdBQAwJzElMCMGA1UEAx4cAGMAaABtAGEAaQBAAHYAaQBzAGEALgBjAG8AbTAeFw0xNDAxMDEwNjAwMDBaFw0yNDAxMDEwNjAwMDBaMCcxJTAjBgNVBAMeHABjAGgAbQBhAGkAQAB2AGkAcwBhAC4AYwBvAG0wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANC8+kgtgmvWF1OzjgDNrjTEBRuo/5MKvlM146pAf7Gx41blE9w4fIXJAD7FfO7QKjIXYNt39rLyy7xDwb/5IkZM60TZ2iI1pj55Uc8fd4fzOpk3ftZaQGXNLYptG1d9V7IS82Oup9MMo1BPVrXTPHNcsM99EPUnPqdbeGc87m0rAgMBAAGjXDBaMFgGA1UdAQRRME+AEHZWPrWtJd7YZ431hCg7YFShKTAnMSUwIwYDVQQDHhwAYwBoAG0AYQBpAEAAdgBpAHMAYQAuAGMAbwBtghBcl+Pf3+U4pk13nVD9nwQQMAkGBSsOAwIdBQADgYEAbUKYCkuIKS9QQ2mFcMYREIm2l+Xg8/JXv+GBVQJkOKoscY4iNDFA/bQlogf9LLU84THwNRnsvV3Prv7RTY81gq0dtC8zYcAaAkCHII3yqMnJ4AOu6EOW9kJk232gSE7WlCtHbfLSKfuSgQX8KXQYuZLk2Rr63N8ApXsXwBL3cJ0xgeAwgd0CAQEwOzAnMSUwIwYDVQQDHhwAYwBoAG0AYQBpAEAAdgBpAHMAYQAuAGMAbwBtAhBcl+Pf3+U4pk13nVD9nwQQMAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEgYBaK3ElOstbH8WooseDABf+Jg/129JcIawm7c6Vxn7ZasNbAq3tAt8Pty+uQCgssXqZkLA7kz2GzMolNtv9wYmu9Ujwar1PHYS+B/oGnoz591wjagXWRz0nMo5y3O1KzX0d8CRHAVa88SrV1a5JIiRev3oStIqwv5xuZldag6Tr8w==' } end # Apple Pay integration with CyberSource for example it 'merges tokenized cards with payment method information' do # Create a payment method with just a first and last name cc_first_name = ::Killbill::Plugin::Model::PluginProperty.new cc_first_name.key = 'cc_first_name' cc_first_name.value = 'John' cc_last_name = ::Killbill::Plugin::Model::PluginProperty.new cc_last_name.key = 'cc_last_name' cc_last_name.value = 'Doe' skip_gw = ::Killbill::Plugin::Model::PluginProperty.new skip_gw.key = 'skip_gw' skip_gw.value = 'true' pm_properties = ::Killbill::Plugin::Model::PaymentMethodPlugin.new plugin.add_payment_method(@kb_account_id, @kb_payment_method_id, pm_properties, true, [skip_gw, cc_first_name, cc_last_name], @call_context) # Build the NetworkTokenizationCreditCard options = { :cc_number => '4242424242424242', :cc_type => 'visa', :cc_expiration_month => 12, :cc_expiration_year => 2019, :payment_cryptogram => 'EHuWW9PiBkWvqE5juRwDzAUFBAk=', :eci => '05' } source = plugin.get_payment_source(@kb_payment_method_id, [], options, @call_context) source.is_a?(::ActiveMerchant::Billing::NetworkTokenizationCreditCard).should be_true source.type.should == 'network_tokenization' source.number.should == '4242424242424242' source.brand.should == 'visa' source.month.should == 12 source.year.should == 2019 source.payment_cryptogram.should == 'EHuWW9PiBkWvqE5juRwDzAUFBAk=' source.eci.should == '05' # The first and last name should have been populated from the payment method source.first_name.should == 'John' source.last_name.should == 'Doe' end end context 'with a dummy gateway' do let(:gateway) { DummyRecordingGateway.new } let(:plugin) do plugin = ::Killbill::Plugin::ActiveMerchant::PaymentPlugin.new(Proc.new { |config| gateway }, :test, ::Killbill::Test::TestPaymentMethod, ::Killbill::Test::TestTransaction, ::Killbill::Test::TestResponse) plugin.kb_apis = kb_apis plugin.logger = logger plugin_config = { :test => [ {:account_id => 'default', :test => true}, ] } with_plugin_yaml_config('test.yml', plugin_config) do |file| plugin.conf_dir = File.dirname(file) plugin.root = File.dirname(file) # Start the plugin here - since the config file will be deleted plugin.start_plugin end plugin end after(:each) do gateway.call_stack.clear end after(:all) do plugin.stop_plugin end it 'sets the kb_payment_transaction_id as order_id by default' do plugin.add_payment_method(@kb_account_id, @kb_payment_method_id, @payment_method_props, true, [], @call_context) kb_payment_transaction_id = SecureRandom.uuid plugin.purchase_payment(@kb_account_id, @kb_payment_id, kb_payment_transaction_id, @kb_payment_method_id, @amount_in_cents, @currency, [], @call_context) sent_options = gateway.call_stack[-1][:options] sent_options.size.should == 11 sent_options[:currency].should == @currency sent_options[:description].should == "Kill Bill purchase for #{kb_payment_transaction_id}" sent_options[:order_id].should == kb_payment_transaction_id end it 'sets the kb_payment_transaction_id as order_id if specified' do plugin.add_payment_method(@kb_account_id, @kb_payment_method_id, @payment_method_props, true, [], @call_context) property = ::Killbill::Plugin::Model::PluginProperty.new property.key = 'external_key_as_order_id' property.value = 'false' kb_payment_transaction_id = SecureRandom.uuid plugin.purchase_payment(@kb_account_id, @kb_payment_id, kb_payment_transaction_id, @kb_payment_method_id, @amount_in_cents, @currency, [property], @call_context) sent_options = gateway.call_stack[-1][:options] sent_options.size.should == 12 sent_options[:currency].should == @currency sent_options[:description].should == "Kill Bill purchase for #{kb_payment_transaction_id}" sent_options[:order_id].should == kb_payment_transaction_id end it 'sets the payment transaction external key as order_id if specified' do plugin.add_payment_method(@kb_account_id, @kb_payment_method_id, @payment_method_props, true, [], @call_context) property = ::Killbill::Plugin::Model::PluginProperty.new property.key = 'external_key_as_order_id' property.value = 'true' kb_payment_transaction_id = SecureRandom.uuid kb_payment_transaction_external_key = SecureRandom.uuid payment_api.add_payment(@kb_payment_id, kb_payment_transaction_id, kb_payment_transaction_external_key, :PURCHASE) plugin.purchase_payment(@kb_account_id, @kb_payment_id, kb_payment_transaction_id, @kb_payment_method_id, @amount_in_cents, @currency, [property], @call_context) sent_options = gateway.call_stack[-1][:options] sent_options.size.should == 12 sent_options[:currency].should == @currency sent_options[:description].should == "Kill Bill purchase for #{kb_payment_transaction_id}" sent_options[:order_id].should == kb_payment_transaction_external_key end it 'closes the connection after each request' do ::ActiveRecord::Base.retrieve_connection ::ActiveRecord::Base.connection_pool.active_connection?.should == true plugin.after_request ::ActiveRecord::Base.connection_pool.active_connection?.should == false end end private def verify_transaction_info_plugin(t_info_plugin, kb_transaction_id, type, transaction_nb, payment_processor_account_id='default') t_info_plugin.kb_payment_id.should == @kb_payment_id t_info_plugin.kb_transaction_payment_id.should == kb_transaction_id t_info_plugin.transaction_type.should == type if type == :VOID t_info_plugin.amount.should be_nil t_info_plugin.currency.should be_nil else t_info_plugin.amount.should == @amount_in_cents t_info_plugin.currency.should == @currency end t_info_plugin.status.should == :PROCESSED # Verify we routed to the right gateway (t_info_plugin.properties.find { |kv| kv.key.to_s == 'payment_processor_account_id' }).value.to_s.should == payment_processor_account_id transactions = plugin.get_payment_info(@kb_account_id, @kb_payment_id, [], @call_context) transactions.size.should == transaction_nb transactions[transaction_nb - 1].to_json.should == t_info_plugin.to_json end class DummyRecordingGateway < ::ActiveMerchant::Billing::Gateway attr_reader :call_stack def initialize @call_stack = [] end def purchase(money, paysource, options = {}) @call_stack << {:money => money, :source => paysource, :options => options} ::ActiveMerchant::Billing::Response.new(true, 'Success!', {:authorized_amount => money}, :test => true, :authorization => 12345) end def store(paysource, options = {}) @call_stack << {:source => paysource, :options => options} ::ActiveMerchant::Billing::Response.new(true, 'Success!', {:billingid => '1'}, :test => true, :authorization => 12345) end end end