module ActiveMerchant #:nodoc: module Billing #:nodoc: class CamsGateway < Gateway self.live_url = 'https://secure.centralams.com/gw/api/transact.php' self.supported_countries = ['US'] self.default_currency = 'USD' self.supported_cardtypes = %i[visa master american_express discover] self.homepage_url = 'https://www.centralams.com/' self.display_name = 'CAMS: Central Account Management System' STANDARD_ERROR_CODE_MAPPING = { '200' => STANDARD_ERROR_CODE[:card_declined], '201' => STANDARD_ERROR_CODE[:card_declined], '202' => STANDARD_ERROR_CODE[:card_declined], '203' => STANDARD_ERROR_CODE[:card_declined], '204' => STANDARD_ERROR_CODE[:card_declined], '220' => STANDARD_ERROR_CODE[:card_declined], '221' => STANDARD_ERROR_CODE[:card_declined], '222' => STANDARD_ERROR_CODE[:incorrect_number], '223' => STANDARD_ERROR_CODE[:expired_card], '224' => STANDARD_ERROR_CODE[:invalid_expiry_date], '225' => STANDARD_ERROR_CODE[:invalid_cvc], '240' => STANDARD_ERROR_CODE[:call_issuer], '250' => STANDARD_ERROR_CODE[:pickup_card], '251' => STANDARD_ERROR_CODE[:pickup_card], '252' => STANDARD_ERROR_CODE[:pickup_card], '253' => STANDARD_ERROR_CODE[:pickup_card], '260' => STANDARD_ERROR_CODE[:card_declined], '261' => STANDARD_ERROR_CODE[:card_declined], '262' => STANDARD_ERROR_CODE[:card_declined], '263' => STANDARD_ERROR_CODE[:processing_error], '264' => STANDARD_ERROR_CODE[:card_declined], '300' => STANDARD_ERROR_CODE[:card_declined], '400' => STANDARD_ERROR_CODE[:processing_error], '410' => STANDARD_ERROR_CODE[:processing_error], '411' => STANDARD_ERROR_CODE[:processing_error], '420' => STANDARD_ERROR_CODE[:processing_error], '421' => STANDARD_ERROR_CODE[:processing_error], '430' => STANDARD_ERROR_CODE[:processing_error], '440' => STANDARD_ERROR_CODE[:processing_error], '441' => STANDARD_ERROR_CODE[:processing_error], '460' => STANDARD_ERROR_CODE[:invalid_number], '461' => STANDARD_ERROR_CODE[:processing_error], '801' => STANDARD_ERROR_CODE[:processing_error], '811' => STANDARD_ERROR_CODE[:processing_error], '812' => STANDARD_ERROR_CODE[:processing_error], '813' => STANDARD_ERROR_CODE[:processing_error], '814' => STANDARD_ERROR_CODE[:processing_error], '815' => STANDARD_ERROR_CODE[:processing_error], '823' => STANDARD_ERROR_CODE[:processing_error], '824' => STANDARD_ERROR_CODE[:processing_error], '881' => STANDARD_ERROR_CODE[:processing_error], '882' => STANDARD_ERROR_CODE[:processing_error], '883' => STANDARD_ERROR_CODE[:processing_error], '884' => STANDARD_ERROR_CODE[:card_declined], '885' => STANDARD_ERROR_CODE[:card_declined], '886' => STANDARD_ERROR_CODE[:card_declined], '887' => STANDARD_ERROR_CODE[:processing_error], '888' => STANDARD_ERROR_CODE[:processing_error], '889' => STANDARD_ERROR_CODE[:processing_error], '890' => STANDARD_ERROR_CODE[:processing_error], '891' => STANDARD_ERROR_CODE[:incorrect_cvc], '892' => STANDARD_ERROR_CODE[:incorrect_cvc], '893' => STANDARD_ERROR_CODE[:processing_error], '894' => STANDARD_ERROR_CODE[:processing_error] } def initialize(options = {}) requires!(options, :username, :password) super end def purchase(money, payment, options = {}) post = {} add_invoice(post, money, options) if payment.respond_to?(:number) add_payment(post, payment) add_address(post, payment, options) elsif payment.kind_of?(String) post[:transactionid] = split_authorization(payment)[0] end commit('sale', post) end def authorize(money, payment, options = {}) post = {} add_invoice(post, money, options) add_payment(post, payment) add_address(post, payment, options) commit('auth', post) end def capture(money, authorization, options = {}) post = {} add_reference(post, authorization) add_invoice(post, money, options) commit('capture', post) end def refund(money, authorization, options = {}) post = {} add_reference(post, authorization) add_invoice(post, money, options) commit('refund', post) end def void(authorization, options = {}) post = {} add_reference(post, authorization) commit('void', post) end def verify(credit_card, options = {}) post = {} add_invoice(post, 0, options) add_payment(post, credit_card) add_address(post, credit_card, options) commit('verify', post) end def supports_scrubbing? true end def scrub(transcript) %w(ccnumber cvv password).each do |field| transcript = transcript.gsub(%r((#{field}=)[^&]+), '\1[FILTERED]\2') end transcript end private def add_address(post, creditcard, options = {}) post[:firstname] = creditcard.first_name post[:lastname] = creditcard.last_name return unless options[:billing_address] address = options[:billing_address] post[:address1] = address[:address1] post[:address2] = address[:address2] post[:city] = address[:city] post[:state] = address[:state] post[:zip] = address[:zip] post[:country] = address[:country] post[:phone] = address[:phone] end def add_reference(post, authorization) transaction_id, authcode = split_authorization(authorization) post['transactionid'] = transaction_id post['authcode'] = authcode end def add_invoice(post, money, options) post[:amount] = amount(money) post[:currency] = (options[:currency] || default_currency) end def add_payment(post, payment) post[:ccnumber] = payment.number post[:ccexp] = "#{payment.month.to_s.rjust(2, '0')}#{payment.year.to_s[-2..-1]}" post[:cvv] = payment.verification_value end def parse(body) kvs = body.split('&') kvs.inject({}) { |h, kv| k, v = kv.split('=') h[k] = v h } end def commit(action, parameters) url = live_url parameters[:type] = action response_body = ssl_post(url, post_data(parameters)) response = parse(response_body) Response.new( success_from(response), message_from(response), response, authorization: authorization_from(response), test: test?, error_code: error_code_from(response) ) end def success_from(response) response['response_code'] == '100' end def message_from(response) response['responsetext'] end def authorization_from(response) [response['transactionid'], response['authcode']].join('#') end def split_authorization(authorization) transaction_id, authcode = authorization.split('#') [transaction_id, authcode] end def post_data(parameters = {}) parameters[:password] = @options[:password] parameters[:username] = @options[:username] parameters.collect { |k, v| "#{k}=#{v}" }.join('&') end def error_code_from(response) STANDARD_ERROR_CODE_MAPPING[response['response_code']] end end end end