activemerchant 1.29.3 → 1.30.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 (47) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG +39 -0
  3. data/CONTRIBUTORS +19 -0
  4. data/README.md +43 -41
  5. data/lib/active_merchant/billing/check.rb +15 -11
  6. data/lib/active_merchant/billing/credit_card.rb +5 -1
  7. data/lib/active_merchant/billing/credit_card_formatting.rb +8 -8
  8. data/lib/active_merchant/billing/gateway.rb +1 -1
  9. data/lib/active_merchant/billing/gateways/authorize_net.rb +9 -1
  10. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +15 -4
  11. data/lib/active_merchant/billing/gateways/balanced.rb +9 -3
  12. data/lib/active_merchant/billing/gateways/banwire.rb +15 -1
  13. data/lib/active_merchant/billing/gateways/beanstream.rb +26 -24
  14. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +6 -2
  15. data/lib/active_merchant/billing/gateways/braintree_blue.rb +5 -2
  16. data/lib/active_merchant/billing/gateways/cyber_source.rb +55 -22
  17. data/lib/active_merchant/billing/gateways/eway.rb +114 -171
  18. data/lib/active_merchant/billing/gateways/eway_managed.rb +52 -22
  19. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +222 -0
  20. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +13 -2
  21. data/lib/active_merchant/billing/gateways/litle.rb +50 -19
  22. data/lib/active_merchant/billing/gateways/merchant_ware.rb +44 -9
  23. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +190 -0
  24. data/lib/active_merchant/billing/gateways/moneris.rb +2 -4
  25. data/lib/active_merchant/billing/gateways/nab_transact.rb +20 -3
  26. data/lib/active_merchant/billing/gateways/netbilling.rb +1 -0
  27. data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
  28. data/lib/active_merchant/billing/gateways/optimal_payment.rb +18 -3
  29. data/lib/active_merchant/billing/gateways/orbital.rb +9 -5
  30. data/lib/active_merchant/billing/gateways/payment_express.rb +62 -1
  31. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -1
  32. data/lib/active_merchant/billing/gateways/paypal_express.rb +2 -0
  33. data/lib/active_merchant/billing/gateways/pin.rb +157 -0
  34. data/lib/active_merchant/billing/gateways/qbms.rb +3 -2
  35. data/lib/active_merchant/billing/gateways/quickpay.rb +66 -28
  36. data/lib/active_merchant/billing/gateways/sage_pay.rb +6 -0
  37. data/lib/active_merchant/billing/gateways/smart_ps.rb +1 -1
  38. data/lib/active_merchant/billing/gateways/spreedly_core.rb +235 -0
  39. data/lib/active_merchant/billing/gateways/stripe.rb +1 -0
  40. data/lib/active_merchant/billing/gateways/wirecard.rb +15 -9
  41. data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +4 -1
  42. data/lib/active_merchant/billing/integrations/paypal/notification.rb +39 -31
  43. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +13 -10
  44. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +14 -14
  45. data/lib/active_merchant/version.rb +1 -1
  46. metadata +109 -49
  47. metadata.gz.sig +0 -0
@@ -65,6 +65,7 @@ module ActiveMerchant #:nodoc:
65
65
  add_credit_card(post, credit_card)
66
66
  add_address(post, options)
67
67
  add_customer_data(post, options)
68
+ add_optional_data(post, options)
68
69
 
69
70
  commit(:purchase, post)
70
71
  end
@@ -79,6 +80,7 @@ module ActiveMerchant #:nodoc:
79
80
  add_credit_card(post, credit_card)
80
81
  add_address(post, options)
81
82
  add_customer_data(post, options)
83
+ add_optional_data(post, options)
82
84
 
83
85
  commit(:authorization, post)
84
86
  end
@@ -156,6 +158,10 @@ module ActiveMerchant #:nodoc:
156
158
  add_pair(post, :ClientIPAddress, options[:ip])
157
159
  end
158
160
 
161
+ def add_optional_data(post, options)
162
+ add_pair(post, :GiftAidPayment, options[:gift_aid_payment]) unless options[:gift_aid_payment].blank?
163
+ end
164
+
159
165
  def add_address(post, options)
160
166
  if billing_address = options[:billing_address] || options[:address]
161
167
  first_name, last_name = parse_first_and_last_name(billing_address[:name])
@@ -221,7 +221,7 @@ module ActiveMerchant #:nodoc:
221
221
  parameters[:amount] = amount(money) if money
222
222
  response = parse( ssl_post(self.live_url, post_data(action,parameters)) )
223
223
  Response.new(response["response"] == "1", message_from(response), response,
224
- :authorization => response["transactionid"],
224
+ :authorization => (response["transactionid"] || response["customer_vault_id"]),
225
225
  :test => test?,
226
226
  :cvv_result => response["cvvresponse"],
227
227
  :avs_result => { :code => response["avsresponse"] }
@@ -0,0 +1,235 @@
1
+ require 'nokogiri'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ # Public: This gateway allows you to interact with any gateway you've
6
+ # created in Spreedly Core (https://spreedlycore.com). It's an adapter
7
+ # which can be particularly useful if you already have code interacting with
8
+ # ActiveMerchant and want to easily take advantage of Core's vault.
9
+ class SpreedlyCoreGateway < Gateway
10
+ self.live_url = 'https://spreedlycore.com/v1'
11
+
12
+ self.supported_countries = %w(AD AE AT AU BD BE BG BN CA CH CY CZ DE DK EE EG ES FI FR GB
13
+ GI GR HK HU ID IE IL IM IN IS IT JO KW LB LI LK LT LU LV MC
14
+ MT MU MV MX MY NL NO NZ OM PH PL PT QA RO SA SE SG SI SK SM
15
+ TR TT UM US VA VN ZA)
16
+
17
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
18
+ self.homepage_url = 'https://spreedlycore.com'
19
+ self.display_name = 'Spreedly Core'
20
+ self.money_format = :cents
21
+ self.default_currency = 'USD'
22
+
23
+ # Public: Create a new Spreedly Core Gateway.
24
+ #
25
+ # options - A hash of options:
26
+ # :login - Your Spreedly Core API login.
27
+ # :password - Your Spreedly Core API secret.
28
+ # :gateway_token - The token of the gateway you've created in
29
+ # Spreedly Core.
30
+ def initialize(options = {})
31
+ requires!(options, :login, :password, :gateway_token)
32
+ super
33
+ end
34
+
35
+ # Public: Run a purchase transaction.
36
+ #
37
+ # money - The monetary amount of the transaction in cents.
38
+ # payment_method - The CreditCard or the Spreedly Core payment method
39
+ # token.
40
+ # options - A standard ActiveMerchant options hash
41
+ def purchase(money, payment_method, options = {})
42
+ if payment_method.is_a?(String)
43
+ purchase_with_token(money, payment_method, options)
44
+ else
45
+ MultiResponse.run do |r|
46
+ r.process { save_card(false, payment_method, options) }
47
+ r.process { purchase_with_token(money, r.authorization, options) }
48
+ end
49
+ end
50
+ end
51
+
52
+ # Public: Run an authorize transaction.
53
+ #
54
+ # money - The monetary amount of the transaction in cents.
55
+ # payment_method - The CreditCard or the Spreedly Core payment method
56
+ # token.
57
+ # options - A standard ActiveMerchant options hash
58
+ def authorize(money, payment_method, options = {})
59
+ if payment_method.is_a?(String)
60
+ authorize_with_token(money, payment_method, options)
61
+ else
62
+ MultiResponse.run do |r|
63
+ r.process { save_card(false, payment_method, options) }
64
+ r.process { authorize_with_token(money, r.authorization, options) }
65
+ end
66
+ end
67
+ end
68
+
69
+ def capture(money, authorization, options={})
70
+ request = build_xml_request('transaction') do |doc|
71
+ add_invoice(doc, money, options)
72
+ end
73
+
74
+ commit("transactions/#{authorization}/capture.xml", request)
75
+ end
76
+
77
+ def refund(money, authorization, options={})
78
+ request = build_xml_request('transaction') do |doc|
79
+ add_invoice(doc, money, options)
80
+ end
81
+
82
+ commit("transactions/#{authorization}/credit.xml", request)
83
+ end
84
+
85
+ def void(authorization, options={})
86
+ commit("transactions/#{authorization}/void.xml", '')
87
+ end
88
+
89
+ # Public: Store a credit card in the Spreedly Core vault and retain it.
90
+ #
91
+ # credit_card - The CreditCard to store
92
+ # options - A standard ActiveMerchant options hash
93
+ def store(credit_card, options={})
94
+ save_card(true, credit_card, options)
95
+ end
96
+
97
+ # Public: Redact the CreditCard in Spreedly Core. This wipes the
98
+ # sensitive payment information from the card.
99
+ #
100
+ # credit_card - The CreditCard to store
101
+ # options - A standard ActiveMerchant options hash
102
+ def unstore(authorization, options={})
103
+ commit("payment_methods/#{authorization}/redact.xml", '', :put)
104
+ end
105
+
106
+ private
107
+ def save_card(retain, credit_card, options)
108
+ request = build_xml_request('payment_method') do |doc|
109
+ add_credit_card(doc, credit_card, options)
110
+ add_data(doc, options)
111
+ doc.retained(true) if retain
112
+ end
113
+
114
+ commit("payment_methods.xml", request, :post, :payment_method_token)
115
+ end
116
+
117
+ def purchase_with_token(money, payment_method_token, options)
118
+ request = auth_purchase_request(money, payment_method_token, options)
119
+ commit("gateways/#{@options[:gateway_token]}/purchase.xml", request)
120
+ end
121
+
122
+ def authorize_with_token(money, payment_method_token, options)
123
+ request = auth_purchase_request(money, payment_method_token, options)
124
+ commit("gateways/#{@options[:gateway_token]}/authorize.xml", request)
125
+ end
126
+
127
+ def auth_purchase_request(money, payment_method_token, options)
128
+ build_xml_request('transaction') do |doc|
129
+ add_invoice(doc, money, options)
130
+ doc.payment_method_token(payment_method_token)
131
+ end
132
+ end
133
+
134
+ def add_invoice(doc, money, options)
135
+ doc.amount amount(money)
136
+ doc.currency_code(options[:currency] || currency(money) || default_currency)
137
+ end
138
+
139
+ def add_credit_card(doc, credit_card, options)
140
+ doc.credit_card do
141
+ doc.number(credit_card.number)
142
+ doc.first_name(credit_card.first_name)
143
+ doc.last_name(credit_card.last_name)
144
+ doc.month(credit_card.month)
145
+ doc.year(credit_card.year)
146
+ doc.email(options[:email])
147
+ doc.address1(options[:billing_address].try(:[], :address1))
148
+ doc.address2(options[:billing_address].try(:[], :address2))
149
+ doc.city(options[:billing_address].try(:[], :city))
150
+ doc.state(options[:billing_address].try(:[], :state))
151
+ doc.zip(options[:billing_address].try(:[], :zip))
152
+ end
153
+ end
154
+
155
+ def add_data(doc, options)
156
+ doc.data do
157
+ data_to_doc(doc, options[:data])
158
+ end
159
+ end
160
+
161
+ def data_to_doc(doc, value)
162
+ return doc.text value unless value.kind_of? Hash
163
+ value.each do |k, v|
164
+ doc.send(k) do
165
+ data_to_doc(doc, v)
166
+ end
167
+ end
168
+ end
169
+
170
+ def parse(xml)
171
+ response = {}
172
+
173
+ doc = Nokogiri::XML(xml)
174
+ doc.root.xpath('*').each do |node|
175
+ if (node.elements.empty?)
176
+ response[node.name.downcase.to_sym] = node.text
177
+ else
178
+ node.elements.each do |childnode|
179
+ childnode_to_response(response, node, childnode)
180
+ end
181
+ end
182
+ end
183
+
184
+ response
185
+ end
186
+
187
+ def childnode_to_response(response, node, childnode)
188
+ name = "#{node.name.downcase}_#{childnode.name.downcase}"
189
+ if name == 'payment_method_data' && !childnode.elements.empty?
190
+ response[name.to_sym] = Hash.from_xml(childnode.to_s).values.first
191
+ else
192
+ response[name.to_sym] = childnode.text
193
+ end
194
+ end
195
+
196
+ def build_xml_request(root)
197
+ builder = Nokogiri::XML::Builder.new
198
+ builder.__send__(root) do |doc|
199
+ yield(doc)
200
+ end
201
+ builder.to_xml
202
+ end
203
+
204
+ def commit(relative_url, request, method = :post, authorization_field = :token)
205
+ begin
206
+ raw_response = ssl_request(method, "#{live_url}/#{relative_url}", request, headers)
207
+ rescue ResponseError => e
208
+ raw_response = e.response.body
209
+ end
210
+
211
+ response_from(raw_response, authorization_field)
212
+ end
213
+
214
+ def response_from(raw_response, authorization_field)
215
+ parsed = parse(raw_response)
216
+ options = {
217
+ :authorization => parsed[authorization_field],
218
+ :test => (parsed[:on_test_gateway] == 'true'),
219
+ :avs_result => { :code => parsed[:response_avs_code] },
220
+ :cvv_result => parsed[:response_cvv_code]
221
+ }
222
+
223
+ Response.new(parsed[:succeeded] == 'true', parsed[:message] || parsed[:error], parsed, options)
224
+ end
225
+
226
+ def headers
227
+ {
228
+ 'Authorization' => ('Basic ' + Base64.strict_encode64("#{@options[:login]}:#{@options[:password]}").chomp),
229
+ 'Content-Type' => 'text/xml'
230
+ }
231
+ end
232
+ end
233
+ end
234
+ end
235
+
@@ -50,6 +50,7 @@ module ActiveMerchant #:nodoc:
50
50
  add_customer(post, options)
51
51
  add_customer_data(post,options)
52
52
  post[:description] = options[:description] || options[:email]
53
+ post[:application_fee] = options[:application_fee] if options[:application_fee]
53
54
  add_flags(post, options)
54
55
 
55
56
  meta = generate_meta(options)
@@ -16,7 +16,7 @@ module ActiveMerchant #:nodoc:
16
16
  'xsi:noNamespaceSchemaLocation' => 'wirecard.xsd'
17
17
  }
18
18
 
19
- PERMITTED_TRANSACTIONS = %w[ AUTHORIZATION CAPTURE_AUTHORIZATION PURCHASE ]
19
+ PERMITTED_TRANSACTIONS = %w[ PREAUTHORIZATION CAPTURE PURCHASE ]
20
20
 
21
21
  RETURN_CODES = %w[ ACK NOK ]
22
22
 
@@ -63,13 +63,13 @@ module ActiveMerchant #:nodoc:
63
63
  # Authorization
64
64
  def authorize(money, creditcard, options = {})
65
65
  options[:credit_card] = creditcard
66
- commit(:authorization, money, options)
66
+ commit(:preauthorization, money, options)
67
67
  end
68
68
 
69
69
  # Capture Authorization
70
70
  def capture(money, authorization, options = {})
71
- options[:authorization] = authorization
72
- commit(:capture_authorization, money, options)
71
+ options[:preauthorization] = authorization
72
+ commit(:capture, money, options)
73
73
  end
74
74
 
75
75
  # Purchase
@@ -148,16 +148,17 @@ module ActiveMerchant #:nodoc:
148
148
  options[:order_id] ||= generate_unique_id
149
149
 
150
150
  xml.tag! "FNC_CC_#{options[:action].to_s.upcase}" do
151
- xml.tag! 'FunctionID', options[:description]
151
+ xml.tag! 'FunctionID', options[:description].to_s.slice(0,32)
152
152
  xml.tag! 'CC_TRANSACTION' do
153
153
  xml.tag! 'TransactionID', options[:order_id]
154
154
  case options[:action]
155
- when :authorization, :purchase
155
+ when :preauthorization, :purchase
156
156
  add_invoice(xml, money, options)
157
157
  add_creditcard(xml, options[:credit_card])
158
158
  add_address(xml, options[:billing_address])
159
- when :capture_authorization
160
- xml.tag! 'GuWID', options[:authorization]
159
+ when :capture
160
+ xml.tag! 'GuWID', options[:preauthorization]
161
+ add_amount(xml, money)
161
162
  end
162
163
  end
163
164
  end
@@ -165,7 +166,7 @@ module ActiveMerchant #:nodoc:
165
166
 
166
167
  # Includes the payment (amount, currency, country) to the transaction-xml
167
168
  def add_invoice(xml, money, options)
168
- xml.tag! 'Amount', amount(money)
169
+ add_amount(xml, money)
169
170
  xml.tag! 'Currency', options[:currency] || currency(money)
170
171
  xml.tag! 'CountryCode', options[:billing_address][:country]
171
172
  xml.tag! 'RECURRING_TRANSACTION' do
@@ -173,6 +174,11 @@ module ActiveMerchant #:nodoc:
173
174
  end
174
175
  end
175
176
 
177
+ # Include the amount in the transaction-xml
178
+ def add_amount(xml, money)
179
+ xml.tag! 'Amount', amount(money)
180
+ end
181
+
176
182
  # Includes the credit-card data to the transaction-xml
177
183
  def add_creditcard(xml, creditcard)
178
184
  raise "Creditcard must be supplied!" if creditcard.nil?
@@ -20,7 +20,6 @@ module ActiveMerchant #:nodoc:
20
20
  mapping :credential2, 'pwd'
21
21
  mapping :credential3, 'partner'
22
22
  mapping :order, 'user1'
23
- mapping :description, 'description'
24
23
 
25
24
  mapping :amount, 'amt'
26
25
 
@@ -35,6 +34,10 @@ module ActiveMerchant #:nodoc:
35
34
 
36
35
  mapping :customer, :name => 'name'
37
36
 
37
+ def description(value)
38
+ add_field('description', "#{value}".delete("#"))
39
+ end
40
+
38
41
  def customer(params = {})
39
42
  add_field(mappings[:customer][:name], [params.delete(:first_name), params.delete(:last_name)].compact.join(' '))
40
43
  end
@@ -1,16 +1,17 @@
1
1
  require 'net/http'
2
+ require 'time'
2
3
 
3
4
  module ActiveMerchant #:nodoc:
4
5
  module Billing #:nodoc:
5
6
  module Integrations #:nodoc:
6
7
  module Paypal
7
- # Parser and handler for incoming Instant payment notifications from paypal.
8
+ # Parser and handler for incoming Instant payment notifications from paypal.
8
9
  # The Example shows a typical handler in a rails application. Note that this
9
10
  # is an example, please read the Paypal API documentation for all the details
10
11
  # on creating a safe payment controller.
11
12
  #
12
13
  # Example
13
- #
14
+ #
14
15
  # class BackendController < ApplicationController
15
16
  # include ActiveMerchant::Billing::Integrations
16
17
  #
@@ -20,28 +21,28 @@ module ActiveMerchant #:nodoc:
20
21
  # if notify.masspay?
21
22
  # masspay_items = notify.items
22
23
  # end
23
- #
24
+ #
24
25
  # order = Order.find(notify.item_id)
25
- #
26
- # if notify.acknowledge
26
+ #
27
+ # if notify.acknowledge
27
28
  # begin
28
- #
29
+ #
29
30
  # if notify.complete? and order.total == notify.amount
30
- # order.status = 'success'
31
- #
31
+ # order.status = 'success'
32
+ #
32
33
  # shop.ship(order)
33
34
  # else
34
35
  # logger.error("Failed to verify Paypal's notification, please investigate")
35
36
  # end
36
- #
37
+ #
37
38
  # rescue => e
38
- # order.status = 'failed'
39
+ # order.status = 'failed'
39
40
  # raise
40
41
  # ensure
41
42
  # order.save
42
43
  # end
43
44
  # end
44
- #
45
+ #
45
46
  # render :nothing
46
47
  # end
47
48
  # end
@@ -52,7 +53,7 @@ module ActiveMerchant #:nodoc:
52
53
  super
53
54
  extend MassPayNotification if masspay?
54
55
  end
55
-
56
+
56
57
  # Was the transaction complete?
57
58
  def complete?
58
59
  status == "Completed"
@@ -63,13 +64,20 @@ module ActiveMerchant #:nodoc:
63
64
  type == "masspay"
64
65
  end
65
66
 
66
- # When was this payment received by the client.
67
- # sometimes it can happen that we get the notification much later.
68
- # One possible scenario is that our web application was down. In this case paypal tries several
67
+ # When was this payment received by the client.
68
+ # sometimes it can happen that we get the notification much later.
69
+ # One possible scenario is that our web application was down. In this case paypal tries several
69
70
  # times an hour to inform us about the notification
70
71
  def received_at
71
- parsed_time_fields = DateTime._strptime(params['payment_date'], "%H:%M:%S %b %d, %Y %z")
72
- Time.mktime(*parsed_time_fields.values_at(:year, :mon, :mday, :hour, :min, :sec, :zone))
72
+ parsed_time_fields = DateTime._strptime(params['payment_date'], "%H:%M:%S %b %d, %Y %Z")
73
+ Time.gm(
74
+ parsed_time_fields[:year],
75
+ parsed_time_fields[:mon],
76
+ parsed_time_fields[:mday],
77
+ parsed_time_fields[:hour],
78
+ parsed_time_fields[:min],
79
+ parsed_time_fields[:sec]
80
+ ) + Time.zone_offset(parsed_time_fields[:zone])
73
81
  end
74
82
 
75
83
  # Status of transaction. List of possible values:
@@ -94,8 +102,8 @@ module ActiveMerchant #:nodoc:
94
102
  params['txn_id']
95
103
  end
96
104
 
97
- # What type of transaction are we dealing with?
98
- # "cart" "send_money" "web_accept" are possible here.
105
+ # What type of transaction are we dealing with?
106
+ # "cart" "send_money" "web_accept" are possible here.
99
107
  def type
100
108
  params['txn_type']
101
109
  end
@@ -115,37 +123,37 @@ module ActiveMerchant #:nodoc:
115
123
  params['mc_currency']
116
124
  end
117
125
 
118
- # This is the item number which we submitted to paypal
126
+ # This is the item number which we submitted to paypal
119
127
  # The custom field is also mapped to item_id because PayPal
120
128
  # doesn't return item_number in dispute notifications
121
129
  def item_id
122
130
  params['item_number'] || params['custom']
123
131
  end
124
132
 
125
- # This is the invoice which you passed to paypal
133
+ # This is the invoice which you passed to paypal
126
134
  def invoice
127
135
  params['invoice']
128
- end
136
+ end
129
137
 
130
138
  # Was this a test transaction?
131
139
  def test?
132
140
  params['test_ipn'] == '1'
133
141
  end
134
-
142
+
135
143
  def account
136
144
  params['business'] || params['receiver_email']
137
145
  end
138
146
 
139
- # Acknowledge the transaction to paypal. This method has to be called after a new
140
- # ipn arrives. Paypal will verify that all the information we received are correct and will return a
141
- # ok or a fail.
142
- #
147
+ # Acknowledge the transaction to paypal. This method has to be called after a new
148
+ # ipn arrives. Paypal will verify that all the information we received are correct and will return a
149
+ # ok or a fail.
150
+ #
143
151
  # Example:
144
- #
152
+ #
145
153
  # def paypal_ipn
146
154
  # notify = PaypalNotification.new(request.raw_post)
147
155
  #
148
- # if notify.acknowledge
156
+ # if notify.acknowledge
149
157
  # ... process order ... if notify.complete?
150
158
  # else
151
159
  # ... log possible hacking attempt ...
@@ -153,11 +161,11 @@ module ActiveMerchant #:nodoc:
153
161
  def acknowledge
154
162
  payload = raw
155
163
 
156
- response = ssl_post(Paypal.service_url + '?cmd=_notify-validate', payload,
164
+ response = ssl_post(Paypal.service_url + '?cmd=_notify-validate', payload,
157
165
  'Content-Length' => "#{payload.size}",
158
166
  'User-Agent' => "Active Merchant -- http://activemerchant.org"
159
167
  )
160
-
168
+
161
169
  raise StandardError.new("Faulty paypal result: #{response}") unless ["VERIFIED", "INVALID"].include?(response)
162
170
 
163
171
  response == "VERIFIED"