activemerchant 1.32.0 → 1.33.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 (52) hide show
  1. data/CHANGELOG +50 -0
  2. data/CONTRIBUTORS +8 -0
  3. data/README.md +6 -4
  4. data/lib/active_merchant/billing/check.rb +4 -3
  5. data/lib/active_merchant/billing/credit_card.rb +7 -3
  6. data/lib/active_merchant/billing/gateways/authorize_net.rb +27 -7
  7. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +8 -1
  8. data/lib/active_merchant/billing/gateways/blue_pay.rb +201 -185
  9. data/lib/active_merchant/billing/gateways/bogus.rb +1 -1
  10. data/lib/active_merchant/billing/gateways/card_stream_modern.rb +155 -0
  11. data/lib/active_merchant/billing/gateways/cc5.rb +0 -4
  12. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +94 -12
  13. data/lib/active_merchant/billing/gateways/garanti.rb +0 -4
  14. data/lib/active_merchant/billing/gateways/litle.rb +41 -11
  15. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +27 -6
  16. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +2 -2
  17. data/lib/active_merchant/billing/gateways/net_registry.rb +8 -3
  18. data/lib/active_merchant/billing/gateways/netaxept.rb +65 -117
  19. data/lib/active_merchant/billing/gateways/orbital.rb +181 -48
  20. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +12 -10
  21. data/lib/active_merchant/billing/gateways/paymill.rb +27 -13
  22. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +11 -6
  23. data/lib/active_merchant/billing/gateways/paypal_express.rb +25 -7
  24. data/lib/active_merchant/billing/gateways/pin.rb +5 -5
  25. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +16 -11
  26. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +1 -1
  27. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +21 -16
  28. data/lib/active_merchant/billing/gateways/sage.rb +10 -5
  29. data/lib/active_merchant/billing/gateways/sage_pay.rb +1 -0
  30. data/lib/active_merchant/billing/gateways/transnational.rb +239 -0
  31. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +9 -4
  32. data/lib/active_merchant/billing/integrations/direc_pay/status.rb +1 -1
  33. data/lib/active_merchant/billing/integrations/direc_pay.rb +1 -1
  34. data/lib/active_merchant/billing/integrations/dwolla/common.rb +21 -0
  35. data/lib/active_merchant/billing/integrations/dwolla/helper.rb +15 -6
  36. data/lib/active_merchant/billing/integrations/dwolla/notification.rb +11 -6
  37. data/lib/active_merchant/billing/integrations/dwolla/return.rb +12 -4
  38. data/lib/active_merchant/billing/integrations/dwolla.rb +5 -12
  39. data/lib/active_merchant/billing/integrations/notification.rb +13 -8
  40. data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +13 -1
  41. data/lib/active_merchant/billing/integrations/payu_in/helper.rb +74 -0
  42. data/lib/active_merchant/billing/integrations/payu_in/notification.rb +167 -0
  43. data/lib/active_merchant/billing/integrations/payu_in/return.rb +53 -0
  44. data/lib/active_merchant/billing/integrations/payu_in.rb +43 -0
  45. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +68 -5
  46. data/lib/active_merchant/billing/integrations/rbkmoney/helper.rb +23 -0
  47. data/lib/active_merchant/billing/integrations/rbkmoney/notification.rb +91 -0
  48. data/lib/active_merchant/billing/integrations/rbkmoney.rb +17 -0
  49. data/lib/active_merchant/version.rb +1 -1
  50. data.tar.gz.sig +0 -0
  51. metadata +72 -62
  52. metadata.gz.sig +0 -0
@@ -0,0 +1,239 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class TransnationalGateway < Gateway
4
+ self.live_url = self.test_url = 'https://secure.networkmerchants.com/api/transact.php'
5
+
6
+ self.supported_countries = ['US']
7
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover]
8
+
9
+ self.homepage_url = 'http://www.tnbci.com/'
10
+ self.display_name = 'Transnational'
11
+
12
+ self.money_format = :dollars
13
+ self.default_currency = 'USD'
14
+
15
+ def initialize(options = {})
16
+ requires!(options, :login, :password)
17
+ super
18
+ end
19
+
20
+ def authorize(money, creditcard_or_vault_id, options = {})
21
+ post = build_auth_post(money, creditcard_or_vault_id, options)
22
+ commit('auth', post)
23
+ end
24
+
25
+ def purchase(money, creditcard_or_vault_id, options = {})
26
+ post = build_purchase_post(money, creditcard_or_vault_id, options)
27
+ commit('sale', post)
28
+ end
29
+
30
+ def capture(money, authorization, options = {})
31
+ post = build_capture_post(money, authorization, options)
32
+ commit('capture', post)
33
+ end
34
+
35
+ def void(authorization, options = {})
36
+ post = build_void_post(authorization, options)
37
+ commit('void', post)
38
+ end
39
+
40
+ def refund(money, authorization, options = {})
41
+ post = build_refund_post(money, authorization, options)
42
+ commit('refund', post)
43
+ end
44
+
45
+ def store(creditcard, options = {})
46
+ post = build_store_post(creditcard, options)
47
+ commit_vault('add_customer', post)
48
+ end
49
+
50
+ def unstore(customer_vault_id, options = {})
51
+ post = build_unstore_post(customer_vault_id, options)
52
+ commit_vault('delete_customer', post)
53
+ end
54
+
55
+ private
56
+
57
+ def build_auth_post(money, creditcard_or_vault_id, options)
58
+ post = {}
59
+ add_order(post, options)
60
+ add_address(post, options)
61
+ add_shipping_address(post, options)
62
+ add_payment_method(post, creditcard_or_vault_id, options)
63
+ add_amount(post, money)
64
+ post
65
+ end
66
+
67
+ def build_purchase_post(money, creditcard, options)
68
+ build_auth_post(money, creditcard, options)
69
+ end
70
+
71
+ def build_capture_post(money, authorization, option)
72
+ post = {}
73
+ post[:transactionid] = authorization
74
+ add_amount(post, money)
75
+ post
76
+ end
77
+
78
+ def build_void_post(authorization, options)
79
+ post = {}
80
+ post[:transactionid] = authorization
81
+ post
82
+ end
83
+
84
+ def build_refund_post(money, authorization, options)
85
+ post = {}
86
+ post[:transactionid] = authorization
87
+ add_amount(post, money)
88
+ post
89
+ end
90
+
91
+ def build_store_post(creditcard_or_check, options)
92
+ post = {}
93
+ add_address(post, options)
94
+ add_shipping_address(post, options)
95
+ add_payment_method(post, creditcard_or_check, options)
96
+ post
97
+ end
98
+
99
+ def build_unstore_post(customer_vault_id, options)
100
+ post = {}
101
+ post['customer_vault_id'] = customer_vault_id
102
+ post
103
+ end
104
+
105
+ def add_order(post, options)
106
+ post[:orderid] = options[:order_id]
107
+ post[:orderdescription] = options[:description]
108
+ end
109
+
110
+ def add_address(post, options)
111
+ post[:email] = options[:email]
112
+ post[:ipaddress] = options[:ip]
113
+
114
+ address = options[:billing_address] || options[:address] || {}
115
+ post[:address1] = address[:address1]
116
+ post[:address2] = address[:address2]
117
+ post[:city] = address[:city]
118
+ post[:state] = address[:state]
119
+ post[:zip] = address[:zip]
120
+ post[:country] = address[:country]
121
+ post[:phone] = address[:phone]
122
+ end
123
+
124
+ def add_shipping_address(post, options)
125
+ shipping_address = options[:shipping_address] || {}
126
+ post[:shipping_address1] = shipping_address[:address1]
127
+ post[:shipping_address2] = shipping_address[:address2]
128
+ post[:shipping_city] = shipping_address[:city]
129
+ post[:shipping_state] = shipping_address[:state]
130
+ post[:shipping_zip] = shipping_address[:zip]
131
+ post[:shipping_country] = shipping_address[:country]
132
+ end
133
+
134
+ def add_swipe_data(post, options)
135
+ # unencrypted tracks
136
+ post[:track_1] = options[:track_1]
137
+ post[:track_2] = options[:track_2]
138
+ post[:track_3] = options[:track_3]
139
+
140
+ # encrypted tracks
141
+ post[:magnesafe_track_1] = options[:magnesafe_track_1]
142
+ post[:magnesafe_track_2] = options[:magnesafe_track_2]
143
+ post[:magnesafe_track_3] = options[:magnesafe_track_3]
144
+ post[:magnesafe_magneprint] = options[:magnesafe_magneprint]
145
+ post[:magnesafe_ksn] = options[:magnesafe_ksn]
146
+ post[:magnesafe_magneprint_status] = options[:magnesafe_magneprint_status]
147
+ end
148
+
149
+ def add_payment_method(post, creditcard_or_check_or_vault_id, options)
150
+ post[:processor_id] = options[:processor_id]
151
+ post[:customer_vault] = 'add_customer' if options[:store]
152
+
153
+ add_swipe_data(post, options)
154
+
155
+ # creditcard_or_check can be blank if using swipe data
156
+ if creditcard_or_check_or_vault_id.is_a?(CreditCard) # creditcard or check
157
+ creditcard = creditcard_or_check_or_vault_id
158
+ post[:firstname] = creditcard.first_name
159
+ post[:lastname] = creditcard.last_name
160
+ post[:ccnumber] = creditcard.number
161
+ post[:ccexp] = format(creditcard.month, :two_digits) + format(creditcard.year, :two_digits)
162
+ post[:cvv] = creditcard.verification_value
163
+ post[:payment] = 'creditcard'
164
+ elsif creditcard_or_check_or_vault_id.is_a?(Check)
165
+ check = creditcard_or_check_or_vault_id
166
+ post[:firstname] = check.first_name
167
+ post[:lastname] = check.last_name
168
+ post[:checkname] = check.name
169
+ post[:checkaba] = check.routing_number
170
+ post[:checkaccount] = check.account_number
171
+ post[:account_type] = check.account_type
172
+ post[:account_holder_type] = check.account_holder_type
173
+ post[:payment] = 'check'
174
+ else
175
+ post[:customer_vault_id] = creditcard_or_check_or_vault_id
176
+ end
177
+ end
178
+
179
+ def add_login(post)
180
+ post[:username] = @options[:login]
181
+ post[:password] = @options[:password]
182
+ end
183
+
184
+ def add_amount(post, money)
185
+ post[:currency] = options[:currency] || currency(money)
186
+ post[:amount] = amount(money)
187
+ end
188
+
189
+ def commit_vault(action, parameters)
190
+ commit(nil, parameters.merge(:customer_vault => action))
191
+ end
192
+
193
+ def commit(action, parameters)
194
+ raw = parse(ssl_post(self.live_url, build_request(action, parameters)))
195
+
196
+ success = (raw['response'] == ResponseCodes::APPROVED)
197
+
198
+ authorization = authorization_from(success, parameters, raw)
199
+
200
+ Response.new(success, raw['responsetext'], raw,
201
+ :test => test?,
202
+ :authorization => authorization,
203
+ :avs_result => { :code => raw['avsresponse']},
204
+ :cvv_result => raw['cvvresponse']
205
+ )
206
+ end
207
+
208
+ def build_request(action, parameters)
209
+ parameters[:type] = action if action
210
+ add_login(parameters)
211
+ parameters.to_query
212
+ end
213
+
214
+ def authorization_from(success, parameters, response)
215
+ return nil unless success
216
+
217
+ authorization = response['transactionid']
218
+ if(parameters[:customer_vault] && (authorization.nil? || authorization.empty?))
219
+ authorization = response['customer_vault_id']
220
+ end
221
+
222
+ authorization
223
+ end
224
+
225
+ class ResponseCodes
226
+ APPROVED = '1'
227
+ DENIED = '2'
228
+ ERROR = '3'
229
+ end
230
+
231
+ def parse(raw_response)
232
+ rsp = CGI.parse(raw_response)
233
+ rsp.keys.each { |k| rsp[k] = rsp[k].first } # flatten out the values
234
+ rsp
235
+ end
236
+ end
237
+ end
238
+ end
239
+
@@ -174,7 +174,7 @@ module ActiveMerchant #:nodoc:
174
174
  :xid => [:string, 'XID'],
175
175
  :cavv => [:string, 'CAVV'],
176
176
  :eci => [:integer, 'ECI'],
177
- :internal_card_authorization => [:boolean, 'InternalCardAduth'],
177
+ :internal_card_authorization => [:boolean, 'InternalCardAuth'],
178
178
  :pares => [:string, 'Pares']
179
179
  } #:nodoc:
180
180
 
@@ -283,14 +283,19 @@ module ActiveMerchant #:nodoc:
283
283
  void_transaction(options.merge!(:reference_number => identification))
284
284
  end
285
285
 
286
- # Credit a previous transaction.
286
+ # Refund a previous transaction.
287
287
  #
288
288
  # Note: See run_transaction for additional options.
289
289
  #
290
- def credit(money, identification, options={})
290
+ def refund(money, identification, options={})
291
291
  refund_transaction(options.merge!(:amount => money, :reference_number => identification))
292
292
  end
293
293
 
294
+ def credit(money, identification, options={})
295
+ deprecated CREDIT_DEPRECATION_MESSAGE
296
+ refund(money, identification, options)
297
+ end
298
+
294
299
  # Customer ======================================================
295
300
 
296
301
  # Add a customer.
@@ -1334,7 +1339,7 @@ module ActiveMerchant #:nodoc:
1334
1339
 
1335
1340
  def build_check_data(soap, options)
1336
1341
  soap.CheckData 'xsi:type' => "ns1:CheckData" do |soap|
1337
- build_tag soap, :string, 'Account', options[:payment_method].number
1342
+ build_tag soap, :string, 'Account', options[:payment_method].account_number
1338
1343
  build_tag soap, :string, 'Routing', options[:payment_method].routing_number
1339
1344
  build_tag soap, :string, 'AccountType', options[:payment_method].account_type.capitalize
1340
1345
  CHECK_DATA_OPTIONS.each do |k,v|
@@ -6,7 +6,7 @@ module ActiveMerchant #:nodoc:
6
6
  class Status
7
7
  include PostsData
8
8
 
9
- STATUS_TEST_URL = 'https://test.timesofmoney.com/direcpay/secure/dpPullMerchAtrnDtls.jsp'
9
+ STATUS_TEST_URL = 'https://test.direcpay.com/direcpay/secure/dpMerchantTransaction.jsp'
10
10
  STATUS_LIVE_URL = 'https://www.timesofmoney.com/direcpay/secure/dpPullMerchAtrnDtls.jsp'
11
11
 
12
12
  attr_reader :account, :options
@@ -10,7 +10,7 @@ module ActiveMerchant #:nodoc:
10
10
  mattr_accessor :production_url, :test_url
11
11
 
12
12
  self.production_url = "https://www.timesofmoney.com/direcpay/secure/dpMerchantTransaction.jsp"
13
- self.test_url = "https://test.timesofmoney.com/direcpay/secure/dpMerchantTransaction.jsp"
13
+ self.test_url = "https://test.direcpay.com/direcpay/secure/dpMerchantTransaction.jsp"
14
14
 
15
15
  def self.service_url
16
16
  mode = ActiveMerchant::Billing::Base.integration_mode
@@ -0,0 +1,21 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ module Dwolla
5
+ module Common
6
+ def verify_signature(checkoutId, amount, notification_signature, secret)
7
+ if secret.nil?
8
+ raise ArgumentError, "You need to provide the Application secret as the option :credential3 to verify that the notification originated from Dwolla"
9
+ end
10
+
11
+ expected_signature = Digest::SHA1.hexdigest(secret + ('%s&%.2f' % [checkoutId, amount]))
12
+
13
+ if notification_signature != expected_signature
14
+ raise StandardError, "Dwolla signature verification failed."
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,29 +1,38 @@
1
+ require 'digest/sha1'
2
+
1
3
  module ActiveMerchant #:nodoc:
2
4
  module Billing #:nodoc:
3
5
  module Integrations #:nodoc:
4
6
  module Dwolla
5
7
  class Helper < ActiveMerchant::Billing::Integrations::Helper
6
-
7
8
  def initialize(order, account, options = {})
8
9
  super
9
10
  add_field('name', 'Store Purchase')
10
11
 
11
12
  if ActiveMerchant::Billing::Base.integration_mode == :test || options[:test]
12
13
  add_field('test', 'true')
13
- end
14
+ end
15
+
16
+ timestamp = Time.now.to_i.to_s
17
+ add_field('timestamp', timestamp)
18
+ add_field('allowFundingSources', 'true')
19
+
20
+ key = options[:credential2].to_s
21
+ secret = options[:credential3].to_s
22
+ orderid = order.to_s
23
+ signature = Digest::SHA1.hexdigest(secret + "#{key}&#{timestamp}&#{orderid}")
24
+ add_field('signature', signature)
14
25
  end
15
-
16
- # Replace with the real mapping
26
+
17
27
  mapping :account, 'destinationid'
18
28
  mapping :credential2, 'key'
19
- mapping :credential3, 'secret'
20
29
  mapping :notify_url, 'callback'
21
30
  mapping :return_url, 'redirect'
22
31
  mapping :description, 'description'
23
32
  mapping :amount, 'amount'
24
33
  mapping :tax, 'tax'
25
34
  mapping :shipping, 'shipping'
26
- mapping :order, 'orderid'
35
+ mapping :order, 'orderid'
27
36
  end
28
37
  end
29
38
  end
@@ -1,12 +1,15 @@
1
1
  require 'net/http'
2
+ require 'digest/sha1'
2
3
 
3
4
  module ActiveMerchant #:nodoc:
4
5
  module Billing #:nodoc:
5
6
  module Integrations #:nodoc:
6
7
  module Dwolla
7
8
  class Notification < ActiveMerchant::Billing::Integrations::Notification
9
+ include Common
10
+
8
11
  def complete?
9
- status == "Completed"
12
+ (status == "Completed")
10
13
  end
11
14
 
12
15
  def status
@@ -30,22 +33,24 @@ module ActiveMerchant #:nodoc:
30
33
  end
31
34
 
32
35
  def error
33
- params['Message']
36
+ params['Error']
34
37
  end
35
38
 
36
- # Was this a test transaction?
37
39
  def test?
38
40
  params['TestMode']
39
41
  end
40
42
 
41
- def acknowledge
43
+ def acknowledge
42
44
  true
43
45
  end
44
- private
45
- # Take the posted data and move the relevant data into a hash
46
+
47
+ private
48
+
46
49
  def parse(post)
47
50
  @raw = post.to_s
48
51
  json_post = JSON.parse(post)
52
+ verify_signature(json_post['CheckoutId'], json_post['Amount'], json_post['Signature'], @options[:credential3])
53
+
49
54
  params.merge!(json_post)
50
55
  end
51
56
  end
@@ -3,9 +3,17 @@ module ActiveMerchant #:nodoc:
3
3
  module Integrations #:nodoc:
4
4
  module Dwolla
5
5
  class Return < ActiveMerchant::Billing::Integrations::Return
6
+ include Common
7
+
8
+ def initialize(data, options)
9
+ params = parse(data)
10
+ verify_signature(params['checkoutId'], params['amount'], params['signature'], options[:credential3])
11
+
12
+ super
13
+ end
6
14
 
7
15
  def success?
8
- self.error.nil? && self.callback_success?
16
+ (self.error.nil? && self.callback_success?)
9
17
  end
10
18
 
11
19
  def error
@@ -17,7 +25,7 @@ module ActiveMerchant #:nodoc:
17
25
  end
18
26
 
19
27
  def checkout_id
20
- params['checkoutid']
28
+ params['checkoutId']
21
29
  end
22
30
 
23
31
  def transaction
@@ -29,9 +37,9 @@ module ActiveMerchant #:nodoc:
29
37
  end
30
38
 
31
39
  def callback_success?
32
- params['postback'] != "failure"
40
+ (params['postback'] != "failure")
33
41
  end
34
- end
42
+ end
35
43
  end
36
44
  end
37
45
  end
@@ -1,28 +1,21 @@
1
- # All mappings in helper.rb are required fields to be sent to Dwolla.
2
- # :account = 'Dwolla Id of merchant'
3
- # :credential1 = 'key from Dwolla Application'
4
- # :credential2 = 'secret from Dwolla Application'
5
- # :redirect_url = 'can be different that what is specified on Dwolla Application creation'
6
- # :return_url = 'can be different that what is specified on Dwolla Application creation'
7
- # :order_id = must be unique for each transaction
8
-
9
1
  module ActiveMerchant #:nodoc:
10
2
  module Billing #:nodoc:
11
3
  module Integrations #:nodoc:
12
- module Dwolla
4
+ module Dwolla
13
5
  autoload :Return, 'active_merchant/billing/integrations/dwolla/return.rb'
14
6
  autoload :Helper, 'active_merchant/billing/integrations/dwolla/helper.rb'
15
7
  autoload :Notification, 'active_merchant/billing/integrations/dwolla/notification.rb'
16
-
8
+ autoload :Common, 'active_merchant/billing/integrations/dwolla/common.rb'
9
+
17
10
  mattr_accessor :service_url
18
11
  self.service_url = 'https://www.dwolla.com/payment/pay'
19
12
 
20
13
  def self.notification(post, options={})
21
- Notification.new(post)
14
+ Notification.new(post, options)
22
15
  end
23
16
 
24
17
  def self.return(query_string, options={})
25
- Return.new(query_string)
18
+ Return.new(query_string, options)
26
19
  end
27
20
  end
28
21
  end
@@ -4,10 +4,15 @@ module ActiveMerchant #:nodoc:
4
4
  class Notification
5
5
  attr_accessor :params
6
6
  attr_accessor :raw
7
-
8
- # set this to an array in the subclass, to specify which IPs are allowed to send requests
7
+
8
+ # set this to an array in the subclass, to specify which IPs are allowed
9
+ # to send requests
9
10
  class_attribute :production_ips
10
11
 
12
+ # * *Args* :
13
+ # - +doc+ -> raw post string
14
+ # - +options+ -> custom options which individual implementations can
15
+ # utilize
11
16
  def initialize(post, options = {})
12
17
  @options = options
13
18
  empty!
@@ -27,19 +32,19 @@ module ActiveMerchant #:nodoc:
27
32
  (gross.to_f * 100.0).round
28
33
  end
29
34
 
30
- # This combines the gross and currency and returns a proper Money object.
35
+ # This combines the gross and currency and returns a proper Money object.
31
36
  # this requires the money library located at http://dist.leetsoft.com/api/money
32
37
  def amount
33
38
  return Money.new(gross_cents, currency) rescue ArgumentError
34
39
  return Money.new(gross_cents) # maybe you have an own money object which doesn't take a currency?
35
40
  end
36
41
 
37
- # reset the notification.
42
+ # reset the notification.
38
43
  def empty!
39
44
  @params = Hash.new
40
- @raw = ""
45
+ @raw = ""
41
46
  end
42
-
47
+
43
48
  # Check if the request comes from an official IP
44
49
  def valid_sender?(ip)
45
50
  return true if ActiveMerchant::Billing::Base.integration_mode == :test || production_ips.blank?
@@ -49,13 +54,13 @@ module ActiveMerchant #:nodoc:
49
54
  def test?
50
55
  false
51
56
  end
52
-
57
+
53
58
  private
54
59
 
55
60
  # Take the posted data and move the relevant data into a hash
56
61
  def parse(post)
57
62
  @raw = post.to_s
58
- for line in @raw.split('&')
63
+ for line in @raw.split('&')
59
64
  key, value = *line.scan( %r{^([A-Za-z0-9_.]+)\=(.*)$} ).flatten
60
65
  params[key] = CGI.unescape(value)
61
66
  end
@@ -35,7 +35,7 @@ module ActiveMerchant #:nodoc:
35
35
  mapping :customer, { :first_name => 'first_name', :last_name => 'last_name' }
36
36
 
37
37
  def description(value)
38
- add_field('description', "#{value}".delete("#"))
38
+ add_field('description', normalize("#{value}").delete("#"))
39
39
  end
40
40
 
41
41
  def customer(params = {})
@@ -97,6 +97,18 @@ module ActiveMerchant #:nodoc:
97
97
 
98
98
  [response['SECURETOKEN'], response['SECURETOKENID']] if response['RESPMSG'] && response['RESPMSG'].downcase == "approved"
99
99
  end
100
+
101
+ def normalize(text)
102
+ return unless text
103
+
104
+ if ActiveSupport::Inflector.method(:transliterate).arity == -2
105
+ ActiveSupport::Inflector.transliterate(text,'')
106
+ elsif RUBY_VERSION >= '1.9'
107
+ text.gsub(/[^\x00-\x7F]+/, '')
108
+ else
109
+ ActiveSupport::Inflector.transliterate(text).to_s
110
+ end
111
+ end
100
112
  end
101
113
  end
102
114
  end
@@ -0,0 +1,74 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ module PayuIn
5
+ class Helper < ActiveMerchant::Billing::Integrations::Helper
6
+
7
+ mapping :amount, 'amount'
8
+ mapping :account, 'key'
9
+ mapping :order, 'txnid'
10
+ mapping :credential2, 'productinfo'
11
+
12
+ mapping :customer, :first_name => 'firstname',
13
+ :last_name => 'lastname',
14
+ :email => 'email',
15
+ :phone => 'phone'
16
+
17
+ mapping :billing_address, :city => 'city',
18
+ :address1 => 'address1',
19
+ :address2 => 'address2',
20
+ :state => 'state',
21
+ :zip => 'zip',
22
+ :country => 'country'
23
+
24
+ # Which tab you want to be open default on PayU
25
+ # CC (CreditCard) or NB (NetBanking)
26
+ mapping :mode, 'pg'
27
+
28
+ mapping :notify_url, 'notify_url'
29
+ mapping :return_url, ['surl', 'furl']
30
+ mapping :cancel_return_url, 'curl'
31
+ mapping :checksum, 'hash'
32
+
33
+ mapping :user_defined, { :var1 => 'udf1',
34
+ :var2 => 'udf2',
35
+ :var3 => 'udf3',
36
+ :var4 => 'udf4',
37
+ :var5 => 'udf5',
38
+ :var6 => 'udf6',
39
+ :var7 => 'udf7',
40
+ :var8 => 'udf8',
41
+ :var9 => 'udf9',
42
+ :var10 => 'udf10'
43
+ }
44
+
45
+ def initialize(order, account, options = {})
46
+ super
47
+ self.pg = 'CC'
48
+ end
49
+
50
+ def form_fields
51
+ @fields.merge(mappings[:checksum] => generate_checksum)
52
+ end
53
+
54
+ def generate_checksum( options = {} )
55
+ checksum_fields = [ :order, :amount, :credential2, { :customer => [ :first_name, :email ] },
56
+ { :user_defined => [ :var1, :var2, :var3, :var4, :var5, :var6, :var7, :var8, :var9, :var10 ] } ]
57
+ checksum_payload_items = checksum_fields.inject( [] ) do | items, field |
58
+ if Hash === field then
59
+ key = field.keys.first
60
+ field[key].inject( items ){ |s,x| items.push( @fields[ mappings[key][x] ] ) }
61
+ else
62
+ items.push( @fields[ mappings[field] ] )
63
+ end
64
+ end
65
+ checksum_payload_items.push( options )
66
+ PayuIn.checksum(@fields["key"], @fields["productinfo"], *checksum_payload_items )
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+ end
73
+ end
74
+ end