lib/active_merchant/billing/gateways/data_cash.rb in activemerchant-1.59.0 vs lib/active_merchant/billing/gateways/data_cash.rb in activemerchant-1.60.0
- old
+ new
@@ -4,72 +4,33 @@
module Billing
class DataCashGateway < Gateway
self.default_currency = 'GBP'
self.supported_countries = ['GB']
- # From the DataCash docs; Page 13, the following cards are
- # usable:
- # American Express, ATM, Carte Blanche, Diners Club, Discover,
- # EnRoute, GE Capital, JCB, Laser, Maestro, Mastercard, Solo,
- # Switch, Visa, Visa Delta, VISA Electron, Visa Purchasing
- #
- # Note continuous authority is only supported for :visa, :master and :american_express card types
self.supported_cardtypes = [ :visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro, :switch, :solo, :laser ]
self.homepage_url = 'http://www.datacash.com/'
self.display_name = 'DataCash'
- # Datacash server URLs
self.test_url = 'https://testserver.datacash.com/Transaction'
self.live_url = 'https://mars.transaction.datacash.com/Transaction'
- # Different Card Transaction Types
AUTH_TYPE = 'auth'
CANCEL_TYPE = 'cancel'
FULFILL_TYPE = 'fulfill'
PRE_TYPE = 'pre'
REFUND_TYPE = 'refund'
TRANSACTION_REFUND_TYPE = 'txn_refund'
- # Constant strings for use in the ExtendedPolicy complex element for
- # CV2 checks
POLICY_ACCEPT = 'accept'
POLICY_REJECT = 'reject'
- # Datacash success code
- DATACASH_SUCCESS = '1'
-
- # Creates a new DataCashGateway
- #
- # The gateway requires that a valid login and password be passed
- # in the +options+ hash.
- #
- # ==== Options
- #
- # * <tt>:login</tt> -- The Datacash account login.
- # * <tt>:password</tt> -- The Datacash account password.
- # * <tt>:test => +true+ or +false+</tt> -- Use the test or live Datacash url.
- #
def initialize(options = {})
requires!(options, :login, :password)
super
end
- # Perform a purchase, which is essentially an authorization and capture in a single operation.
- #
- # ==== Parameters
- # * <tt>money</tt> The amount to be authorized as an Integer value in cents.
- # * <tt>authorization_or_credit_card</tt>:: The continuous authority reference or CreditCard details for the transaction.
- # * <tt>options</tt> A hash of optional parameters.
- # * <tt>:order_id</tt> A unique reference for this order (corresponds to merchantreference in datacash documentation)
- # * <tt>:set_up_continuous_authority</tt>
- # Set to true to set up a recurring historic transaction account be set up.
- # Only supported for :visa, :master and :american_express card types
- # See http://www.datacash.com/services/recurring/historic.php for more details of historic transactions.
- # * <tt>:address</tt>:: billing address for card
- #
- # The continuous authority reference will be available in response#params['ca_reference'] if you have requested one
def purchase(money, authorization_or_credit_card, options = {})
requires!(options, :order_id)
if authorization_or_credit_card.is_a?(String)
request = build_purchase_or_authorization_request_with_continuous_authority_reference_request(AUTH_TYPE, money, authorization_or_credit_card, options)
@@ -78,26 +39,10 @@
end
commit(request)
end
- # Performs an authorization, which reserves the funds on the customer's credit card, but does not
- # charge the card.
- #
- # ==== Parameters
- #
- # * <tt>money</tt> The amount to be authorized as an Integer value in cents.
- # * <tt>authorization_or_credit_card</tt>:: The continuous authority reference or CreditCard details for the transaction.
- # * <tt>options</tt> A hash of optional parameters.
- # * <tt>:order_id</tt> A unique reference for this order (corresponds to merchantreference in datacash documentation)
- # * <tt>:set_up_continuous_authority</tt>::
- # Set to true to set up a recurring historic transaction account be set up.
- # Only supported for :visa, :master and :american_express card types
- # See http://www.datacash.com/services/recurring/historic.php for more details of historic transactions.
- # * <tt>:address</tt>:: billing address for card
- #
- # The continuous authority reference will be available in response#params['ca_reference'] if you have requested one
def authorize(money, authorization_or_credit_card, options = {})
requires!(options, :order_id)
if authorization_or_credit_card.is_a?(String)
request = build_purchase_or_authorization_request_with_continuous_authority_reference_request(AUTH_TYPE, money, authorization_or_credit_card, options)
@@ -106,90 +51,42 @@
end
commit(request)
end
- # Captures the funds from an authorized transaction.
- #
- # ==== Parameters
- #
- # * <tt>money</tt> -- The amount to be captured as anInteger value in cents.
- # * <tt>authorization</tt> -- The authorization returned from the previous authorize request.
def capture(money, authorization, options = {})
commit(build_void_or_capture_request(FULFILL_TYPE, money, authorization, options))
end
- # Void a previous transaction
- #
- # ==== Parameters
- #
- # * <tt>authorization</tt> - The authorization returned from the previous authorize request.
def void(authorization, options = {})
request = build_void_or_capture_request(CANCEL_TYPE, nil, authorization, options)
commit(request)
end
- # Refund to a card
- #
- # ==== Parameters
- #
- # * <tt>money</tt> The amount to be refunded as an Integer value in cents. Set to nil for a full refund on existing transaction.
- # * <tt>reference_or_credit_card</tt> The credit card you want to refund OR the datacash_reference for the existing transaction you are refunding
- # * <tt>options</tt> Are ignored when refunding via reference to an existing transaction, otherwise
- # * <tt>:order_id</tt> A unique reference for this order (corresponds to merchantreference in datacash documentation)
- # * <tt>:address</tt>:: billing address for card
def credit(money, reference_or_credit_card, options = {})
if reference_or_credit_card.is_a?(String)
ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
refund(money, reference_or_credit_card)
else
- request = build_refund_request(money, reference_or_credit_card, options)
+ request = build_credit_request(money, reference_or_credit_card, options)
commit(request)
end
end
def refund(money, reference, options = {})
commit(build_transaction_refund_request(money, reference))
end
+
private
- # Create the xml document for a 'cancel' or 'fulfill' transaction.
- #
- # Final XML should look like:
- # <Request>
- # <Authentication>
- # <client>99000001</client>
- # <password>******</password>
- # </Authentication>
- # <Transaction>
- # <TxnDetails>
- # <amount>25.00</amount>
- # </TxnDetails>
- # <HistoricTxn>
- # <reference>4900200000000001</reference>
- # <authcode>A6</authcode>
- # <method>fulfill</method>
- # </HistoricTxn>
- # </Transaction>
- # </Request>
- #
- # Parameters:
- # * <tt>type</tt> must be FULFILL_TYPE or CANCEL_TYPE
- # * <tt>money</tt> - optional - Integer value in cents
- # * <tt>authorization</tt> - the Datacash authorization from a previous succesful authorize transaction
- # * <tt>options</tt>
- # * <tt>order_id</tt> - A unique reference for the transaction
- #
- # Returns:
- # -Builder xml document
- #
+
def build_void_or_capture_request(type, money, authorization, options)
parsed_authorization = parse_authorization_string(authorization)
xml = Builder::XmlMarkup.new :indent => 2
xml.instruct!
- xml.tag! :Request do
+ xml.tag! :Request, :version => '2' do
add_authentication(xml)
xml.tag! :Transaction do
xml.tag! :HistoricTxn do
xml.tag! :reference, parsed_authorization[:reference]
@@ -207,75 +104,14 @@
end
end
xml.target!
end
- # Create the xml document for an 'auth' or 'pre' transaction with a credit card
- #
- # Final XML should look like:
- #
- # <Request>
- # <Authentication>
- # <client>99000000</client>
- # <password>*******</password>
- # </Authentication>
- # <Transaction>
- # <TxnDetails>
- # <merchantreference>123456</merchantreference>
- # <amount currency="EUR">10.00</amount>
- # </TxnDetails>
- # <CardTxn>
- # <Card>
- # <pan>4444********1111</pan>
- # <expirydate>03/04</expirydate>
- # <Cv2Avs>
- # <street_address1>Flat 7</street_address1>
- # <street_address2>89 Jumble
- # Street</street_address2>
- # <street_address3>Mytown</street_address3>
- # <postcode>AV12FR</postcode>
- # <cv2>123</cv2>
- # <ExtendedPolicy>
- # <cv2_policy notprovided="reject"
- # notchecked="accept"
- # matched="accept"
- # notmatched="reject"
- # partialmatch="reject"/>
- # <postcode_policy notprovided="reject"
- # notchecked="accept"
- # matched="accept"
- # notmatched="reject"
- # partialmatch="accept"/>
- # <address_policy notprovided="reject"
- # notchecked="accept"
- # matched="accept"
- # notmatched="reject"
- # partialmatch="accept"/>
- # </ExtendedPolicy>
- # </Cv2Avs>
- # </Card>
- # <method>auth</method>
- # </CardTxn>
- # </Transaction>
- # </Request>
- #
- # Parameters:
- # -type must be 'auth' or 'pre'
- # -money - A money object with the price and currency
- # -credit_card - The credit_card details to use
- # -options:
- # :order_id is the merchant reference number
- # :billing_address is the billing address for the cc
- # :address is the delivery address
- #
- # Returns:
- # -xml: Builder document containing the markup
- #
def build_purchase_or_authorization_request_with_credit_card_request(type, money, credit_card, options)
xml = Builder::XmlMarkup.new :indent => 2
xml.instruct!
- xml.tag! :Request do
+ xml.tag! :Request, :version => '2' do
add_authentication(xml)
xml.tag! :Transaction do
if options[:set_up_continuous_authority]
xml.tag! :ContAuthTxn, :type => 'setup'
@@ -292,51 +128,17 @@
end
end
xml.target!
end
- # Create the xml document for an 'auth' or 'pre' transaction with
- # continuous authorization
- #
- # Final XML should look like:
- #
- # <Request>
- # <Transaction>
- # <ContAuthTxn type="historic" />
- # <TxnDetails>
- # <merchantreference>3851231</merchantreference>
- # <capturemethod>cont_auth</capturemethod>
- # <amount currency="GBP">18.50</amount>
- # </TxnDetails>
- # <HistoricTxn>
- # <reference>4500200040925092</reference>
- # <method>auth</method>
- # </HistoricTxn>
- # </Transaction>
- # <Authentication>
- # <client>99000001</client>
- # <password>mypasswd</password>
- # </Authentication>
- # </Request>
- #
- # Parameters:
- # -type must be 'auth' or 'pre'
- # -money - A money object with the price and currency
- # -authorization - The authorization containing a continuous authority reference previously set up on a credit card
- # -options:
- # :order_id is the merchant reference number
- #
- # Returns:
- # -xml: Builder document containing the markup
- #
def build_purchase_or_authorization_request_with_continuous_authority_reference_request(type, money, authorization, options)
parsed_authorization = parse_authorization_string(authorization)
raise ArgumentError, "The continuous authority reference is required for continuous authority transactions" if parsed_authorization[:ca_reference].blank?
xml = Builder::XmlMarkup.new :indent => 2
xml.instruct!
- xml.tag! :Request do
+ xml.tag! :Request, :version => '2' do
add_authentication(xml)
xml.tag! :Transaction do
xml.tag! :ContAuthTxn, :type => 'historic'
xml.tag! :HistoricTxn do
xml.tag! :reference, parsed_authorization[:ca_reference]
@@ -350,35 +152,15 @@
end
end
xml.target!
end
- # Create the xml document for a full or partial refund transaction with
- #
- # Final XML should look like:
- #
- # <Request>
- # <Authentication>
- # <client>99000001</client>
- # <password>*******</password>
- # </Authentication>
- # <Transaction>
- # <HistoricTxn>
- # <method>txn_refund</method>
- # <reference>12345678</reference>
- # </HistoricTxn>
- # <TxnDetails>
- # <amount>10.00</amount>
- # </TxnDetails>
- # </Transaction>
- # </Request>
- #
def build_transaction_refund_request(money, authorization)
parsed_authorization = parse_authorization_string(authorization)
xml = Builder::XmlMarkup.new :indent => 2
xml.instruct!
- xml.tag! :Request do
+ xml.tag! :Request, :version => '2' do
add_authentication(xml)
xml.tag! :Transaction do
xml.tag! :HistoricTxn do
xml.tag! :reference, parsed_authorization[:reference]
xml.tag! :method, TRANSACTION_REFUND_TYPE
@@ -391,38 +173,14 @@
end
end
xml.target!
end
- # Create the xml document for a full or partial refund with
- #
- # Final XML should look like:
- #
- # <Request>
- # <Authentication>
- # <client>99000001</client>
- # <password>*****</password>
- # </Authentication>
- # <Transaction>
- # <CardTxn>
- # <Card>
- # <pan>633300*********1</pan>
- # <expirydate>04/06</expirydate>
- # <startdate>01/04</startdate>
- # </Card>
- # <method>refund</method>
- # </CardTxn>
- # <TxnDetails>
- # <merchantreference>1000001</merchantreference>
- # <amount currency="GBP">95.99</amount>
- # </TxnDetails>
- # </Transaction>
- # </Request>
- def build_refund_request(money, credit_card, options)
+ def build_credit_request(money, credit_card, options)
xml = Builder::XmlMarkup.new :indent => 2
xml.instruct!
- xml.tag! :Request do
+ xml.tag! :Request, :version => '2' do
add_authentication(xml)
xml.tag! :Transaction do
xml.tag! :CardTxn do
xml.tag! :method, REFUND_TYPE
add_credit_card(xml, credit_card, options[:billing_address])
@@ -434,36 +192,17 @@
end
end
xml.target!
end
-
- # Adds the authentication element to the passed builder xml doc
- #
- # Parameters:
- # -xml: Builder document that is being built up
- #
- # Returns:
- # -none: The results is stored in the passed xml document
- #
def add_authentication(xml)
xml.tag! :Authentication do
xml.tag! :client, @options[:login]
xml.tag! :password, @options[:password]
end
end
- # Add credit_card details to the passed XML Builder doc
- #
- # Parameters:
- # -xml: Builder document that is being built up
- # -credit_card: ActiveMerchant::Billing::CreditCard object
- # -billing_address: Hash containing all of the billing address details
- #
- # Returns:
- # -none: The results is stored in the passed xml document
- #
def add_credit_card(xml, credit_card, address)
xml.tag! :Card do
# DataCash calls the CC number 'pan'
@@ -518,48 +257,23 @@
end
end
end
end
- # Send the passed data to DataCash for processing
- #
- # Parameters:
- # -request: The XML data that is to be sent to Datacash
- #
- # Returns:
- # - ActiveMerchant::Billing::Response object
- #
def commit(request)
response = parse(ssl_post(test? ? self.test_url : self.live_url, request))
- Response.new(response[:status] == DATACASH_SUCCESS, response[:reason], response,
+ Response.new(response[:status] == '1', response[:reason], response,
:test => test?,
:authorization => "#{response[:datacash_reference]};#{response[:authcode]};#{response[:ca_reference]}"
)
end
- # Returns a date string in the format Datacash expects
- #
- # Parameters:
- # -month: integer, the month
- # -year: integer, the year
- #
- # Returns:
- # -String: date in MM/YY format
- #
def format_date(month, year)
"#{format(month,:two_digits)}/#{format(year, :two_digits)}"
end
- # Parse the datacash response and create a Response object
- #
- # Parameters:
- # -body: The XML returned from Datacash
- #
- # Returns:
- # -a hash with all of the values returned in the Datacash XML response
- #
def parse(body)
response = {}
xml = REXML::Document.new(body)
root = REXML::XPath.first(xml, "//Response")
@@ -569,17 +283,9 @@
end
response
end
- # Parse an xml element
- #
- # Parameters:
- # -response: The hash that the values are being returned in
- # -node: The node that is currently being read
- #
- # Returns:
- # - none (results are stored in the passed hash)
def parse_element(response, node)
if node.has_elements?
node.elements.each{|e| parse_element(response, e) }
else
response[node.name.underscore.to_sym] = node.text