module ActiveMerchant #:nodoc: module Billing #:nodoc: class NetworkMerchantsGateway < Gateway self.live_url = self.test_url = 'https://secure.networkmerchants.com/api/transact.php' self.supported_countries = ['US'] self.supported_cardtypes = %i[visa master american_express discover] self.homepage_url = 'http://www.nmi.com/' self.display_name = 'Network Merchants (NMI)' self.money_format = :dollars self.default_currency = 'USD' def initialize(options = {}) requires!(options, :login, :password) super end def authorize(money, creditcard_or_vault_id, options = {}) post = build_auth_post(money, creditcard_or_vault_id, options) commit('auth', post) end def purchase(money, creditcard_or_vault_id, options = {}) post = build_purchase_post(money, creditcard_or_vault_id, options) commit('sale', post) end def capture(money, authorization, options = {}) post = build_capture_post(money, authorization, options) commit('capture', post) end def void(authorization, options = {}) post = build_void_post(authorization, options) commit('void', post) end def refund(money, authorization, options = {}) post = build_refund_post(money, authorization, options) commit('refund', post) end def store(creditcard, options = {}) post = build_store_post(creditcard, options) commit_vault('add_customer', post) end def unstore(customer_vault_id, options = {}) post = build_unstore_post(customer_vault_id, options) commit_vault('delete_customer', post) end private def build_auth_post(money, creditcard_or_vault_id, options) post = {} add_order(post, options) add_address(post, options) add_shipping_address(post, options) add_payment_method(post, creditcard_or_vault_id, options) add_amount(post, money, options) post end def build_purchase_post(money, creditcard, options) build_auth_post(money, creditcard, options) end def build_capture_post(money, authorization, options) post = {} post[:transactionid] = authorization add_amount(post, money, options) post end def build_void_post(authorization, options) post = {} post[:transactionid] = authorization post end def build_refund_post(money, authorization, options) post = {} post[:transactionid] = authorization add_amount(post, money, options) post end def build_store_post(creditcard_or_check, options) post = {} add_address(post, options) add_shipping_address(post, options) add_payment_method(post, creditcard_or_check, options) post end def build_unstore_post(customer_vault_id, options) post = {} post['customer_vault_id'] = customer_vault_id post end def add_order(post, options) post[:orderid] = options[:order_id] post[:orderdescription] = options[:description] end def add_address(post, options) post[:email] = options[:email] post[:ipaddress] = options[:ip] address = options[:billing_address] || options[:address] || {} post[:address1] = address[:address1] post[:address2] = address[:address2] post[:city] = address[:city] post[:state] = address[:state].blank? ? 'n/a' : address[:state] post[:zip] = address[:zip] post[:country] = address[:country] post[:phone] = address[:phone] end def add_shipping_address(post, options) shipping_address = options[:shipping_address] || {} post[:shipping_address1] = shipping_address[:address1] post[:shipping_address2] = shipping_address[:address2] post[:shipping_city] = shipping_address[:city] post[:shipping_state] = shipping_address[:state] post[:shipping_zip] = shipping_address[:zip] post[:shipping_country] = shipping_address[:country] end def add_swipe_data(post, creditcard, options) # unencrypted tracks if creditcard.respond_to?(:track_data) && creditcard.track_data.present? post[:track_1] = creditcard.track_data else post[:track_1] = options[:track_1] post[:track_2] = options[:track_2] post[:track_3] = options[:track_3] end # encrypted tracks post[:magnesafe_track_1] = options[:magnesafe_track_1] post[:magnesafe_track_2] = options[:magnesafe_track_2] post[:magnesafe_track_3] = options[:magnesafe_track_3] post[:magnesafe_magneprint] = options[:magnesafe_magneprint] post[:magnesafe_ksn] = options[:magnesafe_ksn] post[:magnesafe_magneprint_status] = options[:magnesafe_magneprint_status] end def add_payment_method(post, payment_source, options) post[:processor_id] = options[:processor_id] post[:customer_vault] = 'add_customer' if options[:store] add_swipe_data(post, payment_source, options) if payment_source.is_a?(Check) check = payment_source post[:firstname] = check.first_name post[:lastname] = check.last_name post[:checkname] = check.name post[:checkaba] = check.routing_number post[:checkaccount] = check.account_number post[:account_type] = check.account_type post[:account_holder_type] = check.account_holder_type post[:payment] = 'check' elsif payment_source.respond_to?(:number) creditcard = payment_source post[:firstname] = creditcard.first_name post[:lastname] = creditcard.last_name post[:ccnumber] = creditcard.number post[:ccexp] = format(creditcard.month, :two_digits) + format(creditcard.year, :two_digits) post[:cvv] = creditcard.verification_value post[:payment] = 'creditcard' else post[:customer_vault_id] = payment_source end end def add_login(post) post[:username] = @options[:login] post[:password] = @options[:password] end def add_amount(post, money, options) post[:currency] = options[:currency] || currency(money) post[:amount] = amount(money) end def commit_vault(action, parameters) commit(nil, parameters.merge(customer_vault: action)) end def commit(action, parameters) raw = parse(ssl_post(self.live_url, build_request(action, parameters))) success = (raw['response'] == ResponseCodes::APPROVED) authorization = authorization_from(success, parameters, raw) Response.new( success, raw['responsetext'], raw, test: test?, authorization: authorization, avs_result: { code: raw['avsresponse'] }, cvv_result: raw['cvvresponse'] ) end def build_request(action, parameters) parameters[:type] = action if action add_login(parameters) parameters.to_query end def authorization_from(success, parameters, response) return nil unless success authorization = response['transactionid'] authorization = response['customer_vault_id'] if parameters[:customer_vault] && (authorization.nil? || authorization.empty?) authorization end class ResponseCodes APPROVED = '1' DENIED = '2' ERROR = '3' end def parse(raw_response) rsp = CGI.parse(raw_response) rsp.keys.each { |k| rsp[k] = rsp[k].first } # flatten out the values rsp end end end end