activemerchant 1.44.1 → 1.45.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +1 -3
- data.tar.gz.sig +0 -0
- data/CHANGELOG +48 -0
- data/CONTRIBUTORS +12 -0
- data/README.md +15 -5
- data/lib/active_merchant/billing.rb +2 -0
- data/lib/active_merchant/billing/apple_pay_payment_token.rb +22 -0
- data/lib/active_merchant/billing/gateway.rb +36 -4
- data/lib/active_merchant/billing/gateways/adyen.rb +6 -2
- data/lib/active_merchant/billing/gateways/authorize_net.rb +332 -255
- data/lib/active_merchant/billing/gateways/bank_frick.rb +225 -0
- data/lib/active_merchant/billing/gateways/bogus.rb +9 -9
- data/lib/active_merchant/billing/gateways/borgun.rb +0 -1
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +8 -0
- data/lib/active_merchant/billing/gateways/cashnet.rb +17 -10
- data/lib/active_merchant/billing/gateways/checkout.rb +213 -0
- data/lib/active_merchant/billing/gateways/conekta.rb +1 -1
- data/lib/active_merchant/billing/gateways/cyber_source.rb +1 -1
- data/lib/active_merchant/billing/gateways/elavon.rb +3 -3
- data/lib/active_merchant/billing/gateways/eway_rapid.rb +114 -13
- data/lib/active_merchant/billing/gateways/finansbank.rb +1 -1
- data/lib/active_merchant/billing/gateways/global_transport.rb +183 -0
- data/lib/active_merchant/billing/gateways/hps.rb +27 -20
- data/lib/active_merchant/billing/gateways/iats_payments.rb +68 -35
- data/lib/active_merchant/billing/gateways/litle.rb +36 -1
- data/lib/active_merchant/billing/gateways/merchant_one.rb +0 -1
- data/lib/active_merchant/billing/gateways/merchant_ware.rb +8 -4
- data/lib/active_merchant/billing/gateways/mercury.rb +17 -10
- data/lib/active_merchant/billing/gateways/moneris.rb +11 -6
- data/lib/active_merchant/billing/gateways/moneris_us.rb +126 -33
- data/lib/active_merchant/billing/gateways/money_movers.rb +0 -1
- data/lib/active_merchant/billing/gateways/net_registry.rb +6 -1
- data/lib/active_merchant/billing/gateways/network_merchants.rb +5 -5
- data/lib/active_merchant/billing/gateways/nmi.rb +241 -5
- data/lib/active_merchant/billing/gateways/openpay.rb +1 -0
- data/lib/active_merchant/billing/gateways/optimal_payment.rb +6 -1
- data/lib/active_merchant/billing/gateways/orbital.rb +6 -4
- data/lib/active_merchant/billing/gateways/pay_junction.rb +9 -5
- data/lib/active_merchant/billing/gateways/payex.rb +19 -9
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +2 -2
- data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +4 -0
- data/lib/active_merchant/billing/gateways/payscout.rb +0 -2
- data/lib/active_merchant/billing/gateways/pin.rb +1 -1
- data/lib/active_merchant/billing/gateways/psigate.rb +1 -2
- data/lib/active_merchant/billing/gateways/redsys.rb +37 -40
- data/lib/active_merchant/billing/gateways/secure_pay.rb +181 -9
- data/lib/active_merchant/billing/gateways/stripe.rb +106 -31
- data/lib/active_merchant/billing/gateways/tns.rb +227 -0
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +38 -10
- data/lib/active_merchant/billing/gateways/webpay.rb +14 -0
- data/lib/active_merchant/billing/payment_token.rb +21 -0
- data/lib/active_merchant/billing/response.rb +2 -1
- data/lib/active_merchant/country.rb +6 -1
- data/lib/active_merchant/version.rb +1 -1
- metadata +8 -3
- metadata.gz.sig +0 -0
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 705744a332bbe4db27dc6e0dbbefd63712e94c28
|
4
|
+
data.tar.gz: 452924bd903988716baa84b34969a9248abb6480
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bea4d6dd57b28e0e6b852e05630ace0b08d51e6d3403f5754ba060b8651842ab26871e601833e966b293d2d3d28cc49a52aa6b54352b7fd774c4cb324c84d1fa
|
7
|
+
data.tar.gz: 11dab3ab3cb2b85a54b31283f2127c6adfe0f1e2dbcdeb73a40e9d2096d45fa258474845f62ee73d6a6ecb6564bd04974941b85c2450cb403773bc739c41d3fa
|
checksums.yaml.gz.sig
CHANGED
@@ -1,3 +1 @@
|
|
1
|
-
|
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�&��ҴL�C�N��O�,��+�"G�&�j*��R�|���c�L�i�3�t��Is�K[���������sz>����Շ���Tk�w�%��/�J`ą���Ճ&<����.�)i�m�6�r�^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]
|
data/CONTRIBUTORS
CHANGED
@@ -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
|
-
##
|
211
|
+
## Deprecation Policy
|
209
212
|
|
210
|
-
|
213
|
+
Deprecated functionality is removed on major version changes - for example, deprecations from 2.x are removed in 3.x.
|
211
214
|
|
212
|
-
|
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
|
-
|
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
|
-
|
29
|
-
|
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
|
-
|
39
|
-
|
40
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
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
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
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
|
158
|
-
|
159
|
-
|
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
|
172
|
-
|
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
|
-
|
175
|
-
|
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
|
-
|
178
|
-
|
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
|
-
|
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
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
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
|
-
|
192
|
-
|
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
|
196
|
-
|
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
|
200
|
-
|
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
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
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
|
233
|
-
|
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
|
237
|
-
|
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
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
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
|
250
|
-
if
|
251
|
-
|
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
|
-
|
295
|
+
[options[:first_name], options[:last_name]]
|
254
296
|
end
|
255
297
|
end
|
256
298
|
|
257
|
-
def
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
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
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
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
|
-
|
276
|
-
|
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
|
280
|
-
|
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
|
284
|
-
|
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
|
288
|
-
|
357
|
+
response[:transaction_id] = if(element = doc.at_xpath("//transId"))
|
358
|
+
(empty?(element.content) ? nil : element.content)
|
289
359
|
end
|
290
360
|
|
291
|
-
|
361
|
+
response[:card_code] = if(element = doc.at_xpath("//cvvResultCode"))
|
362
|
+
(empty?(element.content) ? nil : element.content)
|
363
|
+
end
|
292
364
|
|
293
|
-
|
294
|
-
|
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
|
-
|
303
|
-
|
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
|
314
|
-
|
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
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
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
|
-
|
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
|
338
|
-
response[
|
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
|