|
1
|
|
|
module AuthorizeNet::AIM |
|
2
|
|
|
# The AIM response class. Handles parsing the response from the gateway. |
|
3
|
|
|
class Response < AuthorizeNet::KeyValueResponse |
|
4
|
|
|
# Our MD5 digest generator. |
|
5
|
|
|
@@digest = OpenSSL::Digest.new('md5') |
|
|
|
|
|
|
6
|
|
|
|
|
7
|
|
|
include AuthorizeNet::AIM::Fields |
|
8
|
|
|
|
|
9
|
|
|
# Fields to convert to/from booleans. |
|
10
|
|
|
@@boolean_fields = [:tax_exempt] |
|
|
|
|
|
|
11
|
|
|
|
|
12
|
|
|
# Fields to convert to/from BigDecimal. |
|
13
|
|
|
@@decimal_fields = %i[amount tax freight duty requested balance_on_card] |
|
|
|
|
|
|
14
|
|
|
|
|
15
|
|
|
# Constructs a new response object from a +raw_response+ and the +transaction+ that generated |
|
16
|
|
|
# the +raw_response+. You don't typically construct this object yourself, as AuthorizeNet::AIM::Transaction |
|
17
|
|
|
# will build one for you when it makes the request to the gateway. |
|
18
|
|
|
def initialize(raw_response, transaction) |
|
19
|
|
|
@version = transaction.version |
|
20
|
|
|
raise "AuthorizeNet gem only supports AIM version 3.1" unless @version.to_s == '3.1' |
|
21
|
|
|
@raw_response = raw_response |
|
22
|
|
|
@fields = {} |
|
23
|
|
|
@transaction = transaction |
|
24
|
|
|
custom_field_names = transaction.custom_fields.keys.collect(&:to_s).sort.collect(&:to_sym) |
|
25
|
|
|
@custom_fields = {} |
|
26
|
|
|
split_on = transaction.delimiter |
|
27
|
|
|
if @raw_response.is_a?(Net::HTTPOK) || @raw_response.is_a?(Nokogiri::XML::Element) |
|
28
|
|
|
if @raw_response.is_a?(Net::HTTPOK) |
|
29
|
|
|
raw_data = @raw_response.body |
|
30
|
|
|
else |
|
31
|
|
|
raw_data = @raw_response.text |
|
32
|
|
|
end |
|
33
|
|
|
unless transaction.encapsulation_character.nil? |
|
34
|
|
|
split_on = transaction.encapsulation_character + split_on + transaction.encapsulation_character |
|
35
|
|
|
raw_data = raw_data[1..raw_data.length - 2] |
|
36
|
|
|
end |
|
37
|
|
|
raw_data.split(split_on).each_with_index do |field, index| |
|
38
|
|
|
if transaction.cp_version.nil? |
|
39
|
|
|
field_desc = FIELDS |
|
40
|
|
|
else |
|
41
|
|
|
field_desc = CP_FIELDS |
|
42
|
|
|
end |
|
43
|
|
|
if index < field_desc.length |
|
44
|
|
|
@fields[field_desc[index]] = field |
|
45
|
|
|
else |
|
46
|
|
|
@custom_fields[custom_field_names[index - field_desc.length]] = field |
|
47
|
|
|
end |
|
48
|
|
|
end |
|
49
|
|
|
@fields.delete(nil) |
|
50
|
|
|
@fields.each do |k, v| |
|
51
|
|
|
if @@boolean_fields.include?(k) |
|
52
|
|
|
@fields[k] = value_to_boolean(v) |
|
53
|
|
|
elsif @@decimal_fields.include?(k) |
|
54
|
|
|
@fields[k] = value_to_decimal(v) |
|
55
|
|
|
end |
|
56
|
|
|
end |
|
57
|
|
|
end |
|
58
|
|
|
end |
|
59
|
|
|
|
|
60
|
|
|
# Returns True if the MD5 hash found in the response payload validates using |
|
61
|
|
|
# the supplied api_login and secret merchant_value (THIS IS NOT YOUR API KEY). |
|
62
|
|
View Code Duplication |
def valid_md5?(api_login, merchant_value) |
|
|
|
|
|
|
63
|
|
|
return false if @fields[:md5_hash].nil? |
|
64
|
|
|
@@digest.hexdigest("#{merchant_value}#{api_login}#{@fields[:transaction_id]}#{@transaction.fields[:amount]}").casecmp(@fields[:md5_hash]).zero? |
|
65
|
|
|
end |
|
66
|
|
|
|
|
67
|
|
|
# Returns the current API version that we are adhering to. |
|
68
|
|
|
attr_reader :version |
|
69
|
|
|
|
|
70
|
|
|
# Check to see if the response indicated success. Success is defined as a 200 OK response indicating |
|
71
|
|
|
# that the transaction was approved. |
|
72
|
|
|
def success? |
|
73
|
|
|
!connection_failure? && approved? |
|
74
|
|
|
end |
|
75
|
|
|
|
|
76
|
|
|
# Returns true if we failed to open a connection to the gateway or got back a non-200 OK HTTP response. |
|
77
|
|
|
def connection_failure? |
|
78
|
|
|
!@raw_response.is_a?(Net::HTTPOK) && !@raw_response.is_a?(Nokogiri::XML::Element) |
|
79
|
|
|
end |
|
80
|
|
|
|
|
81
|
|
|
# Returns the underlying Net::HTTPResponse object. This has the original response body along with |
|
82
|
|
|
# headers and such. Note that if an exception is generated while making the request (which happens |
|
83
|
|
|
# if there is no internet connection for example), you will get the exception object here instead of |
|
84
|
|
|
# a Net::HTTPResponse object. |
|
85
|
|
|
def raw |
|
86
|
|
|
@raw_response |
|
87
|
|
|
end |
|
88
|
|
|
|
|
89
|
|
|
# Returns the AuthorizeNet::Transaction instance that owns this response. |
|
90
|
|
|
attr_reader :transaction |
|
91
|
|
|
|
|
92
|
|
|
# Returns the transaction's authorization code. This should be shown to the |
|
93
|
|
|
# end user. |
|
94
|
|
|
def authorization_code |
|
95
|
|
|
@fields[:authorization_code] |
|
96
|
|
|
end |
|
97
|
|
|
|
|
98
|
|
|
# Returns the transaction's authorization id. You will need this for future void, refund |
|
99
|
|
|
# and prior authorization capture requests. |
|
100
|
|
|
def transaction_id |
|
101
|
|
|
@fields[:transaction_id] |
|
102
|
|
|
end |
|
103
|
|
|
|
|
104
|
|
|
# Returns the customer id from the response. |
|
105
|
|
|
def customer_id |
|
106
|
|
|
@fields[:customer_id] |
|
107
|
|
|
end |
|
108
|
|
|
|
|
109
|
|
|
# Returns a response code (from AVSResponseCode) indicating the result of any Address Verification |
|
110
|
|
|
# Service checks. |
|
111
|
|
|
def avs_response |
|
112
|
|
|
@fields[:avs_response] |
|
113
|
|
|
end |
|
114
|
|
|
|
|
115
|
|
|
# Returns the credit card type used in the transaction. The values returned can be found in CardType. |
|
116
|
|
|
def card_type |
|
117
|
|
|
@fields[:card_type] |
|
118
|
|
|
end |
|
119
|
|
|
end |
|
120
|
|
|
end |
|
121
|
|
|
|