Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cybersource: add processor response message #4293

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
95 changes: 86 additions & 9 deletions lib/active_merchant/billing/gateways/cyber_source.rb
Expand Up @@ -47,7 +47,7 @@ class CyberSourceGateway < Gateway
self.homepage_url = 'http://www.cybersource.com'
self.display_name = 'CyberSource'

@@credit_card_codes = {
CREDIT_CARD_CODES = {
visa: '001',
master: '002',
american_express: '003',
Expand All @@ -59,12 +59,12 @@ class CyberSourceGateway < Gateway
elo: '054'
}

@@decision_codes = {
DECISION_CODES = {
accept: 'ACCEPT',
review: 'REVIEW'
}

@@response_codes = {
RESPONSE_CODES = {
r100: 'Successful transaction',
r101: 'Request is missing one or more required fields',
r102: 'One or more fields contains invalid data',
Expand Down Expand Up @@ -105,6 +105,74 @@ class CyberSourceGateway < Gateway
r255: 'Your CyberSource account is not configured to process the service in the country you specified'
}

PROCESSOR_ERROR_CODES = {
'00' => 'Approved and completed successfully',
'01' => 'Refer to card issuer',
'02' => 'Refer to card issuer, special condition',
'03' => 'Invalid merchant',
'04' => 'Pick up card (no fraud)',
'05' => 'Do not honor',
'06' => 'Error',
'07' => 'Pick up card, special condition (fraud account)',
'10' => 'Partial approval',
'11' => 'Approved (V.I.P)',
'12' => 'Invalid transaction',
'13' => 'Invalid amount or currency conversion field overflow',
'14' => 'Invalid account number (no such number)',
'15' => 'No such issuer',
'19' => 'Re-enter transaction',
'21' => 'No action taken',
'25' => 'Unable to locate record in file',
'28' => 'File temporarily not available for update or inquiry',
'39' => 'No credit account',
'41' => 'Lost card, pick up (fraud account)',
'43' => 'Stolen card, pick up (fraud account)',
'51' => 'Not sufficient funds',
'52' => 'No checking account',
'53' => 'No savings account',
'54' => 'Expired card or expiration date is missing',
'55' => 'Incorrect PIN or PIN missing',
'57' => 'Transaction not permitted to cardholder',
'58' => 'Transaction not allowed at terminal',
'59' => 'Suspected fraud',
'61' => 'Exceeds approval amount limit',
'62' => 'Restricted card (card invalid in this region or country)',
'63' => 'Security violation (source is not correct issuer)',
'64' => 'Transaction does not fulfill AML requirement',
'65' => 'Exceeds withdrawal frequency limit',
'70' => 'PIN data required',
'74' => 'Different value than that used for PIN encryption errors',
'75' => 'Allowable number of PIN entry tries exceeded',
'76' => 'Unsolicited reversal',
'78' => '"Blocked, first used"—Transaction from new cardholder, and card not properly unblocked',
'79' => 'Already reversed (by Switch)',
'80' => 'No financial impact',
'81' => 'Cryptographic error found in PIN',
'82' => 'Negative CAM, dCVV, iCVV, or CVV results',
'85' => 'No reason to decline a request for address verification, CVV2 verification, or a credit voucher or merchandise return',
'86' => 'Cannot verify PIN; for example, no PVV',
'89' => 'Ineligible to receive financial position information (GIV)',
'91' => 'Issuer or switch inoperative and STIP not applicable or not available for this transaction; Time-out when no stand-in; POS Check Service: Destination unavailable; Credit Voucher and Merchandise Return Authorizations: V.I.P. sent the transaction to the issuer, but the issuer was unavailable.',
'92' => 'Financial institution or intermediate network facility cannot be found for routing (receiving institution ID is invalid)',
'93' => 'Transaction cannot be completed - violation of law',
'1A' => 'Additional customer authentication required',
'B1' => 'Surcharge amount not permitted on Visa cards or EBT food stamps (U.S. acquirers only)',
'B2' => 'Surcharge amount not supported by debit network issuer.',
'N0' => 'Force STIP',
'N3' => 'Cash service not available',
'N4' => 'Cash request exceeds issuer or approved limit',
'N5' => 'Ineligible for resubmission',
'N7' => 'Decline for CVV2 failure',
'N8' => 'Transaction amount exceeds preauthorized approval amount',
'P5' => 'Denied PIN unblock—PIN change or unblock request declined by issuer',
'P6' => 'Denied PIN change—requested PIN unsafe',
'Q1' => 'Card Authentication failed',
'R0' => 'Stop Payment Order',
'R2' => 'Transaction does not qualify for Visa PIN',
'R3' => 'Revocation of all authorizations order',
'Z3' => 'Unable to go online; offline-declined'
}

# These are the options that can be used when creating a new CyberSource
# Gateway object.
#
Expand Down Expand Up @@ -612,7 +680,7 @@ def add_creditcard(xml, creditcard)
xml.tag! 'expirationMonth', format(creditcard.month, :two_digits)
xml.tag! 'expirationYear', format(creditcard.year, :four_digits)
xml.tag!('cvNumber', creditcard.verification_value) unless @options[:ignore_cvv].to_s == 'true' || creditcard.verification_value.blank?
xml.tag! 'cardType', @@credit_card_codes[card_brand(creditcard).to_sym]
xml.tag! 'cardType', CREDIT_CARD_CODES[card_brand(creditcard).to_sym]
end
end

Expand Down Expand Up @@ -1000,10 +1068,10 @@ def commit(request, action, amount, options)
rescue REXML::ParseException => e
response = { message: e.to_s }
end

success = success?(response)
message = message_from(response)
authorization = success || in_fraud_review?(response) ? authorization_from(response, action, amount, options) : nil
add_processor_message!(response)

Response.new(success, message, response,
test: test?,
Expand Down Expand Up @@ -1032,7 +1100,10 @@ def parse(xml)
parse_element(reply, root)
reply[:message] = "#{reply[:faultcode]}: #{reply[:faultstring]}"
end
return reply

add_processor_message!(reply)

reply
end

def parse_element(reply, node)
Expand All @@ -1052,7 +1123,7 @@ def parse_element(reply, node)
def reason_message(reason_code)
return if reason_code.blank?

@@response_codes[:"r#{reason_code}"]
RESPONSE_CODES[:"r#{reason_code}"]
end

def authorization_from(response, action, amount, options)
Expand All @@ -1061,11 +1132,11 @@ def authorization_from(response, action, amount, options)
end

def in_fraud_review?(response)
response[:decision] == @@decision_codes[:review]
response[:decision] == DECISION_CODES[:review]
end

def success?(response)
response[:decision] == @@decision_codes[:accept]
response[:decision] == DECISION_CODES[:accept]
end

def message_from(response)
Expand All @@ -1077,6 +1148,12 @@ def message_from(response)
response[:message]
end
end

def add_processor_message!(response)
return unless processor_code = response[:processorResponse]

response[:processorMessage] = PROCESSOR_ERROR_CODES[processor_code]
end
end
end
end
1 change: 1 addition & 0 deletions test/unit/gateways/cyber_source_test.rb
Expand Up @@ -59,6 +59,7 @@ def test_successful_credit_card_purchase

assert response = @gateway.purchase(@amount, @credit_card, @options)
assert_equal 'Successful transaction', response.message
assert_equal 'Approved and completed successfully', response.params['processorMessage']
assert_success response
assert_equal "#{@options[:order_id]};#{response.params['requestID']};#{response.params['requestToken']};purchase;100;USD;", response.authorization
assert response.test?
Expand Down