killbill 3.1.5 → 3.1.6
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/Jarfile +1 -1
- data/NEWS +5 -0
- data/VERSION +1 -1
- data/generators/active_merchant/templates/Jarfile.rb +1 -1
- data/generators/active_merchant/templates/lib/models/response.rb +2 -2
- data/generators/active_merchant/templates/plugin.gemspec.rb +1 -1
- data/lib/killbill/gen/api/killbill_api.rb +43 -0
- data/lib/killbill/gen/api/require_gen.rb +1 -0
- data/lib/killbill/helpers/active_merchant/active_record/models/helpers.rb +31 -0
- data/lib/killbill/helpers/active_merchant/active_record/models/payment_method.rb +7 -5
- data/lib/killbill/helpers/active_merchant/active_record/models/response.rb +40 -0
- data/lib/killbill/helpers/active_merchant/active_record/models/transaction.rb +11 -7
- data/lib/killbill/helpers/active_merchant/payment_plugin.rb +5 -22
- data/lib/killbill/helpers/active_merchant/utils.rb +40 -2
- data/spec/killbill/helpers/response_spec.rb +34 -0
- data/spec/killbill/helpers/test_schema.rb +3 -2
- data/spec/killbill/helpers/transaction_spec.rb +3 -1
- data/spec/spec_helper.rb +1 -0
- metadata +3 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: ce31dbfe71c1ea2aae402a3a5f30d4635f1f44dc
         | 
| 4 | 
            +
              data.tar.gz: 028044c61a02e5957099524601055f15c596e9a8
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 579efbe60b305303205c3e2cedc03b66cd6b2622244f304b0d05f5fe87729edeff61c07c7117819f38d422d48e8cb8d563c5e5f6759f3ba4fd79eaf061ffc55d
         | 
| 7 | 
            +
              data.tar.gz: 99c8c98f3085e9fa83b1745cef3bd224c74c23efdd394a56cf9dde919ffc1090f59d96873d8fe7c64a1d0d9eadcef0a72fe7bdcff7d38dbc94310c5e37ad398d
         | 
    
        data/Jarfile
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            jar 'org.kill-bill.billing:killbill-api', '0.9. | 
| 1 | 
            +
            jar 'org.kill-bill.billing:killbill-api', '0.9.8'
         | 
| 2 2 | 
             
            jar 'org.kill-bill.billing.plugin:killbill-plugin-api-notification', '0.7.4'
         | 
| 3 3 | 
             
            jar 'org.kill-bill.billing.plugin:killbill-plugin-api-payment', '0.7.4'
         | 
| 4 4 | 
             
            jar 'org.kill-bill.billing.plugin:killbill-plugin-api-currency', '0.7.4'
         | 
    
        data/NEWS
    CHANGED
    
    
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            3.1. | 
| 1 | 
            +
            3.1.6
         | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            jar 'org.kill-bill.billing:killbill-api', '0.9. | 
| 1 | 
            +
            jar 'org.kill-bill.billing:killbill-api', '0.9.8'
         | 
| 2 2 | 
             
            jar 'org.kill-bill.billing.plugin:killbill-plugin-api-notification', '0.7.4'
         | 
| 3 3 | 
             
            jar 'org.kill-bill.billing.plugin:killbill-plugin-api-payment', '0.7.4'
         | 
| 4 4 | 
             
            jar 'org.kill-bill.billing.plugin:killbill-plugin-api-currency', '0.7.4'
         | 
| @@ -6,7 +6,7 @@ module Killbill #:nodoc: | |
| 6 6 |  | 
| 7 7 | 
             
                  has_one :<%= identifier %>_transaction
         | 
| 8 8 |  | 
| 9 | 
            -
                  def self.from_response(api_call, kb_account_id, kb_payment_id, kb_payment_transaction_id, transaction_type, kb_tenant_id, response, extra_params = {})
         | 
| 9 | 
            +
                  def self.from_response(api_call, kb_account_id, kb_payment_id, kb_payment_transaction_id, transaction_type, kb_tenant_id, response, extra_params = {}, model = ::Killbill::<%= class_name %>::<%= class_name %>Response)
         | 
| 10 10 | 
             
                    super(api_call,
         | 
| 11 11 | 
             
                          kb_account_id,
         | 
| 12 12 | 
             
                          kb_payment_id,
         | 
| @@ -19,7 +19,7 @@ module Killbill #:nodoc: | |
| 19 19 | 
             
                              #:params_id => extract(response, 'id'),
         | 
| 20 20 | 
             
                              #:params_card_id => extract(response, 'card', 'id')
         | 
| 21 21 | 
             
                          }.merge!(extra_params),
         | 
| 22 | 
            -
                           | 
| 22 | 
            +
                          model)
         | 
| 23 23 | 
             
                  end
         | 
| 24 24 | 
             
                end
         | 
| 25 25 | 
             
              end
         | 
| @@ -22,7 +22,7 @@ Gem::Specification.new do |s| | |
| 22 22 |  | 
| 23 23 | 
             
              s.rdoc_options << '--exclude' << '.'
         | 
| 24 24 |  | 
| 25 | 
            -
              s.add_dependency 'killbill', '~> 3.1. | 
| 25 | 
            +
              s.add_dependency 'killbill', '~> 3.1.6'
         | 
| 26 26 | 
             
              s.add_dependency 'activemerchant', '~> 1.42.9'
         | 
| 27 27 | 
             
              s.add_dependency 'activerecord', '~> 4.1.0'
         | 
| 28 28 | 
             
              s.add_dependency 'actionpack', '~> 4.1.0'
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            ###################################################################################
         | 
| 2 | 
            +
            #                                                                                 #
         | 
| 3 | 
            +
            #                   Copyright 2010-2013 Ning, Inc.                                #
         | 
| 4 | 
            +
            #                   Copyright 2014 The Billing Project, LLC                       #
         | 
| 5 | 
            +
            #                                                                                 #
         | 
| 6 | 
            +
            #      The Billing Project licenses this file to you under the Apache License,    #
         | 
| 7 | 
            +
            #      version 2.0 (the "License"); you may not use this file except in           #
         | 
| 8 | 
            +
            #      compliance with the License.  You may obtain a copy of the License at:     #
         | 
| 9 | 
            +
            #                                                                                 #
         | 
| 10 | 
            +
            #          http://www.apache.org/licenses/LICENSE-2.0                             #
         | 
| 11 | 
            +
            #                                                                                 #
         | 
| 12 | 
            +
            #      Unless required by applicable law or agreed to in writing, software        #
         | 
| 13 | 
            +
            #      distributed under the License is distributed on an "AS IS" BASIS, WITHOUT  #
         | 
| 14 | 
            +
            #      WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the  #
         | 
| 15 | 
            +
            #      License for the specific language governing permissions and limitations    #
         | 
| 16 | 
            +
            #      under the License.                                                         #
         | 
| 17 | 
            +
            #                                                                                 #
         | 
| 18 | 
            +
            ###################################################################################
         | 
| 19 | 
            +
             | 
| 20 | 
            +
             | 
| 21 | 
            +
            #
         | 
| 22 | 
            +
            #                       DO NOT EDIT!!!
         | 
| 23 | 
            +
            #    File automatically generated by killbill-java-parser (git@github.com:killbill/killbill-java-parser.git)
         | 
| 24 | 
            +
            #
         | 
| 25 | 
            +
             | 
| 26 | 
            +
             | 
| 27 | 
            +
            module Killbill
         | 
| 28 | 
            +
              module Plugin
         | 
| 29 | 
            +
                module Api
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  java_package 'org.killbill.billing'
         | 
| 32 | 
            +
                  class KillbillApi
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    include org.killbill.billing.KillbillApi
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                    def initialize(real_java_api)
         | 
| 37 | 
            +
                      @real_java_api = real_java_api
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
| @@ -86,6 +86,7 @@ require 'killbill/gen/api/invoice_item' | |
| 86 86 | 
             
            require 'killbill/gen/api/invoice_payment'
         | 
| 87 87 | 
             
            require 'killbill/gen/api/invoice_payment_api'
         | 
| 88 88 | 
             
            require 'killbill/gen/api/invoice_user_api'
         | 
| 89 | 
            +
            require 'killbill/gen/api/killbill_api'
         | 
| 89 90 | 
             
            require 'killbill/gen/api/plugin_config_service_api'
         | 
| 90 91 | 
             
            require 'killbill/gen/api/osgi_killbill'
         | 
| 91 92 | 
             
            require 'killbill/gen/api/osgi_plugin_properties'
         | 
| @@ -3,6 +3,37 @@ module Killbill | |
| 3 3 | 
             
                module ActiveMerchant
         | 
| 4 4 | 
             
                  module Helpers
         | 
| 5 5 |  | 
| 6 | 
            +
                    # In our profiling, we noticed that ActiveRecord::Sanitization::ClassMethods.sanitize_sql was taking
         | 
| 7 | 
            +
                    # about 50% of where queries calls time, mainly because of the String#gsub magic in ActiveRecord::Sanitization::ClassMethods.replace_bind_variables.
         | 
| 8 | 
            +
                    # We don't want to issue raw SQL because we still want to be able to support multiple back-ends (at least SQLite and MySQL),
         | 
| 9 | 
            +
                    # so we cache the quoted values (this should also give us SQL injection protection).
         | 
| 10 | 
            +
                    # The gain is not 50% but more around 30% due to the Mutex overhead in the cache
         | 
| 11 | 
            +
                    def build_quotes_cache(max_size=1000)
         | 
| 12 | 
            +
                      # See ::ActiveRecord::Sanitization::ClassMethods.quote_bound_value
         | 
| 13 | 
            +
                      quote_bound_value_proc = Proc.new { |value|
         | 
| 14 | 
            +
                        c = connection
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                        if value.respond_to?(:map) && !value.acts_like?(:string)
         | 
| 17 | 
            +
                          if value.respond_to?(:empty?) && value.empty?
         | 
| 18 | 
            +
                            c.quote(nil)
         | 
| 19 | 
            +
                          else
         | 
| 20 | 
            +
                            value.map { |v| c.quote(v) }.join(',')
         | 
| 21 | 
            +
                          end
         | 
| 22 | 
            +
                        else
         | 
| 23 | 
            +
                          c.quote(value)
         | 
| 24 | 
            +
                        end
         | 
| 25 | 
            +
                      }
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                      Killbill::Plugin::ActiveMerchant::Utils::BoundedLRUCache.new(quote_bound_value_proc, max_size)
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    def shared_activerecord_options
         | 
| 31 | 
            +
                      {
         | 
| 32 | 
            +
                          # We don't use validations -- small performance gain by bypassing the stack
         | 
| 33 | 
            +
                          :validate => false
         | 
| 34 | 
            +
                      }
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
             | 
| 6 37 | 
             
                    # Useful helper to extract params from AM response objects, e.g. extract(response, 'card', 'address_country')
         | 
| 7 38 | 
             
                    def extract(response, key1, key2=nil, key3=nil)
         | 
| 8 39 | 
             
                      return nil if response.nil? || response.params.nil?
         | 
| @@ -12,6 +12,8 @@ module Killbill | |
| 12 12 |  | 
| 13 13 | 
             
                      self.abstract_class = true
         | 
| 14 14 |  | 
| 15 | 
            +
                      @@quotes_cache = build_quotes_cache
         | 
| 16 | 
            +
             | 
| 15 17 | 
             
                      def self.from_response(kb_account_id, kb_payment_method_id, kb_tenant_id, cc_or_token, response, options, extra_params = {}, model = PaymentMethod)
         | 
| 16 18 | 
             
                        model.new({
         | 
| 17 19 | 
             
                                      :kb_account_id        => kb_account_id,
         | 
| @@ -35,17 +37,17 @@ module Killbill | |
| 35 37 |  | 
| 36 38 | 
             
                      def self.from_kb_account_id(kb_account_id, kb_tenant_id)
         | 
| 37 39 | 
             
                        if kb_tenant_id.nil?
         | 
| 38 | 
            -
                          where( | 
| 40 | 
            +
                          where("kb_account_id = #{@@quotes_cache[kb_account_id]} AND kb_tenant_id is NULL AND is_deleted = #{@@quotes_cache[false]}")
         | 
| 39 41 | 
             
                        else
         | 
| 40 | 
            -
                          where( | 
| 42 | 
            +
                          where("kb_account_id = #{@@quotes_cache[kb_account_id]} AND kb_tenant_id = #{@@quotes_cache[kb_tenant_id]} AND is_deleted = #{@@quotes_cache[false]}")
         | 
| 41 43 | 
             
                        end
         | 
| 42 44 | 
             
                      end
         | 
| 43 45 |  | 
| 44 46 | 
             
                      def self.from_kb_payment_method_id(kb_payment_method_id, kb_tenant_id)
         | 
| 45 47 | 
             
                        if kb_tenant_id.nil?
         | 
| 46 | 
            -
                          payment_methods = where( | 
| 48 | 
            +
                          payment_methods = where("kb_payment_method_id = #{@@quotes_cache[kb_payment_method_id]} AND kb_tenant_id is NULL AND is_deleted = #{@@quotes_cache[false]}")
         | 
| 47 49 | 
             
                        else
         | 
| 48 | 
            -
                          payment_methods = where( | 
| 50 | 
            +
                          payment_methods = where("kb_payment_method_id = #{@@quotes_cache[kb_payment_method_id]} AND kb_tenant_id = #{@@quotes_cache[kb_tenant_id]} AND is_deleted = #{@@quotes_cache[false]}")
         | 
| 49 51 | 
             
                        end
         | 
| 50 52 | 
             
                        raise "No payment method found for payment method #{kb_payment_method_id}" if payment_methods.empty?
         | 
| 51 53 | 
             
                        raise "Kill Bill payment method #{kb_payment_method_id} mapping to multiple active plugin payment methods" if payment_methods.size > 1
         | 
| @@ -55,7 +57,7 @@ module Killbill | |
| 55 57 | 
             
                      def self.mark_as_deleted!(kb_payment_method_id, kb_tenant_id)
         | 
| 56 58 | 
             
                        payment_method = from_kb_payment_method_id(kb_payment_method_id, kb_tenant_id)
         | 
| 57 59 | 
             
                        payment_method.is_deleted = true
         | 
| 58 | 
            -
                        payment_method.save!
         | 
| 60 | 
            +
                        payment_method.save!(shared_activerecord_options)
         | 
| 59 61 | 
             
                      end
         | 
| 60 62 |  | 
| 61 63 | 
             
                      # Override in your plugin if needed
         | 
| @@ -35,6 +35,46 @@ module Killbill | |
| 35 35 | 
             
                                  }.merge!(extra_params))
         | 
| 36 36 | 
             
                      end
         | 
| 37 37 |  | 
| 38 | 
            +
                      def self.create_response_and_transaction(identifier, transaction_model, api_call, kb_account_id, kb_payment_id, kb_payment_transaction_id, transaction_type, kb_tenant_id, am_response, amount_in_cents, currency, extra_params = {}, model = Response)
         | 
| 39 | 
            +
                        response, transaction, exception = nil
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                        # Rails wraps all create/save calls in a transaction. To speed things up, create a single transaction for both rows.
         | 
| 42 | 
            +
                        # This has a small gotcha in the unhappy path though (see below).
         | 
| 43 | 
            +
                        transaction do
         | 
| 44 | 
            +
                          # Save the response to our logs
         | 
| 45 | 
            +
                          response = from_response(api_call, kb_account_id, kb_payment_id, kb_payment_transaction_id, transaction_type, kb_tenant_id, am_response, extra_params, model)
         | 
| 46 | 
            +
                          response.save!(shared_activerecord_options)
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                          transaction = nil
         | 
| 49 | 
            +
                          txn_id      = response.txn_id
         | 
| 50 | 
            +
                          if response.success and !kb_payment_id.blank? and !txn_id.blank?
         | 
| 51 | 
            +
                            # Record the transaction
         | 
| 52 | 
            +
                            # Note that we want to avoid throwing an exception here because we don't want to rollback the response row
         | 
| 53 | 
            +
                            begin
         | 
| 54 | 
            +
                              # Originally, we used response.send("build_#{identifier}_transaction"), but the ActiveRecord magic was adding
         | 
| 55 | 
            +
                              # about 20% overhead - instead, we now construct the transaction record manually
         | 
| 56 | 
            +
                              transaction = transaction_model.new(:kb_account_id              => kb_account_id,
         | 
| 57 | 
            +
                                                                  :kb_tenant_id               => kb_tenant_id,
         | 
| 58 | 
            +
                                                                  :amount_in_cents            => amount_in_cents,
         | 
| 59 | 
            +
                                                                  :currency                   => currency,
         | 
| 60 | 
            +
                                                                  :api_call                   => api_call,
         | 
| 61 | 
            +
                                                                  :kb_payment_id              => kb_payment_id,
         | 
| 62 | 
            +
                                                                  :kb_payment_transaction_id  => kb_payment_transaction_id,
         | 
| 63 | 
            +
                                                                  :transaction_type           => transaction_type,
         | 
| 64 | 
            +
                                                                  :txn_id                     => txn_id,
         | 
| 65 | 
            +
                                                                  "#{identifier}_response_id" => response.id)
         | 
| 66 | 
            +
                              transaction.save!(shared_activerecord_options)
         | 
| 67 | 
            +
                            rescue => e
         | 
| 68 | 
            +
                              exception = e
         | 
| 69 | 
            +
                            end
         | 
| 70 | 
            +
                          end
         | 
| 71 | 
            +
                        end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                        raise exception unless exception.nil?
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                        return response, transaction
         | 
| 76 | 
            +
                      end
         | 
| 77 | 
            +
             | 
| 38 78 | 
             
                      def to_transaction_info_plugin(transaction=nil)
         | 
| 39 79 | 
             
                        if transaction.nil?
         | 
| 40 80 | 
             
                          amount_in_cents = nil
         | 
| @@ -6,9 +6,14 @@ module Killbill | |
| 6 6 |  | 
| 7 7 | 
             
                    class Transaction < ::ActiveRecord::Base
         | 
| 8 8 |  | 
| 9 | 
            +
                      extend ::Killbill::Plugin::ActiveMerchant::Helpers
         | 
| 10 | 
            +
             | 
| 9 11 | 
             
                      self.abstract_class = true
         | 
| 10 12 |  | 
| 13 | 
            +
                      @@quotes_cache = build_quotes_cache
         | 
| 14 | 
            +
             | 
| 11 15 | 
             
                      class << self
         | 
| 16 | 
            +
             | 
| 12 17 | 
             
                        def transactions_from_kb_payment_id(kb_payment_id, kb_tenant_id)
         | 
| 13 18 | 
             
                          where(:kb_payment_id => kb_payment_id, :kb_tenant_id => kb_tenant_id).order(:created_at)
         | 
| 14 19 | 
             
                        end
         | 
| @@ -44,15 +49,14 @@ module Killbill | |
| 44 49 | 
             
                        def do_find_candidate_transaction_for_refund(api_call, kb_payment_id, kb_tenant_id, amount_in_cents)
         | 
| 45 50 | 
             
                          # Find one successful charge which amount is at least the amount we are trying to refund
         | 
| 46 51 | 
             
                          if kb_tenant_id.nil?
         | 
| 47 | 
            -
                            transactions = where( | 
| 52 | 
            +
                            transactions = where("amount_in_cents >= #{@@quotes_cache[amount_in_cents]} AND api_call = #{@@quotes_cache[api_call]} AND kb_tenant_id is NULL AND kb_payment_id = #{@@quotes_cache[kb_payment_id]}").order(:created_at)
         | 
| 48 53 | 
             
                          else
         | 
| 49 | 
            -
                            transactions = where( | 
| 54 | 
            +
                            transactions = where("amount_in_cents >= #{@@quotes_cache[amount_in_cents]} AND api_call = #{@@quotes_cache[api_call]} AND kb_tenant_id = #{@@quotes_cache[kb_tenant_id]} AND kb_payment_id = #{@@quotes_cache[kb_payment_id]}").order(:created_at)
         | 
| 50 55 | 
             
                          end
         | 
| 51 56 | 
             
                          raise "Unable to find transaction for payment #{kb_payment_id} and api_call #{api_call}" if transactions.size == 0
         | 
| 52 57 |  | 
| 53 58 | 
             
                          # We have candidates, but we now need to make sure we didn't refund more than for the specified amount
         | 
| 54 | 
            -
                          amount_refunded_in_cents = where( | 
| 55 | 
            -
                                                     .sum('amount_in_cents')
         | 
| 59 | 
            +
                          amount_refunded_in_cents = where("api_call = #{@@quotes_cache['refund']} and kb_payment_id = #{@@quotes_cache[kb_payment_id]}").sum('amount_in_cents')
         | 
| 56 60 |  | 
| 57 61 | 
             
                          amount_left_to_refund_in_cents = -amount_refunded_in_cents
         | 
| 58 62 | 
             
                          transactions.map { |transaction| amount_left_to_refund_in_cents += transaction.amount_in_cents }
         | 
| @@ -67,13 +71,13 @@ module Killbill | |
| 67 71 | 
             
                              if transaction_type.nil?
         | 
| 68 72 | 
             
                                transactions = where("kb_tenant_id is NULL AND #{attribute.to_s} = ?", attribute_value).order(:created_at)
         | 
| 69 73 | 
             
                              else
         | 
| 70 | 
            -
                                transactions = where("transaction_type =  | 
| 74 | 
            +
                                transactions = where("transaction_type = #{@@quotes_cache[transaction_type]} AND kb_tenant_id is NULL AND #{attribute.to_s} = #{@@quotes_cache[attribute_value]}").order(:created_at)
         | 
| 71 75 | 
             
                              end
         | 
| 72 76 | 
             
                            else
         | 
| 73 77 | 
             
                              if transaction_type.nil?
         | 
| 74 | 
            -
                                transactions = where("kb_tenant_id =  | 
| 78 | 
            +
                                transactions = where("kb_tenant_id = #{@@quotes_cache[kb_tenant_id]} AND #{attribute.to_s} = #{@@quotes_cache[attribute_value]}").order(:created_at)
         | 
| 75 79 | 
             
                              else
         | 
| 76 | 
            -
                                transactions = where("transaction_type =  | 
| 80 | 
            +
                                transactions = where("transaction_type = #{@@quotes_cache[transaction_type]} AND kb_tenant_id = #{@@quotes_cache[kb_tenant_id]} AND #{attribute.to_s} = #{@@quotes_cache[attribute_value]}").order(:created_at)
         | 
| 77 81 | 
             
                              end
         | 
| 78 82 | 
             
                            end
         | 
| 79 83 | 
             
                            if how_many == :single
         | 
| @@ -152,7 +152,7 @@ module Killbill | |
| 152 152 | 
             
                    end
         | 
| 153 153 |  | 
| 154 154 | 
             
                    def add_payment_method(kb_account_id, kb_payment_method_id, payment_method_props, set_default, properties, context)
         | 
| 155 | 
            -
                      all_properties | 
| 155 | 
            +
                      all_properties        = (payment_method_props.nil? || payment_method_props.properties.nil? ? [] : payment_method_props.properties) + properties
         | 
| 156 156 | 
             
                      options               = properties_to_hash(properties)
         | 
| 157 157 | 
             
                      options[:set_default] ||= set_default
         | 
| 158 158 | 
             
                      options[:order_id]    ||= kb_payment_method_id
         | 
| @@ -401,27 +401,10 @@ module Killbill | |
| 401 401 | 
             
                    def save_response_and_transaction(response, api_call, kb_account_id, kb_tenant_id, kb_payment_id=nil, kb_payment_transaction_id=nil, transaction_type=nil, amount_in_cents=0, currency=nil)
         | 
| 402 402 | 
             
                      @logger.warn "Unsuccessful #{api_call}: #{response.message}" unless response.success?
         | 
| 403 403 |  | 
| 404 | 
            -
                       | 
| 405 | 
            -
             | 
| 406 | 
            -
                       | 
| 407 | 
            -
             | 
| 408 | 
            -
                      transaction = nil
         | 
| 409 | 
            -
                      txn_id      = response.txn_id
         | 
| 410 | 
            -
                      if response.success and !kb_payment_id.blank? and !txn_id.blank?
         | 
| 411 | 
            -
                        # Record the transaction
         | 
| 412 | 
            -
                        transaction = response.send("create_#{@identifier}_transaction!",
         | 
| 413 | 
            -
                                                    :kb_account_id             => kb_account_id,
         | 
| 414 | 
            -
                                                    :kb_tenant_id              => kb_tenant_id,
         | 
| 415 | 
            -
                                                    :amount_in_cents           => amount_in_cents,
         | 
| 416 | 
            -
                                                    :currency                  => currency,
         | 
| 417 | 
            -
                                                    :api_call                  => api_call,
         | 
| 418 | 
            -
                                                    :kb_payment_id             => kb_payment_id,
         | 
| 419 | 
            -
                                                    :kb_payment_transaction_id => kb_payment_transaction_id,
         | 
| 420 | 
            -
                                                    :transaction_type          => transaction_type,
         | 
| 421 | 
            -
                                                    :txn_id                    => txn_id)
         | 
| 422 | 
            -
             | 
| 423 | 
            -
                        @logger.debug "Recorded transaction: #{transaction.inspect}"
         | 
| 424 | 
            -
                      end
         | 
| 404 | 
            +
                      response, transaction = @response_model.create_response_and_transaction(@identifier, @transaction_model, api_call, kb_account_id, kb_payment_id, kb_payment_transaction_id, transaction_type, kb_tenant_id, response, amount_in_cents, currency, {}, @response_model)
         | 
| 405 | 
            +
             | 
| 406 | 
            +
                      @logger.debug "Recorded transaction: #{transaction.inspect}" unless transaction.nil?
         | 
| 407 | 
            +
             | 
| 425 408 | 
             
                      return response, transaction
         | 
| 426 409 | 
             
                    end
         | 
| 427 410 |  | 
| @@ -7,15 +7,53 @@ module Killbill | |
| 7 7 |  | 
| 8 8 | 
             
                    def self.compact_uuid(uuid)
         | 
| 9 9 | 
             
                      uuid = uuid.gsub(/-/, '')
         | 
| 10 | 
            -
                      uuid.hex.base(62).map{ |i| BASE62[i].chr } * ''
         | 
| 10 | 
            +
                      uuid.hex.base(62).map { |i| BASE62[i].chr } * ''
         | 
| 11 11 | 
             
                    end
         | 
| 12 12 |  | 
| 13 13 | 
             
                    def self.unpack_uuid(base62_uuid)
         | 
| 14 | 
            -
                      as_hex | 
| 14 | 
            +
                      as_hex     = base62_uuid.split(//).inject(0) { |i, e| i*62 + BASE62.index(e[0]) }
         | 
| 15 15 | 
             
                      no_hyphens = "%x" % as_hex
         | 
| 16 16 | 
             
                      no_hyphens = '0' * (32 - no_hyphens.size) + no_hyphens
         | 
| 17 17 | 
             
                      no_hyphens.insert(8, "-").insert(13, "-").insert(18, "-").insert(23, "-")
         | 
| 18 18 | 
             
                    end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    # Relies on the fact that hashes enumerate their values in the order that the corresponding keys were inserted (Ruby 1.9+)
         | 
| 21 | 
            +
                    class BoundedLRUCache
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                      def initialize(proc, max_size=1000)
         | 
| 24 | 
            +
                        @proc     = proc
         | 
| 25 | 
            +
                        @max_size = max_size
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                        @semaphore = Mutex.new
         | 
| 28 | 
            +
                        # TODO Pre-allocate?
         | 
| 29 | 
            +
                        @data      = {}
         | 
| 30 | 
            +
                      end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                      def [](key)
         | 
| 33 | 
            +
                        @semaphore.synchronize do
         | 
| 34 | 
            +
                          found = true
         | 
| 35 | 
            +
                          value = @data.delete(key) { found = false }
         | 
| 36 | 
            +
                          if found
         | 
| 37 | 
            +
                            @data[key] = value
         | 
| 38 | 
            +
                          else
         | 
| 39 | 
            +
                            value      = @proc.call(key)
         | 
| 40 | 
            +
                            @data[key] = value
         | 
| 41 | 
            +
                            value
         | 
| 42 | 
            +
                          end
         | 
| 43 | 
            +
                        end
         | 
| 44 | 
            +
                      end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                      def []=(key, val)
         | 
| 47 | 
            +
                        @semaphore.synchronize do
         | 
| 48 | 
            +
                          @data.delete(key)
         | 
| 49 | 
            +
                          @data[key] = val
         | 
| 50 | 
            +
                          if @data.length > @max_size
         | 
| 51 | 
            +
                            @data.delete(@data.first[0])
         | 
| 52 | 
            +
                          end
         | 
| 53 | 
            +
                          val
         | 
| 54 | 
            +
                        end
         | 
| 55 | 
            +
                      end
         | 
| 56 | 
            +
                    end
         | 
| 19 57 | 
             
                  end
         | 
| 20 58 | 
             
                end
         | 
| 21 59 | 
             
              end
         | 
| @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'spec/killbill/helpers/transaction_spec'
         | 
| 2 3 |  | 
| 3 4 | 
             
            module Killbill #:nodoc:
         | 
| 4 5 | 
             
              module Test #:nodoc:
         | 
| @@ -6,6 +7,8 @@ module Killbill #:nodoc: | |
| 6 7 |  | 
| 7 8 | 
             
                  self.table_name = 'test_responses'
         | 
| 8 9 |  | 
| 10 | 
            +
                  has_one :test_transaction
         | 
| 11 | 
            +
             | 
| 9 12 | 
             
                end
         | 
| 10 13 | 
             
              end
         | 
| 11 14 | 
             
            end
         | 
| @@ -66,6 +69,37 @@ describe Killbill::Plugin::ActiveMerchant::ActiveRecord::Response do | |
| 66 69 | 
             
                ptip.properties.size.should == 11
         | 
| 67 70 | 
             
              end
         | 
| 68 71 |  | 
| 72 | 
            +
              it 'should create responses and transactions correctly' do
         | 
| 73 | 
            +
                api_call                  = 'for debugging only'
         | 
| 74 | 
            +
                kb_account_id             = SecureRandom.uuid
         | 
| 75 | 
            +
                kb_payment_id             = SecureRandom.uuid
         | 
| 76 | 
            +
                kb_payment_transaction_id = SecureRandom.uuid
         | 
| 77 | 
            +
                transaction_type          = :PURCHASE
         | 
| 78 | 
            +
                kb_tenant_id              = SecureRandom.uuid
         | 
| 79 | 
            +
                success_response          = ::ActiveMerchant::Billing::Response.new(true, 'Message', {}, {
         | 
| 80 | 
            +
                    :authorization => SecureRandom.uuid,
         | 
| 81 | 
            +
                    :avs_result    => ::ActiveMerchant::Billing::AVSResult.new(:code => 'P')
         | 
| 82 | 
            +
                })
         | 
| 83 | 
            +
                failure_response          = ::ActiveMerchant::Billing::Response.new(false, 'Message', {}, {
         | 
| 84 | 
            +
                    :authorization => SecureRandom.uuid,
         | 
| 85 | 
            +
                    :avs_result    => ::ActiveMerchant::Billing::AVSResult.new(:code => 'P')
         | 
| 86 | 
            +
                })
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                response, transaction = ::Killbill::Test::TestResponse.create_response_and_transaction('test', ::Killbill::Test::TestTransaction, api_call, kb_account_id, kb_payment_id, kb_payment_transaction_id, transaction_type, kb_tenant_id, success_response, 120, 'USD', {}, ::Killbill::Test::TestResponse)
         | 
| 89 | 
            +
                found_response        = ::Killbill::Test::TestResponse.find(response.id)
         | 
| 90 | 
            +
                found_response.should == response
         | 
| 91 | 
            +
                found_response.test_transaction.should == transaction
         | 
| 92 | 
            +
                found_transaction = ::Killbill::Test::TestTransaction.find(transaction.id)
         | 
| 93 | 
            +
                found_transaction.should == transaction
         | 
| 94 | 
            +
                found_transaction.test_response.should == response
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                response, transaction = ::Killbill::Test::TestResponse.create_response_and_transaction('test', ::Killbill::Test::TestTransaction, api_call, kb_account_id, kb_payment_id, kb_payment_transaction_id, transaction_type, kb_tenant_id, failure_response, 120, 'USD', {}, ::Killbill::Test::TestResponse)
         | 
| 97 | 
            +
                transaction.should be_nil
         | 
| 98 | 
            +
                found_response = ::Killbill::Test::TestResponse.find(response.id)
         | 
| 99 | 
            +
                found_response.should == response
         | 
| 100 | 
            +
                found_response.test_transaction.should be_nil
         | 
| 101 | 
            +
              end
         | 
| 102 | 
            +
             | 
| 69 103 | 
             
              it 'should generate the right SQL query' do
         | 
| 70 104 | 
             
                # Check count query (search query numeric)
         | 
| 71 105 | 
             
                expected_query = "SELECT COUNT(DISTINCT \"test_responses\".\"id\") FROM \"test_responses\"  WHERE ((((\"test_responses\".\"kb_payment_id\" = '1234' OR \"test_responses\".\"kb_payment_transaction_id\" = '1234') OR \"test_responses\".\"message\" = '1234') OR \"test_responses\".\"authorization\" = '1234') OR \"test_responses\".\"fraud_review\" = '1234') AND \"test_responses\".\"success\" = 't' AND \"test_responses\".\"kb_tenant_id\" = '11-22-33'  ORDER BY \"test_responses\".\"id\""
         | 
| @@ -27,11 +27,12 @@ ActiveRecord::Schema.define(:version => 20140410153635) do | |
| 27 27 | 
             
              add_index(:test_payment_methods, :kb_payment_method_id)
         | 
| 28 28 |  | 
| 29 29 | 
             
              create_table "test_transactions", :force => true do |t|
         | 
| 30 | 
            -
                t.integer  " | 
| 30 | 
            +
                t.integer  "test_response_id",          :null => false
         | 
| 31 31 | 
             
                t.string   "api_call",                  :null => false
         | 
| 32 32 | 
             
                t.string   "kb_payment_id",             :null => false
         | 
| 33 33 | 
             
                t.string   "kb_payment_transaction_id", :null => false
         | 
| 34 34 | 
             
                t.string   "transaction_type",          :null => false
         | 
| 35 | 
            +
                t.string   "txn_id"
         | 
| 35 36 | 
             
                t.integer  "amount_in_cents",           :null => false
         | 
| 36 37 | 
             
                t.string   "currency",                  :null => false
         | 
| 37 38 | 
             
                t.datetime "created_at",                :null => false
         | 
| @@ -43,7 +44,7 @@ ActiveRecord::Schema.define(:version => 20140410153635) do | |
| 43 44 | 
             
              add_index(:test_transactions, :kb_payment_id)
         | 
| 44 45 |  | 
| 45 46 | 
             
              create_table "test_responses", :force => true do |t|
         | 
| 46 | 
            -
                t.string   "api_call", | 
| 47 | 
            +
                t.string   "api_call",          :null => false
         | 
| 47 48 | 
             
                t.string   "kb_payment_id"
         | 
| 48 49 | 
             
                t.string   "kb_payment_transaction_id"
         | 
| 49 50 | 
             
                t.string   "transaction_type"
         | 
| @@ -6,6 +6,8 @@ module Killbill #:nodoc: | |
| 6 6 |  | 
| 7 7 | 
             
                  self.table_name = 'test_transactions'
         | 
| 8 8 |  | 
| 9 | 
            +
                  belongs_to :test_response
         | 
| 10 | 
            +
             | 
| 9 11 | 
             
                end
         | 
| 10 12 | 
             
              end
         | 
| 11 13 | 
             
            end
         | 
| @@ -129,6 +131,6 @@ describe Killbill::Plugin::ActiveMerchant::ActiveRecord::Transaction do | |
| 129 131 | 
             
                                                         :currency                  => currency,
         | 
| 130 132 | 
             
                                                         :kb_account_id             => kb_account_id,
         | 
| 131 133 | 
             
                                                         :kb_tenant_id              => kb_tenant_id,
         | 
| 132 | 
            -
                                                         : | 
| 134 | 
            +
                                                         :test_response_id          => 0)
         | 
| 133 135 | 
             
              end
         | 
| 134 136 | 
             
            end
         | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: killbill
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 3.1. | 
| 4 | 
            +
              version: 3.1.6
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Kill Bill core team
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2014-07 | 
| 11 | 
            +
            date: 2014-08-07 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: sinatra
         | 
| @@ -247,6 +247,7 @@ files: | |
| 247 247 | 
             
            - lib/killbill/gen/api/invoice_payment.rb
         | 
| 248 248 | 
             
            - lib/killbill/gen/api/invoice_payment_api.rb
         | 
| 249 249 | 
             
            - lib/killbill/gen/api/invoice_user_api.rb
         | 
| 250 | 
            +
            - lib/killbill/gen/api/killbill_api.rb
         | 
| 250 251 | 
             
            - lib/killbill/gen/api/limit.rb
         | 
| 251 252 | 
             
            - lib/killbill/gen/api/listing.rb
         | 
| 252 253 | 
             
            - lib/killbill/gen/api/migration_plan.rb
         |