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