activemerchant 1.3.2 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +58 -0
  3. data/CONTRIBUTERS +25 -0
  4. data/MIT-LICENSE +3 -3
  5. data/README +16 -10
  6. data/Rakefile +4 -3
  7. data/lib/active_merchant.rb +7 -1
  8. data/lib/active_merchant/billing/check.rb +16 -9
  9. data/lib/active_merchant/billing/gateway.rb +1 -1
  10. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +702 -0
  11. data/lib/active_merchant/billing/gateways/beanstream.rb +102 -0
  12. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +233 -0
  13. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
  14. data/lib/active_merchant/billing/gateways/braintree.rb +10 -1
  15. data/lib/active_merchant/billing/gateways/cyber_source.rb +26 -2
  16. data/lib/active_merchant/billing/gateways/data_cash.rb +255 -59
  17. data/lib/active_merchant/billing/gateways/modern_payments.rb +36 -0
  18. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +214 -0
  19. data/lib/active_merchant/billing/gateways/net_registry.rb +1 -0
  20. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +2 -2
  21. data/lib/active_merchant/billing/gateways/payflow_express.rb +3 -11
  22. data/lib/active_merchant/billing/gateways/payment_express.rb +2 -2
  23. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +39 -21
  24. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  25. data/lib/active_merchant/billing/gateways/paypal_express.rb +3 -12
  26. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +20 -0
  27. data/lib/active_merchant/billing/gateways/protx.rb +25 -25
  28. data/lib/active_merchant/billing/gateways/sage.rb +145 -0
  29. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +88 -0
  30. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +110 -0
  31. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
  32. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +3 -1
  33. data/lib/active_merchant/billing/gateways/skip_jack.rb +2 -0
  34. data/lib/active_merchant/billing/gateways/trust_commerce.rb +1 -1
  35. data/lib/active_merchant/billing/gateways/wirecard.rb +304 -0
  36. data/lib/active_merchant/billing/integrations.rb +8 -2
  37. data/lib/active_merchant/billing/integrations/action_view_helper.rb +18 -4
  38. data/lib/active_merchant/billing/integrations/hi_trust/notification.rb +4 -2
  39. data/lib/active_merchant/billing/integrations/notification.rb +10 -1
  40. data/lib/active_merchant/lib/posts_data.rb +12 -3
  41. data/script/destroy +0 -0
  42. data/script/generate +0 -0
  43. data/test/extra/binding_of_caller.rb +0 -0
  44. data/test/extra/breakpoint.rb +0 -0
  45. data/test/fixtures.yml +24 -0
  46. data/test/remote/gateways/remote_authorize_net_cim_test.rb +459 -0
  47. data/test/remote/gateways/remote_beanstream_interac_test.rb +53 -0
  48. data/test/remote/gateways/remote_beanstream_test.rb +150 -0
  49. data/test/remote/gateways/remote_braintree_test.rb +22 -0
  50. data/test/remote/gateways/remote_cyber_source_test.rb +28 -3
  51. data/test/remote/gateways/remote_data_cash_test.rb +250 -48
  52. data/test/remote/gateways/remote_modern_payments_cim_test.rb +58 -0
  53. data/test/remote/gateways/remote_modern_payments_test.rb +43 -0
  54. data/test/remote/gateways/remote_sage_bankcard_test.rb +109 -0
  55. data/test/remote/gateways/remote_sage_test.rb +87 -0
  56. data/test/remote/gateways/remote_sage_virtual_check_test.rb +62 -0
  57. data/test/remote/gateways/remote_wirecard_test.rb +76 -0
  58. data/test/remote/integrations/remote_paypal_integration_test.rb +15 -3
  59. data/test/test_helper.rb +31 -13
  60. data/test/unit/check_test.rb +14 -2
  61. data/test/unit/credit_card_methods_test.rb +18 -0
  62. data/test/unit/gateways/authorize_net_cim_test.rb +641 -0
  63. data/test/unit/gateways/beanstream_interac_test.rb +51 -0
  64. data/test/unit/gateways/beanstream_test.rb +108 -0
  65. data/test/unit/gateways/braintree_test.rb +2 -5
  66. data/test/unit/gateways/cyber_source_test.rb +18 -0
  67. data/test/unit/gateways/data_cash_test.rb +32 -4
  68. data/test/unit/gateways/gateway_test.rb +8 -1
  69. data/test/unit/gateways/modern_payments_cim_test.rb +171 -0
  70. data/test/unit/gateways/net_registry_test.rb +6 -0
  71. data/test/unit/gateways/payflow_express_test.rb +18 -2
  72. data/test/unit/gateways/paypal_express_test.rb +154 -0
  73. data/test/unit/gateways/paypal_test.rb +140 -0
  74. data/test/unit/gateways/sage_bankcard_test.rb +162 -0
  75. data/test/unit/gateways/sage_virtual_check_test.rb +71 -0
  76. data/test/unit/gateways/secure_pay_au_test.rb +58 -1
  77. data/test/unit/gateways/skip_jack_test.rb +8 -0
  78. data/test/unit/gateways/verifi_test.rb +0 -1
  79. data/test/unit/gateways/wirecard_test.rb +232 -0
  80. data/test/unit/integrations/action_view_helper_test.rb +3 -0
  81. data/test/unit/integrations/notifications/hi_trust_notification_test.rb +23 -2
  82. data/test/unit/integrations/notifications/notification_test.rb +13 -0
  83. data/test/unit/posts_data_test.rb +20 -6
  84. metadata +40 -5
  85. metadata.gz.sig +0 -0
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/modern_payments_cim'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class ModernPaymentsGateway < Gateway
6
+ self.supported_countries = ModernPaymentsCimGateway.supported_countries
7
+ self.supported_cardtypes = ModernPaymentsCimGateway.supported_cardtypes
8
+ self.homepage_url = ModernPaymentsCimGateway.homepage_url
9
+ self.display_name = ModernPaymentsCimGateway.display_name
10
+
11
+ def initialize(options = {})
12
+ requires!(options, :login, :password)
13
+ @options = options
14
+ super
15
+ end
16
+
17
+ def purchase(money, credit_card, options = {})
18
+ customer_response = cim.create_customer(options)
19
+ return customer_response unless customer_response.success?
20
+
21
+ customer_id = customer_response.params["create_customer_result"]
22
+
23
+ card_response = cim.modify_customer_credit_card(customer_id, credit_card)
24
+ return card_response unless card_response.success?
25
+
26
+ cim.authorize_credit_card_payment(customer_id, money)
27
+ end
28
+
29
+ private
30
+ def cim
31
+ @cim ||= ModernPaymentsCimGateway.new(@options)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
@@ -0,0 +1,214 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class ModernPaymentsCimGateway < Gateway #:nodoc:
4
+ TEST_URL = "https://secure.modpay.com/netservices/test/ModpayTest.asmx"
5
+ LIVE_URL = 'https://secure.modpay.com/ws/modpay.asmx'
6
+
7
+ LIVE_XMLNS = "http://secure.modpay.com:81/ws/"
8
+ TEST_XMLNS = "https://secure.modpay.com/netservices/test/"
9
+
10
+ self.supported_countries = ['US']
11
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
12
+ self.homepage_url = 'http://www.modpay.com'
13
+ self.display_name = 'Modern Payments'
14
+
15
+ SUCCESS_MESSAGE = "Transaction accepted"
16
+ FAILURE_MESSAGE = "Transaction failed"
17
+ ERROR_MESSAGE = "Transaction error"
18
+
19
+ PAYMENT_METHOD = {
20
+ :check => 1,
21
+ :credit_card => 2
22
+ }
23
+
24
+ def initialize(options = {})
25
+ requires!(options, :login, :password)
26
+ @options = options
27
+ super
28
+ end
29
+
30
+ def create_customer(options = {})
31
+ post = {}
32
+ add_customer_data(post, options)
33
+ add_address(post, options)
34
+
35
+ commit('CreateCustomer', post)
36
+ end
37
+
38
+ def modify_customer_credit_card(customer_id, credit_card)
39
+ raise ArgumentError, "The customer_id cannot be blank" if customer_id.blank?
40
+
41
+ post = {}
42
+ add_customer_id(post, customer_id)
43
+ add_credit_card(post, credit_card)
44
+
45
+ commit('ModifyCustomerCreditCard', post)
46
+ end
47
+
48
+ def authorize_credit_card_payment(customer_id, amount)
49
+ raise ArgumentError, "The customer_id cannot be blank" if customer_id.blank?
50
+
51
+ post = {}
52
+ add_customer_id(post, customer_id)
53
+ add_amount(post, amount)
54
+
55
+ commit('AuthorizeCreditCardPayment', post)
56
+ end
57
+
58
+ def create_payment(customer_id, amount, options = {})
59
+ raise ArgumentError, "The customer_id cannot be blank" if customer_id.blank?
60
+
61
+ post = {}
62
+ add_customer_id(post, customer_id)
63
+ add_amount(post, amount)
64
+ add_payment_details(post, options)
65
+
66
+ commit('CreatePayment', post)
67
+ end
68
+
69
+ private
70
+ def add_payment_details(post, options)
71
+ post[:pmtDate] = (options[:payment_date] || Time.now.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
72
+ post[:pmtType] = PAYMENT_METHOD[options[:payment_method] || :credit_card]
73
+ end
74
+
75
+ def add_amount(post, money)
76
+ post[:pmtAmount] = amount(money)
77
+ end
78
+
79
+ def add_customer_id(post, customer_id)
80
+ post[:custId] = customer_id
81
+ end
82
+
83
+ def add_customer_data(post, options)
84
+ post[:acctNum] = options[:customer]
85
+ end
86
+
87
+ def add_address(post, options)
88
+ address = options[:billing_address] || options[:address] || {}
89
+
90
+ if name = address[:name]
91
+ segments = name.split(' ')
92
+ post[:lastName] = segments.pop
93
+ post[:firstName] = segments.join(' ')
94
+ else
95
+ post[:firstName] = address[:first_name]
96
+ post[:lastName] = address[:last_name]
97
+ end
98
+
99
+ post[:address] = address[:address1]
100
+ post[:city] = address[:city]
101
+ post[:state] = address[:state]
102
+ post[:zip] = address[:zip]
103
+ post[:phone] = address[:phone]
104
+ post[:fax] = address[:fax]
105
+ post[:email] = address[:email]
106
+ end
107
+
108
+ def add_credit_card(post, credit_card)
109
+ post[:ccName] = credit_card.name
110
+ post[:ccNum] = credit_card.number
111
+ post[:expMonth] = credit_card.month
112
+ post[:expYear] = credit_card.year
113
+ end
114
+
115
+ def build_request(action, params)
116
+ xml = Builder::XmlMarkup.new :indent => 2
117
+ xml.instruct!
118
+ xml.tag! 'env:Envelope',
119
+ { 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
120
+ 'xmlns:env' => 'http://schemas.xmlsoap.org/soap/envelope/',
121
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance' } do
122
+
123
+ xml.tag! 'env:Body' do
124
+ xml.tag! action, { "xmlns" => xmlns(action) } do
125
+ xml.tag! "clientId", @options[:login]
126
+ xml.tag! "clientCode", @options[:password]
127
+ params.each {|key, value| xml.tag! key, value }
128
+ end
129
+ end
130
+ end
131
+ xml.target!
132
+ end
133
+
134
+ def xmlns(action)
135
+ if test? && action == 'AuthorizeCreditCardPayment'
136
+ TEST_XMLNS
137
+ else
138
+ LIVE_XMLNS
139
+ end
140
+ end
141
+
142
+ def url(action)
143
+ if test? && action == 'AuthorizeCreditCardPayment'
144
+ TEST_URL
145
+ else
146
+ LIVE_URL
147
+ end
148
+ end
149
+
150
+ def commit(action, params)
151
+ data = ssl_post(url(action), build_request(action, params),
152
+ { 'Content-Type' =>'text/xml; charset=utf-8',
153
+ 'SOAPAction' => "#{xmlns(action)}#{action}" }
154
+ )
155
+
156
+ response = parse(action, data)
157
+ Response.new(successful?(action, response), message_from(action, response), response,
158
+ :test => test?,
159
+ :authorization => authorization_from(action, response),
160
+ :avs_result => { :code => response[:avs_code] }
161
+ )
162
+ end
163
+
164
+ def authorization_from(action, response)
165
+ response[result_key(action)]
166
+ end
167
+
168
+ def result_key(action)
169
+ action == "AuthorizeCreditCardPayment" ? :trans_id : "#{action.underscore}_result".to_sym
170
+ end
171
+
172
+ def successful?(action, response)
173
+ response[result_key(action)].to_i > 0
174
+ end
175
+
176
+ def message_from(action, response)
177
+ if response[:faultcode]
178
+ ERROR_MESSAGE
179
+ elsif successful?(action, response)
180
+ SUCCESS_MESSAGE
181
+ else
182
+ FAILURE_MESSAGE
183
+ end
184
+ end
185
+
186
+ def parse(action, xml)
187
+ response = {}
188
+ response[:action] = action
189
+
190
+ xml = REXML::Document.new(xml)
191
+ if root = REXML::XPath.first(xml, "//#{action}Response")
192
+ root.elements.to_a.each do |node|
193
+ parse_element(response, node)
194
+ end
195
+ elsif root = REXML::XPath.first(xml, "//soap:Fault")
196
+ root.elements.to_a.each do |node|
197
+ response[node.name.underscore.to_sym] = node.text
198
+ end
199
+ end
200
+
201
+ response
202
+ end
203
+
204
+ def parse_element(response, node)
205
+ if node.has_elements?
206
+ node.elements.each{|e| parse_element(response, e) }
207
+ else
208
+ response[node.name.underscore.to_sym] = node.text
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end
214
+
@@ -72,6 +72,7 @@ module ActiveMerchant
72
72
  # described in "Programming for NetRegistry's E-commerce
73
73
  # Gateway." [http://rubyurl.com/hNG]
74
74
  def capture(money, authorization, options = {})
75
+ requires!(options, :credit_card)
75
76
  credit_card = options[:credit_card]
76
77
 
77
78
  params = {
@@ -28,8 +28,8 @@ module ActiveMerchant #:nodoc:
28
28
  end
29
29
 
30
30
  XMLNS = 'http://www.paypal.com/XMLPay'
31
- TEST_URL = 'https://pilot-payflowpro.verisign.com'
32
- LIVE_URL = 'https://payflowpro.verisign.com'
31
+ TEST_URL = 'https://pilot-payflowpro.paypal.com'
32
+ LIVE_URL = 'https://payflowpro.paypal.com'
33
33
 
34
34
  CARD_MAPPING = {
35
35
  :visa => 'Visa',
@@ -1,25 +1,17 @@
1
1
  require File.dirname(__FILE__) + '/payflow/payflow_common_api'
2
2
  require File.dirname(__FILE__) + '/payflow/payflow_express_response'
3
+ require File.dirname(__FILE__) + '/paypal_express_common'
3
4
 
4
5
  module ActiveMerchant #:nodoc:
5
6
  module Billing #:nodoc:
6
7
  class PayflowExpressGateway < Gateway
7
8
  include PayflowCommonAPI
9
+ include PaypalExpressCommon
8
10
 
9
- LIVE_REDIRECT_URL = 'https://www.paypal.com/cgibin/webscr?cmd=_express-checkout&token='
10
- TEST_REDIRECT_URL = 'https://test-expresscheckout.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token='
11
-
11
+ self.test_redirect_url = 'https://test-expresscheckout.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token='
12
12
  self.homepage_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=xpt/merchant/ExpressCheckoutIntro-outside'
13
13
  self.display_name = 'PayPal Express Checkout'
14
14
 
15
- def redirect_url
16
- test? ? TEST_REDIRECT_URL : LIVE_REDIRECT_URL
17
- end
18
-
19
- def redirect_url_for(token)
20
- "#{redirect_url}#{token}"
21
- end
22
-
23
15
  def authorize(money, options = {})
24
16
  requires!(options, :token, :payer_id)
25
17
  request = build_sale_or_authorization_request('Authorization', money, options)
@@ -21,7 +21,7 @@ module ActiveMerchant #:nodoc:
21
21
  self.homepage_url = 'http://www.paymentexpress.com/'
22
22
  self.display_name = 'PaymentExpress'
23
23
 
24
- PAYMENT_URL = 'https://www.paymentexpress.com/pxpost.aspx'
24
+ URL = 'https://www.paymentexpress.com/pxpost.aspx'
25
25
 
26
26
  APPROVED = '1'
27
27
 
@@ -196,7 +196,7 @@ module ActiveMerchant #:nodoc:
196
196
  add_transaction_type(request, action)
197
197
 
198
198
  # Parse the XML response
199
- response = parse( ssl_post(PAYMENT_URL, request.to_s) )
199
+ response = parse( ssl_post(URL, request.to_s) )
200
200
 
201
201
  # Return a response
202
202
  PaymentExpressResponse.new(response[:success] == APPROVED, response[:response_text], response,
@@ -8,7 +8,7 @@ module ActiveMerchant #:nodoc:
8
8
  base.cattr_accessor :signature
9
9
  end
10
10
 
11
- API_VERSION = '2.0'
11
+ API_VERSION = '52.0'
12
12
 
13
13
  URLS = {
14
14
  :test => { :certificate => 'https://api.sandbox.paypal.com/2.0/',
@@ -42,6 +42,8 @@ module ActiveMerchant #:nodoc:
42
42
 
43
43
  SUCCESS_CODES = [ 'Success', 'SuccessWithWarning' ]
44
44
 
45
+ FRAUD_REVIEW_CODE = "11610"
46
+
45
47
  # The gateway must be configured with either your PayPal PEM file
46
48
  # or your PayPal API Signature. Only one is required.
47
49
  #
@@ -109,7 +111,7 @@ module ActiveMerchant #:nodoc:
109
111
 
110
112
  private
111
113
  def build_reauthorize_request(money, authorization, options)
112
- xml = Builder::XmlMarkup.new :indent => 2
114
+ xml = Builder::XmlMarkup.new
113
115
 
114
116
  xml.tag! 'DoReauthorizationReq', 'xmlns' => PAYPAL_NAMESPACE do
115
117
  xml.tag! 'DoReauthorizationRequest', 'xmlns:n2' => EBAY_NAMESPACE do
@@ -123,7 +125,7 @@ module ActiveMerchant #:nodoc:
123
125
  end
124
126
 
125
127
  def build_capture_request(money, authorization, options)
126
- xml = Builder::XmlMarkup.new :indent => 2
128
+ xml = Builder::XmlMarkup.new
127
129
 
128
130
  xml.tag! 'DoCaptureReq', 'xmlns' => PAYPAL_NAMESPACE do
129
131
  xml.tag! 'DoCaptureRequest', 'xmlns:n2' => EBAY_NAMESPACE do
@@ -139,7 +141,7 @@ module ActiveMerchant #:nodoc:
139
141
  end
140
142
 
141
143
  def build_credit_request(money, identification, options)
142
- xml = Builder::XmlMarkup.new :indent => 2
144
+ xml = Builder::XmlMarkup.new
143
145
 
144
146
  xml.tag! 'RefundTransactionReq', 'xmlns' => PAYPAL_NAMESPACE do
145
147
  xml.tag! 'RefundTransactionRequest', 'xmlns:n2' => EBAY_NAMESPACE do
@@ -155,7 +157,7 @@ module ActiveMerchant #:nodoc:
155
157
  end
156
158
 
157
159
  def build_void_request(authorization, options)
158
- xml = Builder::XmlMarkup.new :indent => 2
160
+ xml = Builder::XmlMarkup.new
159
161
 
160
162
  xml.tag! 'DoVoidReq', 'xmlns' => PAYPAL_NAMESPACE do
161
163
  xml.tag! 'DoVoidRequest', 'xmlns:n2' => EBAY_NAMESPACE do
@@ -172,7 +174,7 @@ module ActiveMerchant #:nodoc:
172
174
  default_options = args.last.is_a?(Hash) ? args.pop : {}
173
175
  recipients = args.first.is_a?(Array) ? args : [args]
174
176
 
175
- xml = Builder::XmlMarkup.new :indent => 2
177
+ xml = Builder::XmlMarkup.new
176
178
 
177
179
  xml.tag! 'MassPayReq', 'xmlns' => PAYPAL_NAMESPACE do
178
180
  xml.tag! 'MassPayRequest', 'xmlns:n2' => EBAY_NAMESPACE do
@@ -192,19 +194,41 @@ module ActiveMerchant #:nodoc:
192
194
 
193
195
  xml.target!
194
196
  end
195
-
197
+
196
198
  def parse(action, xml)
197
199
  response = {}
200
+
201
+ error_messages = []
202
+ error_codes = []
203
+
198
204
  xml = REXML::Document.new(xml)
199
205
  if root = REXML::XPath.first(xml, "//#{action}Response")
200
- root.elements.to_a.each do |node|
206
+ root.elements.each do |node|
201
207
  case node.name
202
208
  when 'Errors'
203
- response[:message] = node.elements.to_a('//LongMessage').collect{|error| error.text}.join('.')
209
+ short_message = nil
210
+ long_message = nil
211
+
212
+ node.elements.each do |child|
213
+ case child.name
214
+ when "LongMessage"
215
+ long_message = child.text unless child.text.blank?
216
+ when "ShortMessage"
217
+ short_message = child.text unless child.text.blank?
218
+ when "ErrorCode"
219
+ error_codes << child.text unless child.text.blank?
220
+ end
221
+ end
222
+
223
+ if message = long_message || short_message
224
+ error_messages << message
225
+ end
204
226
  else
205
227
  parse_element(response, node)
206
228
  end
207
229
  end
230
+ response[:message] = error_messages.uniq.join(". ") unless error_messages.empty?
231
+ response[:error_codes] = error_codes.uniq.join(",") unless error_codes.empty?
208
232
  elsif root = REXML::XPath.first(xml, "//SOAP-ENV:Fault")
209
233
  parse_element(response, root)
210
234
  response[:message] = "#{response[:faultcode]}: #{response[:faultstring]} - #{response[:detail]}"
@@ -224,19 +248,8 @@ module ActiveMerchant #:nodoc:
224
248
  end
225
249
  end
226
250
 
227
- def response_type_for(action)
228
- case action
229
- when 'Authorization', 'Purchase'
230
- 'DoDirectPaymentResponse'
231
- when 'Void'
232
- 'DoVoidResponse'
233
- when 'Capture'
234
- 'DoCaptureResponse'
235
- end
236
- end
237
-
238
251
  def build_request(body)
239
- xml = Builder::XmlMarkup.new :indent => 2
252
+ xml = Builder::XmlMarkup.new
240
253
 
241
254
  xml.instruct!
242
255
  xml.tag! 'env:Envelope', ENVELOPE_NAMESPACES do
@@ -286,11 +299,16 @@ module ActiveMerchant #:nodoc:
286
299
  build_response(successful?(response), message_from(response), response,
287
300
  :test => test?,
288
301
  :authorization => authorization_from(response),
302
+ :fraud_review => fraud_review?(response),
289
303
  :avs_result => { :code => response[:avs_code] },
290
304
  :cvv_result => response[:cvv2_code]
291
305
  )
292
306
  end
293
307
 
308
+ def fraud_review?(response)
309
+ response[:error_codes] == FRAUD_REVIEW_CODE
310
+ end
311
+
294
312
  def authorization_from(response)
295
313
  response[:transaction_id] || response[:authorization_id] # latter one is from reauthorization
296
314
  end