adyen 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/.travis.yml +8 -0
- data/Gemfile +2 -0
- data/README.rdoc +13 -22
- data/adyen.gemspec +12 -5
- data/lib/adyen.rb +2 -1
- data/lib/adyen/api.rb +42 -20
- data/lib/adyen/api/payment_service.rb +12 -10
- data/lib/adyen/api/recurring_service.rb +44 -16
- data/lib/adyen/api/response.rb +7 -0
- data/lib/adyen/api/simple_soap_client.rb +15 -10
- data/lib/adyen/api/templates/recurring_service.rb +12 -0
- data/lib/adyen/templates/notification_model.rb +2 -2
- data/spec/api/api_spec.rb +11 -0
- data/spec/api/payment_service_spec.rb +12 -13
- data/spec/api/recurring_service_spec.rb +42 -2
- data/spec/api/response_spec.rb +24 -0
- data/spec/api/simple_soap_client_spec.rb +51 -9
- data/spec/api/spec_helper.rb +15 -0
- data/spec/functional/api_spec.rb +17 -8
- data/spec/spec_helper.rb +1 -3
- data/tasks/github-gem.rake +7 -5
- metadata +22 -16
    
        data/.gitignore
    CHANGED
    
    
    
        data/.travis.yml
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/README.rdoc
    CHANGED
    
    | @@ -2,6 +2,8 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            Package to simplify including the Adyen payments services into a Ruby on Rails application.
         | 
| 4 4 |  | 
| 5 | 
            +
            Visit the wiki for documentation: https://github.com/wvanbergen/adyen/wiki.
         | 
| 6 | 
            +
             | 
| 5 7 | 
             
            Adyen integration relies on three modes of communication between Adyen, your server and
         | 
| 6 8 | 
             
            your client/customer:
         | 
| 7 9 |  | 
| @@ -13,30 +15,9 @@ This library aims to ease the implementation of all these modes into your applic | |
| 13 15 | 
             
            Moreover, it provides matchers, assertions and mocks to make it easier to implement an
         | 
| 14 16 | 
             
            automated test suite to assert the integration is working correctly.
         | 
| 15 17 |  | 
| 16 | 
            -
            == Installation
         | 
| 17 | 
            -
             | 
| 18 | 
            -
            <b>Bundler / Rails 3</b>: Add the following line to your <tt>Gemfile</tt>:
         | 
| 19 | 
            -
             | 
| 20 | 
            -
              gem 'adyen'
         | 
| 21 | 
            -
             | 
| 22 | 
            -
            <b>Rails 2.x</b>: Add the following line to your <tt>environment.rb</tt> and run <tt>rake gems:install</tt>
         | 
| 23 | 
            -
            to make the Adyen functionality available in your Rails project:
         | 
| 24 | 
            -
             | 
| 25 | 
            -
              config.gem 'adyen'
         | 
| 26 | 
            -
             | 
| 27 | 
            -
            The Adyen gem will happily use REXML for communication with Adyen’s SOAP API, however, if
         | 
| 28 | 
            -
            you have the Nokogiri gem installed and required the gem will use that for performance.
         | 
| 29 | 
            -
             | 
| 30 | 
            -
            == Generators
         | 
| 31 | 
            -
             | 
| 32 | 
            -
            The gem ships with a generator for Rails 3. To create an ActiveRecord migration, mode, and
         | 
| 33 | 
            -
            ActionController for the notifications send by Adyen, run the following:
         | 
| 34 | 
            -
             | 
| 35 | 
            -
              $ rails generate adyen:notification
         | 
| 36 | 
            -
             | 
| 37 18 | 
             
            == Usage
         | 
| 38 19 |  | 
| 39 | 
            -
            See the project wiki on  | 
| 20 | 
            +
            See the project wiki on https://github.com/wvanbergen/adyen/wiki to get started. Complete
         | 
| 40 21 | 
             
            RDoc documentation for the project can be found on http://rdoc.info/projects/wvanbergen/adyen.
         | 
| 41 22 |  | 
| 42 23 | 
             
            * For more information about Adyen, see http://www.adyen.com
         | 
| @@ -49,3 +30,13 @@ This package is written by Michel Barbosa and Willem van Bergen for Floorplanner | |
| 49 30 | 
             
            made public under the MIT license (see LICENSE). Its is currently maintained by Willem van
         | 
| 50 31 | 
             
            Bergen, Stefan Borsje and Eloy Duran. We are not affiliated with Adyen B.V. The software 
         | 
| 51 32 | 
             
            comes without warranty of any kind, so use at your own risk.
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            Contributions are welcomed; this is very much a scratch your own itch project. Some notes:
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            * Fork the project, implement your stuff and issue a pull request. Topic branches not necessary.
         | 
| 37 | 
            +
            * All functionality must include tests and preferably documentation.
         | 
| 38 | 
            +
            * New SOAP API calls should include functional tests that actually test if the call is working. 
         | 
| 39 | 
            +
              Adyen has a nasty tendency to switch things up every now and then, so this is vital.
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            Please visit the changelog at https://github.com/wvanbergen/adyen/wiki/Changelog to see the 
         | 
| 42 | 
            +
            changes in the different releases.
         | 
    
        data/adyen.gemspec
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            Gem::Specification.new do |s|
         | 
| 2 2 | 
             
              s.name    = 'adyen'
         | 
| 3 | 
            -
              s.version = "1. | 
| 4 | 
            -
              s.date    = "2011- | 
| 3 | 
            +
              s.version = "1.3.0"
         | 
| 4 | 
            +
              s.date    = "2011-10-10"
         | 
| 5 5 |  | 
| 6 6 | 
             
              s.summary = "Integrate Adyen payment services in your Ruby on Rails application."
         | 
| 7 7 | 
             
              s.description = <<-EOS
         | 
| @@ -16,15 +16,22 @@ Gem::Specification.new do |s| | |
| 16 16 | 
             
              s.homepage = 'http://github.com/wvanbergen/adyen/wiki'
         | 
| 17 17 |  | 
| 18 18 | 
             
              s.add_development_dependency('rake')
         | 
| 19 | 
            -
              s.add_development_dependency('rspec', '~> 2 | 
| 20 | 
            -
              s.add_development_dependency('nokogiri')
         | 
| 19 | 
            +
              s.add_development_dependency('rspec', '~> 2')
         | 
| 21 20 | 
             
              s.add_development_dependency('rails', '>= 2.3')
         | 
| 22 21 |  | 
| 22 | 
            +
              if RUBY_PLATFORM == 'java'
         | 
| 23 | 
            +
                s.add_development_dependency('nokogiri', '~> 1.4.6')
         | 
| 24 | 
            +
              else
         | 
| 25 | 
            +
                s.add_development_dependency('nokogiri')
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
              
         | 
| 28 | 
            +
              s.add_runtime_dependency('jruby-openssl') if RUBY_PLATFORM == 'java'
         | 
| 29 | 
            +
              
         | 
| 23 30 | 
             
              s.requirements << 'Having Nokogiri installed will speed up XML handling when using the SOAP API.'
         | 
| 24 31 |  | 
| 25 32 | 
             
              s.rdoc_options << '--title' << s.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
         | 
| 26 33 | 
             
              s.extra_rdoc_files = ['README.rdoc']
         | 
| 27 34 |  | 
| 28 | 
            -
              s.files = %w(.gitignore .kick LICENSE README.rdoc Rakefile TODO adyen.gemspec lib/adyen.rb lib/adyen/api.rb lib/adyen/api/cacert.pem lib/adyen/api/payment_service.rb lib/adyen/api/recurring_service.rb lib/adyen/api/response.rb lib/adyen/api/simple_soap_client.rb lib/adyen/api/templates/payment_service.rb lib/adyen/api/templates/recurring_service.rb lib/adyen/api/test_helpers.rb lib/adyen/api/xml_querier.rb lib/adyen/configuration.rb lib/adyen/encoding.rb lib/adyen/form.rb lib/adyen/formatter.rb lib/adyen/matchers.rb lib/adyen/notification_generator.rb lib/adyen/railtie.rb lib/adyen/templates/notification_migration.rb lib/adyen/templates/notification_model.rb spec/adyen_spec.rb spec/api/api_spec.rb spec/api/payment_service_spec.rb spec/api/recurring_service_spec.rb spec/api/response_spec.rb spec/api/simple_soap_client_spec.rb spec/api/spec_helper.rb spec/api/test_helpers_spec.rb spec/form_spec.rb spec/functional/api_spec.rb spec/functional/initializer.rb.sample spec/spec_helper.rb tasks/github-gem.rake yard_extensions.rb)
         | 
| 35 | 
            +
              s.files = %w(.gitignore .kick .travis.yml Gemfile LICENSE README.rdoc Rakefile TODO adyen.gemspec lib/adyen.rb lib/adyen/api.rb lib/adyen/api/cacert.pem lib/adyen/api/payment_service.rb lib/adyen/api/recurring_service.rb lib/adyen/api/response.rb lib/adyen/api/simple_soap_client.rb lib/adyen/api/templates/payment_service.rb lib/adyen/api/templates/recurring_service.rb lib/adyen/api/test_helpers.rb lib/adyen/api/xml_querier.rb lib/adyen/configuration.rb lib/adyen/encoding.rb lib/adyen/form.rb lib/adyen/formatter.rb lib/adyen/matchers.rb lib/adyen/notification_generator.rb lib/adyen/railtie.rb lib/adyen/templates/notification_migration.rb lib/adyen/templates/notification_model.rb spec/adyen_spec.rb spec/api/api_spec.rb spec/api/payment_service_spec.rb spec/api/recurring_service_spec.rb spec/api/response_spec.rb spec/api/simple_soap_client_spec.rb spec/api/spec_helper.rb spec/api/test_helpers_spec.rb spec/form_spec.rb spec/functional/api_spec.rb spec/functional/initializer.rb.sample spec/spec_helper.rb tasks/github-gem.rake yard_extensions.rb)
         | 
| 29 36 | 
             
              s.test_files = %w(spec/adyen_spec.rb spec/api/api_spec.rb spec/api/payment_service_spec.rb spec/api/recurring_service_spec.rb spec/api/response_spec.rb spec/api/simple_soap_client_spec.rb spec/api/test_helpers_spec.rb spec/form_spec.rb spec/functional/api_spec.rb)
         | 
| 30 37 | 
             
            end
         | 
    
        data/lib/adyen.rb
    CHANGED
    
    | @@ -12,7 +12,7 @@ module Adyen | |
| 12 12 | 
             
              # Version constant for the Adyen plugin.
         | 
| 13 13 | 
             
              # DO NOT CHANGE THIS VALUE BY HAND. It will be updated automatically by
         | 
| 14 14 | 
             
              # the gem:release rake task.
         | 
| 15 | 
            -
              VERSION = "1. | 
| 15 | 
            +
              VERSION = "1.3.0"
         | 
| 16 16 |  | 
| 17 17 | 
             
              # @return [Configuration] The configuration singleton.
         | 
| 18 18 | 
             
              def self.configuration
         | 
| @@ -24,5 +24,6 @@ require 'adyen/configuration' | |
| 24 24 | 
             
            require 'adyen/encoding'
         | 
| 25 25 | 
             
            require 'adyen/formatter'
         | 
| 26 26 | 
             
            require 'adyen/form'
         | 
| 27 | 
            +
            require 'adyen/api'
         | 
| 27 28 |  | 
| 28 29 | 
             
            require 'adyen/railtie' if defined?(::Rails) && ::Rails::VERSION::MAJOR >= 3
         | 
    
        data/lib/adyen/api.rb
    CHANGED
    
    | @@ -57,14 +57,15 @@ module Adyen | |
| 57 57 | 
             
                #     invoice.id,
         | 
| 58 58 | 
             
                #     { :currency => 'EUR', :value => invoice.amount },
         | 
| 59 59 | 
             
                #     { :reference => user.id, :email => user.email, :ip => '8.8.8.8' },
         | 
| 60 | 
            -
                #     { :holder_name => "Simon Hopper", :number => '4444333322221111', :cvc => '737', | 
| 60 | 
            +
                #     { :holder_name => "Simon Hopper", :number => '4444333322221111', :cvc => '737',
         | 
| 61 | 
            +
                #       :expiry_month => 12, :expiry_year => 2012 }
         | 
| 61 62 | 
             
                #   )
         | 
| 62 63 | 
             
                #   response.authorised? # => true
         | 
| 63 64 | 
             
                #
         | 
| 64 65 | 
             
                # @param          [Numeric,String] reference      Your reference (ID) for this payment.
         | 
| 65 66 | 
             
                # @param          [Hash]           amount         A hash describing the money to charge.
         | 
| 66 67 | 
             
                # @param          [Hash]           shopper        A hash describing the shopper.
         | 
| 67 | 
            -
                # @param          [Hash]           card           A hash describing the  | 
| 68 | 
            +
                # @param          [Hash]           card           A hash describing the credit card details.
         | 
| 68 69 | 
             
                #
         | 
| 69 70 | 
             
                # @option amount  [String]         :currency      The ISO currency code (EUR, GBP, USD, etc).
         | 
| 70 71 | 
             
                # @option amount  [Integer]        :value         The value of the payment in discrete cents,
         | 
| @@ -278,15 +279,25 @@ module Adyen | |
| 278 279 | 
             
                  }).disable
         | 
| 279 280 | 
             
                end
         | 
| 280 281 |  | 
| 281 | 
            -
                # Stores and tokenises the  | 
| 282 | 
            -
                # future.
         | 
| 282 | 
            +
                # Stores and tokenises the payment details so that recurring payments can be made in the
         | 
| 283 | 
            +
                # future. It can be either a credit card or ELV (Elektronisches Lastschriftverfahren).
         | 
| 283 284 | 
             
                #
         | 
| 284 | 
            -
                #  | 
| 285 | 
            +
                #  For instance, this is how you would store credit card details:
         | 
| 285 286 | 
             
                #
         | 
| 286 287 | 
             
                # # @example
         | 
| 287 288 | 
             
                #   response = Adyen::API.store_recurring_token(
         | 
| 288 289 | 
             
                #     { :reference => user.id, :email => user.email, :ip => '8.8.8.8' },
         | 
| 289 | 
            -
                #     { :holder_name => "Simon Hopper", :number => '4444333322221111', | 
| 290 | 
            +
                #     { :holder_name => "Simon Hopper", :number => '4444333322221111',
         | 
| 291 | 
            +
                #       :expiry_month => 12, :expiry_year => 2012 }
         | 
| 292 | 
            +
                #   )
         | 
| 293 | 
            +
                #
         | 
| 294 | 
            +
                # Or use the following to store ELV details:
         | 
| 295 | 
            +
                #
         | 
| 296 | 
            +
                # # @example
         | 
| 297 | 
            +
                #   response = Adyen::API.store_recurring_token(
         | 
| 298 | 
            +
                #     { :reference => user.id, :email => user.email, :ip => '8.8.8.8' },
         | 
| 299 | 
            +
                #     { :bank_location => "Berlin", :bank_name => "TestBank", :bank_location_id => "12345678",
         | 
| 300 | 
            +
                #       :holder_name => "Simon Hopper", :number => "1234567890" }
         | 
| 290 301 | 
             
                #   )
         | 
| 291 302 | 
             
                #   response.stored? # => true
         | 
| 292 303 | 
             
                #
         | 
| @@ -299,24 +310,35 @@ module Adyen | |
| 299 310 | 
             
                #   )
         | 
| 300 311 | 
             
                #   authorize_response.authorised? # => true
         | 
| 301 312 | 
             
                #
         | 
| 302 | 
            -
                # @param | 
| 303 | 
            -
                #  | 
| 313 | 
            +
                # @param            [Hash]           params                A hash describing the credit card or
         | 
| 314 | 
            +
                #                                                          ELV details.
         | 
| 304 315 | 
             
                #
         | 
| 305 | 
            -
                # @option shopper | 
| 306 | 
            -
                # @option shopper | 
| 307 | 
            -
                # @option shopper | 
| 316 | 
            +
                # @option shopper   [Numeric,String] :reference            The shopper’s reference (ID).
         | 
| 317 | 
            +
                # @option shopper   [String]         :email                The shopper’s email address.
         | 
| 318 | 
            +
                # @option shopper   [String]         :ip                   The shopper’s IP address.
         | 
| 308 319 | 
             
                #
         | 
| 309 | 
            -
                # @option  | 
| 310 | 
            -
                #  | 
| 311 | 
            -
                # @option  | 
| 312 | 
            -
                # | 
| 320 | 
            +
                # @option params    [String]         :holder_name          The full name on the card or of the
         | 
| 321 | 
            +
                #                                                          account holder.
         | 
| 322 | 
            +
                # @option params    [String]         :number               The card or account number.
         | 
| 323 | 
            +
                #
         | 
| 324 | 
            +
                # ##### Credit card specific options:
         | 
| 325 | 
            +
                #
         | 
| 326 | 
            +
                # @option params    [Numeric,String] :expiry_month         The month in which the card expires.
         | 
| 327 | 
            +
                # @option params    [Numeric,String] :expiry_year          The year in which the card expires.
         | 
| 328 | 
            +
                #
         | 
| 329 | 
            +
                # ##### ELV specific options:
         | 
| 330 | 
            +
                #
         | 
| 331 | 
            +
                # @option params    [String]         :bank_location        The Bank Location.
         | 
| 332 | 
            +
                # @option params    [String]         :bank_name            The Bank Name.
         | 
| 333 | 
            +
                # @option params    [Numeric,String] :bank_location_id     The Bank Location ID (Bankleitzahl).
         | 
| 313 334 | 
             
                #
         | 
| 314 335 | 
             
                # @return [RecurringService::StoreTokenResponse] The response object
         | 
| 315 | 
            -
                def store_recurring_token(shopper,  | 
| 316 | 
            -
             | 
| 317 | 
            -
                     | 
| 318 | 
            -
             | 
| 319 | 
            -
             | 
| 336 | 
            +
                def store_recurring_token(shopper, params)
         | 
| 337 | 
            +
                    payment_method = params.include?(:bank_location_id) ? :elv : :card
         | 
| 338 | 
            +
                    RecurringService.new({
         | 
| 339 | 
            +
                      :shopper => shopper,
         | 
| 340 | 
            +
                      payment_method => params
         | 
| 341 | 
            +
                    }).store_token
         | 
| 320 342 | 
             
                end
         | 
| 321 343 | 
             
              end
         | 
| 322 344 | 
             
            end
         | 
| @@ -158,14 +158,7 @@ module Adyen | |
| 158 158 | 
             
                    }
         | 
| 159 159 |  | 
| 160 160 | 
             
                    AUTHORISED = 'Authorised'
         | 
| 161 | 
            -
             | 
| 162 | 
            -
                    def self.original_fault_message_for(attribute, message)
         | 
| 163 | 
            -
                      if error = ERRORS.find { |_, (a, m)| a == attribute && m == message }
         | 
| 164 | 
            -
                        error.first
         | 
| 165 | 
            -
                      else
         | 
| 166 | 
            -
                        message
         | 
| 167 | 
            -
                      end
         | 
| 168 | 
            -
                    end
         | 
| 161 | 
            +
                    REFUSED    = 'Refused'
         | 
| 169 162 |  | 
| 170 163 | 
             
                    response_attrs :result_code, :auth_code, :refusal_reason, :psp_reference
         | 
| 171 164 |  | 
| @@ -173,7 +166,12 @@ module Adyen | |
| 173 166 | 
             
                      super && params[:result_code] == AUTHORISED
         | 
| 174 167 | 
             
                    end
         | 
| 175 168 |  | 
| 176 | 
            -
                     | 
| 169 | 
            +
                    def refused?
         | 
| 170 | 
            +
                      params[:result_code] == REFUSED
         | 
| 171 | 
            +
                    end
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                    alias_method :authorised?, :success?
         | 
| 174 | 
            +
                    alias_method :authorized?, :success?
         | 
| 177 175 |  | 
| 178 176 | 
             
                    # @return [Boolean] Returns whether or not the request was valid.
         | 
| 179 177 | 
             
                    def invalid_request?
         | 
| @@ -193,8 +191,12 @@ module Adyen | |
| 193 191 | 
             
                    def error(prefix = nil)
         | 
| 194 192 | 
             
                      if error = ERRORS[fault_message]
         | 
| 195 193 | 
             
                        prefix ? ["#{prefix}_#{error[0]}".to_sym, error[1]] : error
         | 
| 196 | 
            -
                       | 
| 194 | 
            +
                      elsif fault_message
         | 
| 197 195 | 
             
                        [:base, fault_message]
         | 
| 196 | 
            +
                      elsif refused?
         | 
| 197 | 
            +
                        [:base, 'Transaction was refused.']
         | 
| 198 | 
            +
                      else
         | 
| 199 | 
            +
                        [:base, 'Transaction failed for unkown reasons.']
         | 
| 198 200 | 
             
                      end
         | 
| 199 201 | 
             
                    end
         | 
| 200 202 |  | 
| @@ -46,6 +46,14 @@ module Adyen | |
| 46 46 | 
             
                    CARD_PARTIAL % card
         | 
| 47 47 | 
             
                  end
         | 
| 48 48 |  | 
| 49 | 
            +
                  ELV_ATTRS = [:bank_location, :bank_name, :bank_location_id, :holder_name, :number]
         | 
| 50 | 
            +
                  # The ELV - (Elektronisches Lastschriftverfahren) does not require bank_location, so insert 'nil'.
         | 
| 51 | 
            +
                  def elv_partial
         | 
| 52 | 
            +
                    validate_parameters!(:elv => ELV_ATTRS)
         | 
| 53 | 
            +
                    elv  = @params[:elv].values_at(*ELV_ATTRS)
         | 
| 54 | 
            +
                    ELV_PARTIAL % elv
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 49 57 | 
             
                  def list_request_body
         | 
| 50 58 | 
             
                    validate_parameters!(:merchant_account, :shopper => [:reference])
         | 
| 51 59 | 
             
                    LIST_LAYOUT % [@params[:merchant_account], @params[:shopper][:reference]]
         | 
| @@ -61,7 +69,10 @@ module Adyen | |
| 61 69 |  | 
| 62 70 | 
             
                  def store_token_request_body
         | 
| 63 71 | 
             
                    validate_parameters!(:merchant_account, :shopper => [:email, :reference])
         | 
| 64 | 
            -
                    content =  | 
| 72 | 
            +
                    content = []
         | 
| 73 | 
            +
                    content << card_partial unless @params[:card].nil?
         | 
| 74 | 
            +
                    content << elv_partial  unless @params[:elv].nil?    
         | 
| 75 | 
            +
                    raise ArgumentError, "The required parameter 'card' or 'elv' is missing." if content.empty?    
         | 
| 65 76 | 
             
                    STORE_TOKEN_LAYOUT % [@params[:merchant_account], @params[:shopper][:reference], @params[:shopper][:email], content]
         | 
| 66 77 | 
             
                  end
         | 
| 67 78 |  | 
| @@ -74,7 +85,7 @@ module Adyen | |
| 74 85 | 
             
                      super && DISABLED_RESPONSES.include?(params[:response])
         | 
| 75 86 | 
             
                    end
         | 
| 76 87 |  | 
| 77 | 
            -
                     | 
| 88 | 
            +
                    alias_method :disabled?, :success?
         | 
| 78 89 |  | 
| 79 90 | 
             
                    def params
         | 
| 80 91 | 
             
                      @params ||= { :response => xml_querier.text('//recurring:disableResponse/recurring:result/recurring:response') }
         | 
| @@ -111,12 +122,17 @@ module Adyen | |
| 111 122 | 
             
                      }
         | 
| 112 123 |  | 
| 113 124 | 
             
                      card = node.xpath('./recurring:card')
         | 
| 114 | 
            -
                       | 
| 115 | 
            -
             | 
| 116 | 
            -
                       | 
| 125 | 
            +
                      elv  = node.xpath('./recurring:elv')  
         | 
| 126 | 
            +
                      bank = node.xpath('./recurring:bank')        
         | 
| 127 | 
            +
                      
         | 
| 128 | 
            +
                      if !card.children.empty?
         | 
| 117 129 | 
             
                        result[:card] = parse_card_details(card)
         | 
| 130 | 
            +
                      elsif !elv.children.empty?
         | 
| 131 | 
            +
                        result[:elv] = parse_elv_details(elv)
         | 
| 132 | 
            +
                      else
         | 
| 133 | 
            +
                        result[:bank] = parse_bank_details(bank)
         | 
| 118 134 | 
             
                      end
         | 
| 119 | 
            -
             | 
| 135 | 
            +
                      
         | 
| 120 136 | 
             
                      result
         | 
| 121 137 | 
             
                    end
         | 
| 122 138 |  | 
| @@ -128,15 +144,25 @@ module Adyen | |
| 128 144 | 
             
                      }
         | 
| 129 145 | 
             
                    end
         | 
| 130 146 |  | 
| 147 | 
            +
                    def parse_elv_details(elv)
         | 
| 148 | 
            +
                      {
         | 
| 149 | 
            +
                        :holder_name      => bank.text('./payment:accountHolderName'),
         | 
| 150 | 
            +
                        :number           => bank.text('./payment:bankAccountNumber'),
         | 
| 151 | 
            +
                        :bank_location    => bank.text('./payment:bankLocation'),
         | 
| 152 | 
            +
                        :bank_location_id => bank.text('./payment:bankLocationId'),
         | 
| 153 | 
            +
                        :bank_name        => bank.text('./payment:bankName')
         | 
| 154 | 
            +
                      }
         | 
| 155 | 
            +
                    end
         | 
| 156 | 
            +
             | 
| 131 157 | 
             
                    def parse_bank_details(bank)
         | 
| 132 158 | 
             
                      {
         | 
| 133 | 
            -
                        : | 
| 134 | 
            -
                        :bank_location_id | 
| 135 | 
            -
                        :bank_name | 
| 136 | 
            -
                        :bic | 
| 137 | 
            -
                        :country_code | 
| 138 | 
            -
                        :iban | 
| 139 | 
            -
                        : | 
| 159 | 
            +
                        :number           => bank.text('./payment:bankAccountNumber'),
         | 
| 160 | 
            +
                        :bank_location_id => bank.text('./payment:bankLocationId'),
         | 
| 161 | 
            +
                        :bank_name        => bank.text('./payment:bankName'),
         | 
| 162 | 
            +
                        :bic              => bank.text('./payment:bic'),
         | 
| 163 | 
            +
                        :country_code     => bank.text('./payment:countryCode'),
         | 
| 164 | 
            +
                        :iban             => bank.text('./payment:iban'),
         | 
| 165 | 
            +
                        :holder_name      => bank.text('./payment:ownerName')
         | 
| 140 166 | 
             
                      }
         | 
| 141 167 | 
             
                    end
         | 
| 142 168 | 
             
                  end
         | 
| @@ -152,12 +178,14 @@ module Adyen | |
| 152 178 | 
             
                      super && params[:response] == 'Success'
         | 
| 153 179 | 
             
                    end
         | 
| 154 180 |  | 
| 155 | 
            -
                     | 
| 181 | 
            +
                    alias_method :stored?, :success?
         | 
| 156 182 |  | 
| 157 183 | 
             
                    def params
         | 
| 158 | 
            -
                      @params ||= { | 
| 184 | 
            +
                      @params ||= {
         | 
| 185 | 
            +
                        :response => xml_querier.text('//recurring:storeTokenResponse/recurring:result/recurring:result'),
         | 
| 159 186 | 
             
                        :reference =>  xml_querier.text('//recurring:storeTokenResponse/recurring:result/recurring:rechargeReference'),
         | 
| 160 | 
            -
                        :recurring_detail_reference => xml_querier.text('//recurring:storeTokenResponse/recurring:result/recurring:recurringDetailReference') | 
| 187 | 
            +
                        :recurring_detail_reference => xml_querier.text('//recurring:storeTokenResponse/recurring:result/recurring:recurringDetailReference')
         | 
| 188 | 
            +
                      }
         | 
| 161 189 | 
             
                    end
         | 
| 162 190 | 
             
                  end
         | 
| 163 191 | 
             
                end
         | 
    
        data/lib/adyen/api/response.rb
    CHANGED
    
    | @@ -32,6 +32,13 @@ module Adyen | |
| 32 32 | 
             
                    !@http_response.is_a?(Net::HTTPSuccess)
         | 
| 33 33 | 
             
                  end
         | 
| 34 34 |  | 
| 35 | 
            +
                  # @return [Boolean] Whether or not the SOAP request itself was a success.
         | 
| 36 | 
            +
                  # Adyen returns a 500 status code for e.g. failed CC validation and in this case, we don't
         | 
| 37 | 
            +
                  # want to throw a server error but rather treat it as something normal.
         | 
| 38 | 
            +
                  def server_error?
         | 
| 39 | 
            +
                    @http_response.is_a?(Net::HTTPServerError) && fault_message.nil?
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 35 42 | 
             
                  # @return [XMLQuerier] The response body wrapped in a XMLQuerier.
         | 
| 36 43 | 
             
                  def xml_querier
         | 
| 37 44 | 
             
                    @xml_querier ||= XMLQuerier.new(@http_response.body)
         | 
| @@ -22,23 +22,27 @@ EOS | |
| 22 22 | 
             
                  # @see http://curl.haxx.se/ca/cacert.pem
         | 
| 23 23 | 
             
                  CACERT = File.expand_path('../cacert.pem', __FILE__)
         | 
| 24 24 |  | 
| 25 | 
            -
                  class  | 
| 25 | 
            +
                  class StandardError < ::StandardError
         | 
| 26 26 | 
             
                    def initialize(response, action, endpoint)
         | 
| 27 27 | 
             
                      @response, @action, @endpoint = response, action, endpoint
         | 
| 28 28 | 
             
                    end
         | 
| 29 29 |  | 
| 30 | 
            -
                     | 
| 31 | 
            -
             | 
| 30 | 
            +
                    private
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    def message_prefix
         | 
| 33 | 
            +
                      %{[#{@response.http_response.code} #{@response.http_response.message}] A %s error occurred while calling SOAP action `#{@action}' on endpoint `#{@endpoint}'.}
         | 
| 32 34 | 
             
                    end
         | 
| 33 35 | 
             
                  end
         | 
| 34 36 |  | 
| 35 | 
            -
                  class  | 
| 36 | 
            -
                    def  | 
| 37 | 
            -
                       | 
| 37 | 
            +
                  class ClientError < StandardError
         | 
| 38 | 
            +
                    def message
         | 
| 39 | 
            +
                      "#{message_prefix % "client"} Fault message: #{@response.fault_message}."
         | 
| 38 40 | 
             
                    end
         | 
| 41 | 
            +
                  end
         | 
| 39 42 |  | 
| 43 | 
            +
                  class ServerError < StandardError
         | 
| 40 44 | 
             
                    def message
         | 
| 41 | 
            -
                       | 
| 45 | 
            +
                      message_prefix % 'server'
         | 
| 42 46 | 
             
                    end
         | 
| 43 47 | 
             
                  end
         | 
| 44 48 |  | 
| @@ -118,9 +122,10 @@ EOS | |
| 118 122 |  | 
| 119 123 | 
             
                      request.start do |http|
         | 
| 120 124 | 
             
                        http_response = http.request(post)
         | 
| 121 | 
            -
                         | 
| 122 | 
            -
                        raise  | 
| 123 | 
            -
                         | 
| 125 | 
            +
                        response = response_class.new(http_response)
         | 
| 126 | 
            +
                        raise ClientError.new(response, action, endpoint) if http_response.is_a?(Net::HTTPClientError)
         | 
| 127 | 
            +
                        raise ServerError.new(response, action, endpoint) if response.server_error?
         | 
| 128 | 
            +
                        response
         | 
| 124 129 | 
             
                      end
         | 
| 125 130 | 
             
                    end
         | 
| 126 131 | 
             
                  end
         | 
| @@ -54,6 +54,18 @@ EOS | |
| 54 54 | 
             
                      <payment:expiryMonth>%02d</payment:expiryMonth>
         | 
| 55 55 | 
             
                    </recurring:card>
         | 
| 56 56 | 
             
            EOS
         | 
| 57 | 
            +
                  # Electronic bank debit in Germany. Semi real-time payment method.
         | 
| 58 | 
            +
                  # @private
         | 
| 59 | 
            +
                  ELV_PARTIAL = <<EOS
         | 
| 60 | 
            +
                    <recurring:elv>
         | 
| 61 | 
            +
                      <payment:bankLocation>%s</payment:bankLocation>
         | 
| 62 | 
            +
                      <payment:bankName>%s</payment:bankName>
         | 
| 63 | 
            +
                      <payment:bankLocationId>%s</payment:bankLocationId>
         | 
| 64 | 
            +
                      <payment:accountHolderName>%s</payment:accountHolderName>
         | 
| 65 | 
            +
                      <payment:bankAccountNumber>%02d</payment:bankAccountNumber>
         | 
| 66 | 
            +
                    </recurring:elv>
         | 
| 67 | 
            +
            EOS
         | 
| 68 | 
            +
             | 
| 57 69 | 
             
                end
         | 
| 58 70 | 
             
              end
         | 
| 59 71 | 
             
            end
         | 
| @@ -56,7 +56,7 @@ class AdyenNotification < ActiveRecord::Base | |
| 56 56 | 
             
                event_code == 'AUTHORISATION'
         | 
| 57 57 | 
             
              end
         | 
| 58 58 |  | 
| 59 | 
            -
               | 
| 59 | 
            +
              alias_method :authorization?, :authorisation?
         | 
| 60 60 |  | 
| 61 61 | 
             
              # Returns true if this notification is an AUTHORISATION notification and
         | 
| 62 62 | 
             
              # the success status indicates that the authorization was successfull.
         | 
| @@ -66,5 +66,5 @@ class AdyenNotification < ActiveRecord::Base | |
| 66 66 | 
             
                event_code == 'AUTHORISATION' && success?
         | 
| 67 67 | 
             
              end
         | 
| 68 68 |  | 
| 69 | 
            -
               | 
| 69 | 
            +
              alias_method :successful_authorization?, :successful_authorisation?
         | 
| 70 70 | 
             
            end
         | 
    
        data/spec/api/api_spec.rb
    CHANGED
    
    | @@ -131,6 +131,17 @@ describe Adyen::API do | |
| 131 131 | 
             
                    )
         | 
| 132 132 | 
             
                  end
         | 
| 133 133 |  | 
| 134 | 
            +
                  it "performs a `tokenize ELV details' request" do
         | 
| 135 | 
            +
                    should_map_shortcut_to(:store_token,
         | 
| 136 | 
            +
                      :shopper => { :reference => 'user-id', :email => 's.hopper@example.com' },
         | 
| 137 | 
            +
                      :elv => { :bank_location => "Berlin", :bank_name => "TestBank", :bank_location_id => "12345678", :holder_name => "Simon Hopper", :number => "1234567890" }
         | 
| 138 | 
            +
                    )
         | 
| 139 | 
            +
                    Adyen::API.store_recurring_token(
         | 
| 140 | 
            +
                      { :reference => 'user-id', :email => 's.hopper@example.com' },
         | 
| 141 | 
            +
                      { :bank_location => "Berlin", :bank_name => "TestBank", :bank_location_id => "12345678", :holder_name => "Simon Hopper", :number => "1234567890" }
         | 
| 142 | 
            +
                    )
         | 
| 143 | 
            +
                  end
         | 
| 144 | 
            +
             | 
| 134 145 | 
             
                  it "preforms a `list recurring details' request" do
         | 
| 135 146 | 
             
                    should_map_shortcut_to(:list, :shopper => { :reference => 'user-id' })
         | 
| 136 147 | 
             
                    Adyen::API.list_recurring_details('user-id')
         | 
| @@ -156,6 +156,18 @@ describe Adyen::API::PaymentService do | |
| 156 156 | 
             
                  end
         | 
| 157 157 | 
             
                end
         | 
| 158 158 |  | 
| 159 | 
            +
                describe "with a `refused' response" do
         | 
| 160 | 
            +
                  before do
         | 
| 161 | 
            +
                    stub_net_http(AUTHORISE_REQUEST_REFUSED_RESPONSE)
         | 
| 162 | 
            +
                    @response = @payment.authorise_payment
         | 
| 163 | 
            +
                  end
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                  it "returns that the payment was refused" do
         | 
| 166 | 
            +
                    @response.should be_refused
         | 
| 167 | 
            +
                    @response.error.should == [:base, 'Transaction was refused.']
         | 
| 168 | 
            +
                  end
         | 
| 169 | 
            +
                end
         | 
| 170 | 
            +
             | 
| 159 171 | 
             
                describe "with a `invalid' response" do
         | 
| 160 172 | 
             
                  before do
         | 
| 161 173 | 
             
                    stub_net_http(AUTHORISE_REQUEST_INVALID_RESPONSE % 'validation 101 Invalid card number')
         | 
| @@ -202,19 +214,6 @@ describe Adyen::API::PaymentService do | |
| 202 214 | 
             
                    end
         | 
| 203 215 | 
             
                  end
         | 
| 204 216 |  | 
| 205 | 
            -
                  it "returns the original message corresponding to the given attribute and message" do
         | 
| 206 | 
            -
                    [
         | 
| 207 | 
            -
                      ["validation 101 Invalid card number",                           [:number,       'is not a valid creditcard number']],
         | 
| 208 | 
            -
                      ["validation 103 CVC is not the right length",                   [:cvc,          'is not the right length']],
         | 
| 209 | 
            -
                      ["validation 128 Card Holder Missing",                           [:holder_name,  'can\'t be blank']],
         | 
| 210 | 
            -
                      ["validation Couldn't parse expiry year",                        [:expiry_year,  'could not be recognized']],
         | 
| 211 | 
            -
                      ["validation Expiry month should be between 1 and 12 inclusive", [:expiry_month, 'could not be recognized']],
         | 
| 212 | 
            -
                      ["validation 130 Reference Missing",                             [:base,         'validation 130 Reference Missing']],
         | 
| 213 | 
            -
                    ].each do |expected, attr_and_message|
         | 
| 214 | 
            -
                      Adyen::API::PaymentService::AuthorisationResponse.original_fault_message_for(*attr_and_message).should == expected
         | 
| 215 | 
            -
                    end
         | 
| 216 | 
            -
                  end
         | 
| 217 | 
            -
             | 
| 218 217 | 
             
                  private
         | 
| 219 218 |  | 
| 220 219 | 
             
                  def response_with_fault_message(message)
         | 
| @@ -27,6 +27,14 @@ describe Adyen::API::RecurringService do | |
| 27 27 | 
             
                    #:issue_number => ,
         | 
| 28 28 | 
             
                    #:start_month => ,
         | 
| 29 29 | 
             
                    #:start_year => ,
         | 
| 30 | 
            +
                  },
         | 
| 31 | 
            +
                  # German's Direct Debit (Elektronisches Lastschriftverfahren)
         | 
| 32 | 
            +
                  :elv => {
         | 
| 33 | 
            +
                    :holder_name      => 'Simon わくわく Hopper',
         | 
| 34 | 
            +
                    :number           => '1234567890',
         | 
| 35 | 
            +
                    :bank_location    => 'Berlin',
         | 
| 36 | 
            +
                    :bank_location_id => '12345678',
         | 
| 37 | 
            +
                    :bank_name        => 'TestBank',
         | 
| 30 38 | 
             
                  }
         | 
| 31 39 | 
             
                }
         | 
| 32 40 | 
             
                @recurring = @object = Adyen::API::RecurringService.new(@params)
         | 
| @@ -67,13 +75,13 @@ describe Adyen::API::RecurringService do | |
| 67 75 | 
             
                    },
         | 
| 68 76 | 
             
                    {
         | 
| 69 77 | 
             
                      :bank => {
         | 
| 70 | 
            -
                        : | 
| 78 | 
            +
                        :number => '123456789',
         | 
| 71 79 | 
             
                        :bank_location_id => 'bank-location-id',
         | 
| 72 80 | 
             
                        :bank_name => 'AnyBank',
         | 
| 73 81 | 
             
                        :bic => 'BBBBCCLLbbb',
         | 
| 74 82 | 
             
                        :country_code => 'NL',
         | 
| 75 83 | 
             
                        :iban => 'NL69PSTB0001234567',
         | 
| 76 | 
            -
                        : | 
| 84 | 
            +
                        :holder_name => 'S. Hopper'
         | 
| 77 85 | 
             
                      },
         | 
| 78 86 | 
             
                      :recurring_detail_reference => 'RecurringDetailReference2',
         | 
| 79 87 | 
             
                      :variant => 'IDEAL',
         | 
| @@ -161,6 +169,38 @@ describe Adyen::API::RecurringService do | |
| 161 169 | 
             
                  text('./recurring:recurring/payment:contract').should == 'RECURRING'
         | 
| 162 170 | 
             
                end
         | 
| 163 171 | 
             
              end
         | 
| 172 | 
            +
              
         | 
| 173 | 
            +
              describe_request_body_of :store_token, '//recurring:storeToken/recurring:request' do
         | 
| 174 | 
            +
                it_should_validate_request_parameters :merchant_account,
         | 
| 175 | 
            +
                                                      :shopper => [:email, :reference]
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                it "includes the merchant account handle" do
         | 
| 178 | 
            +
                  text('./recurring:merchantAccount').should == 'SuperShopper'
         | 
| 179 | 
            +
                end
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                it "includes the shopper’s reference" do
         | 
| 182 | 
            +
                  text('./recurring:shopperReference').should == 'user-id'
         | 
| 183 | 
            +
                end
         | 
| 184 | 
            +
             | 
| 185 | 
            +
                it "includes the shopper’s email" do
         | 
| 186 | 
            +
                  text('./recurring:shopperEmail').should == 's.hopper@example.com'
         | 
| 187 | 
            +
                end
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                it "includes the ELV details" do
         | 
| 190 | 
            +
                  xpath('./recurring:elv') do |elv|
         | 
| 191 | 
            +
                    # there's no reason why Nokogiri should escape these characters, but as long as they're correct        
         | 
| 192 | 
            +
                    elv.text('./payment:accountHolderName').should == 'Simon わくわく Hopper'
         | 
| 193 | 
            +
                    elv.text('./payment:bankAccountNumber').should == '1234567890'
         | 
| 194 | 
            +
                    elv.text('./payment:bankLocation').should == 'Berlin'
         | 
| 195 | 
            +
                    elv.text('./payment:bankLocationId').should == '12345678'
         | 
| 196 | 
            +
                    elv.text('./payment:bankName').should == 'TestBank'
         | 
| 197 | 
            +
                  end
         | 
| 198 | 
            +
                end
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                it "includes the necessary recurring and one-click contract info if the `:recurring' param is truthful" do
         | 
| 201 | 
            +
                  text('./recurring:recurring/payment:contract').should == 'RECURRING'
         | 
| 202 | 
            +
                end
         | 
| 203 | 
            +
              end
         | 
| 164 204 |  | 
| 165 205 | 
             
              describe_response_from :disable, (DISABLE_RESPONSE % '[detail-successfully-disabled]'), 'disable' do
         | 
| 166 206 | 
             
                it "returns whether or not it was disabled" do
         | 
    
        data/spec/api/response_spec.rb
    CHANGED
    
    | @@ -32,4 +32,28 @@ describe Adyen::API::Response do | |
| 32 32 | 
             
                  @response.should_not be_a_success
         | 
| 33 33 | 
             
                end
         | 
| 34 34 | 
             
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              describe "with a server error HTTP response and _no_ SOAP fault message" do
         | 
| 37 | 
            +
                before do
         | 
| 38 | 
            +
                  http_response = Net::HTTPServerError.new('1.1', '500', 'Internal Server Error')
         | 
| 39 | 
            +
                  http_response.stub!(:body).and_return(%{<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soap:Body></soap:Body></soap:Envelope>})
         | 
| 40 | 
            +
                  @response = Adyen::API::Response.new(http_response)
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                it "`server_error?` returns that the (HTTP) request did cause a server error" do
         | 
| 44 | 
            +
                  @response.server_error?.should be_true
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              describe "with a server error HTTP response _and_ SOAP fault message" do
         | 
| 49 | 
            +
                before do
         | 
| 50 | 
            +
                  http_response = Net::HTTPServerError.new('1.1', '500', 'Internal Server Error')
         | 
| 51 | 
            +
                  http_response.stub!(:body).and_return(%{<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>Illegal argument. For input string: "100.0"</faultstring></soap:Fault></soap:Body></soap:Envelope>})
         | 
| 52 | 
            +
                  @response = Adyen::API::Response.new(http_response)
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                it "`server_error?` returns that the (HTTP) request did not cause a server error" do
         | 
| 56 | 
            +
                  @response.server_error?.should be_false
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
              end
         | 
| 35 59 | 
             
            end
         | 
| @@ -76,16 +76,58 @@ describe Adyen::API::SimpleSOAPClient do | |
| 76 76 | 
             
                  @response.xml_querier.to_s.should == AUTHORISE_RESPONSE
         | 
| 77 77 | 
             
                end
         | 
| 78 78 |  | 
| 79 | 
            -
                 | 
| 80 | 
            -
                   | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 83 | 
            -
                     | 
| 84 | 
            -
                   | 
| 85 | 
            -
             | 
| 79 | 
            +
                [
         | 
| 80 | 
            +
                  [
         | 
| 81 | 
            +
                    "[401 Bad request] A client",
         | 
| 82 | 
            +
                    Net::HTTPBadRequest.new('1.1', '401', 'Bad request'),
         | 
| 83 | 
            +
                    Adyen::API::SimpleSOAPClient::ClientError
         | 
| 84 | 
            +
                  ]
         | 
| 85 | 
            +
                ].each do |label, response, expected_exception|
         | 
| 86 | 
            +
                  it "raises when the HTTP response is a subclass of #{response.class.name}" do
         | 
| 87 | 
            +
                    response.stub!(:body).and_return(%{<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>Illegal argument. For input string: "100.0"</faultstring></soap:Fault></soap:Body></soap:Envelope>})
         | 
| 88 | 
            +
                    Net::HTTP.stubbed_response = response
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                    exception = nil
         | 
| 91 | 
            +
                    begin
         | 
| 92 | 
            +
                      @client.call_webservice_action('Action', '<bananas>Yes, please</bananas>', Adyen::API::Response)
         | 
| 93 | 
            +
                    rescue expected_exception => e
         | 
| 94 | 
            +
                      exception = e
         | 
| 95 | 
            +
                    end
         | 
| 96 | 
            +
                    exception.message.should ==  %{#{label} error occurred while calling SOAP action `Action' on endpoint `https://test.example.com/soap/Action'. Fault message: Illegal argument. For input string: "100.0".}
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                describe 'server error' do
         | 
| 101 | 
            +
                  [
         | 
| 102 | 
            +
                    ["[500 Internal Server Error] A server",      Net::HTTPBadGateway.new('1.1', '500', 'Internal Server Error')],
         | 
| 103 | 
            +
                    ["[501 Not Implemented] A server",            Net::HTTPBadGateway.new('1.1', '501', 'Not Implemented')],
         | 
| 104 | 
            +
                    ["[502 Bad Gateway] A server",                Net::HTTPBadGateway.new('1.1', '502', 'Bad Gateway')],
         | 
| 105 | 
            +
                    ["[503 Service Unavailable] A server",        Net::HTTPBadGateway.new('1.1', '503', 'Service Unavailable')],
         | 
| 106 | 
            +
                    ["[504 Gateway Timeout] A server",            Net::HTTPBadGateway.new('1.1', '504', 'Gateway Timeout')],
         | 
| 107 | 
            +
                    ["[505 HTTP Version Not Supported] A server", Net::HTTPBadGateway.new('1.1', '505', 'HTTP Version Not Supported')],
         | 
| 108 | 
            +
                  ].each do |label, response|
         | 
| 109 | 
            +
                    it "is raised when the HTTP response is a `real` server error by status code" do
         | 
| 110 | 
            +
                      response.stub!(:body).and_return(%{<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soap:Body></soap:Body></soap:Envelope>})
         | 
| 111 | 
            +
                      Net::HTTP.stubbed_response = response
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                      exception = nil
         | 
| 114 | 
            +
                      begin
         | 
| 115 | 
            +
                        @client.call_webservice_action('Action', '<bananas>Yes, please</bananas>', Adyen::API::Response)
         | 
| 116 | 
            +
                      rescue Adyen::API::SimpleSOAPClient::ServerError => e
         | 
| 117 | 
            +
                        exception = e
         | 
| 118 | 
            +
                      end
         | 
| 119 | 
            +
                      exception.message.should ==  %{#{label} error occurred while calling SOAP action `Action' on endpoint `https://test.example.com/soap/Action'.}
         | 
| 120 | 
            +
                    end
         | 
| 121 | 
            +
                  end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                  it "is not raised when the HTTP response has a 500 status code with a fault message" do
         | 
| 124 | 
            +
                    response = Net::HTTPServerError.new('1.1', '500', 'Internal Server Error')
         | 
| 125 | 
            +
                    response.stub!(:body).and_return(%{<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>Illegal argument. For input string: "100.0"</faultstring></soap:Fault></soap:Body></soap:Envelope>})
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                     lambda do
         | 
| 128 | 
            +
                        @client.call_webservice_action('Action', '<bananas>Yes, please</bananas>', Adyen::API::Response)
         | 
| 129 | 
            +
                      end.should_not raise_error Adyen::API::SimpleSOAPClient::ServerError
         | 
| 86 130 | 
             
                  end
         | 
| 87 | 
            -
                  msg = "[401 Bad request] A client error occurred while calling SOAP action `Action' on endpoint `https://test.example.com/soap/Action'."
         | 
| 88 | 
            -
                  exception.message.should == msg
         | 
| 89 131 | 
             
                end
         | 
| 90 132 | 
             
              end
         | 
| 91 133 | 
             
            end
         | 
    
        data/spec/api/spec_helper.rb
    CHANGED
    
    | @@ -274,6 +274,21 @@ AUTHORISE_REQUEST_INVALID_RESPONSE = <<EOS | |
| 274 274 | 
             
            </soap:Envelope>
         | 
| 275 275 | 
             
            EOS
         | 
| 276 276 |  | 
| 277 | 
            +
            AUTHORISE_REQUEST_REFUSED_RESPONSE = <<EOS
         | 
| 278 | 
            +
            <?xml version="1.0" encoding="UTF-8"?>
         | 
| 279 | 
            +
            <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
         | 
| 280 | 
            +
              <soap:Body>
         | 
| 281 | 
            +
                <ns1:authoriseResponse xmlns:ns1="http://payment.services.adyen.com">
         | 
| 282 | 
            +
                  <ns1:paymentResult>
         | 
| 283 | 
            +
                    <refusalReason xmlns="http://payment.services.adyen.com">You need to actually own money.</refusalReason>
         | 
| 284 | 
            +
                    <resultCode xmlns="http://payment.services.adyen.com">Refused</resultCode>
         | 
| 285 | 
            +
                  </ns1:paymentResult>
         | 
| 286 | 
            +
                </ns1:authoriseResponse>
         | 
| 287 | 
            +
              </soap:Body>
         | 
| 288 | 
            +
            </soap:Envelope>
         | 
| 289 | 
            +
            EOS
         | 
| 290 | 
            +
             | 
| 291 | 
            +
             | 
| 277 292 | 
             
            LIST_RESPONSE = <<EOS
         | 
| 278 293 | 
             
            <?xml version="1.0"?>
         | 
| 279 294 | 
             
            <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
         | 
    
        data/spec/functional/api_spec.rb
    CHANGED
    
    | @@ -57,14 +57,23 @@ if File.exist?(API_SPEC_INITIALIZER) | |
| 57 57 | 
             
                  response.psp_reference.should_not be_empty
         | 
| 58 58 | 
             
                end
         | 
| 59 59 |  | 
| 60 | 
            -
                 | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
                    { : | 
| 64 | 
            -
             | 
| 65 | 
            -
                   | 
| 66 | 
            -
                  response. | 
| 67 | 
            -
             | 
| 60 | 
            +
                # TODO disabled for now: https://github.com/wvanbergen/adyen/issues/29
         | 
| 61 | 
            +
                #it "stores the provided ELV account details" do
         | 
| 62 | 
            +
                  #response = Adyen::API.store_recurring_token(
         | 
| 63 | 
            +
                    #{ :email => "#{@user_id}@example.com", :reference => @user_id },
         | 
| 64 | 
            +
                    #{ :bank_location => "Berlin", :bank_name => "TestBank", :bank_location_id => "12345678", :holder_name => "Simon #{@user_id} Hopper", :number => "1234567890" }
         | 
| 65 | 
            +
                  #)
         | 
| 66 | 
            +
                  #response.should be_stored
         | 
| 67 | 
            +
                  #response.recurring_detail_reference.should_not be_empty
         | 
| 68 | 
            +
                #end
         | 
| 69 | 
            +
                #it "stores the provided creditcard details" do
         | 
| 70 | 
            +
                  #response = Adyen::API.store_recurring_token(
         | 
| 71 | 
            +
                    #{ :email => "#{@user_id}@example.com", :reference => @user_id },
         | 
| 72 | 
            +
                    #{ :expiry_month => 12, :expiry_year => 2012, :holder_name => "Simon #{@user_id} Hopper", :number => '4111111111111111' }
         | 
| 73 | 
            +
                  #)
         | 
| 74 | 
            +
                  #response.should be_stored
         | 
| 75 | 
            +
                  #response.recurring_detail_reference.should_not be_empty
         | 
| 76 | 
            +
                #end
         | 
| 68 77 |  | 
| 69 78 | 
             
                it "captures a payment" do
         | 
| 70 79 | 
             
                  response = Adyen::API.capture_payment(@payment_response.psp_reference, { :currency => 'EUR', :value => '1234' })
         | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    
    
        data/tasks/github-gem.rake
    CHANGED
    
    | @@ -13,8 +13,8 @@ module GithubGem | |
| 13 13 |  | 
| 14 14 | 
             
              # Detects the main include file of this project using heuristics
         | 
| 15 15 | 
             
              def self.detect_main_include
         | 
| 16 | 
            -
                if  | 
| 17 | 
            -
                  "lib/#{ | 
| 16 | 
            +
                if File.exist?(File.expand_path("../lib/#{File.basename(detect_gemspec_file, '.gemspec').gsub(/-/, '/')}.rb", detect_gemspec_file))
         | 
| 17 | 
            +
                  "lib/#{File.basename(detect_gemspec_file, '.gemspec').gsub(/-/, '/')}.rb"
         | 
| 18 18 | 
             
                elsif FileList['lib/*.rb'].length == 1
         | 
| 19 19 | 
             
                  FileList['lib/*.rb'].first
         | 
| 20 20 | 
             
                else
         | 
| @@ -24,6 +24,8 @@ module GithubGem | |
| 24 24 |  | 
| 25 25 | 
             
              class RakeTasks
         | 
| 26 26 |  | 
| 27 | 
            +
                include Rake::DSL if Rake.const_defined?('DSL')
         | 
| 28 | 
            +
             | 
| 27 29 | 
             
                attr_reader   :gemspec, :modified_files
         | 
| 28 30 | 
             
                attr_accessor :gemspec_file, :task_namespace, :main_include, :root_dir, :spec_pattern, :test_pattern, :remote, :remote_branch, :local_branch
         | 
| 29 31 |  | 
| @@ -331,7 +333,7 @@ module GithubGem | |
| 331 333 |  | 
| 332 334 | 
             
                    # Reload the gemspec so the changes are incorporated
         | 
| 333 335 | 
             
                    load_gemspec!
         | 
| 334 | 
            -
             | 
| 336 | 
            +
                    
         | 
| 335 337 | 
             
                    # Also mark the Gemfile.lock file as changed because of the new version.
         | 
| 336 338 | 
             
                    modified_files << 'Gemfile.lock' if File.exist?(File.join(root_dir, 'Gemfile.lock'))
         | 
| 337 339 | 
             
                  end
         | 
| @@ -341,8 +343,8 @@ module GithubGem | |
| 341 343 | 
             
                def update_tasks_task
         | 
| 342 344 | 
             
                  require 'net/https'
         | 
| 343 345 | 
             
                  require 'uri'
         | 
| 344 | 
            -
             | 
| 345 | 
            -
                  uri = URI.parse('https://github.com/wvanbergen/github-gem/ | 
| 346 | 
            +
                  
         | 
| 347 | 
            +
                  uri = URI.parse('https://raw.github.com/wvanbergen/github-gem/master/tasks/github-gem.rake')
         | 
| 346 348 | 
             
                  http = Net::HTTP.new(uri.host, uri.port)
         | 
| 347 349 | 
             
                  http.use_ssl = true
         | 
| 348 350 | 
             
                  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
         | 
    
        metadata
    CHANGED
    
    | @@ -1,12 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: adyen
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
               | 
| 4 | 
            +
              hash: 27
         | 
| 5 | 
            +
              prerelease: 
         | 
| 5 6 | 
             
              segments: 
         | 
| 6 7 | 
             
              - 1
         | 
| 7 | 
            -
              -  | 
| 8 | 
            +
              - 3
         | 
| 8 9 | 
             
              - 0
         | 
| 9 | 
            -
              version: 1. | 
| 10 | 
            +
              version: 1.3.0
         | 
| 10 11 | 
             
            platform: ruby
         | 
| 11 12 | 
             
            authors: 
         | 
| 12 13 | 
             
            - Willem van Bergen
         | 
| @@ -17,8 +18,7 @@ autorequire: | |
| 17 18 | 
             
            bindir: bin
         | 
| 18 19 | 
             
            cert_chain: []
         | 
| 19 20 |  | 
| 20 | 
            -
            date: 2011- | 
| 21 | 
            -
            default_executable: 
         | 
| 21 | 
            +
            date: 2011-10-10 00:00:00 Z
         | 
| 22 22 | 
             
            dependencies: 
         | 
| 23 23 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 24 24 | 
             
              name: rake
         | 
| @@ -28,6 +28,7 @@ dependencies: | |
| 28 28 | 
             
                requirements: 
         | 
| 29 29 | 
             
                - - ">="
         | 
| 30 30 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 31 | 
            +
                    hash: 3
         | 
| 31 32 | 
             
                    segments: 
         | 
| 32 33 | 
             
                    - 0
         | 
| 33 34 | 
             
                    version: "0"
         | 
| @@ -41,37 +42,39 @@ dependencies: | |
| 41 42 | 
             
                requirements: 
         | 
| 42 43 | 
             
                - - ~>
         | 
| 43 44 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 45 | 
            +
                    hash: 7
         | 
| 44 46 | 
             
                    segments: 
         | 
| 45 47 | 
             
                    - 2
         | 
| 46 | 
            -
                     | 
| 47 | 
            -
                    version: "2.0"
         | 
| 48 | 
            +
                    version: "2"
         | 
| 48 49 | 
             
              type: :development
         | 
| 49 50 | 
             
              version_requirements: *id002
         | 
| 50 51 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 51 | 
            -
              name:  | 
| 52 | 
            +
              name: rails
         | 
| 52 53 | 
             
              prerelease: false
         | 
| 53 54 | 
             
              requirement: &id003 !ruby/object:Gem::Requirement 
         | 
| 54 55 | 
             
                none: false
         | 
| 55 56 | 
             
                requirements: 
         | 
| 56 57 | 
             
                - - ">="
         | 
| 57 58 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 59 | 
            +
                    hash: 5
         | 
| 58 60 | 
             
                    segments: 
         | 
| 59 | 
            -
                    -  | 
| 60 | 
            -
                     | 
| 61 | 
            +
                    - 2
         | 
| 62 | 
            +
                    - 3
         | 
| 63 | 
            +
                    version: "2.3"
         | 
| 61 64 | 
             
              type: :development
         | 
| 62 65 | 
             
              version_requirements: *id003
         | 
| 63 66 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 64 | 
            -
              name:  | 
| 67 | 
            +
              name: nokogiri
         | 
| 65 68 | 
             
              prerelease: false
         | 
| 66 69 | 
             
              requirement: &id004 !ruby/object:Gem::Requirement 
         | 
| 67 70 | 
             
                none: false
         | 
| 68 71 | 
             
                requirements: 
         | 
| 69 72 | 
             
                - - ">="
         | 
| 70 73 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 74 | 
            +
                    hash: 3
         | 
| 71 75 | 
             
                    segments: 
         | 
| 72 | 
            -
                    -  | 
| 73 | 
            -
                     | 
| 74 | 
            -
                    version: "2.3"
         | 
| 76 | 
            +
                    - 0
         | 
| 77 | 
            +
                    version: "0"
         | 
| 75 78 | 
             
              type: :development
         | 
| 76 79 | 
             
              version_requirements: *id004
         | 
| 77 80 | 
             
            description: "    Package to simplify including the Adyen payments services into a Ruby on Rails application.\n    The package provides functionality to create payment forms, handling and storing notifications \n    sent by Adyen and consuming the SOAP services provided by Adyen. Moreover, it contains helper\n    methods, mocks and matchers to simpify writing tests/specsfor your code.\n"
         | 
| @@ -89,6 +92,8 @@ extra_rdoc_files: | |
| 89 92 | 
             
            files: 
         | 
| 90 93 | 
             
            - .gitignore
         | 
| 91 94 | 
             
            - .kick
         | 
| 95 | 
            +
            - .travis.yml
         | 
| 96 | 
            +
            - Gemfile
         | 
| 92 97 | 
             
            - LICENSE
         | 
| 93 98 | 
             
            - README.rdoc
         | 
| 94 99 | 
             
            - Rakefile
         | 
| @@ -128,7 +133,6 @@ files: | |
| 128 133 | 
             
            - spec/spec_helper.rb
         | 
| 129 134 | 
             
            - tasks/github-gem.rake
         | 
| 130 135 | 
             
            - yard_extensions.rb
         | 
| 131 | 
            -
            has_rdoc: true
         | 
| 132 136 | 
             
            homepage: http://github.com/wvanbergen/adyen/wiki
         | 
| 133 137 | 
             
            licenses: []
         | 
| 134 138 |  | 
| @@ -147,6 +151,7 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 147 151 | 
             
              requirements: 
         | 
| 148 152 | 
             
              - - ">="
         | 
| 149 153 | 
             
                - !ruby/object:Gem::Version 
         | 
| 154 | 
            +
                  hash: 3
         | 
| 150 155 | 
             
                  segments: 
         | 
| 151 156 | 
             
                  - 0
         | 
| 152 157 | 
             
                  version: "0"
         | 
| @@ -155,13 +160,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 155 160 | 
             
              requirements: 
         | 
| 156 161 | 
             
              - - ">="
         | 
| 157 162 | 
             
                - !ruby/object:Gem::Version 
         | 
| 163 | 
            +
                  hash: 3
         | 
| 158 164 | 
             
                  segments: 
         | 
| 159 165 | 
             
                  - 0
         | 
| 160 166 | 
             
                  version: "0"
         | 
| 161 167 | 
             
            requirements: 
         | 
| 162 168 | 
             
            - Having Nokogiri installed will speed up XML handling when using the SOAP API.
         | 
| 163 169 | 
             
            rubyforge_project: 
         | 
| 164 | 
            -
            rubygems_version: 1. | 
| 170 | 
            +
            rubygems_version: 1.8.7
         | 
| 165 171 | 
             
            signing_key: 
         | 
| 166 172 | 
             
            specification_version: 3
         | 
| 167 173 | 
             
            summary: Integrate Adyen payment services in your Ruby on Rails application.
         |