activemerchant 1.29.1 → 1.34.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 (92) hide show
  1. data/CHANGELOG +143 -0
  2. data/CONTRIBUTORS +43 -0
  3. data/README.md +59 -51
  4. data/lib/active_merchant/billing/check.rb +15 -14
  5. data/lib/active_merchant/billing/credit_card.rb +14 -5
  6. data/lib/active_merchant/billing/credit_card_formatting.rb +8 -8
  7. data/lib/active_merchant/billing/gateway.rb +2 -2
  8. data/lib/active_merchant/billing/gateways/authorize_net.rb +36 -8
  9. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +17 -5
  10. data/lib/active_merchant/billing/gateways/balanced.rb +9 -3
  11. data/lib/active_merchant/billing/gateways/banwire.rb +15 -1
  12. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +8 -1
  13. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +7 -2
  14. data/lib/active_merchant/billing/gateways/beanstream.rb +26 -24
  15. data/lib/active_merchant/billing/gateways/blue_pay.rb +201 -187
  16. data/lib/active_merchant/billing/gateways/bogus.rb +1 -1
  17. data/lib/active_merchant/billing/gateways/braintree_blue.rb +7 -3
  18. data/lib/active_merchant/billing/gateways/card_stream_modern.rb +155 -0
  19. data/lib/active_merchant/billing/gateways/cc5.rb +156 -0
  20. data/lib/active_merchant/billing/gateways/cyber_source.rb +55 -22
  21. data/lib/active_merchant/billing/gateways/data_cash.rb +3 -3
  22. data/lib/active_merchant/billing/gateways/evo_ca.rb +308 -0
  23. data/lib/active_merchant/billing/gateways/eway.rb +114 -171
  24. data/lib/active_merchant/billing/gateways/eway_managed.rb +52 -22
  25. data/lib/active_merchant/billing/gateways/finansbank.rb +22 -0
  26. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +314 -0
  27. data/lib/active_merchant/billing/gateways/garanti.rb +0 -4
  28. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +13 -2
  29. data/lib/active_merchant/billing/gateways/iridium.rb +8 -2
  30. data/lib/active_merchant/billing/gateways/litle.rb +354 -105
  31. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +28 -7
  32. data/lib/active_merchant/billing/gateways/merchant_ware.rb +44 -9
  33. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +190 -0
  34. data/lib/active_merchant/billing/gateways/moneris.rb +4 -6
  35. data/lib/active_merchant/billing/gateways/moneris_us.rb +1 -1
  36. data/lib/active_merchant/billing/gateways/nab_transact.rb +20 -3
  37. data/lib/active_merchant/billing/gateways/net_registry.rb +8 -3
  38. data/lib/active_merchant/billing/gateways/netaxept.rb +65 -117
  39. data/lib/active_merchant/billing/gateways/netbilling.rb +1 -0
  40. data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
  41. data/lib/active_merchant/billing/gateways/ogone.rb +7 -5
  42. data/lib/active_merchant/billing/gateways/optimal_payment.rb +43 -18
  43. data/lib/active_merchant/billing/gateways/orbital.rb +190 -53
  44. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +12 -10
  45. data/lib/active_merchant/billing/gateways/payment_express.rb +62 -1
  46. data/lib/active_merchant/billing/gateways/paymill.rb +179 -0
  47. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +12 -7
  48. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +14 -9
  49. data/lib/active_merchant/billing/gateways/paypal_express.rb +59 -18
  50. data/lib/active_merchant/billing/gateways/pin.rb +165 -0
  51. data/lib/active_merchant/billing/gateways/qbms.rb +3 -2
  52. data/lib/active_merchant/billing/gateways/quickpay.rb +66 -28
  53. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +16 -11
  54. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +1 -1
  55. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +21 -16
  56. data/lib/active_merchant/billing/gateways/sage.rb +10 -5
  57. data/lib/active_merchant/billing/gateways/sage_pay.rb +7 -0
  58. data/lib/active_merchant/billing/gateways/smart_ps.rb +1 -1
  59. data/lib/active_merchant/billing/gateways/spreedly_core.rb +233 -0
  60. data/lib/active_merchant/billing/gateways/stripe.rb +49 -21
  61. data/lib/active_merchant/billing/gateways/transnational.rb +239 -0
  62. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +9 -4
  63. data/lib/active_merchant/billing/gateways/webpay.rb +8 -0
  64. data/lib/active_merchant/billing/gateways/wirecard.rb +15 -9
  65. data/lib/active_merchant/billing/gateways/worldpay.rb +60 -24
  66. data/lib/active_merchant/billing/integrations/direc_pay/status.rb +1 -1
  67. data/lib/active_merchant/billing/integrations/direc_pay.rb +1 -1
  68. data/lib/active_merchant/billing/integrations/dwolla/common.rb +23 -0
  69. data/lib/active_merchant/billing/integrations/dwolla/helper.rb +18 -6
  70. data/lib/active_merchant/billing/integrations/dwolla/notification.rb +16 -7
  71. data/lib/active_merchant/billing/integrations/dwolla/return.rb +16 -5
  72. data/lib/active_merchant/billing/integrations/dwolla.rb +5 -12
  73. data/lib/active_merchant/billing/integrations/notification.rb +13 -8
  74. data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +19 -3
  75. data/lib/active_merchant/billing/integrations/paypal/notification.rb +39 -31
  76. data/lib/active_merchant/billing/integrations/payu_in/helper.rb +74 -0
  77. data/lib/active_merchant/billing/integrations/payu_in/notification.rb +167 -0
  78. data/lib/active_merchant/billing/integrations/payu_in/return.rb +53 -0
  79. data/lib/active_merchant/billing/integrations/payu_in.rb +43 -0
  80. data/lib/active_merchant/billing/integrations/pxpay/helper.rb +1 -0
  81. data/lib/active_merchant/billing/integrations/quickpay/helper.rb +13 -10
  82. data/lib/active_merchant/billing/integrations/quickpay/notification.rb +78 -15
  83. data/lib/active_merchant/billing/integrations/rbkmoney/helper.rb +23 -0
  84. data/lib/active_merchant/billing/integrations/rbkmoney/notification.rb +91 -0
  85. data/lib/active_merchant/billing/integrations/rbkmoney.rb +17 -0
  86. data/lib/active_merchant/billing/integrations/robokassa/common.rb +1 -1
  87. data/lib/active_merchant/billing/integrations/sage_pay_form/helper.rb +7 -3
  88. data/lib/active_merchant/billing/integrations/world_pay.rb +15 -8
  89. data/lib/active_merchant/version.rb +1 -1
  90. data.tar.gz.sig +0 -0
  91. metadata +124 -50
  92. metadata.gz.sig +0 -0
@@ -1,5 +1,3 @@
1
- require 'json'
2
-
3
1
  module ActiveMerchant #:nodoc:
4
2
  module Billing #:nodoc:
5
3
  class StripeGateway < Gateway
@@ -35,6 +33,14 @@ module ActiveMerchant #:nodoc:
35
33
  super
36
34
  end
37
35
 
36
+ def authorize(money, creditcard, options = {})
37
+ post = create_post_for_auth_or_purchase(money, creditcard, options)
38
+ post[:capture] = "false"
39
+ meta = generate_meta(options)
40
+
41
+ commit(:post, 'charges', post, meta)
42
+ end
43
+
38
44
  # To create a charge on a card or a token, call
39
45
  #
40
46
  # purchase(money, card_hash_or_token, { ... })
@@ -43,22 +49,20 @@ module ActiveMerchant #:nodoc:
43
49
  #
44
50
  # purchase(money, nil, { :customer => id, ... })
45
51
  def purchase(money, creditcard, options = {})
46
- post = {}
47
-
48
- add_amount(post, money, options)
49
- add_creditcard(post, creditcard, options)
50
- add_customer(post, options)
51
- add_customer_data(post,options)
52
- post[:description] = options[:description] || options[:email]
53
- add_flags(post, options)
54
-
52
+ post = create_post_for_auth_or_purchase(money, creditcard, options)
55
53
  meta = generate_meta(options)
56
54
 
57
- raise ArgumentError.new("Customer or Credit Card required.") if !post[:card] && !post[:customer]
58
-
59
55
  commit(:post, 'charges', post, meta)
60
56
  end
61
57
 
58
+ def capture(money, authorization, options = {})
59
+ post = {}
60
+ post[:amount] = amount(money)
61
+ add_application_fee(post, options)
62
+
63
+ commit(:post, "charges/#{CGI.escape(authorization)}/capture", post)
64
+ end
65
+
62
66
  def void(identification, options = {})
63
67
  commit(:post, "charges/#{CGI.escape(identification)}/refund", {})
64
68
  end
@@ -100,11 +104,27 @@ module ActiveMerchant #:nodoc:
100
104
 
101
105
  private
102
106
 
107
+ def create_post_for_auth_or_purchase(money, creditcard, options)
108
+ post = {}
109
+ add_amount(post, money, options)
110
+ add_creditcard(post, creditcard, options)
111
+ add_customer(post, options)
112
+ add_customer_data(post,options)
113
+ post[:description] = options[:description] || options[:email]
114
+ add_flags(post, options)
115
+ add_application_fee(post, options)
116
+ post
117
+ end
118
+
103
119
  def add_amount(post, money, options)
104
120
  post[:amount] = amount(money)
105
121
  post[:currency] = (options[:currency] || currency(money)).downcase
106
122
  end
107
123
 
124
+ def add_application_fee(post, options)
125
+ post[:application_fee] = options[:application_fee] if options[:application_fee]
126
+ end
127
+
108
128
  def add_customer_data(post, options)
109
129
  metadata_options = [:description,:browser_ip,:user_agent,:referrer]
110
130
  post.update(options.slice(*metadata_options))
@@ -126,19 +146,27 @@ module ActiveMerchant #:nodoc:
126
146
  end
127
147
 
128
148
  def add_creditcard(post, creditcard, options)
149
+ card = {}
129
150
  if creditcard.respond_to?(:number)
130
- card = {}
131
- card[:number] = creditcard.number
132
- card[:exp_month] = creditcard.month
133
- card[:exp_year] = creditcard.year
134
- card[:cvc] = creditcard.verification_value if creditcard.verification_value?
135
- card[:name] = creditcard.name if creditcard.name
136
- post[:card] = card
151
+ if creditcard.respond_to?(:track_data) && creditcard.track_data.present?
152
+ card[:swipe_data] = creditcard.track_data
153
+ else
154
+ card[:number] = creditcard.number
155
+ card[:exp_month] = creditcard.month
156
+ card[:exp_year] = creditcard.year
157
+ card[:cvc] = creditcard.verification_value if creditcard.verification_value?
158
+ card[:name] = creditcard.name if creditcard.name
159
+ end
137
160
 
138
161
  add_address(post, options)
139
162
  elsif creditcard.kind_of?(String)
140
- post[:card] = creditcard
163
+ if options[:track_data]
164
+ card[:swipe_data] = options[:track_data]
165
+ else
166
+ card[:number] = creditcard
167
+ end
141
168
  end
169
+ post[:card] = card
142
170
  end
143
171
 
144
172
  def add_customer(post, options)
@@ -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|
@@ -13,6 +13,14 @@ module ActiveMerchant #:nodoc:
13
13
  self.homepage_url = 'https://webpay.jp/'
14
14
  self.display_name = 'WebPay'
15
15
 
16
+ def authorize(money, credit_card, options = {})
17
+ raise NotImplementedError.new
18
+ end
19
+
20
+ def capture(money, credit_card, options = {})
21
+ raise NotImplementedError.new
22
+ end
23
+
16
24
  def json_error(raw_response)
17
25
  msg = 'Invalid response received from the WebPay API. Please contact support@webpay.jp if you continue to receive this message.'
18
26
  msg += " (The raw response returned by the API was #{raw_response.inspect})"
@@ -16,7 +16,7 @@ module ActiveMerchant #:nodoc:
16
16
  'xsi:noNamespaceSchemaLocation' => 'wirecard.xsd'
17
17
  }
18
18
 
19
- PERMITTED_TRANSACTIONS = %w[ AUTHORIZATION CAPTURE_AUTHORIZATION PURCHASE ]
19
+ PERMITTED_TRANSACTIONS = %w[ PREAUTHORIZATION CAPTURE PURCHASE ]
20
20
 
21
21
  RETURN_CODES = %w[ ACK NOK ]
22
22
 
@@ -63,13 +63,13 @@ module ActiveMerchant #:nodoc:
63
63
  # Authorization
64
64
  def authorize(money, creditcard, options = {})
65
65
  options[:credit_card] = creditcard
66
- commit(:authorization, money, options)
66
+ commit(:preauthorization, money, options)
67
67
  end
68
68
 
69
69
  # Capture Authorization
70
70
  def capture(money, authorization, options = {})
71
- options[:authorization] = authorization
72
- commit(:capture_authorization, money, options)
71
+ options[:preauthorization] = authorization
72
+ commit(:capture, money, options)
73
73
  end
74
74
 
75
75
  # Purchase
@@ -148,16 +148,17 @@ module ActiveMerchant #:nodoc:
148
148
  options[:order_id] ||= generate_unique_id
149
149
 
150
150
  xml.tag! "FNC_CC_#{options[:action].to_s.upcase}" do
151
- xml.tag! 'FunctionID', options[:description]
151
+ xml.tag! 'FunctionID', options[:description].to_s.slice(0,32)
152
152
  xml.tag! 'CC_TRANSACTION' do
153
153
  xml.tag! 'TransactionID', options[:order_id]
154
154
  case options[:action]
155
- when :authorization, :purchase
155
+ when :preauthorization, :purchase
156
156
  add_invoice(xml, money, options)
157
157
  add_creditcard(xml, options[:credit_card])
158
158
  add_address(xml, options[:billing_address])
159
- when :capture_authorization
160
- xml.tag! 'GuWID', options[:authorization]
159
+ when :capture
160
+ xml.tag! 'GuWID', options[:preauthorization]
161
+ add_amount(xml, money)
161
162
  end
162
163
  end
163
164
  end
@@ -165,7 +166,7 @@ module ActiveMerchant #:nodoc:
165
166
 
166
167
  # Includes the payment (amount, currency, country) to the transaction-xml
167
168
  def add_invoice(xml, money, options)
168
- xml.tag! 'Amount', amount(money)
169
+ add_amount(xml, money)
169
170
  xml.tag! 'Currency', options[:currency] || currency(money)
170
171
  xml.tag! 'CountryCode', options[:billing_address][:country]
171
172
  xml.tag! 'RECURRING_TRANSACTION' do
@@ -173,6 +174,11 @@ module ActiveMerchant #:nodoc:
173
174
  end
174
175
  end
175
176
 
177
+ # Include the amount in the transaction-xml
178
+ def add_amount(xml, money)
179
+ xml.tag! 'Amount', amount(money)
180
+ end
181
+
176
182
  # Includes the credit-card data to the transaction-xml
177
183
  def add_creditcard(xml, creditcard)
178
184
  raise "Creditcard must be supplied!" if creditcard.nil?
@@ -16,6 +16,9 @@ module ActiveMerchant #:nodoc:
16
16
  'master' => 'ECMC-SSL',
17
17
  'discover' => 'DISCOVER-SSL',
18
18
  'american_express' => 'AMEX-SSL',
19
+ 'jcb' => 'JCB-SSL',
20
+ 'maestro' => 'MAESTRO-SSL',
21
+ 'laser' => 'LASER-SSL'
19
22
  }
20
23
 
21
24
  def initialize(options = {})
@@ -38,6 +41,10 @@ module ActiveMerchant #:nodoc:
38
41
  def capture(money, authorization, options = {})
39
42
  MultiResponse.run do |r|
40
43
  r.process{inquire_request(authorization, options, "AUTHORISED")} unless options[:authorization_validated]
44
+ if r.params
45
+ authorization_currency = r.params['amount_currency_code']
46
+ options = options.merge(:currency => authorization_currency) if authorization_currency.present?
47
+ end
41
48
  r.process{capture_request(money, authorization, options)}
42
49
  end
43
50
  end
@@ -51,7 +58,7 @@ module ActiveMerchant #:nodoc:
51
58
 
52
59
  def refund(money, authorization, options = {})
53
60
  MultiResponse.run do |r|
54
- r.process{inquire_request(authorization, options, "CAPTURED")}
61
+ r.process{inquire_request(authorization, options, "CAPTURED", "SETTLED")}
55
62
  r.process{refund_request(money, authorization, options)}
56
63
  end
57
64
  end
@@ -70,17 +77,17 @@ module ActiveMerchant #:nodoc:
70
77
  commit('cancel', build_void_request(authorization, options), :ok)
71
78
  end
72
79
 
73
- def inquire_request(authorization, options, success_criteria)
74
- commit('inquiry', build_order_inquiry_request(authorization, options), success_criteria)
80
+ def inquire_request(authorization, options, *success_criteria)
81
+ commit('inquiry', build_order_inquiry_request(authorization, options), *success_criteria)
75
82
  end
76
83
 
77
84
  def refund_request(money, authorization, options)
78
- commit('inquiry', build_refund_request(money, authorization, options), :ok)
85
+ commit('refund', build_refund_request(money, authorization, options), :ok)
79
86
  end
80
87
 
81
88
  def build_request
82
89
  xml = Builder::XmlMarkup.new :indent => 2
83
- xml.instruct!
90
+ xml.instruct! :xml, :encoding => 'ISO-8859-1'
84
91
  xml.declare! :DOCTYPE, :paymentService, :PUBLIC, "-//WorldPay//DTD WorldPay PaymentService v1//EN", "http://dtd.wp3.rbsworldpay.com/paymentService_v1.dtd"
85
92
  xml.tag! 'paymentService', 'version' => "1.4", 'merchantCode' => @options[:login] do
86
93
  yield xml
@@ -142,16 +149,26 @@ module ActiveMerchant #:nodoc:
142
149
  def build_refund_request(money, authorization, options)
143
150
  build_order_modify_request(authorization) do |xml|
144
151
  xml.tag! 'refund' do
145
- add_amount(xml, money, options)
152
+ add_amount(xml, money, options.merge(:debit_credit_indicator => "credit"))
146
153
  end
147
154
  end
148
155
  end
149
156
 
150
157
  def add_amount(xml, money, options)
151
- xml.tag! 'amount',
152
- :value => amount(money),
153
- 'currencyCode' => (options[:currency] || currency(money)),
158
+ currency = options[:currency] || currency(money)
159
+ amount = localized_amount(money, currency)
160
+
161
+ amount_hash = {
162
+ :value => amount,
163
+ 'currencyCode' => currency,
154
164
  'exponent' => 2
165
+ }
166
+
167
+ if options[:debit_credit_indicator]
168
+ amount_hash.merge!('debitCreditIndicator' => options[:debit_credit_indicator])
169
+ end
170
+
171
+ xml.tag! 'amount', amount_hash
155
172
  end
156
173
 
157
174
  def add_payment_method(xml, amount, payment_method, options)
@@ -219,20 +236,18 @@ module ActiveMerchant #:nodoc:
219
236
  raw
220
237
  end
221
238
 
222
- def commit(action, request, success_criteria)
223
- xmr = ssl_post((test? ? self.test_url : self.live_url),
224
- request,
225
- 'Content-Type' => 'text/xml',
226
- 'Authorization' => encoded_credentials)
227
-
239
+ def commit(action, request, *success_criteria)
240
+ xmr = ssl_post(url, request, 'Content-Type' => 'text/xml', 'Authorization' => encoded_credentials)
228
241
  raw = parse(action, xmr)
242
+ success, message = success_and_message_from(raw, success_criteria)
229
243
 
230
244
  Response.new(
231
- success_from(raw, success_criteria),
232
- message_from(raw),
245
+ success,
246
+ message,
233
247
  raw,
234
248
  :authorization => authorization_from(raw),
235
249
  :test => test?)
250
+
236
251
  rescue ActiveMerchant::ResponseError => e
237
252
  if e.response.code.to_s == "401"
238
253
  return Response.new(false, "Invalid credentials", {}, :test => test?)
@@ -241,15 +256,29 @@ module ActiveMerchant #:nodoc:
241
256
  end
242
257
  end
243
258
 
244
- def success_from(raw, success_criteria)
245
- (raw[:last_event] == success_criteria ||
246
- raw[:ok].present?)
259
+ def url
260
+ test? ? self.test_url : self.live_url
247
261
  end
248
262
 
249
- def message_from(raw)
250
- (raw[:iso8583_return_code_description] ||
251
- raw[:error] ||
252
- "SUCCESS")
263
+ # success_criteria can be:
264
+ # - a string or an array of strings (if one of many responses)
265
+ # - An array of strings if one of many responses could be considered a
266
+ # success.
267
+ def success_and_message_from(raw, success_criteria)
268
+ success = (success_criteria.include?(raw[:last_event]) || raw[:ok].present?)
269
+ if success
270
+ message = "SUCCESS"
271
+ else
272
+ message = (raw[:iso8583_return_code_description] || raw[:error] || required_status_message(raw, success_criteria))
273
+ end
274
+
275
+ [ success, message ]
276
+ end
277
+
278
+ def required_status_message(raw, success_criteria)
279
+ if(!success_criteria.include?(raw[:last_event]))
280
+ "A transaction status of #{success_criteria.collect{|c| "'#{c}'"}.join(" or ")} is required."
281
+ end
253
282
  end
254
283
 
255
284
  def authorization_from(raw)
@@ -261,6 +290,13 @@ module ActiveMerchant #:nodoc:
261
290
  credentials = "#{@options[:login]}:#{@options[:password]}"
262
291
  "Basic #{[credentials].pack('m').strip}"
263
292
  end
293
+
294
+ def localized_amount(money, currency)
295
+ amount = amount(money)
296
+ return amount unless CURRENCIES_WITHOUT_FRACTIONS.include?(currency.to_s)
297
+
298
+ amount.to_i / 100 * 100
299
+ end
264
300
  end
265
301
  end
266
302
  end
@@ -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,23 @@
1
+ require "openssl"
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ module Integrations #:nodoc:
6
+ module Dwolla
7
+ module Common
8
+ def verify_signature(checkoutId, amount, notification_signature, secret)
9
+ if secret.nil?
10
+ raise ArgumentError, "You need to provide the Application secret as the option :credential3 to verify that the notification originated from Dwolla"
11
+ end
12
+
13
+ expected_signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, secret, "%s&%.2f" % [checkoutId, amount])
14
+
15
+ if notification_signature != expected_signature
16
+ raise StandardError, "Dwolla signature verification failed."
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end