lib/active_merchant/billing/gateways/elavon.rb in jelaniharris-activemerchant-1.24.1 vs lib/active_merchant/billing/gateways/elavon.rb in jelaniharris-activemerchant-1.29.1

- old
+ new

@@ -27,11 +27,13 @@ # # puts response.success? # Check whether the transaction was successful # puts response.message # Retrieve the message returned by Elavon # puts response.authorization # Retrieve the unique transaction ID returned by Elavon # - class ElavonGateway < ViaklixGateway + class ElavonGateway < Gateway + class_attribute :test_url, :live_url, :delimiter, :actions + self.test_url = 'https://demo.myvirtualmerchant.com/VirtualMerchantDemo/process.do' self.live_url = 'https://www.myvirtualmerchant.com/VirtualMerchant/process.do' self.display_name = 'Elavon MyVirtualMerchant' self.supported_countries = ['US', 'CA'] @@ -40,78 +42,197 @@ self.delimiter = "\n" self.actions = { :purchase => 'CCSALE', :credit => 'CCCREDIT', + :refund => 'CCRETURN', :authorize => 'CCAUTHONLY', - :capture => 'CCFORCE' + :capture => 'CCFORCE', + :void => 'CCVOID' } - + + # Initialize the Gateway + # + # The gateway requires that a valid login and password be passed + # in the +options+ hash. + # + # ==== Options + # + # * <tt>:login</tt> -- Merchant ID + # * <tt>:password</tt> -- PIN + # * <tt>:user</tt> -- Specify a subuser of the account (optional) + # * <tt>:test => +true+ or +false+</tt> -- Force test transactions + def initialize(options = {}) + requires!(options, :login, :password) + super + end + + # Make a purchase + def purchase(money, creditcard, options = {}) + form = {} + add_salestax(form, options) + add_invoice(form, options) + add_creditcard(form, creditcard) + add_address(form, options) + add_customer_data(form, options) + add_test_mode(form, options) + commit(:purchase, money, form) + end + # Authorize a credit card for a given amount. - # + # # ==== Parameters # * <tt>money</tt> - The amount to be authorized as an Integer value in cents. # * <tt>credit_card</tt> - The CreditCard details for the transaction. # * <tt>options</tt> - # * <tt>:billing_address</tt> - The billing address for the cardholder. + # * <tt>:billing_address</tt> - The billing address for the cardholder. def authorize(money, creditcard, options = {}) form = {} + add_salestax(form, options) add_invoice(form, options) - add_creditcard(form, creditcard) - add_address(form, options) + add_creditcard(form, creditcard) + add_address(form, options) add_customer_data(form, options) add_test_mode(form, options) commit(:authorize, money, form) end - + # Capture authorized funds from a credit card. - # + # # ==== Parameters # * <tt>money</tt> - The amount to be captured as an Integer value in cents. # * <tt>authorization</tt> - The approval code returned from the initial authorization. # * <tt>options</tt> # * <tt>:credit_card</tt> - The CreditCard details from the initial transaction (required). def capture(money, authorization, options = {}) requires!(options, :credit_card) - + form = {} - add_reference(form, authorization) + add_salestax(form, options) + add_approval_code(form, authorization) add_invoice(form, options) add_creditcard(form, options[:credit_card]) add_customer_data(form, options) add_test_mode(form, options) commit(:capture, money, form) end - + + # Refund a transaction. + # + # This transaction indicates to the gateway that + # money should flow from the merchant to the customer. + # + # ==== Parameters + # + # * <tt>money</tt> -- The amount to be credited to the customer as an Integer value in cents. + # * <tt>identification</tt> -- The ID of the original transaction against which the refund is being issued. + # * <tt>options</tt> -- A hash of parameters. + def refund(money, identification, options = {}) + form = {} + add_txn_id(form, identification) + add_test_mode(form, options) + commit(:refund, money, form) + end + + # Void a previous transaction + # + # ==== Parameters + # + # * <tt>authorization</tt> - The authorization returned from the previous request. + def void(identification, options = {}) + form = {} + add_txn_id(form, identification) + add_test_mode(form, options) + commit(:void, nil, form) + end + + # Make a credit to a card. Use the refund method if you'd like to credit using + # previous transaction + # + # ==== Parameters + # * <tt>money</tt> - The amount to be credited as an Integer value in cents. + # * <tt>creditcard</tt> - The credit card to be credited. + # * <tt>options</tt> + def credit(money, creditcard, options = {}) + if creditcard.is_a?(String) + raise ArgumentError, "Reference credits are not supported. Please supply the original credit card or use the #refund method." + end + + form = {} + add_invoice(form, options) + add_creditcard(form, creditcard) + add_address(form, options) + add_customer_data(form, options) + add_test_mode(form, options) + commit(:credit, money, form) + end + + private - def add_reference(form, authorization) - form[:approval_code] = authorization + def add_invoice(form,options) + form[:invoice_number] = (options[:order_id] || options[:invoice]).to_s.slice(0, 10) + form[:description] = options[:description].to_s.slice(0, 255) end - + + def add_approval_code(form, authorization) + form[:approval_code] = authorization.split(';').first + end + + def add_txn_id(form, authorization) + form[:txn_id] = authorization.split(';').last + end + def authorization_from(response) - response['approval_code'] + [response['approval_code'], response['txn_id']].join(';') end - + + def add_creditcard(form, creditcard) + form[:card_number] = creditcard.number + form[:exp_date] = expdate(creditcard) + + if creditcard.verification_value? + add_verification_value(form, creditcard) + end + + form[:first_name] = creditcard.first_name.to_s.slice(0, 20) + form[:last_name] = creditcard.last_name.to_s.slice(0, 30) + end + def add_verification_value(form, creditcard) - form[:cvv2cvc2] = creditcard.verification_value + form[:cvv2cvc2] = creditcard.verification_value form[:cvv2cvc2_indicator] = '1' end + def add_customer_data(form, options) + form[:email] = options[:email].to_s.slice(0, 100) unless options[:email].blank? + form[:customer_code] = options[:customer].to_s.slice(0, 10) unless options[:customer].blank? + end + + def add_salestax(form, options) + form[:salestax] = options[:tax] if options[:tax].present? + end + + def expdate(creditcard) + year = sprintf("%.4i", creditcard.year) + month = sprintf("%.2i", creditcard.month) + "#{month}#{year[2..3]}" + end + def add_address(form,options) - billing_address = options[:billing_address] || options[:address] - + billing_address = options[:billing_address] || options[:address] + if billing_address form[:avs_address] = billing_address[:address1].to_s.slice(0, 30) form[:address2] = billing_address[:address2].to_s.slice(0, 30) form[:avs_zip] = billing_address[:zip].to_s.slice(0, 10) form[:city] = billing_address[:city].to_s.slice(0, 30) form[:state] = billing_address[:state].to_s.slice(0, 10) form[:company] = billing_address[:company].to_s.slice(0, 50) form[:phone] = billing_address[:phone].to_s.slice(0, 20) form[:country] = billing_address[:country].to_s.slice(0, 50) end - + if shipping_address = options[:shipping_address] first_name, last_name = parse_first_and_last_name(shipping_address[:name]) form[:ship_to_first_name] = first_name.to_s.slice(0, 20) form[:ship_to_last_name] = last_name.to_s.slice(0, 30) form[:ship_to_address1] = shipping_address[:address1].to_s.slice(0, 30) @@ -121,17 +242,71 @@ form[:ship_to_company] = shipping_address[:company].to_s.slice(0, 50) form[:ship_to_country] = shipping_address[:country].to_s.slice(0, 50) form[:ship_to_zip] = shipping_address[:zip].to_s.slice(0, 10) end end - + + def parse_first_and_last_name(value) + name = value.to_s.split(' ') + + last_name = name.pop || '' + first_name = name.join(' ') + [ first_name, last_name ] + end + + def add_test_mode(form, options) + form[:test_mode] = 'TRUE' if options[:test_mode] + end + def message_from(response) success?(response) ? response['result_message'] : response['errorMessage'] end - + def success?(response) !response.has_key?('errorMessage') end + + def commit(action, money, parameters) + parameters[:amount] = amount(money) + parameters[:transaction_type] = self.actions[action] + + response = parse( ssl_post(test? ? self.test_url : self.live_url, post_data(parameters)) ) + + Response.new(response['result'] == '0', message_from(response), response, + :test => @options[:test] || test?, + :authorization => authorization_from(response), + :avs_result => { :code => response['avs_response'] }, + :cvv_result => response['cvv2_response'] + ) + end + + def post_data(parameters) + result = preamble + result.merge!(parameters) + result.collect { |key, value| "ssl_#{key}=#{CGI.escape(value.to_s)}" }.join("&") + end + + def preamble + result = { + 'merchant_id' => @options[:login], + 'pin' => @options[:password], + 'show_form' => 'false', + 'result_format' => 'ASCII' + } + + result['user_id'] = @options[:user] unless @options[:user].blank? + result + end + + def parse(msg) + resp = {} + msg.split(self.delimiter).collect{|li| + key, value = li.split("=") + resp[key.strip.gsub(/^ssl_/, '')] = value.to_s.strip + } + resp + end + end end end