lib/active_merchant/billing/gateways/redsys.rb in activemerchant-1.79.2 vs lib/active_merchant/billing/gateways/redsys.rb in activemerchant-1.80.0

- old
+ new

@@ -33,59 +33,59 @@ # specify the key/value :signature_algorithm => "sha256" to use the # SHA256 method. Otherwise it will default to using the SHA1. # # class RedsysGateway < Gateway - self.live_url = "https://sis.sermepa.es/sis/operaciones" - self.test_url = "https://sis-t.redsys.es:25443/sis/operaciones" + self.live_url = 'https://sis.sermepa.es/sis/operaciones' + self.test_url = 'https://sis-t.redsys.es:25443/sis/operaciones' self.supported_countries = ['ES'] self.default_currency = 'EUR' self.money_format = :cents # Not all card types may be activated by the bank! self.supported_cardtypes = [:visa, :master, :american_express, :jcb, :diners_club] - self.homepage_url = "http://www.redsys.es/" - self.display_name = "Redsys" + self.homepage_url = 'http://www.redsys.es/' + self.display_name = 'Redsys' CURRENCY_CODES = { - "AED" => '784', - "ARS" => '32', - "AUD" => '36', - "BRL" => '986', - "BOB" => '68', - "CAD" => '124', - "CHF" => '756', - "CLP" => '152', - "CNY" => '156', - "COP" => '170', - "CRC" => '188', - "CZK" => '203', - "DKK" => '208', - "DOP" => '214', - "EUR" => '978', - "GBP" => '826', - "GTQ" => '320', - "HUF" => '348', - "IDR" => '360', - "INR" => '356', - "JPY" => '392', - "KRW" => '410', - "MYR" => '458', - "MXN" => '484', - "NOK" => '578', - "NZD" => '554', - "PEN" => '604', - "PLN" => '985', - "RUB" => '643', - "SAR" => '682', - "SEK" => '752', - "SGD" => '702', - "THB" => '764', - "TWD" => '901', - "USD" => '840', - "UYU" => '858' + 'AED' => '784', + 'ARS' => '32', + 'AUD' => '36', + 'BRL' => '986', + 'BOB' => '68', + 'CAD' => '124', + 'CHF' => '756', + 'CLP' => '152', + 'CNY' => '156', + 'COP' => '170', + 'CRC' => '188', + 'CZK' => '203', + 'DKK' => '208', + 'DOP' => '214', + 'EUR' => '978', + 'GBP' => '826', + 'GTQ' => '320', + 'HUF' => '348', + 'IDR' => '360', + 'INR' => '356', + 'JPY' => '392', + 'KRW' => '410', + 'MYR' => '458', + 'MXN' => '484', + 'NOK' => '578', + 'NZD' => '554', + 'PEN' => '604', + 'PLN' => '985', + 'RUB' => '643', + 'SAR' => '682', + 'SEK' => '752', + 'SGD' => '702', + 'THB' => '764', + 'TWD' => '901', + 'USD' => '840', + 'UYU' => '858' } # The set of supported transactions for this gateway. # More operations are supported by the gateway itself, but # are not supported in this library. @@ -99,76 +99,76 @@ # These are the text meanings sent back by the acquirer when # a card has been rejected. Syntax or general request errors # are not covered here. RESPONSE_TEXTS = { - 0 => "Transaction Approved", - 400 => "Cancellation Accepted", - 481 => "Cancellation Accepted", - 500 => "Reconciliation Accepted", - 900 => "Refund / Confirmation approved", + 0 => 'Transaction Approved', + 400 => 'Cancellation Accepted', + 481 => 'Cancellation Accepted', + 500 => 'Reconciliation Accepted', + 900 => 'Refund / Confirmation approved', - 101 => "Card expired", - 102 => "Card blocked temporarily or under susciption of fraud", - 104 => "Transaction not permitted", - 107 => "Contact the card issuer", - 109 => "Invalid identification by merchant or POS terminal", - 110 => "Invalid amount", - 114 => "Card cannot be used to the requested transaction", - 116 => "Insufficient credit", - 118 => "Non-registered card", - 125 => "Card not effective", - 129 => "CVV2/CVC2 Error", - 167 => "Contact the card issuer: suspected fraud", - 180 => "Card out of service", - 181 => "Card with credit or debit restrictions", - 182 => "Card with credit or debit restrictions", - 184 => "Authentication error", - 190 => "Refusal with no specific reason", - 191 => "Expiry date incorrect", + 101 => 'Card expired', + 102 => 'Card blocked temporarily or under susciption of fraud', + 104 => 'Transaction not permitted', + 107 => 'Contact the card issuer', + 109 => 'Invalid identification by merchant or POS terminal', + 110 => 'Invalid amount', + 114 => 'Card cannot be used to the requested transaction', + 116 => 'Insufficient credit', + 118 => 'Non-registered card', + 125 => 'Card not effective', + 129 => 'CVV2/CVC2 Error', + 167 => 'Contact the card issuer: suspected fraud', + 180 => 'Card out of service', + 181 => 'Card with credit or debit restrictions', + 182 => 'Card with credit or debit restrictions', + 184 => 'Authentication error', + 190 => 'Refusal with no specific reason', + 191 => 'Expiry date incorrect', - 201 => "Card expired", - 202 => "Card blocked temporarily or under suspicion of fraud", - 204 => "Transaction not permitted", - 207 => "Contact the card issuer", - 208 => "Lost or stolen card", - 209 => "Lost or stolen card", - 280 => "CVV2/CVC2 Error", - 290 => "Declined with no specific reason", + 201 => 'Card expired', + 202 => 'Card blocked temporarily or under suspicion of fraud', + 204 => 'Transaction not permitted', + 207 => 'Contact the card issuer', + 208 => 'Lost or stolen card', + 209 => 'Lost or stolen card', + 280 => 'CVV2/CVC2 Error', + 290 => 'Declined with no specific reason', - 480 => "Original transaction not located, or time-out exceeded", - 501 => "Original transaction not located, or time-out exceeded", - 502 => "Original transaction not located, or time-out exceeded", - 503 => "Original transaction not located, or time-out exceeded", + 480 => 'Original transaction not located, or time-out exceeded', + 501 => 'Original transaction not located, or time-out exceeded', + 502 => 'Original transaction not located, or time-out exceeded', + 503 => 'Original transaction not located, or time-out exceeded', - 904 => "Merchant not registered at FUC", - 909 => "System error", - 912 => "Issuer not available", - 913 => "Duplicate transmission", - 916 => "Amount too low", - 928 => "Time-out exceeded", - 940 => "Transaction cancelled previously", - 941 => "Authorization operation already cancelled", - 942 => "Original authorization declined", - 943 => "Different details from origin transaction", - 944 => "Session error", - 945 => "Duplicate transmission", - 946 => "Cancellation of transaction while in progress", - 947 => "Duplicate tranmission while in progress", - 949 => "POS Inoperative", - 950 => "Refund not possible", - 9064 => "Card number incorrect", - 9078 => "No payment method available", - 9093 => "Non-existent card", - 9218 => "Recursive transaction in bad gateway", - 9253 => "Check-digit incorrect", - 9256 => "Preauth not allowed for merchant", - 9257 => "Preauth not allowed for card", - 9261 => "Operating limit exceeded", - 9912 => "Issuer not available", - 9913 => "Confirmation error", - 9914 => "KO Confirmation" + 904 => 'Merchant not registered at FUC', + 909 => 'System error', + 912 => 'Issuer not available', + 913 => 'Duplicate transmission', + 916 => 'Amount too low', + 928 => 'Time-out exceeded', + 940 => 'Transaction cancelled previously', + 941 => 'Authorization operation already cancelled', + 942 => 'Original authorization declined', + 943 => 'Different details from origin transaction', + 944 => 'Session error', + 945 => 'Duplicate transmission', + 946 => 'Cancellation of transaction while in progress', + 947 => 'Duplicate tranmission while in progress', + 949 => 'POS Inoperative', + 950 => 'Refund not possible', + 9064 => 'Card number incorrect', + 9078 => 'No payment method available', + 9093 => 'Non-existent card', + 9218 => 'Recursive transaction in bad gateway', + 9253 => 'Check-digit incorrect', + 9256 => 'Preauth not allowed for merchant', + 9257 => 'Preauth not allowed for card', + 9261 => 'Operating limit exceeded', + 9912 => 'Issuer not available', + 9913 => 'Confirmation error', + 9914 => 'KO Confirmation' } # Creates a new instance # # Redsys requires a login and secret_key, and optionally also accepts a @@ -182,11 +182,11 @@ # * <tt>:test</tt> -- +true+ or +false+. Defaults to +false+. (OPTIONAL) # * <tt>:signature_algorithm</tt> -- +"sha256"+ Defaults to +"sha1"+. (OPTIONAL) def initialize(options = {}) requires!(options, :login, :secret_key) options[:terminal] ||= 1 - options[:signature_algorithm] ||= "sha1" + options[:signature_algorithm] ||= 'sha1' super end def purchase(money, payment, options = {}) requires!(options, :order_id) @@ -297,12 +297,12 @@ def add_payment(data, card) if card.is_a?(String) data[:credit_card_token] = card else name = [card.first_name, card.last_name].join(' ').slice(0, 60) - year = sprintf("%.4i", card.year) - month = sprintf("%.2i", card.month) + year = sprintf('%.4i', card.year) + month = sprintf('%.2i', card.month) data[:card] = { :name => name, :pan => card.number, :date => "#{year[2..3]}#{month}", :cvv => card.verification_value @@ -393,33 +393,34 @@ xml.DS_MERCHANT_EXPIRYDATE data[:card][:date] xml.DS_MERCHANT_CVV2 data[:card][:cvv] xml.DS_MERCHANT_IDENTIFIER 'REQUIRED' if data[:store_in_vault] elsif data[:credit_card_token] xml.DS_MERCHANT_IDENTIFIER data[:credit_card_token] + xml.DS_MERCHANT_DIRECTPAYMENT 'true' end end end def parse(data) params = {} success = false - message = "" + message = '' options = @options.merge(:test => test?) xml = Nokogiri::XML(data) - code = xml.xpath("//RETORNOXML/CODIGO").text - if code == "0" - op = xml.xpath("//RETORNOXML/OPERACION") + code = xml.xpath('//RETORNOXML/CODIGO').text + if code == '0' + op = xml.xpath('//RETORNOXML/OPERACION') op.children.each do |element| params[element.name.downcase.to_sym] = element.text end if validate_signature(params) message = response_text(params[:ds_response]) options[:authorization] = build_authorization(params) success = is_success_response?(params[:ds_response]) else - message = "Response failed validation check" + message = 'Response failed validation check' end else # Some kind of programmer error with the request! message = "#{code} ERROR" end @@ -446,15 +447,15 @@ data[:ds_signature].to_s.downcase == sig end end def build_authorization(params) - [params[:ds_order], params[:ds_amount], params[:ds_currency]].join("|") + [params[:ds_order], params[:ds_amount], params[:ds_currency]].join('|') end def split_authorization(authorization) - order_id, amount, currency = authorization.split("|") + order_id, amount, currency = authorization.split('|') [order_id, amount.to_i, currency] end def currency_code(currency) return currency if currency =~ /^\d+$/ @@ -467,11 +468,11 @@ end def response_text(code) code = code.to_i code = 0 if code < 100 - RESPONSE_TEXTS[code] || "Unkown code, please check in manual" + RESPONSE_TEXTS[code] || 'Unkown code, please check in manual' end def is_success_response?(code) (code.to_i < 100) || [400, 481, 500, 900].include?(code.to_i) end @@ -479,16 +480,16 @@ def clean_order_id(order_id) cleansed = order_id.gsub(/[^\da-zA-Z]/, '') if cleansed =~ /^\d{4}/ cleansed[0..11] else - "%04d%s" % [rand(0..9999), cleansed[0...8]] + '%04d%s' % [rand(0..9999), cleansed[0...8]] end end def sha256_authentication? - @options[:signature_algorithm] == "sha256" + @options[:signature_algorithm] == 'sha256' end def sign_request(xml_request_string, order_id) key = encrypt(@options[:secret_key], order_id) Base64.strict_encode64(mac256(key, xml_request_string)) @@ -512,11 +513,17 @@ def mac256(key, data) OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), key, data) end def xml_signed_fields(data) - data[:ds_amount] + data[:ds_order] + data[:ds_merchantcode] + data[:ds_currency] + - data[:ds_response] + data[:ds_transactiontype] + data[:ds_securepayment] + xml_signed_fields = data[:ds_amount] + data[:ds_order] + data[:ds_merchantcode] + + data[:ds_currency] + data[:ds_response] + + if data[:ds_cardnumber] + xml_signed_fields += data[:ds_cardnumber] + end + + xml_signed_fields += data[:ds_transactiontype] + data[:ds_securepayment] end def get_key(order_id) encrypt(@options[:secret_key], order_id) end