require "handsoap"
module Adyen
# The SOAP module contains classes that interact with the Adyen
# SOAP services. The clients are based on the Handsoap library.
# Shared functionality for all services is implemented in the
# Adyen::SOAP::Base class.
#
# Note that you'll need an Adyen notification PSP reference for
# most SOAP calls. Because of this, store all notifications that
# Adyen sends to you. (e.g. using the Adyen::Notification ActiveRecord
# class). Moreover, most SOAP calls do not respond that they were
# successful immediately, but a notifications to indicate that will
# be sent later on.
#
# You'll need to provide a username and password to interact
# with the Adyen SOAP services:
#
# Adyen::SOAP.username = 'ws@Company.MyAccount'
# Adyen::SOAP.password = 'very$ecret'
#
# You can setup default values for every SOAP call that needs them:
#
# Adyen::SOAP.default_arguments[:merchent_account] = 'MyMerchant'
#
# For now, only the recurring payment service client is implemented
# (Adyen::SOAP::RecurringService).
module SOAP
class << self
# Set up accessors for HTTP Basic Authentication and
# for adding default arguments to SOAP calls.
attr_accessor :username, :password, :default_arguments
end
# Use no default arguments by default
self.default_arguments = {}
# The base class sets up XML namespaces and HTTP authentication
# for all the Adyen SOAP services
class Base < Handsoap::Service
def self.inherited(klass)
# The version must be set to construct the request envelopes,
# the URI wil be set later using the correct Adyen.environment.
klass.endpoint :version => 1, :uri => 'bogus'
end
# Setup some CURL options to handle redirects correctly.
def on_after_create_http_client(http_client)
http_client.follow_location = true
http_client.max_redirects = 1
end
# Setup basic authentication
def on_after_create_http_request(http_request)
debug { |logger| logger.puts "Authorization: #{Adyen::SOAP.username}:#{Adyen::SOAP.password}..." }
http_request.set_auth Adyen::SOAP.username, Adyen::SOAP.password
end
# Setup XML namespaces for SOAP request body
def on_create_document(doc)
doc.alias 'payment', 'http://payment.services.adyen.com'
doc.alias 'recurring', 'http://recurring.services.adyen.com'
doc.alias 'common', 'http://common.services.adyen.com'
end
# Setup XML namespaces for SOAP response
def on_response_document(doc)
doc.add_namespace 'payment', 'http://payment.services.adyen.com'
doc.add_namespace 'recurring', 'http://recurring.services.adyen.com'
doc.add_namespace 'common', 'http://common.services.adyen.com'
end
# Set endpoint URI before dispatch, so that changes in environment
# are reflected correctly.
def on_before_dispatch
self.class.endpoint(:uri => self.class::ENDPOINT_URI % Adyen.environment.to_s, :version => 1)
end
end
# SOAP client to interact with the payment modification service of Adyen.
# At this moment, none of the calls are implemented.
class PaymentService < Base
ENDPOINT_URI = 'https://pal-%s.adyen.com/pal/servlet/soap/Payment'
end
# SOAP client to interact with the recurring payment service of Adyen.
# This client implements the submitRecurring call to submit payments
# for a recurring contract. Moreover, it implements the deactiveRecurring
# call to cancel a recurring contract.
#
# See the Adyen Recurring manual for more information about this SOAP service
class RecurringService < Base
ENDPOINT_URI = 'https://pal-%s.adyen.com/pal/servlet/soap/Recurring'
# Submits a recurring payment. Requires the following arguments as hash:
#
# * :currency The currency code (EUR, GBP, USD, etc)
# * :value The value of the payments in cents
# * :merchent_account The merchant account under which to place
# this payment.
# * :recurring_reference The psp_reference of the RECURRING_CONTRACT
# notification that was sent after the initial payment.
# * :reference The (merchant) reference for this payment.
# * :shopper_email The email address of the shopper.
# * :shopper_reference The refrence of the shopper. This should be
# the same as the reference that was used to create the recurring contract.
def submit(args = {})
invoke_args = Adyen::SOAP.default_arguments.merge(args)
response = invoke('recurring:submitRecurring') do |message|
message.add('recurring:recurringRequest') do |req|
req.add('recurring:amount') do |amount|
amount.add('common:currency', invoke_args[:currency])
amount.add('common:value', invoke_args[:value])
end
req.add('recurring:merchantAccount', invoke_args[:merchant_account])
req.add('recurring:recurringReference', invoke_args[:recurring_reference])
req.add('recurring:reference', invoke_args[:reference])
req.add('recurring:shopperEmail', invoke_args[:shopper_email])
req.add('recurring:shopperReference', invoke_args[:shopper_reference])
end
end
end
# Retrieves the recurring contracts for a shopper. Requires the following arguments:
#
# * :merchent_account The merchant account under which to place
# this payment.
# * :shopper_reference The refrence of the shopper. This should be
# the same as the reference that was used to create the recurring contract.
def list(args = {})
invoke_args = Adyen::SOAP.default_arguments.merge(args)
response = invoke('recurring:listRecurringDetails') do |message|
message.add('recurring:recurringRequest') do |req|
req.add('recurring:merchantAccount', invoke_args[:merchant_account])
req.add('recurring:shopperReference', invoke_args[:shopper_reference])
end
end
end
# Deactivates a recurring payment contract. Requires the following arguments:
#
# * :merchent_account The merchant account under which to place
# this payment.
# * :recurring_reference The psp_reference of the RECURRING_CONTRACT
# notification that was sent after the initial payment.
# * :reference The (merchant) reference for this deactivation.
# * :shopper_reference The refrence of the shopper. This should be
# the same as the reference that was used to create the recurring contract.
def deactivate(args = {})
invoke_args = Adyen::SOAP.default_arguments.merge(args)
response = invoke('recurring:deactivateRecurring') do |message|
message.add('recurring:recurringRequest') do |req|
req.add('recurring:merchantAccount', invoke_args[:merchant_account])
req.add('recurring:recurringReference', invoke_args[:recurring_reference])
req.add('recurring:reference', invoke_args[:reference])
req.add('recurring:shopperReference', invoke_args[:shopper_reference])
end
end
end
end
end
end