activemerchant 1.41.0 → 1.42.0

Sign up to get free protection for your applications and to get access to all the features.
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