You can only capture a transaction once, even if you didn’t capture the full amount the first time.
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 90 90: def capture(money, identification, options = {}) 91: post = {} 92: 93: add_reference(post, identification) 94: add_release_amount(post, money, options) 95: 96: commit(:capture, post) 97: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 121 121: def credit(money, identification, options = {}) 122: deprecated CREDIT_DEPRECATION_MESSAGE 123: refund(money, identification, options) 124: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 61 61: def purchase(money, credit_card, options = {}) 62: requires!(options, :order_id) 63: 64: post = {} 65: 66: add_amount(post, money, options) 67: add_invoice(post, options) 68: add_credit_card(post, credit_card) 69: add_address(post, options) 70: add_customer_data(post, options) 71: 72: commit(:purchase, post) 73: end
Refunding requires a new order_id to passed in, as well as a description
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 109 109: def refund(money, identification, options = {}) 110: requires!(options, :order_id, :description) 111: 112: post = {} 113: 114: add_credit_reference(post, identification) 115: add_amount(post, money, options) 116: add_invoice(post, options) 117: 118: commit(:credit, post) 119: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 57 57: def test? 58: @options[:test] || super 59: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 99 99: def void(identification, options = {}) 100: post = {} 101: 102: add_reference(post, identification) 103: action = abort_or_void_from(identification) 104: 105: commit(action, post) 106: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 257 257: def abort_or_void_from(identification) 258: original_transaction = identification.split(';').last 259: original_transaction == 'authorization' ? :abort : :void 260: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 162 162: def add_address(post, options) 163: if billing_address = options[:billing_address] || options[:address] 164: first_name, last_name = parse_first_and_last_name(billing_address[:name]) 165: add_pair(post, :BillingSurname, last_name) 166: add_pair(post, :BillingFirstnames, first_name) 167: add_pair(post, :BillingAddress1, billing_address[:address1]) 168: add_pair(post, :BillingAddress2, billing_address[:address2]) 169: add_pair(post, :BillingCity, billing_address[:city]) 170: add_pair(post, :BillingState, billing_address[:state]) if billing_address[:country] == 'US' 171: add_pair(post, :BillingCountry, billing_address[:country]) 172: add_pair(post, :BillingPostCode, billing_address[:zip]) 173: end 174: 175: if shipping_address = options[:shipping_address] || billing_address 176: first_name, last_name = parse_first_and_last_name(shipping_address[:name]) 177: add_pair(post, :DeliverySurname, last_name) 178: add_pair(post, :DeliveryFirstnames, first_name) 179: add_pair(post, :DeliveryAddress1, shipping_address[:address1]) 180: add_pair(post, :DeliveryAddress2, shipping_address[:address2]) 181: add_pair(post, :DeliveryCity, shipping_address[:city]) 182: add_pair(post, :DeliveryState, shipping_address[:state]) if shipping_address[:country] == 'US' 183: add_pair(post, :DeliveryCountry, shipping_address[:country]) 184: add_pair(post, :DeliveryPostCode, shipping_address[:zip]) 185: end 186: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 145 145: def add_amount(post, money, options) 146: currency = options[:currency] || currency(money) 147: add_pair(post, :Amount, localized_amount(money, currency), :required => true) 148: add_pair(post, :Currency, currency, :required => true) 149: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 193 193: def add_credit_card(post, credit_card) 194: add_pair(post, :CardHolder, credit_card.name, :required => true) 195: add_pair(post, :CardNumber, credit_card.number, :required => true) 196: 197: add_pair(post, :ExpiryDate, format_date(credit_card.month, credit_card.year), :required => true) 198: 199: if requires_start_date_or_issue_number?(credit_card) 200: add_pair(post, :StartDate, format_date(credit_card.start_month, credit_card.start_year)) 201: add_pair(post, :IssueNumber, credit_card.issue_number) 202: end 203: add_pair(post, :CardType, map_card_type(credit_card)) 204: 205: add_pair(post, :CV2, credit_card.verification_value) 206: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 136 136: def add_credit_reference(post, identification) 137: order_id, transaction_id, authorization, security_key = identification.split(';') 138: 139: add_pair(post, :RelatedVendorTxCode, order_id) 140: add_pair(post, :RelatedVPSTxId, transaction_id) 141: add_pair(post, :RelatedTxAuthNo, authorization) 142: add_pair(post, :RelatedSecurityKey, security_key) 143: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 156 156: def add_customer_data(post, options) 157: add_pair(post, :CustomerEMail, options[:email][0,255]) unless options[:email].blank? 158: add_pair(post, :BillingPhone, options[:phone].gsub(/[^0-9+]/, '')[0,20]) unless options[:phone].blank? 159: add_pair(post, :ClientIPAddress, options[:ip]) 160: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 188 188: def add_invoice(post, options) 189: add_pair(post, :VendorTxCode, sanitize_order_id(options[:order_id]), :required => true) 190: add_pair(post, :Description, options[:description] || options[:order_id]) 191: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 301 301: def add_pair(post, key, value, options = {}) 302: post[key] = value if !value.blank? || options[:required] 303: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 127 127: def add_reference(post, identification) 128: order_id, transaction_id, authorization, security_key = identification.split(';') 129: 130: add_pair(post, :VendorTxCode, order_id) 131: add_pair(post, :VPSTxId, transaction_id) 132: add_pair(post, :TxAuthNo, authorization) 133: add_pair(post, :SecurityKey, security_key) 134: end
doesn’t actually use the currency — dodgy!
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 152 152: def add_release_amount(post, money, options) 153: add_pair(post, :ReleaseAmount, amount(money), :required => true) 154: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 271 271: def build_simulator_url(action) 272: endpoint = [ :purchase, :authorization ].include?(action) ? "VSPDirectGateway.asp" : "VSPServerGateway.asp?Service=Vendor#{TRANSACTIONS[action].capitalize}Tx" 273: "#{SIMULATOR_URL}/#{endpoint}" 274: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 266 266: def build_url(action) 267: endpoint = [ :purchase, :authorization ].include?(action) ? "vspdirect-register" : TRANSACTIONS[action].downcase 268: "#{test? ? TEST_URL : LIVE_URL}/#{endpoint}.vsp" 269: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 235 235: def commit(action, parameters) 236: response = parse( ssl_post(url_for(action), post_data(action, parameters)) ) 237: 238: Response.new(response["Status"] == APPROVED, message_from(response), response, 239: :test => test?, 240: :authorization => authorization_from(response, parameters, action), 241: :avs_result => { 242: :street_match => AVS_CVV_CODE[ response["AddressResult"] ], 243: :postal_match => AVS_CVV_CODE[ response["PostCodeResult"] ], 244: }, 245: :cvv_result => AVS_CVV_CODE[ response["CV2Result"] ] 246: ) 247: end
MMYY format
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 226 226: def format_date(month, year) 227: return nil if year.blank? || month.blank? 228: 229: year = sprintf("%.4i", year) 230: month = sprintf("%.2i", month) 231: 232: "#{month}#{year[-2..-1]}" 233: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 313 313: def localized_amount(money, currency) 314: amount = amount(money) 315: CURRENCIES_WITHOUT_FRACTIONS.include?(currency.to_s) ? amount.split('.').first : amount 316: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 212 212: def map_card_type(credit_card) 213: raise ArgumentError, "The credit card type must be provided" if card_brand(credit_card).blank? 214: 215: card_type = card_brand(credit_card).to_sym 216: 217: # Check if it is an electron card 218: if card_type == :visa && credit_card.number =~ ELECTRON 219: CREDIT_CARDS[:electron] 220: else 221: CREDIT_CARDS[card_type] 222: end 223: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 276 276: def message_from(response) 277: response['Status'] == APPROVED ? 'Success' : (response['StatusDetail'] || 'Unspecified error') # simonr 20080207 can't actually get non-nil blanks, so this is shorter 278: end
SagePay returns data in the following format Key1=value1 Key2=value2
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 293 293: def parse(body) 294: result = {} 295: body.to_s.each_line do |pair| 296: result[$1] = $2 if pair.strip =~ /\A([^=]+)=(.+)\Z/m 297: end 298: result 299: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 305 305: def parse_first_and_last_name(value) 306: name = value.to_s.split(' ') 307: 308: last_name = name.pop || '' 309: first_name = name.join(' ') 310: [ first_name[0,20], last_name[0,20] ] 311: end
# File lib/active_merchant/billing/gateways/sage_pay.rb, line 280 280: def post_data(action, parameters = {}) 281: parameters.update( 282: :Vendor => @options[:login], 283: :TxType => TRANSACTIONS[action], 284: :VPSProtocol => "2.23" 285: ) 286: 287: parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&") 288: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.