Skip to content

Instantly share code, notes, and snippets.

@telent
Created November 4, 2010 17:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save telent/662821 to your computer and use it in GitHub Desktop.
Save telent/662821 to your computer and use it in GitHub Desktop.
Talking to Sagepay Reporting & Admin API from Ruby
require 'patron'
require 'time'
require 'active_support/core_ext/hash.rb'
require 'digest/md5'
require 'nokogiri'
module SagePay;end
class SagePay::Admin
def initialize(args)
@sess = Patron::Session.new
@sess.timeout = args[:timeout] || 10
@sess.base_url = args[:base_url] || "https://live.sagepay.com/access/"
@sess.headers['User-Agent'] = 'Can o Worms/0.1'
@sess.headers['Content-Type'] = 'application/x-www-form-urlencoded'
@vendor=args[:vendor]
@username=args[:username]
@password=args[:password]
@verbose=args[:verbose]
end
def send_rq(contents)
opts={:root=>'V',:skip_instruct=>true,:indent=>0}
data=contents.merge({
:vendor=>@vendor,
:user=>@username,
:password=>@password
})
# the authentication method in use here was clearly designed by
# someone who did not "get" xml. It is whitespace-sensitive,
# so the only sane thing to do is not to generate any.
# https://support.sagepay.com/forum/Topic11669-39-1.aspx
string=(data.to_xml(opts).delete "\n").gsub(/^<V>(.+)<\/V>$/,'\1')
digest = Digest::MD5.hexdigest(string)
string=string.gsub(%r{<password>.*</password>},
"<signature>#{digest}</signature>")
print ">> #{string}\n" if @verbose
r=Nokogiri.XML(@sess.post("access.htm",
"XML=<vspaccess>"+string+"</vspaccess>").body)
print "<< #{r}" if @verbose
r
end
def get_transaction_list(args={})
offset=args[:startrow] || 0
limit=args[:endrow] || nil
Enumerator.new do |yielder|
cursor=offset
loop do
doc=
send_rq({
:command=>"getTransactionList",
:startdate=>args[:startdate].strftime("%d/%m/%Y %H:%M:%S"),
:enddate=>args[:enddate].strftime("%d/%m/%Y %H:%M:%S"),
:includeaddresses=>(args[:includeaddresses] ? "YES": :"NO"),
:startrow=>cursor.to_s,
:sorttype=>"ByDate", # or "ByVendorTxCode"
:sortorder=>"ASC"
})
error= doc.css('vspaccess errorcode').first.content.to_i
if(error.zero?)
totalrows=doc.css('vspaccess transactions totalrows').first.content.to_i
if limit.nil? then limit=totalrows end
endrow=doc.css('vspaccess transactions endrow').first.content.to_i
doc.css('vspaccess transactions transaction').each do |tx|
hash={}
tx.children.each do |k|
hash[k.node_name.to_sym]=k.content
end
if ! hash[:rownumber].empty? then
yielder.yield hash
end
end
else
raise doc.css('vspaccess error').first.content
end
if endrow >= limit then
break
else
cursor=endrow+1
end
end
end
end
end
### and here is example code for using it
sagepay=SagePay::Admin.new(:vendor=>"vendorname",
:username=>"username",
:password=>"very secret",
:verbose=>false,
:timeout=>30
)
start=Time.parse("2010-10-29 08:58:00")
sagepay.get_transaction_list(:includeaddresses=>true,
:startdate=>start,
:enddate=>start+1800).each do |tx|
if (tx[:result] != "SUCCESS") then
warn tx
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment