lib/active_merchant/billing/gateways/sage_pay.rb in activemerchant-1.43.3 vs lib/active_merchant/billing/gateways/sage_pay.rb in activemerchant-1.44.0
- old
+ new
@@ -16,11 +16,13 @@
:purchase => 'PAYMENT',
:credit => 'REFUND',
:authorization => 'DEFERRED',
:capture => 'RELEASE',
:void => 'VOID',
- :abort => 'ABORT'
+ :abort => 'ABORT',
+ :store => 'TOKEN',
+ :unstore => 'REMOVETOKEN'
}
CREDIT_CARDS = {
:visa => "VISA",
:master => "MC",
@@ -53,33 +55,33 @@
def initialize(options = {})
requires!(options, :login)
super
end
- def purchase(money, credit_card, options = {})
+ def purchase(money, payment_method, options = {})
requires!(options, :order_id)
post = {}
add_amount(post, money, options)
add_invoice(post, options)
- add_credit_card(post, credit_card)
+ add_payment_method(post, payment_method, options)
add_address(post, options)
add_customer_data(post, options)
add_optional_data(post, options)
commit(:purchase, post)
end
- def authorize(money, credit_card, options = {})
+ def authorize(money, payment_method, options = {})
requires!(options, :order_id)
post = {}
add_amount(post, money, options)
add_invoice(post, options)
- add_credit_card(post, credit_card)
+ add_payment_method(post, payment_method, options)
add_address(post, options)
add_customer_data(post, options)
add_optional_data(post, options)
commit(:authorization, post)
@@ -116,14 +118,28 @@
commit(:credit, post)
end
def credit(money, identification, options = {})
- deprecated CREDIT_DEPRECATION_MESSAGE
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
refund(money, identification, options)
end
+ def store(credit_card, options = {})
+ post = {}
+ add_credit_card(post, credit_card)
+ add_currency(post, 0, options)
+
+ commit(:store, post)
+ end
+
+ def unstore(token, options = {})
+ post = {}
+ add_token(post, token)
+ commit(:unstore, post)
+ end
+
private
def add_reference(post, identification)
order_id, transaction_id, authorization, security_key = identification.split(';')
add_pair(post, :VendorTxCode, order_id)
@@ -145,59 +161,78 @@
currency = options[:currency] || currency(money)
add_pair(post, :Amount, localized_amount(money, currency), :required => true)
add_pair(post, :Currency, currency, :required => true)
end
+ def add_currency(post, money, options)
+ currency = options[:currency] || currency(money)
+ add_pair(post, :Currency, currency, :required => true)
+ end
+
# doesn't actually use the currency -- dodgy!
def add_release_amount(post, money, options)
add_pair(post, :ReleaseAmount, amount(money), :required => true)
end
def add_customer_data(post, options)
- add_pair(post, :CustomerEMail, options[:email][0,255]) unless options[:email].blank?
- add_pair(post, :BillingPhone, options[:phone].gsub(/[^0-9+]/, '')[0,20]) unless options[:phone].blank?
+ add_pair(post, :CustomerEMail, truncate(options[:email], 255)) unless options[:email].blank?
add_pair(post, :ClientIPAddress, options[:ip])
end
def add_optional_data(post, options)
add_pair(post, :GiftAidPayment, options[:gift_aid_payment]) unless options[:gift_aid_payment].blank?
add_pair(post, :Apply3DSecure, options[:apply_3d_secure]) unless options[:apply_3d_secure].blank?
+ add_pair(post, :CreateToken, 1) unless options[:store].blank?
+ add_pair(post, :FIRecipientAcctNumber, options[:recipient_account_number])
+ add_pair(post, :FIRecipientSurname, options[:recipient_surname])
+ add_pair(post, :FIRecipientPostcode, options[:recipient_postcode])
+ add_pair(post, :FIRecipientDoB, options[:recipient_dob])
end
def add_address(post, options)
if billing_address = options[:billing_address] || options[:address]
first_name, last_name = parse_first_and_last_name(billing_address[:name])
add_pair(post, :BillingSurname, last_name)
add_pair(post, :BillingFirstnames, first_name)
- add_pair(post, :BillingAddress1, billing_address[:address1])
- add_pair(post, :BillingAddress2, billing_address[:address2])
- add_pair(post, :BillingCity, billing_address[:city])
- add_pair(post, :BillingState, billing_address[:state]) if billing_address[:country] == 'US'
- add_pair(post, :BillingCountry, billing_address[:country])
- add_pair(post, :BillingPostCode, billing_address[:zip])
+ add_pair(post, :BillingAddress1, truncate(billing_address[:address1], 100))
+ add_pair(post, :BillingAddress2, truncate(billing_address[:address2], 100))
+ add_pair(post, :BillingCity, truncate(billing_address[:city], 40))
+ add_pair(post, :BillingState, truncate(billing_address[:state], 2)) if is_usa(billing_address[:country])
+ add_pair(post, :BillingCountry, truncate(billing_address[:country], 2))
+ add_pair(post, :BillingPhone, sanitize_phone(billing_address[:phone]))
+ add_pair(post, :BillingPostCode, truncate(billing_address[:zip], 10))
end
if shipping_address = options[:shipping_address] || billing_address
first_name, last_name = parse_first_and_last_name(shipping_address[:name])
add_pair(post, :DeliverySurname, last_name)
add_pair(post, :DeliveryFirstnames, first_name)
- add_pair(post, :DeliveryAddress1, shipping_address[:address1])
- add_pair(post, :DeliveryAddress2, shipping_address[:address2])
- add_pair(post, :DeliveryCity, shipping_address[:city])
- add_pair(post, :DeliveryState, shipping_address[:state]) if shipping_address[:country] == 'US'
- add_pair(post, :DeliveryCountry, shipping_address[:country])
- add_pair(post, :DeliveryPostCode, shipping_address[:zip])
+ add_pair(post, :DeliveryAddress1, truncate(shipping_address[:address1], 100))
+ add_pair(post, :DeliveryAddress2, truncate(shipping_address[:address2], 100))
+ add_pair(post, :DeliveryCity, truncate(shipping_address[:city], 40))
+ add_pair(post, :DeliveryState, truncate(shipping_address[:state], 2)) if is_usa(shipping_address[:country])
+ add_pair(post, :DeliveryCountry, truncate(shipping_address[:country], 2))
+ add_pair(post, :DeliveryPhone, sanitize_phone(shipping_address[:phone]))
+ add_pair(post, :DeliveryPostCode, truncate(shipping_address[:zip], 10))
end
end
def add_invoice(post, options)
add_pair(post, :VendorTxCode, sanitize_order_id(options[:order_id]), :required => true)
- add_pair(post, :Description, truncate_description(options[:description] || options[:order_id]))
+ add_pair(post, :Description, truncate(options[:description] || options[:order_id], 100))
end
+ def add_payment_method(post, payment_method, options)
+ if payment_method.respond_to?(:number)
+ add_credit_card(post, payment_method)
+ else
+ add_token_details(post, payment_method, options)
+ end
+ end
+
def add_credit_card(post, credit_card)
- add_pair(post, :CardHolder, credit_card.name, :required => true)
+ add_pair(post, :CardHolder, truncate(credit_card.name, 50), :required => true)
add_pair(post, :CardNumber, credit_card.number, :required => true)
add_pair(post, :ExpiryDate, format_date(credit_card.month, credit_card.year), :required => true)
if requires_start_date_or_issue_number?(credit_card)
@@ -207,19 +242,39 @@
add_pair(post, :CardType, map_card_type(credit_card))
add_pair(post, :CV2, credit_card.verification_value)
end
+ def add_token_details(post, token, options)
+ add_token(post, token)
+ add_pair(post, :StoreToken, options[:customer])
+ end
+
+ def add_token(post, token)
+ add_pair(post, :Token, token)
+ end
+
def sanitize_order_id(order_id)
- order_id.to_s.gsub(/[^-a-zA-Z0-9._]/, '')
+ cleansed = order_id.to_s.gsub(/[^-a-zA-Z0-9._]/, '')
+ truncate(cleansed, 40)
end
- def truncate_description(description)
- return nil unless description
- description[0, 100]
+ def sanitize_phone(phone)
+ return nil unless phone
+ cleansed = phone.to_s.gsub(/[^0-9+]/, '')
+ truncate(cleansed, 20)
end
+ def truncate(value, max_size)
+ return nil unless value
+ value[0, max_size]
+ end
+
+ def is_usa(country)
+ truncate(country, 2) == 'US'
+ end
+
def map_card_type(credit_card)
raise ArgumentError, "The credit card type must be provided" if card_brand(credit_card).blank?
card_type = card_brand(credit_card).to_sym
@@ -254,15 +309,20 @@
:cvv_result => AVS_CVV_CODE[ response["CV2Result"] ]
)
end
def authorization_from(response, params, action)
+ case action
+ when :store
+ response['Token']
+ else
[ params[:VendorTxCode],
response["VPSTxId"],
response["TxAuthNo"],
response["SecurityKey"],
action ].join(";")
+ end
end
def abort_or_void_from(identification)
original_transaction = identification.split(';').last
original_transaction == 'authorization' ? :abort : :void
@@ -271,11 +331,15 @@
def url_for(action)
simulate ? build_simulator_url(action) : build_url(action)
end
def build_url(action)
- endpoint = [ :purchase, :authorization ].include?(action) ? "vspdirect-register" : TRANSACTIONS[action].downcase
+ endpoint = case action
+ when :purchase, :authorization then "vspdirect-register"
+ when :store then 'directtoken'
+ else TRANSACTIONS[action].downcase
+ end
"#{test? ? self.test_url : self.live_url}/#{endpoint}.vsp"
end
def build_simulator_url(action)
endpoint = [ :purchase, :authorization ].include?(action) ? "VSPDirectGateway.asp" : "VSPServerGateway.asp?Service=Vendor#{TRANSACTIONS[action].capitalize}Tx"
@@ -318,16 +382,17 @@
def parse_first_and_last_name(value)
name = value.to_s.split(' ')
last_name = name.pop || ''
first_name = name.join(' ')
- [ first_name[0,20], last_name[0,20] ]
+ [ truncate(first_name, 20), truncate(last_name, 20) ]
end
def localized_amount(money, currency)
amount = amount(money)
CURRENCIES_WITHOUT_FRACTIONS.include?(currency.to_s) ? amount.split('.').first : amount
end
end
+
end
end