activemerchant 1.44.1 → 1.45.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -3
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG +48 -0
  5. data/CONTRIBUTORS +12 -0
  6. data/README.md +15 -5
  7. data/lib/active_merchant/billing.rb +2 -0
  8. data/lib/active_merchant/billing/apple_pay_payment_token.rb +22 -0
  9. data/lib/active_merchant/billing/gateway.rb +36 -4
  10. data/lib/active_merchant/billing/gateways/adyen.rb +6 -2
  11. data/lib/active_merchant/billing/gateways/authorize_net.rb +332 -255
  12. data/lib/active_merchant/billing/gateways/bank_frick.rb +225 -0
  13. data/lib/active_merchant/billing/gateways/bogus.rb +9 -9
  14. data/lib/active_merchant/billing/gateways/borgun.rb +0 -1
  15. data/lib/active_merchant/billing/gateways/braintree_blue.rb +8 -0
  16. data/lib/active_merchant/billing/gateways/cashnet.rb +17 -10
  17. data/lib/active_merchant/billing/gateways/checkout.rb +213 -0
  18. data/lib/active_merchant/billing/gateways/conekta.rb +1 -1
  19. data/lib/active_merchant/billing/gateways/cyber_source.rb +1 -1
  20. data/lib/active_merchant/billing/gateways/elavon.rb +3 -3
  21. data/lib/active_merchant/billing/gateways/eway_rapid.rb +114 -13
  22. data/lib/active_merchant/billing/gateways/finansbank.rb +1 -1
  23. data/lib/active_merchant/billing/gateways/global_transport.rb +183 -0
  24. data/lib/active_merchant/billing/gateways/hps.rb +27 -20
  25. data/lib/active_merchant/billing/gateways/iats_payments.rb +68 -35
  26. data/lib/active_merchant/billing/gateways/litle.rb +36 -1
  27. data/lib/active_merchant/billing/gateways/merchant_one.rb +0 -1
  28. data/lib/active_merchant/billing/gateways/merchant_ware.rb +8 -4
  29. data/lib/active_merchant/billing/gateways/mercury.rb +17 -10
  30. data/lib/active_merchant/billing/gateways/moneris.rb +11 -6
  31. data/lib/active_merchant/billing/gateways/moneris_us.rb +126 -33
  32. data/lib/active_merchant/billing/gateways/money_movers.rb +0 -1
  33. data/lib/active_merchant/billing/gateways/net_registry.rb +6 -1
  34. data/lib/active_merchant/billing/gateways/network_merchants.rb +5 -5
  35. data/lib/active_merchant/billing/gateways/nmi.rb +241 -5
  36. data/lib/active_merchant/billing/gateways/openpay.rb +1 -0
  37. data/lib/active_merchant/billing/gateways/optimal_payment.rb +6 -1
  38. data/lib/active_merchant/billing/gateways/orbital.rb +6 -4
  39. data/lib/active_merchant/billing/gateways/pay_junction.rb +9 -5
  40. data/lib/active_merchant/billing/gateways/payex.rb +19 -9
  41. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +2 -2
  42. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +4 -0
  43. data/lib/active_merchant/billing/gateways/payscout.rb +0 -2
  44. data/lib/active_merchant/billing/gateways/pin.rb +1 -1
  45. data/lib/active_merchant/billing/gateways/psigate.rb +1 -2
  46. data/lib/active_merchant/billing/gateways/redsys.rb +37 -40
  47. data/lib/active_merchant/billing/gateways/secure_pay.rb +181 -9
  48. data/lib/active_merchant/billing/gateways/stripe.rb +106 -31
  49. data/lib/active_merchant/billing/gateways/tns.rb +227 -0
  50. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +38 -10
  51. data/lib/active_merchant/billing/gateways/webpay.rb +14 -0
  52. data/lib/active_merchant/billing/payment_token.rb +21 -0
  53. data/lib/active_merchant/billing/response.rb +2 -1
  54. data/lib/active_merchant/country.rb +6 -1
  55. data/lib/active_merchant/version.rb +1 -1
  56. metadata +8 -3
  57. metadata.gz.sig +0 -0
  58. data/lib/active_merchant/billing/gateways/samurai.rb +0 -130
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eca92a2d6a93b9c3de6bcacaf0ca4ff928826124
4
- data.tar.gz: 24ed6b72ce5bed57175e5b23808e3471ed3a15f0
3
+ metadata.gz: 705744a332bbe4db27dc6e0dbbefd63712e94c28
4
+ data.tar.gz: 452924bd903988716baa84b34969a9248abb6480
5
5
  SHA512:
6
- metadata.gz: 9a51d9b4a6a140298e8c1af1952f5b2c8f320b4f722510c3c57e8fa43887335ba9e53c6a80a00e086e718dc9f1872459331d478dd5c3a5e961012d802733ff46
7
- data.tar.gz: 21f734179dede5a752de2f42d6d9f1269b66f8d2274abdde3486345ad2740999f4e1414b266a247958f3909bb7573054402c578000f3c7a4e920f07d3534ffc4
6
+ metadata.gz: bea4d6dd57b28e0e6b852e05630ace0b08d51e6d3403f5754ba060b8651842ab26871e601833e966b293d2d3d28cc49a52aa6b54352b7fd774c4cb324c84d1fa
7
+ data.tar.gz: 11dab3ab3cb2b85a54b31283f2127c6adfe0f1e2dbcdeb73a40e9d2096d45fa258474845f62ee73d6a6ecb6564bd04974941b85c2450cb403773bc739c41d3fa
@@ -1,3 +1 @@
1
- [hbu0Jo��F�������ԴUO��T�}�G&C����xFYhGa0
2
- >�7�IE�;���2G2U���=+I��1'��;����p�@��t
3
- Tw�ц!�nQ9He���2��u�]3.�������-yR�t�L �據0�rvJ�0���˗�=�+ ��4ІgqKA��ࢂ� Y��2PKK�[�����!M���׺O;�����l�7yP\��{P�9���?vW�4$Wq��o��j%
1
+ ��j#D>j(QVr�B��<���N�ז���zV�&��ҴLC�N ��O�,��+�"G�&�j*��R�|���c�Li3�t��IsK[���������sz>����Շ���Tkw�%��/�J`ą���Ճ&<����.�)im6r�^5��~/��8q�D<If ���͈����p��iL�}Iٺ_x5e�*8��>>���w*�^h�G\A#���g����9�);T Z+i
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,5 +1,53 @@
1
1
  = ActiveMerchant CHANGELOG
2
2
 
3
+ == Version 1.45.0 (December 1, 2014)
4
+
5
+ * HPS: Always pass CardHolderData element [SecureSubmit, ntalbott]
6
+ * PayJunction: Include 'track' parameter if provided [hron]
7
+ * WebPay: Fix API calls [tomykaira]
8
+ * Moneris US: Add store, unstore, and update [AntoineInsa]
9
+ * Moneris US: Add CVV and AVS [AntoineInsa]
10
+ * Stripe: Add support for statement_description [markabe]
11
+ * CASHNet: Add support for fname and lname [markabe]
12
+ * Orbital: Fix customer profile auth/purchase [denis]
13
+ * Payex: Fix expiry month to allow 4 digit year [duff]
14
+ * Cashnet: Allow overriding custcode [hoenth]
15
+ * Cashnet: Fix overridding item_code per transaction [ntalbott]
16
+ * Add Checkout.com gateway [ravish-ramrakha-cko]
17
+ * HPS: Add verify support [SecureSubmit]
18
+ * Add Bank Frick gateway [varyonic]
19
+ * Add Global Transport gateway [duff]
20
+ * iATS: Add #store and #unstore [duff]
21
+ * Authorize.Net: Fix amount formatting [ntalbott]
22
+ * Authorize.Net: Truncate order_id to 20 characters [ntalbott]
23
+ * Authorize.Net: Truncate more fields [duff]
24
+ * Authorize.Net: Truncate invoiceNumber [ntalbott]
25
+ * Adyen: Add support for verify operation [duff]
26
+ * USAePay: Add track_data support [louiskearns]
27
+ * Payex: Use the right url for the purchase call [duff]
28
+ * Braintree: Allow dynamic descriptors [duff]
29
+ * Openpay: Add support for device session id [guillermo-delucio, ismaelem]
30
+ * Redsys: Add support for verify [duff]
31
+ * Redsys: Handle unknown currencies [duff]
32
+ * Stripe: Make #unstore signature consistent [duff]
33
+ * Remove defunct Samurai gateway [ntalbott]
34
+ * eWay Rapid: Tweak authorization support [duff]
35
+ * Litle: Add support for dynamic descriptors [duff]
36
+ * Add TNS gateway [markabe]
37
+ * TNS: Update countries and supported card types [markabe]
38
+ * Conekta: Add AMEX as a supported card type [MauricioMurga]
39
+ * Checkout: pass through currency type [markabe]
40
+ * Bogus: return standard error codes [jpcaissy]
41
+ * Add PaymentToken and ApplePayPaymentToken objects for token-based transactions [bizla]
42
+ * Authorize.Net: Add ApplePay in-app transaction support [bizla]
43
+ * Stripe: Add ApplePay in-app transaction support [bizla]
44
+ * eWAY Rapid: Add PartnerID param [j-mutter]
45
+ * GlobalTransport: Truncate order_id [duff]
46
+ * Redsys: Allow a description to be specified [duff]
47
+ * NetworkMerchants: Fix currency [j-mutter]
48
+ * Redsys: Improve handling of order_id [duff]
49
+ * Checkout: Add support for void, refund, and verify [markabe]
50
+
3
51
  == Version 1.44.1 (Aug 28, 2014)
4
52
 
5
53
  * Allow SSLv3 for PsiGate [mutemule]
@@ -497,3 +497,15 @@ Commercegate (June 2014)
497
497
  Worldpay US (August 2014)
498
498
 
499
499
  * Mark Bennett (markabe)
500
+
501
+ Checkout.com (September 2014)
502
+
503
+ * (ravish-ramrakha-cko)
504
+
505
+ Bank Frick (September 2014)
506
+
507
+ * Piers Chambers (varyonic)
508
+
509
+ Global Transport (September 2014)
510
+
511
+ * Duff O'Melia (duff)
data/README.md CHANGED
@@ -87,6 +87,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
87
87
  * [Authorize.Net CIM](http://www.authorize.net/) - US
88
88
  * [Authorize.Net](http://www.authorize.net/) - AD, AT, AU, BE, BG, CA, CH, CY, CZ, DE, DK, ES, FI, FR, GB, GB, GI, GR, HU, IE, IT, LI, LU, MC, MT, NL, NO, PL, PT, RO, SE, SI, SK, SM, TR, US, VA
89
89
  * [Balanced](https://www.balancedpayments.com/) - US
90
+ * [Bank Frick](http://www.bankfrickacquiring.com/) - LI, US
90
91
  * [Banwire](http://www.banwire.com/) - MX
91
92
  * [Barclays ePDQ Extra Plus](http://www.barclaycard.co.uk/business/accepting-payments/epdq-ecomm/) - GB
92
93
  * [Barclays ePDQ MPI](http://www.barclaycard.co.uk/business/accepting-payments/epdq-mpi/) - GB
@@ -101,6 +102,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
101
102
  * [Cashnet](http://www.higherone.com/) - US
102
103
  * [Cecabank](http://www.ceca.es/es/) - ES
103
104
  * [CertoDirect](http://www.certodirect.com/) - BE, BG, CZ, DK, DE, EE, IE, EL, ES, FR, IT, CY, LV, LT, LU, HU, MT, NL, AT, PL, PT, RO, SI, SK, FI, SE, GB
105
+ * [Checkout.com](https://www.checkout.com/) - AT, BE, BG, CY, CZ, DE, DK, EE, ES, FI, FR, GR, HR, HU, IE, IS, IT, LI, LT, LU, LV, MT, MU, NL, NO, PL, PT, RO, SE, SI, SK, US
104
106
  * [Commercegate](http://www.commercegate.com/) - AD, AT, AX, BE, BG, CH, CY, CZ, DE, DK, ES, FI, FR, GB, GG, GI, GR, HR, HU, IE, IM, IS, IT, JE, LI, LT, LU, LV, MC, MT, NL, NO, PL, PT, RO, SE, SI, SK, VA
105
107
  * [Conekta](https://conekta.io) - MX
106
108
  * [CyberSource](http://www.cybersource.com) - US, BR, CA, CN, DK, FI, FR, DE, JP, MX, NO, SE, GB, SG
@@ -119,6 +121,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
119
121
  * [FirstData Global Gateway e4](http://www.firstdata.com) - CA, US
120
122
  * [FirstGiving](http://www.firstgiving.com/) - US
121
123
  * [Garanti Sanal POS](https://sanalposweb.garanti.com.tr) - US, TR
124
+ * [Global Transport](https://www.globalpaymentsinc.com) - CA, PR, US
122
125
  * [HDFC](http://www.hdfcbank.com/sme/sme-details/merchant-services/guzh6m0i) - IN
123
126
  * [Heartland Payment Systems](http://developer.heartlandpaymentsystems.com/SecureSubmit/) - US
124
127
  * [iATS Payments](http://home.iatspayments.com/) - AU, BR, CA, CH, DE, DK, ES, FI, FR, GR, HK, IE, IT, NL, NO, PT, SE, SG, TR, UK, US
@@ -169,7 +172,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
169
172
  * [Payscout](http://www.payscout.com/) - US
170
173
  * [Paystation](http://paystation.co.nz) - NZ
171
174
  * [Pay Way](http://www.payway.com.au) - AU
172
- * [Pin](http://www.pin.net.au/) - AU
175
+ * [Pin Payments](http://www.pin.net.au/) - AU
173
176
  * [Plug'n Pay](http://www.plugnpay.com/) - US
174
177
  * [Psigate](http://www.psigate.com/) - CA
175
178
  * [PSL Payment Solutions](http://www.paymentsolutionsltd.com/) - GB
@@ -182,7 +185,6 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
182
185
  * [SagePay](http://www.sagepay.com) - GB, IE
183
186
  * [Sage Payment Solutions](http://www.sagepayments.com) - US, CA
184
187
  * [Sallie Mae](http://www.salliemae.com/) - US
185
- * [Samurai](https://samurai.feefighters.com) - US
186
188
  * [SecureNet](http://www.securenet.com/) - US
187
189
  * [SecurePay](http://www.securepay.com/) - US, CA, GB, AU
188
190
  * [SecurePayTech](http://www.securepaytech.com/) - NZ
@@ -192,6 +194,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
192
194
  * [Stripe](https://stripe.com/) - AU, BE, CA, CH, DE, ES, FI, FR, GB, IE, IT, LU, NL, US
193
195
  * [Swipe](https://www.swipehq.com/checkout) - CA, NZ
194
196
  * [TransFirst](http://www.transfirst.com/) - US
197
+ * [TNS](http://www.tnsi.com/) - AR, AU, BR, FR, DE, HK, MX, NZ, SG, GB, US
195
198
  * [NELiX TransaX](https://www.nelixtransax.com/) - US
196
199
  * [Transnational](http://www.tnbci.com/) - US
197
200
  * [TrustCommerce](http://www.trustcommerce.com/) - US
@@ -205,14 +208,21 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
205
208
  * [Worldpay](http://www.worldpay.com/) - HK, US, GB, AU, AD, BE, CH, CY, CZ, DE, DK, ES, FI, FR, GI, GR, HU, IE, IL, IT, LI, LU, MC, MT, NL, NO, NZ, PL, PT, SE, SG, SI, SM, TR, UM, VA
206
209
  * [Worldpay US](http://www.worldpay.com/us) - US
207
210
 
208
- ## Contributing
211
+ ## Deprecation Policy
209
212
 
210
- The source code is hosted at [GitHub](http://github.com/Shopify/active_merchant), and can be fetched using:
213
+ Deprecated functionality is removed on major version changes - for example, deprecations from 2.x are removed in 3.x.
211
214
 
212
- git clone git://github.com/Shopify/active_merchant.git
215
+ ## Contributing
216
+
217
+ 1. [Fork it](http://github.com/Shopify/active_merchant/fork) and clone your new repo
218
+ 2. Create a branch (`git checkout -b my_awesome_feature`)
219
+ 3. Commit your changes (`git add my/awesome/file.rb; git commit -m "Added my awesome feature"`)
220
+ 4. Push your changes to your fork (`git push origin my_awesome_feature`)
221
+ 5. Open a [Pull Request](https://github.com/shopify/active_merchant/pulls)
213
222
 
214
223
  Please see the [ActiveMerchant Guide to Contributing](http://github.com/Shopify/active_merchant/wikis/contributing) for
215
224
  information on adding a new gateway to ActiveMerchant.
216
225
 
217
226
  Please don't touch the CHANGELOG in your pull requests, we'll add the appropriate CHANGELOG entries
218
227
  at release time.
228
+
@@ -7,5 +7,7 @@ require 'active_merchant/billing/credit_card_formatting'
7
7
  require 'active_merchant/billing/credit_card'
8
8
  require 'active_merchant/billing/base'
9
9
  require 'active_merchant/billing/check'
10
+ require 'active_merchant/billing/payment_token'
11
+ require 'active_merchant/billing/apple_pay_payment_token'
10
12
  require 'active_merchant/billing/response'
11
13
  require 'active_merchant/billing/gateways'
@@ -0,0 +1,22 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class ApplePayPaymentToken < PaymentToken
4
+ # This is a representation of the token object specified here:
5
+ # https://developer.apple.com/library/ios/documentation/PassKit/Reference/PKPaymentToken_Ref/
6
+ # https://developer.apple.com/library/IOs//documentation/PassKit/Reference/PaymentTokenJSON/PaymentTokenJSON.html
7
+
8
+ attr_reader :payment_instrument_name, :payment_network
9
+ attr_accessor :transaction_identifier
10
+
11
+ def initialize(payment_data, options = {})
12
+ super
13
+ @payment_instrument_name = @metadata[:payment_instrument_name]
14
+ @payment_network = @metadata[:payment_network]
15
+ end
16
+
17
+ def type
18
+ 'apple_pay'
19
+ end
20
+ end
21
+ end
22
+ end
@@ -58,9 +58,40 @@ module ActiveMerchant #:nodoc:
58
58
 
59
59
  DEBIT_CARDS = [ :switch, :solo ]
60
60
  CURRENCIES_WITHOUT_FRACTIONS = [ 'BIF', 'BYR', 'CLP', 'CVE', 'DJF', 'GNF', 'HUF', 'ISK', 'JPY', 'KMF', 'KRW', 'PYG', 'RWF', 'TWD', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF' ]
61
+
61
62
  CREDIT_DEPRECATION_MESSAGE = "Support for using credit to refund existing transactions is deprecated and will be removed from a future release of ActiveMerchant. Please use the refund method instead."
62
63
  RECURRING_DEPRECATION_MESSAGE = "Recurring functionality in ActiveMerchant is deprecated and will be removed in a future version. Please contact the ActiveMerchant maintainers if you have an interest in taking ownership of a separate gem that continues support for it."
63
64
 
65
+ # == Standardized Error Codes
66
+ #
67
+ # :incorrect_number - Card number does not comply with ISO/IEC 7812 numbering standard
68
+ # :invalid_number - Card number was not matched by processor
69
+ # :invalid_expiry_date - Expiry date deos not match correct formatting
70
+ # :invalid_cvc - Security codes does not match correct format (3-4 digits)
71
+ # :expired_card - Card number is expired
72
+ # :incorrect_cvc - Secerity code was not matched by the processor
73
+ # :incorrect_zip - Zip code is not in correct format
74
+ # :incorrect_address - Billing address info was not matched by the processor
75
+ # :card_declined - Card number declined by processor
76
+ # :processing_error - Processor error
77
+ # :call_issuer - Transaction requires voice authentication, call issuer
78
+ # :pickup_card - Issuer requests that you pickup the card from merchant
79
+
80
+ STANDARD_ERROR_CODE = {
81
+ :incorrect_number => 'incorrect_number',
82
+ :invalid_number => 'invalid_number',
83
+ :invalid_expiry_date => 'invalid_expiry_date',
84
+ :invalid_cvc => 'invalid_cvc',
85
+ :expired_card => 'expired_card',
86
+ :incorrect_cvc => 'incorrect_cvc',
87
+ :incorrect_zip => 'incorrect_zip',
88
+ :incorrect_address => 'incorrect_address',
89
+ :card_declined => 'card_declined',
90
+ :processing_error => 'processing_error',
91
+ :call_issuer => 'call_issuer',
92
+ :pickup_card => 'pick_up_card'
93
+ }
94
+
64
95
  cattr_reader :implementations
65
96
  @@implementations = []
66
97
 
@@ -112,6 +143,10 @@ module ActiveMerchant #:nodoc:
112
143
  result.to_s.downcase
113
144
  end
114
145
 
146
+ def self.non_fractional_currency?(currency)
147
+ CURRENCIES_WITHOUT_FRACTIONS.include?(currency.to_s)
148
+ end
149
+
115
150
  def self.supported_countries=(country_codes)
116
151
  country_codes.each do |country_code|
117
152
  unless ActiveMerchant::Country.find(country_code)
@@ -197,7 +232,7 @@ module ActiveMerchant #:nodoc:
197
232
  def localized_amount(money, currency)
198
233
  amount = amount(money)
199
234
 
200
- return amount unless non_fractional_currency?(currency)
235
+ return amount unless Gateway.non_fractional_currency?(currency)
201
236
 
202
237
  if self.money_format == :cents
203
238
  sprintf("%.0f", amount.to_f / 100)
@@ -206,9 +241,6 @@ module ActiveMerchant #:nodoc:
206
241
  end
207
242
  end
208
243
 
209
- def non_fractional_currency?(currency)
210
- CURRENCIES_WITHOUT_FRACTIONS.include?(currency.to_s)
211
- end
212
244
 
213
245
  def currency(money)
214
246
  money.respond_to?(:currency) ? money.currency : self.default_currency
@@ -51,7 +51,7 @@ module ActiveMerchant #:nodoc:
51
51
  post = {}
52
52
  post[:modificationRequest] = modification_request(authorization, options)
53
53
  post[:modificationRequest][:modificationAmount] = amount_hash(money, options[:currency])
54
-
54
+
55
55
  commit('Payment.capture', post)
56
56
  end
57
57
 
@@ -61,7 +61,7 @@ module ActiveMerchant #:nodoc:
61
61
  post = {}
62
62
  post[:modificationRequest] = modification_request(authorization, options)
63
63
  post[:modificationRequest][:modificationAmount] = amount_hash(money, options[:currency])
64
-
64
+
65
65
  commit('Payment.refund', post)
66
66
  end
67
67
 
@@ -74,6 +74,10 @@ module ActiveMerchant #:nodoc:
74
74
  commit('Payment.cancel', post)
75
75
  end
76
76
 
77
+ def verify(creditcard, options = {})
78
+ authorize(0, creditcard, options)
79
+ end
80
+
77
81
  private
78
82
 
79
83
  def commit(action, post)
@@ -1,162 +1,114 @@
1
+ require 'nokogiri'
2
+
1
3
  module ActiveMerchant #:nodoc:
2
4
  module Billing #:nodoc:
3
- # For more information on the Authorize.Net Gateway please visit their {Integration Center}[http://developer.authorize.net/]
4
- #
5
- # The login and password are not the username and password you use to
6
- # login to the Authorize.Net Merchant Interface. Instead, you will
7
- # use the API Login ID as the login and Transaction Key as the
8
- # password.
9
- #
10
- # ==== How to Get Your API Login ID and Transaction Key
11
- #
12
- # 1. Log into the Merchant Interface
13
- # 2. Select Settings from the Main Menu
14
- # 3. Click on API Login ID and Transaction Key in the Security section
15
- # 4. Type in the answer to the secret question configured on setup
16
- # 5. Click Submit
17
- #
18
5
  class AuthorizeNetGateway < Gateway
19
- API_VERSION = '3.1'
20
-
21
- self.test_url = "https://test.authorize.net/gateway/transact.dll"
22
- self.live_url = "https://secure.authorize.net/gateway/transact.dll"
23
-
24
- class_attribute :duplicate_window
25
-
26
- APPROVED, DECLINED, ERROR, FRAUD_REVIEW = 1, 2, 3, 4
6
+ include Empty
27
7
 
28
- RESPONSE_CODE, RESPONSE_REASON_CODE, RESPONSE_REASON_TEXT, AUTHORIZATION_CODE = 0, 2, 3, 4
29
- AVS_RESULT_CODE, TRANSACTION_ID, CARD_CODE_RESPONSE_CODE, CARDHOLDER_AUTH_CODE = 5, 6, 38, 39
30
-
31
- self.default_currency = 'USD'
8
+ self.test_url = 'https://apitest.authorize.net/xml/v1/request.api'
9
+ self.live_url = 'https://api.authorize.net/xml/v1/request.api'
32
10
 
33
11
  self.supported_countries = %w(AD AT AU BE BG CA CH CY CZ DE DK ES FI FR GB GB GI GR HU IE IT LI LU MC MT NL NO PL PT RO SE SI SK SM TR US VA)
12
+ self.default_currency = 'USD'
13
+ self.money_format = :dollars
34
14
  self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb, :maestro]
15
+
35
16
  self.homepage_url = 'http://www.authorize.net/'
36
17
  self.display_name = 'Authorize.Net'
37
18
 
38
- CARD_CODE_ERRORS = %w( N S )
39
- AVS_ERRORS = %w( A E N R W Z )
40
- AVS_REASON_CODES = %w(27 45)
19
+ class_attribute :duplicate_window
20
+
21
+ APPROVED, DECLINED, ERROR, FRAUD_REVIEW = 1, 2, 3, 4
41
22
  TRANSACTION_ALREADY_ACTIONED = %w(310 311)
42
23
 
43
- # Creates a new AuthorizeNetGateway
44
- #
45
- # The gateway requires that a valid login and password be passed
46
- # in the +options+ hash.
47
- #
48
- # ==== Options
49
- #
50
- # * <tt>:login</tt> -- The Authorize.Net API Login ID (REQUIRED)
51
- # * <tt>:password</tt> -- The Authorize.Net Transaction Key. (REQUIRED)
52
- # * <tt>:test</tt> -- +true+ or +false+. If true, perform transactions against the test server.
53
- # Otherwise, perform transactions against the production server.
54
- def initialize(options = {})
24
+ CARD_CODE_ERRORS = %w(N S)
25
+ AVS_ERRORS = %w(A E N R W Z)
26
+ AVS_REASON_CODES = %w(27 45)
27
+
28
+ TRACKS = {
29
+ 1 => /^%(?<format_code>.)(?<pan>[\d]{1,19}+)\^(?<name>.{2,26})\^(?<expiration>[\d]{0,4}|\^)(?<service_code>[\d]{0,3}|\^)(?<discretionary_data>.*)\?\Z/,
30
+ 2 => /\A;(?<pan>[\d]{1,19}+)=(?<expiration>[\d]{0,4}|=)(?<service_code>[\d]{0,3}|=)(?<discretionary_data>.*)\?\Z/
31
+ }.freeze
32
+
33
+ APPLE_PAY_DATA_DESCRIPTOR = "COMMON.APPLE.INAPP.PAYMENT"
34
+
35
+ def initialize(options={})
55
36
  requires!(options, :login, :password)
56
37
  super
57
38
  end
58
39
 
59
- # Performs an authorization, which reserves the funds on the customer's credit card, but does not
60
- # charge the card.
61
- #
62
- # ==== Parameters
63
- #
64
- # * <tt>money</tt> -- The amount to be authorized as an Integer value in cents.
65
- # * <tt>paysource</tt> -- The CreditCard or Check details for the transaction.
66
- # * <tt>options</tt> -- A hash of optional parameters.
67
- def authorize(money, paysource, options = {})
68
- post = {}
69
- add_currency_code(post, money, options)
70
- add_invoice(post, options)
71
- add_payment_source(post, paysource, options)
72
- add_address(post, options)
73
- add_customer_data(post, options)
74
- add_duplicate_window(post)
75
-
76
- commit('AUTH_ONLY', money, post)
77
- end
78
-
79
- # Perform a purchase, which is essentially an authorization and capture in a single operation.
80
- #
81
- # ==== Parameters
82
- #
83
- # * <tt>money</tt> -- The amount to be purchased as an Integer value in cents.
84
- # * <tt>paysource</tt> -- The CreditCard or Check details for the transaction.
85
- # * <tt>options</tt> -- A hash of optional parameters.
86
- def purchase(money, paysource, options = {})
87
- post = {}
88
- add_currency_code(post, money, options)
89
- add_invoice(post, options)
90
- add_payment_source(post, paysource, options)
91
- add_address(post, options)
92
- add_customer_data(post, options)
93
- add_duplicate_window(post)
94
-
95
- commit('AUTH_CAPTURE', money, post)
40
+ def purchase(amount, payment, options = {})
41
+ commit("AUTH_CAPTURE") do |xml|
42
+ add_order_id(xml, options)
43
+ xml.transactionRequest do
44
+ xml.transactionType 'authCaptureTransaction'
45
+ xml.amount amount(amount)
46
+ add_payment_source(xml, payment)
47
+ add_invoice(xml, options)
48
+ add_customer_data(xml, payment, options)
49
+ add_retail_data(xml, payment)
50
+ add_settings(xml, payment, options)
51
+ add_user_fields(xml, amount, options)
52
+ end
53
+ end
96
54
  end
97
55
 
98
- # Captures the funds from an authorized transaction.
99
- #
100
- # ==== Parameters
101
- #
102
- # * <tt>money</tt> -- The amount to be captured as an Integer value in cents.
103
- # * <tt>authorization</tt> -- The authorization returned from the previous authorize request.
104
- def capture(money, authorization, options = {})
105
- post = {:trans_id => authorization}
106
- add_customer_data(post, options)
107
- add_invoice(post, options)
108
- commit('PRIOR_AUTH_CAPTURE', money, post)
56
+ def authorize(amount, payment, options={})
57
+ commit("AUTH_ONLY") do |xml|
58
+ add_order_id(xml, options)
59
+ xml.transactionRequest do
60
+ xml.transactionType 'authOnlyTransaction'
61
+ xml.amount amount(amount)
62
+ add_payment_source(xml, payment)
63
+ add_invoice(xml, options)
64
+ add_customer_data(xml, payment, options)
65
+ add_settings(xml, payment, options)
66
+ add_user_fields(xml, amount, options)
67
+ end
68
+ end
109
69
  end
110
70
 
111
- # Void a previous transaction
112
- #
113
- # ==== Parameters
114
- #
115
- # * <tt>authorization</tt> - The authorization returned from the previous authorize request.
116
- def void(authorization, options = {})
117
- post = {:trans_id => authorization}
118
- add_duplicate_window(post)
119
- commit('VOID', nil, post)
71
+ def capture(amount, authorization, options={})
72
+ commit("PRIOR_AUTH_CAPTURE") do |xml|
73
+ add_order_id(xml, options)
74
+ xml.transactionRequest do
75
+ xml.transactionType 'priorAuthCaptureTransaction'
76
+ xml.amount amount(amount)
77
+ xml.refTransId split_authorization(authorization)[0]
78
+ add_invoice(xml, options)
79
+ add_user_fields(xml, amount, options)
80
+ end
81
+ end
120
82
  end
121
83
 
122
- # Refund a transaction.
123
- #
124
- # This transaction indicates to the gateway that
125
- # money should flow from the merchant to the customer.
126
- #
127
- # ==== Parameters
128
- #
129
- # * <tt>money</tt> -- The amount to be credited to the customer as an Integer value in cents.
130
- # * <tt>identification</tt> -- The ID of the original transaction against which the refund is being issued.
131
- # * <tt>options</tt> -- A hash of parameters.
132
- #
133
- # ==== Options
134
- #
135
- # * <tt>:card_number</tt> -- The credit card number the refund is being issued to. (REQUIRED)
136
- # You can either pass the last four digits of the card number or the full card number.
137
- # * <tt>:first_name</tt> -- The first name of the account being refunded.
138
- # * <tt>:last_name</tt> -- The last name of the account being refunded.
139
- # * <tt>:zip</tt> -- The postal code of the account being refunded.
140
- def refund(money, identification, options = {})
141
- requires!(options, :card_number)
142
-
143
- post = { :trans_id => identification,
144
- :card_num => options[:card_number]
145
- }
146
-
147
- post[:first_name] = options[:first_name] if options[:first_name]
148
- post[:last_name] = options[:last_name] if options[:last_name]
149
- post[:zip] = options[:zip] if options[:zip]
150
-
151
- add_invoice(post, options)
152
- add_duplicate_window(post)
153
-
154
- commit('CREDIT', money, post)
84
+ def refund(amount, authorization, options={})
85
+ transaction_id, card_number = split_authorization(authorization)
86
+ commit("CREDIT") do |xml|
87
+ xml.transactionRequest do
88
+ xml.transactionType 'refundTransaction'
89
+ xml.amount (amount.nil? ? 0 : amount(amount))
90
+ xml.payment do
91
+ xml.creditCard do
92
+ xml.cardNumber(card_number || options[:card_number])
93
+ xml.expirationDate 'XXXX'
94
+ end
95
+ end
96
+ xml.refTransId transaction_id
97
+ add_customer_data(xml, nil, options)
98
+ add_user_fields(xml, amount, options)
99
+ end
100
+ end
155
101
  end
156
102
 
157
- def credit(money, identification, options = {})
158
- ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
159
- refund(money, identification, options)
103
+ def void(authorization, options={})
104
+ commit("VOID") do |xml|
105
+ add_order_id(xml, options)
106
+ xml.transactionRequest do
107
+ xml.transactionType 'voidTransaction'
108
+ xml.refTransId split_authorization(authorization)[0]
109
+ add_user_fields(xml, nil, options)
110
+ end
111
+ end
160
112
  end
161
113
 
162
114
  def verify(credit_card, options = {})
@@ -168,175 +120,300 @@ module ActiveMerchant #:nodoc:
168
120
 
169
121
  private
170
122
 
171
- def commit(action, money, parameters)
172
- parameters[:amount] = amount(money) unless action == 'VOID'
123
+ def add_payment_source(xml, source)
124
+ return unless source
125
+ if card_brand(source) == 'check'
126
+ add_check(xml, source)
127
+ elsif card_brand(source) == 'apple_pay'
128
+ add_apple_pay_payment_token(xml, source)
129
+ else
130
+ add_credit_card(xml, source)
131
+ end
132
+ end
173
133
 
174
- url = test? ? self.test_url : self.live_url
175
- data = ssl_post url, post_data(action, parameters)
134
+ def add_settings(xml, source, options)
135
+ xml.transactionSettings do
136
+ if(card_brand(source) == "check" && options[:recurring])
137
+ xml.setting do
138
+ xml.settingName "recurringBilling"
139
+ xml.settingValue "true"
140
+ end
141
+ end
142
+ if(self.class.duplicate_window)
143
+ xml.setting do
144
+ xml.settingName "duplicateWindow"
145
+ xml.settingValue self.class.duplicate_window
146
+ end
147
+ end
148
+ end
149
+ end
176
150
 
177
- response = parse(data)
178
- response[:action] = action
151
+ def add_user_fields(xml, amount, options)
152
+ xml.userFields do
153
+ if(currency = (options[:currency] || currency(amount)))
154
+ xml.userField do
155
+ xml.name "x_currency_code"
156
+ xml.value currency
157
+ end
158
+ end
159
+ if(application_id.present? && application_id != "ActiveMerchant")
160
+ xml.userField do
161
+ xml.name "x_solution_id"
162
+ xml.value application_id
163
+ end
164
+ end
165
+ end
166
+ end
179
167
 
180
- message = message_from(response)
168
+ def add_credit_card(xml, credit_card)
169
+ if credit_card.track_data
170
+ add_swipe_data(xml, credit_card)
171
+ else
172
+ xml.payment do
173
+ xml.creditCard do
174
+ xml.cardNumber credit_card.number
175
+ xml.expirationDate (format(credit_card.month, :two_digits) + '/' + format(credit_card.year, :four_digits))
176
+ unless empty?(credit_card.verification_value)
177
+ xml.cardCode credit_card.verification_value
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
181
183
 
182
- Response.new(success?(response), message, response,
183
- :test => test?,
184
- :authorization => response[:transaction_id],
185
- :fraud_review => fraud_review?(response),
186
- :avs_result => { :code => response[:avs_result_code] },
187
- :cvv_result => response[:card_code]
188
- )
184
+ def add_swipe_data(xml, credit_card)
185
+ TRACKS.each do |key, regex|
186
+ if regex.match(credit_card.track_data)
187
+ @valid_track_data = true
188
+ xml.payment do
189
+ xml.trackData do
190
+ xml.public_send(:"track#{key}", credit_card.track_data)
191
+ end
192
+ end
193
+ end
194
+ end
189
195
  end
190
196
 
191
- def success?(response)
192
- response[:response_code] == APPROVED && TRANSACTION_ALREADY_ACTIONED.exclude?(response[:response_reason_code])
197
+ # http://developer.authorize.net/api/reference/#apple-pay-transactions
198
+ def add_apple_pay_payment_token(xml, apple_pay_payment_token)
199
+ xml.payment do
200
+ xml.opaqueData do
201
+ xml.dataDescriptor APPLE_PAY_DATA_DESCRIPTOR
202
+ xml.dataValue Base64.strict_encode64(apple_pay_payment_token.payment_data.to_json)
203
+ end
204
+ end
193
205
  end
194
206
 
195
- def fraud_review?(response)
196
- response[:response_code] == FRAUD_REVIEW
207
+ def add_retail_data(xml, payment)
208
+ return unless valid_track_data
209
+ xml.retail do
210
+ # As per http://www.authorize.net/support/CP_guide.pdf, '2' is for Retail, the only current market_type
211
+ xml.marketType 2
212
+ end
197
213
  end
198
214
 
199
- def parse(body)
200
- fields = split(body)
201
-
202
- results = {
203
- :response_code => fields[RESPONSE_CODE].to_i,
204
- :response_reason_code => fields[RESPONSE_REASON_CODE],
205
- :response_reason_text => fields[RESPONSE_REASON_TEXT],
206
- :avs_result_code => fields[AVS_RESULT_CODE],
207
- :transaction_id => fields[TRANSACTION_ID],
208
- :card_code => fields[CARD_CODE_RESPONSE_CODE],
209
- :authorization_code => fields[AUTHORIZATION_CODE],
210
- :cardholder_authentication_code => fields[CARDHOLDER_AUTH_CODE]
211
- }
212
- results
215
+ def valid_track_data
216
+ @valid_track_data ||= false
213
217
  end
214
218
 
215
- def post_data(action, parameters = {})
216
- post = {}
217
-
218
- post[:version] = API_VERSION
219
- post[:login] = @options[:login]
220
- post[:tran_key] = @options[:password]
221
- post[:relay_response] = "FALSE"
222
- post[:type] = action
223
- post[:delim_data] = "TRUE"
224
- post[:delim_char] = ","
225
- post[:encap_char] = "$"
226
- post[:solution_ID] = application_id if application_id.present? && application_id != "ActiveMerchant"
227
-
228
- request = post.merge(parameters).collect { |key, value| "x_#{key}=#{CGI.escape(value.to_s)}" }.join("&")
229
- request
219
+ def add_check(xml, check)
220
+ xml.payment do
221
+ xml.bankAccount do
222
+ xml.routingNumber check.routing_number
223
+ xml.accountNumber check.account_number
224
+ xml.nameOnAccount check.name
225
+ xml.echeckType "WEB"
226
+ xml.bankName check.bank_name
227
+ xml.checkNumber check.number
228
+ end
229
+ end
230
230
  end
231
231
 
232
- def add_currency_code(post, money, options)
233
- post[:currency_code] = options[:currency] || currency(money)
232
+ def add_customer_data(xml, payment_source, options)
233
+ billing_address = options[:billing_address] || options[:address] || {}
234
+ shipping_address = options[:shipping_address] || options[:address] || {}
235
+
236
+ xml.customer do
237
+ xml.id(options[:customer]) unless empty?(options[:customer]) || options[:customer] !~ /^\d+$/
238
+ xml.email(options[:email]) unless empty?(options[:email])
239
+ end
240
+
241
+ xml.billTo do
242
+ first_name, last_name = names_from(payment_source, billing_address, options)
243
+ xml.firstName(truncate(first_name, 50)) unless empty?(first_name)
244
+ xml.lastName(truncate(last_name, 50)) unless empty?(last_name)
245
+
246
+ xml.company(truncate(billing_address[:company], 50)) unless empty?(billing_address[:company])
247
+ xml.address(truncate(billing_address[:address1], 60))
248
+ xml.city(truncate(billing_address[:city], 40))
249
+ xml.state(empty?(billing_address[:state]) ? 'n/a' : truncate(billing_address[:state], 40))
250
+ xml.zip(truncate((billing_address[:zip] || options[:zip]), 20))
251
+ xml.country(truncate(billing_address[:country], 60))
252
+ xml.phoneNumber(truncate(billing_address[:phone], 25)) unless empty?(billing_address[:phone])
253
+ xml.faxNumber(truncate(billing_address[:fax], 25)) unless empty?(billing_address[:fax])
254
+ end
255
+
256
+ unless shipping_address.blank?
257
+ xml.shipTo do
258
+ first_name, last_name = names_from(payment_source, shipping_address, options)
259
+ xml.firstName(truncate(first_name, 50)) unless empty?(first_name)
260
+ xml.lastName(truncate(last_name, 50)) unless empty?(last_name)
261
+
262
+ xml.company(truncate(shipping_address[:company], 50)) unless empty?(shipping_address[:company])
263
+ xml.address(truncate(shipping_address[:address1], 60))
264
+ xml.city(truncate(shipping_address[:city], 40))
265
+ xml.state(truncate(shipping_address[:state], 40))
266
+ xml.zip(truncate(shipping_address[:zip], 20))
267
+ xml.country(truncate(shipping_address[:country], 60))
268
+ end
269
+ end
270
+
271
+ xml.customerIP(options[:ip]) unless empty?(options[:ip])
272
+
273
+ xml.cardholderAuthentication do
274
+ xml.authenticationIndicator options[:authentication_indicator]
275
+ xml.cardholderAuthenticationValue options[:cardholder_authentication_value]
276
+ end
234
277
  end
235
278
 
236
- def add_invoice(post, options)
237
- post[:invoice_num] = options[:order_id]
238
- post[:description] = options[:description]
279
+ def add_order_id(xml, options)
280
+ xml.refId truncate(options[:order_id], 20)
239
281
  end
240
282
 
241
- def add_creditcard(post, creditcard, options={})
242
- post[:card_num] = creditcard.number
243
- post[:card_code] = creditcard.verification_value if creditcard.verification_value?
244
- post[:exp_date] = expdate(creditcard)
245
- post[:first_name] = creditcard.first_name
246
- post[:last_name] = creditcard.last_name
283
+ def add_invoice(xml, options)
284
+ xml.order do
285
+ xml.invoiceNumber truncate(options[:order_id], 20)
286
+ xml.description truncate(options[:description], 255)
287
+ end
247
288
  end
248
289
 
249
- def add_payment_source(params, source, options={})
250
- if card_brand(source) == "check"
251
- add_check(params, source, options)
290
+ def names_from(payment_source, address, options)
291
+ if payment_source && !payment_source.is_a?(PaymentToken)
292
+ first_name, last_name = (address[:name] || "").split
293
+ [(payment_source.first_name || first_name), (payment_source.last_name || last_name)]
252
294
  else
253
- add_creditcard(params, source, options)
295
+ [options[:first_name], options[:last_name]]
254
296
  end
255
297
  end
256
298
 
257
- def add_check(post, check, options)
258
- post[:method] = "ECHECK"
259
- post[:bank_name] = check.bank_name
260
- post[:bank_aba_code] = check.routing_number
261
- post[:bank_acct_num] = check.account_number
262
- post[:bank_acct_type] = check.account_type
263
- post[:echeck_type] = "WEB"
264
- post[:bank_acct_name] = check.name
265
- post[:bank_check_number] = check.number if check.number.present?
266
- post[:recurring_billing] = (options[:recurring] ? "TRUE" : "FALSE")
299
+ def commit(action, &payload)
300
+ url = (test? ? test_url : live_url)
301
+ response = parse(action, ssl_post(url, post_data(&payload), 'Content-Type' => 'text/xml'))
302
+
303
+ avs_result = AVSResult.new(code: response[:avs_result_code])
304
+ cvv_result = CVVResult.new(response[:card_code])
305
+ Response.new(
306
+ success_from(response),
307
+ message_from(response, avs_result, cvv_result),
308
+ response,
309
+ authorization: authorization_from(response),
310
+ test: test?,
311
+ avs_result: avs_result,
312
+ cvv_result: cvv_result,
313
+ fraud_review: fraud_review?(response)
314
+ )
267
315
  end
268
316
 
269
- def add_customer_data(post, options)
270
- if options.has_key? :email
271
- post[:email] = options[:email]
272
- post[:email_customer] = false
273
- end
317
+ def post_data
318
+ Nokogiri::XML::Builder.new do |xml|
319
+ xml.createTransactionRequest('xmlns' => 'AnetApi/xml/v1/schema/AnetApiSchema.xsd') do
320
+ xml.merchantAuthentication do
321
+ xml.name @options[:login]
322
+ xml.transactionKey @options[:password]
323
+ end
324
+ yield(xml)
325
+ end
326
+ end.to_xml(indent: 0)
327
+ end
274
328
 
275
- if options.has_key? :customer
276
- post[:cust_id] = options[:customer] if Float(options[:customer]) rescue nil
329
+ def parse(action, body)
330
+ doc = Nokogiri::XML(body)
331
+ doc.remove_namespaces!
332
+
333
+ response = {action: action}
334
+
335
+ response[:response_code] = if(element = doc.at_xpath("//transactionResponse/responseCode"))
336
+ (empty?(element.content) ? nil : element.content.to_i)
277
337
  end
278
338
 
279
- if options.has_key? :ip
280
- post[:customer_ip] = options[:ip]
339
+ if(element = doc.at_xpath("//errors/error"))
340
+ response[:response_reason_code] = element.at_xpath("errorCode").content[/0*(\d+)$/, 1]
341
+ response[:response_reason_text] = element.at_xpath("errorText").content.chomp('.')
342
+ elsif(element = doc.at_xpath("//transactionResponse/messages/message"))
343
+ response[:response_reason_code] = element.at_xpath("code").content[/0*(\d+)$/, 1]
344
+ response[:response_reason_text] = element.at_xpath("description").content.chomp('.')
345
+ elsif(element = doc.at_xpath("//messages/message"))
346
+ response[:response_reason_code] = element.at_xpath("code").content[/0*(\d+)$/, 1]
347
+ response[:response_reason_text] = element.at_xpath("text").content.chomp('.')
348
+ else
349
+ response[:response_reason_code] = nil
350
+ response[:response_reason_text] = ""
281
351
  end
282
352
 
283
- if options.has_key? :cardholder_authentication_value
284
- post[:cardholder_authentication_value] = options[:cardholder_authentication_value]
353
+ response[:avs_result_code] = if(element = doc.at_xpath("//avsResultCode"))
354
+ (empty?(element.content) ? nil : element.content)
285
355
  end
286
356
 
287
- if options.has_key? :authentication_indicator
288
- post[:authentication_indicator] = options[:authentication_indicator]
357
+ response[:transaction_id] = if(element = doc.at_xpath("//transId"))
358
+ (empty?(element.content) ? nil : element.content)
289
359
  end
290
360
 
291
- end
361
+ response[:card_code] = if(element = doc.at_xpath("//cvvResultCode"))
362
+ (empty?(element.content) ? nil : element.content)
363
+ end
292
364
 
293
- # x_duplicate_window won't be sent by default, because sending it changes the response.
294
- # "If this field is present in the request with or without a value, an enhanced duplicate transaction response will be sent."
295
- # (as of 2008-12-30) http://www.authorize.net/support/AIM_guide_SCC.pdf
296
- def add_duplicate_window(post)
297
- unless duplicate_window.nil?
298
- post[:duplicate_window] = duplicate_window
365
+ response[:authorization_code] = if(element = doc.at_xpath("//authCode"))
366
+ (empty?(element.content) ? nil : element.content)
299
367
  end
300
- end
301
368
 
302
- def add_address(post, options)
303
- if address = options[:billing_address] || options[:address]
304
- post[:address] = address[:address1].to_s
305
- post[:company] = address[:company].to_s
306
- post[:phone] = address[:phone].to_s
307
- post[:zip] = address[:zip].to_s
308
- post[:city] = address[:city].to_s
309
- post[:country] = address[:country].to_s
310
- post[:state] = address[:state].blank? ? 'n/a' : address[:state]
369
+ response[:cardholder_authentication_code] = if(element = doc.at_xpath("//cavvResultCode"))
370
+ (empty?(element.content) ? nil : element.content)
311
371
  end
312
372
 
313
- if address = options[:shipping_address]
314
- post[:ship_to_first_name] = address[:first_name].to_s
315
- post[:ship_to_last_name] = address[:last_name].to_s
316
- post[:ship_to_address] = address[:address1].to_s
317
- post[:ship_to_company] = address[:company].to_s
318
- post[:ship_to_phone] = address[:phone].to_s
319
- post[:ship_to_zip] = address[:zip].to_s
320
- post[:ship_to_city] = address[:city].to_s
321
- post[:ship_to_country] = address[:country].to_s
322
- post[:ship_to_state] = address[:state].blank? ? 'n/a' : address[:state]
373
+ response[:account_number] = if(element = doc.at_xpath("//accountNumber"))
374
+ (empty?(element.content) ? nil : element.content[-4..-1])
323
375
  end
376
+
377
+ response
324
378
  end
325
379
 
326
- def message_from(results)
327
- if results[:response_code] == DECLINED
328
- return CVVResult.messages[ results[:card_code] ] if CARD_CODE_ERRORS.include?(results[:card_code])
329
- if AVS_REASON_CODES.include?(results[:response_reason_code]) && AVS_ERRORS.include?(results[:avs_result_code])
330
- return AVSResult.messages[ results[:avs_result_code] ]
380
+ def success_from(response)
381
+ (
382
+ response[:response_code] == APPROVED &&
383
+ TRANSACTION_ALREADY_ACTIONED.exclude?(response[:response_reason_code])
384
+ )
385
+ end
386
+
387
+ def message_from(response, avs_result, cvv_result)
388
+ if response[:response_code] == DECLINED
389
+ if CARD_CODE_ERRORS.include?(cvv_result.code)
390
+ return cvv_result.message
391
+ elsif(AVS_REASON_CODES.include?(response[:response_reason_code]) && AVS_ERRORS.include?(avs_result.code))
392
+ return avs_result.message
331
393
  end
332
394
  end
333
395
 
334
- (results[:response_reason_text] ? results[:response_reason_text].chomp('.') : '')
396
+ response[:response_reason_text]
397
+ end
398
+
399
+ def authorization_from(response)
400
+ [response[:transaction_id], response[:account_number]].join("#")
401
+ end
402
+
403
+ def split_authorization(authorization)
404
+ transaction_id, card_number = authorization.split("#")
405
+ [transaction_id, card_number]
335
406
  end
336
407
 
337
- def split(response)
338
- response[1..-2].split(/\$,\$/)
408
+ def fraud_review?(response)
409
+ (response[:response_code] == FRAUD_REVIEW)
339
410
  end
411
+
412
+ def truncate(value, max_size)
413
+ return nil unless value
414
+ value.to_s[0, max_size]
415
+ end
416
+
340
417
  end
341
418
  end
342
419
  end