lib/active_merchant/billing/gateways/linkpoint.rb in activemerchant-1.28.0 vs lib/active_merchant/billing/gateways/linkpoint.rb in activemerchant-1.29.0
- old
+ new
@@ -1,77 +1,77 @@
require 'rexml/document'
module ActiveMerchant #:nodoc:
module Billing #:nodoc:
-
+
# Initialization Options
# :login Your store number
# :pem The text of your linkpoint PEM file. Note
# this is not the path to file, but its
# contents. If you are only using one PEM
- # file on your site you can declare it
+ # file on your site you can declare it
# globally and then you won't need to
# include this option
#
#
- # A valid store number is required. Unfortunately, with LinkPoint
- # YOU CAN'T JUST USE ANY OLD STORE NUMBER. Also, you can't just
- # generate your own PEM file. You'll need to use a special PEM file
- # provided by LinkPoint.
+ # A valid store number is required. Unfortunately, with LinkPoint
+ # YOU CAN'T JUST USE ANY OLD STORE NUMBER. Also, you can't just
+ # generate your own PEM file. You'll need to use a special PEM file
+ # provided by LinkPoint.
#
- # Go to http://www.linkpoint.com/support/sup_teststore.asp to set up
+ # Go to http://www.linkpoint.com/support/sup_teststore.asp to set up
# a test account and obtain your PEM file.
#
# Declaring PEM file Globally
# ActiveMerchant::Billing::LinkpointGateway.pem_file = File.read( File.dirname(__FILE__) + '/../mycert.pem' )
- #
- #
+ #
+ #
# Valid Order Options
- # :result =>
+ # :result =>
# LIVE Production mode
# GOOD Approved response in test mode
# DECLINE Declined response in test mode
# DUPLICATE Duplicate response in test mode
- #
+ #
# :ponumber Order number
#
# :transactionorigin => Source of the transaction
# ECI Email or Internet
# MAIL Mail order
# MOTO Mail order/Telephone
# TELEPHONE Telephone
# RETAIL Face-to-face
#
- # :ordertype =>
+ # :ordertype =>
# SALE Real live sale
# PREAUTH Authorize only
# POSTAUTH Forced Ticket or Ticket Only transaction
- # VOID
- # CREDIT
+ # VOID
+ # CREDIT
# CALCSHIPPING For shipping charges calculations
# CALCTAX For sales tax calculations
- #
- # Recurring Options
- # :action =>
- # SUBMIT
- # MODIFY
- # CANCEL
- #
+ #
+ # Recurring Options
+ # :action =>
+ # SUBMIT
+ # MODIFY
+ # CANCEL
+ #
# :installments Identifies how many recurring payments to charge the customer
# :startdate Date to begin charging the recurring payments. Format: YYYYMMDD or "immediate"
- # :periodicity =>
- # MONTHLY
- # BIMONTHLY
- # WEEKLY
- # BIWEEKLY
- # YEARLY
- # DAILY
+ # :periodicity =>
+ # MONTHLY
+ # BIMONTHLY
+ # WEEKLY
+ # BIWEEKLY
+ # YEARLY
+ # DAILY
# :threshold Tells how many times to retry the transaction (if it fails) before contacting the merchant.
# :comments Uh... comments
#
#
- # For reference:
+ # For reference:
#
# https://www.linkpointcentral.com/lpc/docs/Help/APIHelp/lpintguide.htm
#
# Entities = {
# :payment => [:subtotal, :tax, :vattax, :shipping, :chargetotal],
@@ -83,11 +83,11 @@
# :periodic => [:action, :installments, :threshold, :startdate, :periodicity, :comments],
# :notes => [:comments, :referred]
# :items => [:item => [:price, :quantity, :description, :id, :options => [:option => [:name, :value]]]]
# }
#
- #
+ #
# LinkPoint's Items entity is an optional entity that can be attached to orders.
# It is entered as :line_items to be consistent with the CyberSource implementation
#
# The line_item hash goes in the options hash and should look like
#
@@ -115,61 +115,61 @@
# :quantity => '1'
# }
# ]
# This functionality is only supported by this particular gateway may
# be changed at any time
- #
- class LinkpointGateway < Gateway
+ #
+ class LinkpointGateway < Gateway
# Your global PEM file. This will be assigned to you by linkpoint
- #
- # Example:
- #
+ #
+ # Example:
+ #
# ActiveMerchant::Billing::LinkpointGateway.pem_file = File.read( File.dirname(__FILE__) + '/../mycert.pem' )
- #
+ #
cattr_accessor :pem_file
-
+
self.test_url = 'https://staging.linkpt.net:1129/'
self.live_url = 'https://secure.linkpt.net:1129/'
-
+
self.supported_countries = ['US']
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club]
self.homepage_url = 'http://www.linkpoint.com/'
self.display_name = 'LinkPoint'
-
+
def initialize(options = {})
requires!(options, :login)
-
+
@options = {
:result => 'LIVE',
:pem => LinkpointGateway.pem_file
}.update(options)
-
+
raise ArgumentError, "You need to pass in your pem file using the :pem parameter or set it globally using ActiveMerchant::Billing::LinkpointGateway.pem_file = File.read( File.dirname(__FILE__) + '/../mycert.pem' ) or similar" if @options[:pem].blank?
end
-
+
# Send a purchase request with periodic options
- # Recurring Options
- # :action =>
- # SUBMIT
- # MODIFY
- # CANCEL
- #
+ # Recurring Options
+ # :action =>
+ # SUBMIT
+ # MODIFY
+ # CANCEL
+ #
# :installments Identifies how many recurring payments to charge the customer
# :startdate Date to begin charging the recurring payments. Format: YYYYMMDD or "immediate"
- # :periodicity =>
- # :monthly
- # :bimonthly
- # :weekly
- # :biweekly
- # :yearly
- # :daily
+ # :periodicity =>
+ # :monthly
+ # :bimonthly
+ # :weekly
+ # :biweekly
+ # :yearly
+ # :daily
# :threshold Tells how many times to retry the transaction (if it fails) before contacting the merchant.
# :comments Uh... comments
#
def recurring(money, creditcard, options={})
requires!(options, [:periodicity, :bimonthly, :monthly, :biweekly, :weekly, :yearly, :daily], :installments, :order_id )
-
+
options.update(
:ordertype => "SALE",
:action => options[:action] || "SUBMIT",
:installments => options[:installments] || 12,
:startdate => options[:startdate] || "immediate",
@@ -177,59 +177,59 @@
:comments => options[:comments] || nil,
:threshold => options[:threshold] || 3
)
commit(money, creditcard, options)
end
-
+
# Buy the thing
def purchase(money, creditcard, options={})
requires!(options, :order_id)
options.update(
:ordertype => "SALE"
)
commit(money, creditcard, options)
end
-
+
#
# Authorize the transaction
- #
+ #
# Reserves the funds on the customer's credit card, but does not charge the card.
#
def authorize(money, creditcard, options = {})
requires!(options, :order_id)
options.update(
:ordertype => "PREAUTH"
)
commit(money, creditcard, options)
end
-
+
#
- # Post an authorization.
+ # Post an authorization.
#
- # Captures the funds from an authorized transaction.
+ # Captures the funds from an authorized transaction.
# Order_id must be a valid order id from a prior authorized transaction.
- #
+ #
def capture(money, authorization, options = {})
options.update(
:order_id => authorization,
:ordertype => "POSTAUTH"
)
- commit(money, nil, options)
+ commit(money, nil, options)
end
-
+
# Void a previous transaction
def void(identification, options = {})
options.update(
:order_id => identification,
:ordertype => "VOID"
)
commit(nil, nil, options)
end
-
- #
+
+ #
# Refund an order
- #
+ #
# identification must be a valid order id previously submitted by SALE
#
def refund(money, identification, options = {})
options.update(
:ordertype => "CREDIT",
@@ -240,54 +240,50 @@
def credit(money, identification, options = {})
deprecated CREDIT_DEPRECATION_MESSAGE
refund(money, identification, options)
end
-
- def test?
- @options[:test] || super
- end
-
+
private
# Commit the transaction by posting the XML file to the LinkPoint server
def commit(money, creditcard, options = {})
response = parse(ssl_post(test? ? self.test_url : self.live_url, post_data(money, creditcard, options)))
-
- Response.new(successful?(response), response[:message], response,
+
+ Response.new(successful?(response), response[:message], response,
:test => test?,
:authorization => response[:ordernum],
:avs_result => { :code => response[:avs].to_s[2,1] },
:cvv_result => response[:avs].to_s[3,1]
)
end
-
+
def successful?(response)
response[:approved] == "APPROVED"
end
-
+
# Build the XML file
def post_data(money, creditcard, options)
params = parameters(money, creditcard, options)
-
+
xml = REXML::Document.new
order = xml.add_element("order")
-
+
# Merchant Info
merchantinfo = order.add_element("merchantinfo")
merchantinfo.add_element("configfile").text = @options[:login]
-
+
# Loop over the params hash to construct the XML string
for key, value in params
elem = order.add_element(key.to_s)
if key == :items
build_items(elem, value)
else
for k, v in params[key]
elem.add_element(k.to_s).text = params[key][k].to_s if params[key][k]
end
end
- # Linkpoint doesn't understand empty elements:
+ # Linkpoint doesn't understand empty elements:
order.delete(elem) if elem.size == 0
end
return xml.to_s
end
@@ -309,13 +305,13 @@
end
end
end
# Set up the parameters hash just once so we don't have to do it
- # for every action.
+ # for every action.
def parameters(money, creditcard, options = {})
-
+
params = {
:payment => {
:subtotal => amount(options[:subtotal]),
:tax => amount(options[:tax]),
:vattax => amount(options[:vattax]),
@@ -328,23 +324,23 @@
:ponumber => options[:ponumber],
:taxexempt => options[:taxexempt],
:terminaltype => options[:terminaltype],
:ip => options[:ip],
:reference_number => options[:reference_number],
- :recurring => options[:recurring] || "NO", #DO NOT USE if you are using the periodic billing option.
+ :recurring => options[:recurring] || "NO", #DO NOT USE if you are using the periodic billing option.
:tdate => options[:tdate]
},
:orderoptions => {
:ordertype => options[:ordertype],
:result => @options[:result]
},
:periodic => {
:action => options[:action],
- :installments => options[:installments],
- :threshold => options[:threshold],
- :startdate => options[:startdate],
- :periodicity => options[:periodicity],
+ :installments => options[:installments],
+ :threshold => options[:threshold],
+ :startdate => options[:startdate],
+ :periodicity => options[:periodicity],
:comments => options[:comments]
},
:telecheck => {
:routing => options[:telecheck_routing],
:account => options[:telecheck_account],
@@ -355,61 +351,61 @@
:void => options[:telecheck_void],
:accounttype => options[:telecheck_accounttype],
:ssn => options[:telecheck_ssn],
}
}
-
+
if creditcard
params[:creditcard] = {
:cardnumber => creditcard.number,
:cardexpmonth => creditcard.month,
:cardexpyear => format_creditcard_expiry_year(creditcard.year),
:track => nil
}
-
+
if creditcard.verification_value?
params[:creditcard][:cvmvalue] = creditcard.verification_value
params[:creditcard][:cvmindicator] = 'provided'
else
params[:creditcard][:cvmindicator] = 'not_provided'
- end
+ end
end
-
- if billing_address = options[:billing_address] || options[:address]
-
- params[:billing] = {}
+
+ if billing_address = options[:billing_address] || options[:address]
+
+ params[:billing] = {}
params[:billing][:name] = billing_address[:name] || (creditcard ? creditcard.name : nil)
params[:billing][:address1] = billing_address[:address1] unless billing_address[:address1].blank?
params[:billing][:address2] = billing_address[:address2] unless billing_address[:address2].blank?
params[:billing][:city] = billing_address[:city] unless billing_address[:city].blank?
params[:billing][:state] = billing_address[:state] unless billing_address[:state].blank?
params[:billing][:zip] = billing_address[:zip] unless billing_address[:zip].blank?
params[:billing][:country] = billing_address[:country] unless billing_address[:country].blank?
params[:billing][:company] = billing_address[:company] unless billing_address[:company].blank?
params[:billing][:phone] = billing_address[:phone] unless billing_address[:phone].blank?
params[:billing][:email] = options[:email] unless options[:email].blank?
- end
+ end
- if shipping_address = options[:shipping_address]
+ if shipping_address = options[:shipping_address]
params[:shipping] = {}
- params[:shipping][:name] = shipping_address[:name] || creditcard ? creditcard.name : nil
+ params[:shipping][:name] = shipping_address[:name] || (creditcard ? creditcard.name : nil)
params[:shipping][:address1] = shipping_address[:address1] unless shipping_address[:address1].blank?
params[:shipping][:address2] = shipping_address[:address2] unless shipping_address[:address2].blank?
params[:shipping][:city] = shipping_address[:city] unless shipping_address[:city].blank?
params[:shipping][:state] = shipping_address[:state] unless shipping_address[:state].blank?
params[:shipping][:zip] = shipping_address[:zip] unless shipping_address[:zip].blank?
params[:shipping][:country] = shipping_address[:country] unless shipping_address[:country].blank?
- end
+ end
params[:items] = options[:line_items] if options[:line_items]
-
+
return params
end
-
+
def parse(xml)
-
+
# For reference, a typical response...
# <r_csp></r_csp>
# <r_time></r_time>
# <r_ref></r_ref>
# <r_error></r_error>
@@ -419,33 +415,33 @@
# <r_tdate>Thu Feb 2 15:40:21 2006</r_tdate>
# <r_score></r_score>
# <r_authresponse></r_authresponse>
# <r_approved>APPROVED</r_approved>
# <r_avs></r_avs>
-
+
response = {:message => "Global Error Receipt", :complete => false}
-
+
xml = REXML::Document.new("<response>#{xml}</response>")
xml.root.elements.each do |node|
response[node.name.downcase.sub(/^r_/, '').to_sym] = normalize(node.text)
end unless xml.root.nil?
-
+
response
end
-
+
# Make a ruby type out of the response string
def normalize(field)
case field
when "true" then true
when "false" then false
when "" then nil
when "null" then nil
else field
- end
+ end
end
def format_creditcard_expiry_year(year)
sprintf("%.4i", year)[-2..-1]
- end
+ end
end
end
end