activemerchant 1.41.0 → 1.42.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 (36) hide show
  1. checksums.yaml +15 -0
  2. data/CHANGELOG +23 -1
  3. data/CONTRIBUTORS +12 -0
  4. data/README.md +3 -0
  5. data/lib/active_merchant/billing/gateway.rb +8 -1
  6. data/lib/active_merchant/billing/gateways/app55.rb +185 -0
  7. data/lib/active_merchant/billing/gateways/authorize_net.rb +12 -2
  8. data/lib/active_merchant/billing/gateways/balanced.rb +9 -3
  9. data/lib/active_merchant/billing/gateways/card_stream_modern.rb +2 -1
  10. data/lib/active_merchant/billing/gateways/elavon.rb +1 -1
  11. data/lib/active_merchant/billing/gateways/eway_rapid.rb +2 -2
  12. data/lib/active_merchant/billing/gateways/litle.rb +5 -5
  13. data/lib/active_merchant/billing/gateways/mercury.rb +22 -0
  14. data/lib/active_merchant/billing/gateways/orbital.rb +25 -2
  15. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +187 -0
  16. data/lib/active_merchant/billing/gateways/paymill.rb +60 -28
  17. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +1 -1
  18. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +4 -2
  19. data/lib/active_merchant/billing/gateways/spreedly_core.rb +4 -2
  20. data/lib/active_merchant/billing/gateways/stripe.rb +35 -15
  21. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +158 -0
  22. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +62 -46
  23. data/lib/active_merchant/billing/gateways/webpay.rb +1 -2
  24. data/lib/active_merchant/billing/integrations/bit_pay.rb +2 -2
  25. data/lib/active_merchant/billing/integrations/bit_pay/helper.rb +15 -19
  26. data/lib/active_merchant/billing/integrations/bit_pay/notification.rb +38 -20
  27. data/lib/active_merchant/billing/integrations/notification.rb +2 -2
  28. data/lib/active_merchant/billing/integrations/wirecard_checkout_page.rb +39 -0
  29. data/lib/active_merchant/billing/integrations/wirecard_checkout_page/common.rb +104 -0
  30. data/lib/active_merchant/billing/integrations/wirecard_checkout_page/helper.rb +145 -0
  31. data/lib/active_merchant/billing/integrations/wirecard_checkout_page/notification.rb +101 -0
  32. data/lib/active_merchant/billing/integrations/wirecard_checkout_page/return.rb +35 -0
  33. data/lib/active_merchant/version.rb +1 -1
  34. metadata +16 -59
  35. data.tar.gz.sig +0 -0
  36. metadata.gz.sig +0 -0
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTFmNGE4MzgzOGE3NTEzOTJmYmQ5M2Q1ZGE5YzIxNjBlZWQzNjRiYw==
5
+ data.tar.gz: !binary |-
6
+ NWFlYTUzMTExZTBiMDc2MDFmOTcwYTU3YTVkNDI5NjM1YjA1MjVkNA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NTBkNWU0NDkyN2ViMDM5NjFhMDVlYmFkODUyODQyMGU4NGRiY2RmZmRhNGM0
10
+ YmM1ZDlhM2Y0OGM2ZTExMDVmYmQ5MTM1NmMxOWY0YjQyMGNlYTQ0NTkzNmM4
11
+ MWQ0YWI0MGNjMjhiMWQwZWYwMjNlMzk3Mjg4YTIzMmEyNzFhMzY=
12
+ data.tar.gz: !binary |-
13
+ NDQ3YzBlNWFiMjhkZTcyYmFkMDQyN2M3ZDVkNWVhMzVmYTUzOGMzYzJiZDU0
14
+ YzMwM2JkODAyMzJiYjA0NWY0ZjEzYTM5NWMxOGEzNjA2NWIxMGIzYzE5YzJh
15
+ Y2JjNWZiZDFhMGRiN2ZiZWU4NGMwZjA1ZTFhMWNiZTY4NGU4ODY=
data/CHANGELOG CHANGED
@@ -1,5 +1,28 @@
1
1
  = ActiveMerchant CHANGELOG
2
2
 
3
+ == Version 1.42.0 (November 13th, 2013)
4
+
5
+ * Fix NoMethodError "tr" for params with dash [TimothyKlim]
6
+ * Authorize.Net: Add cardholder authentication options (CAVV) support [structure]
7
+ * CardStreamModern: Added better checks on inputs from the gateway [ExxKA]
8
+ * Stripe: Send :ip to the gateway instead of :browser_ip [f3ndot]
9
+ * Wirecard Page: new offsite gateway [mbretter]
10
+ * Mercury: Add support for requesting a token [kcdragon]
11
+ * Add App55 gateway [ianbutler55]
12
+ * UsaEpayTransaction: Support for split payments [GBH]
13
+ * Add Swipe Checkout gateway [matt-optimizerhq]
14
+ * Spreedly Core: Allow overriding the gateway token when running a transaction [hoenth]
15
+ * Spreedly Core: Add order_id [hoenth]
16
+ * Spreedly Core: Allow store without retain [hoenth]
17
+ * Stripe: Support multiple cards on account [pierre]
18
+ * Stripe: Add card_id parameter to unstore call [pierre]
19
+ * Remove usage of `uname -a` [ntalbott]
20
+ * Litle: Allow easier access to the response code [duff]
21
+ * Stripe: Add the option to pass a version header [odorcicd]
22
+ * Elavon: Update supported countries [duff]
23
+ * Add Raven PacNet gateway [llopez]
24
+ * BitPay: Fix BitPay issues and implement Notification#acknowledge [odorcicd]
25
+
3
26
  == Version 1.41.0 (October 24th, 2013)
4
27
 
5
28
  * Stripe: Payments won't fail when specifying a customer with a creditcard number [melari]
@@ -1262,4 +1285,3 @@ value [jduff]
1262
1285
  * Credit card validation methods as static methods of the credit card object
1263
1286
 
1264
1287
  == PlanetArgon fork for integrating Merchant eSolutions gateway
1265
-
@@ -424,3 +424,15 @@ Be2Bill (September 2013)
424
424
  Conekta (October 2013)
425
425
 
426
426
  * Leo Fischer (leofischer)
427
+
428
+ App55 (November 2013)
429
+
430
+ * (ianbutler55)
431
+
432
+ Swipe Checkout (November 2013)
433
+
434
+ * (matt-optimizerhq)
435
+
436
+ Raven PacNet (November 2013)
437
+
438
+ * Luis Lopez (llopez)
data/README.md CHANGED
@@ -81,6 +81,7 @@ For more in-depth documentation and tutorials, see [GettingStarted.md](GettingSt
81
81
 
82
82
  The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) contains a [table of features supported by each gateway](http://github.com/Shopify/active_merchant/wikis/gatewayfeaturematrix).
83
83
 
84
+ * [App55](https://www.app55.com/) - AU, BR, CA, CH, CL, CN, CO, CZ, DK, EU, GB, HK, HU, ID, IS, JP, KE, KR, MX, MY, NO, NZ, PH, PL, TH, TW, US, VN, ZA
84
85
  * [Authorize.Net CIM](http://www.authorize.net/) - US
85
86
  * [Authorize.Net](http://www.authorize.net/) - US, CA, GB
86
87
  * [Balanced](https://www.balancedpayments.com/) - US
@@ -161,6 +162,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
161
162
  * [QuickBooks Merchant Services](http://payments.intuit.com/) - US
162
163
  * [Quantum Gateway](http://www.quantumgateway.com) - US
163
164
  * [Quickpay](http://quickpay.dk/) - DK, SE
165
+ * [Raven PacNet](http://www.pacnetservices.com/) - US
164
166
  * [Realex](http://www.realexpayments.com/) - IE, GB, FR, BE, NL, LU, IT
165
167
  * [Redsys](http://www.redsys.es/) - ES
166
168
  * [SagePay](http://www.sagepay.com) - GB, IE
@@ -173,6 +175,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
173
175
  * [SkipJack](http://www.skipjack.com/) - US, CA
174
176
  * [Spreedly](https://spreedly.com) - AD, AE, AT, AU, BD, BE, BG, BN, CA, CH, CY, CZ, DE, DK, EE, EG, ES, FI, FR, GB, GI, GR, HK, HU, ID, IE, IL, IM, IN, IS, IT, JO, KW, LB, LI, LK, LT, LU, LV, MC, MT, MU, MV, MX, MY, NL, NO, NZ, OM, PH, PL, PT, QA, RO, SA, SE, SG, SI, SK, SM, TR, TT, UM, US, VA, VN, ZA
175
177
  * [Stripe](https://stripe.com/) - US, CA, GB, AU, IE, FR, NL, BE, DE, ES
178
+ * [Swipe](https://www.swipehq.com/checkout) - CA, NZ
176
179
  * [TransFirst](http://www.transfirst.com/) - US
177
180
  * [NELiX TransaX](https://www.nelixtransax.com/) - US
178
181
  * [Transnational](http://www.tnbci.com/) - US
@@ -161,7 +161,14 @@ module ActiveMerchant #:nodoc:
161
161
 
162
162
  def localized_amount(money, currency)
163
163
  amount = amount(money)
164
- non_fractional_currency?(currency) ? amount.split('.').first : amount
164
+
165
+ return amount unless non_fractional_currency?(currency)
166
+
167
+ if self.money_format == :cents
168
+ sprintf("%.0f", amount.to_f / 100)
169
+ else
170
+ amount.split('.').first
171
+ end
165
172
  end
166
173
 
167
174
  def non_fractional_currency?(currency)
@@ -0,0 +1,185 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class App55Gateway < Gateway
4
+ self.test_url = 'https://sandbox.app55.com/v1/'
5
+ self.live_url = 'https://api.app55.com/v1/'
6
+
7
+ self.supported_countries = ['AU', 'BR', 'CA', 'CH', 'CL', 'CN', 'CO', 'CZ', 'DK', 'EU', 'GB', 'HK', 'HU', 'ID', 'IS', 'JP', 'KE', 'KR', 'MX', 'MY', 'NO', 'NZ', 'PH', 'PL', 'TH', 'TW', 'US', 'VN', 'ZA']
8
+ self.supported_cardtypes = [:visa, :master, :american_express, :jcb, :maestro, :solo]
9
+ self.default_currency = 'UKP'
10
+ self.money_format = :dollars
11
+ self.homepage_url = 'https://www.app55.com/'
12
+ self.display_name = 'App55'
13
+
14
+ # Create gateway
15
+ #
16
+ # options:
17
+ # :api_key - merchants App55 API Key
18
+ # :api_secret - merchants App55 Secret Key
19
+ def initialize(options = {})
20
+ requires!(options, :api_key, :api_secret)
21
+ @api_key = options[:api_key]
22
+ @api_secret = options[:api_secret]
23
+ super
24
+ end
25
+
26
+ # Make a purchase (authorize and commit)
27
+ #
28
+ # money - The monetary amount of the transaction in cents.
29
+ # payment_method - The CreditCard or the App55 card token.
30
+ # options - A standard ActiveMerchant options hash
31
+ def purchase(money, payment_method, options = {})
32
+ authorize(money, payment_method, options.merge(commit: true))
33
+ end
34
+
35
+ # Authorize a transaction.
36
+ #
37
+ # money - The monetary amount of the transaction in cents.
38
+ # payment_method - The CreditCard or the App55 card token.
39
+ # options - A standard ActiveMerchant options hash
40
+ def authorize(money, payment_method, options = {})
41
+ post = {}
42
+ add_creditcard(post, payment_method, options)
43
+ add_transaction(post, money, options)
44
+
45
+ commit(:post, 'transaction', post)
46
+ end
47
+
48
+ # Commit a pre-authorized transaction.
49
+ #
50
+ # money - The monetary amount of the transaction in cents.
51
+ # authorization - The App55 transaction id string.
52
+ # options - A standard ActiveMerchant options hash
53
+ def capture(money, authorization, options = {})
54
+ commit(:post, "transaction/#{authorization}")
55
+ end
56
+
57
+ private
58
+
59
+ def add_customer_data(post, options)
60
+ metadata_options = [:description, :browser_ip, :user_agent, :referrer]
61
+ post.update(options.slice(*metadata_options))
62
+ end
63
+
64
+ def add_creditcard(post, creditcard, options)
65
+ card = {}
66
+ card[:number] = creditcard.number
67
+ card[:expiry] = ("%02d". % creditcard.month) + '/' + creditcard.year.to_s
68
+ card[:security_code] = creditcard.verification_value if creditcard.verification_value?
69
+ card[:holder_name] = creditcard.name if creditcard.name
70
+ add_address(card, options)
71
+ post[:card] = card
72
+ end
73
+
74
+ def add_address(card, options)
75
+ return unless card && card.kind_of?(Hash)
76
+ address_hash = {}
77
+ if address = (options[:billing_address] || options[:address])
78
+ address_hash[:street] = address[:address1] if address[:address1]
79
+ address_hash[:street2] = address[:address2] if address[:address2]
80
+ address_hash[:country] = address[:country] if address[:country]
81
+ address_hash[:postal_code] = address[:zip] if address[:zip]
82
+ address_hash[:city] = address[:city] if address[:city]
83
+ card[:address] = address_hash
84
+ end
85
+ end
86
+
87
+ def add_transaction(post, money, options)
88
+ transaction = {}
89
+ add_amount(transaction, money, options)
90
+ transaction[:description] = (options[:description] || options[:email])
91
+ transaction[:commit] = options[:commit]
92
+ post[:transaction] = transaction
93
+ end
94
+
95
+ def add_amount(obj, money, options)
96
+ obj[:amount] = amount(money)
97
+ obj[:currency] = (options[:currency] || currency(money))
98
+ end
99
+
100
+ def parse(body)
101
+ JSON.parse(body)
102
+ rescue JSON::ParserError
103
+ json_error(raw_response)
104
+ end
105
+
106
+ def commit(method, resource, parameters=nil, meta={})
107
+ success = false
108
+ begin
109
+ raw_response = ssl_request(
110
+ method,
111
+ url(resource),
112
+ post_data(parameters),
113
+ headers
114
+ )
115
+ response = parse(raw_response)
116
+ success = response.key?("sig")
117
+ rescue ResponseError => e
118
+ response = parse(e.response.body)
119
+ end
120
+
121
+ Response.new(
122
+ success,
123
+ (success ? "OK" : response["error"]["message"]),
124
+ response,
125
+ test: test?,
126
+ authorization: authorization_from(response)
127
+ )
128
+ end
129
+
130
+ def authorization_from(response)
131
+ if response.key?("transaction")
132
+ response["transaction"]["id"]
133
+ elsif response.key?("card")
134
+ response["card"]["token"]
135
+ end
136
+ end
137
+
138
+ def json_error(raw_response)
139
+ msg = "Invalid response from app55 server: Received: #{raw_response.inspect})"
140
+ {
141
+ "error" => {
142
+ "message" => msg
143
+ }
144
+ }
145
+ end
146
+
147
+ def url(resource)
148
+ (test? ? self.test_url : self.live_url) + resource
149
+ end
150
+
151
+ def post_data(params)
152
+ return nil unless params
153
+
154
+ params.map do |key, value|
155
+ next if value.blank?
156
+ if value.is_a?(Hash)
157
+ h = {}
158
+ value.each do |k, v|
159
+ h["#{key}.#{k}"] = v unless v.blank?
160
+ end
161
+ post_data(h)
162
+ else
163
+ "#{key}=#{CGI.escape(value.to_s)}"
164
+ end
165
+ end.compact.join("&")
166
+ end
167
+
168
+ def headers
169
+ @@ua ||= JSON.dump(
170
+ :bindings_version => ActiveMerchant::VERSION,
171
+ :lang => 'ruby',
172
+ :lang_version => "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})",
173
+ :platform => RUBY_PLATFORM,
174
+ :publisher => 'active_merchant'
175
+ )
176
+
177
+ {
178
+ "Authorization" => "Basic " + Base64.strict_encode64(@options[:api_key].to_s + ":" + @options[:api_secret].to_s),
179
+ "User-Agent" => "ActiveMerchantBindings/#{ActiveMerchant::VERSION}",
180
+ }
181
+ end
182
+ end
183
+ end
184
+ end
185
+
@@ -39,7 +39,7 @@ module ActiveMerchant #:nodoc:
39
39
  APPROVED, DECLINED, ERROR, FRAUD_REVIEW = 1, 2, 3, 4
40
40
 
41
41
  RESPONSE_CODE, RESPONSE_REASON_CODE, RESPONSE_REASON_TEXT, AUTHORIZATION_CODE = 0, 2, 3, 4
42
- AVS_RESULT_CODE, TRANSACTION_ID, CARD_CODE_RESPONSE_CODE = 5, 6, 38
42
+ AVS_RESULT_CODE, TRANSACTION_ID, CARD_CODE_RESPONSE_CODE, CARDHOLDER_AUTH_CODE = 5, 6, 38, 39
43
43
 
44
44
  self.default_currency = 'USD'
45
45
 
@@ -311,7 +311,8 @@ module ActiveMerchant #:nodoc:
311
311
  :avs_result_code => fields[AVS_RESULT_CODE],
312
312
  :transaction_id => fields[TRANSACTION_ID],
313
313
  :card_code => fields[CARD_CODE_RESPONSE_CODE],
314
- :authorization_code => fields[AUTHORIZATION_CODE]
314
+ :authorization_code => fields[AUTHORIZATION_CODE],
315
+ :cardholder_authentication_code => fields[CARDHOLDER_AUTH_CODE]
315
316
  }
316
317
  results
317
318
  end
@@ -383,6 +384,15 @@ module ActiveMerchant #:nodoc:
383
384
  if options.has_key? :ip
384
385
  post[:customer_ip] = options[:ip]
385
386
  end
387
+
388
+ if options.has_key? :cardholder_authentication_value
389
+ post[:cardholder_authentication_value] = options[:cardholder_authentication_value]
390
+ end
391
+
392
+ if options.has_key? :authentication_indicator
393
+ post[:authentication_indicator] = options[:authentication_indicator]
394
+ end
395
+
386
396
  end
387
397
 
388
398
  # x_duplicate_window won't be sent by default, because sending it changes the response.
@@ -261,11 +261,17 @@ module ActiveMerchant #:nodoc:
261
261
  post = {}
262
262
  account_uri = create_or_find_account(post, options)
263
263
  if credit_card.respond_to? :number
264
- add_credit_card(post, credit_card, options)
264
+ card_uri = add_credit_card(post, credit_card, options)
265
265
  else
266
- associate_card_to_account(account_uri, credit_card)
267
- credit_card
266
+ card_uri = associate_card_to_account(account_uri, credit_card)
268
267
  end
268
+
269
+ is_test = false
270
+ if @marketplace_uri
271
+ is_test = (@marketplace_uri.index("TEST") ? true : false)
272
+ end
273
+
274
+ Response.new(true, "Card stored", {}, :test => is_test, :authorization => [card_uri, account_uri].compact.join(';'))
269
275
  rescue Error => ex
270
276
  failed_response(ex.response)
271
277
  end
@@ -114,7 +114,8 @@ module ActiveMerchant #:nodoc:
114
114
  pairs = body.split("&")
115
115
  pairs.each do |pair|
116
116
  a = pair.split("=")
117
- result[a[0].to_sym] = CGI.unescape(a[1])
117
+ #Make sure there is a value, else set it to empty string
118
+ result[a[0].to_sym] = a[1] ? CGI.unescape(a[1]) : ""
118
119
  end
119
120
  result
120
121
  end
@@ -36,7 +36,7 @@ module ActiveMerchant #:nodoc:
36
36
  self.live_url = 'https://www.myvirtualmerchant.com/VirtualMerchant/process.do'
37
37
 
38
38
  self.display_name = 'Elavon MyVirtualMerchant'
39
- self.supported_countries = ['US', 'CA']
39
+ self.supported_countries = %w(US CA PR DE IE NO PL LU BE NL)
40
40
  self.supported_cardtypes = [:visa, :master, :american_express, :discover]
41
41
  self.homepage_url = 'http://www.elavon.com/'
42
42
 
@@ -141,10 +141,10 @@ module ActiveMerchant #:nodoc:
141
141
 
142
142
  def add_invoice(doc, money, options)
143
143
  doc.Payment do
144
- doc.TotalAmount amount(money)
144
+ currency_code = options[:currency] || currency(money)
145
+ doc.TotalAmount localized_amount(money, currency_code)
145
146
  doc.InvoiceReference options[:order_id]
146
147
  doc.InvoiceDescription options[:description]
147
- currency_code = (options[:currency] || currency(money) || default_currency)
148
148
  doc.CurrencyCode currency_code
149
149
  end
150
150
  end
@@ -171,11 +171,11 @@ module ActiveMerchant #:nodoc:
171
171
  Response.new(
172
172
  valid_responses.include?(detail['response']),
173
173
  detail['message'],
174
- { :litleOnlineResponse => response },
175
- :authorization => authorization_from(detail, kind),
176
- :avs_result => { :code => fraud['avs'] },
177
- :cvv_result => fraud['cvv'],
178
- :test => test?
174
+ { litleOnlineResponse: response, response_code: detail['response'] },
175
+ authorization: authorization_from(detail, kind),
176
+ avs_result: { :code => fraud['avs'] },
177
+ cvv_result: fraud['cvv'],
178
+ test: test?
179
179
  )
180
180
  else
181
181
  Response.new(false, response['message'], :litleOnlineResponse => response, :test => test?)
@@ -77,6 +77,11 @@ module ActiveMerchant #:nodoc:
77
77
  commit('VoidSale', request)
78
78
  end
79
79
 
80
+ def store(credit_card, options={})
81
+ request = build_card_lookup_request(credit_card, options)
82
+ commit('CardLookup', request)
83
+ end
84
+
80
85
  private
81
86
 
82
87
  def build_non_authorized_request(action, money, credit_card, options)
@@ -129,6 +134,23 @@ module ActiveMerchant #:nodoc:
129
134
  xml = xml.target!
130
135
  end
131
136
 
137
+ def build_card_lookup_request(credit_card, options)
138
+ xml = Builder::XmlMarkup.new
139
+
140
+ xml.tag! "TStream" do
141
+ xml.tag! "Transaction" do
142
+ xml.tag! 'TranType', 'CardLookup'
143
+ xml.tag! 'RecordNo', 'RecordNumberRequested'
144
+ xml.tag! 'Frequency', 'OneTime'
145
+
146
+ xml.tag! 'Memo', options[:description]
147
+ add_customer_data(xml, options)
148
+ add_credit_card(xml, credit_card, options)
149
+ end
150
+ end
151
+ xml.target!
152
+ end
153
+
132
154
  def add_invoice(xml, invoice_no, ref_no, options)
133
155
  if /^\d+$/ !~ invoice_no.to_s
134
156
  raise ArgumentError.new("order_id '#{invoice_no}' is not numeric as required by Mercury")
@@ -80,6 +80,25 @@ module ActiveMerchant #:nodoc:
80
80
  "EUR" => '978'
81
81
  }
82
82
 
83
+ CURRENCY_EXPONENTS = {
84
+ "AUD" => '2',
85
+ "CAD" => '2',
86
+ "CZK" => '2',
87
+ "DKK" => '2',
88
+ "HKD" => '2',
89
+ "ICK" => '2',
90
+ "JPY" => '0',
91
+ "MXN" => '2',
92
+ "NZD" => '2',
93
+ "NOK" => '2',
94
+ "SGD" => '2',
95
+ "SEK" => '2',
96
+ "CHF" => '2',
97
+ "GBP" => '2',
98
+ "USD" => '2',
99
+ "EUR" => '2'
100
+ }
101
+
83
102
  # INDUSTRY TYPES
84
103
  ECOMMERCE_TRANSACTION = 'EC'
85
104
  RECURRING_PAYMENT_TRANSACTION = 'RC'
@@ -333,7 +352,7 @@ module ActiveMerchant #:nodoc:
333
352
  end
334
353
 
335
354
  xml.tag! :CurrencyCode, currency_code(currency)
336
- xml.tag! :CurrencyExponent, '2' # Will need updating to support currencies such as the Yen.
355
+ xml.tag! :CurrencyExponent, currency_exponents(currency)
337
356
 
338
357
  # If you are trying to collect a Card Verification Number
339
358
  # (CardSecVal) for a Visa or Discover transaction, pass one of these values:
@@ -356,7 +375,7 @@ module ActiveMerchant #:nodoc:
356
375
  xml.tag! :AccountNum, nil
357
376
 
358
377
  xml.tag! :CurrencyCode, currency_code(currency)
359
- xml.tag! :CurrencyExponent, '2' # Will need updating to support currencies such as the Yen.
378
+ xml.tag! :CurrencyExponent, currency_exponents(currency)
360
379
  end
361
380
 
362
381
  def add_managed_billing(xml, options)
@@ -544,6 +563,10 @@ module ActiveMerchant #:nodoc:
544
563
  CURRENCY_CODES[(currency || self.default_currency)].to_s
545
564
  end
546
565
 
566
+ def currency_exponents(currency)
567
+ CURRENCY_EXPONENTS[(currency || self.default_currency)].to_s
568
+ end
569
+
547
570
  def expiry_date(credit_card)
548
571
  "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
549
572
  end