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.
- data/CHANGELOG +50 -0
- data/CONTRIBUTORS +8 -0
- data/README.md +6 -4
- data/lib/active_merchant/billing/check.rb +4 -3
- data/lib/active_merchant/billing/credit_card.rb +7 -3
- data/lib/active_merchant/billing/gateways/authorize_net.rb +27 -7
- data/lib/active_merchant/billing/gateways/barclays_epdq.rb +8 -1
- data/lib/active_merchant/billing/gateways/blue_pay.rb +201 -185
- data/lib/active_merchant/billing/gateways/bogus.rb +1 -1
- data/lib/active_merchant/billing/gateways/card_stream_modern.rb +155 -0
- data/lib/active_merchant/billing/gateways/cc5.rb +0 -4
- data/lib/active_merchant/billing/gateways/firstdata_e4.rb +94 -12
- data/lib/active_merchant/billing/gateways/garanti.rb +0 -4
- data/lib/active_merchant/billing/gateways/litle.rb +41 -11
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +27 -6
- data/lib/active_merchant/billing/gateways/merchant_warrior.rb +2 -2
- data/lib/active_merchant/billing/gateways/net_registry.rb +8 -3
- data/lib/active_merchant/billing/gateways/netaxept.rb +65 -117
- data/lib/active_merchant/billing/gateways/orbital.rb +181 -48
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +12 -10
- data/lib/active_merchant/billing/gateways/paymill.rb +27 -13
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +11 -6
- data/lib/active_merchant/billing/gateways/paypal_express.rb +25 -7
- data/lib/active_merchant/billing/gateways/pin.rb +5 -5
- data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +16 -11
- data/lib/active_merchant/billing/gateways/sage/sage_core.rb +1 -1
- data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +21 -16
- data/lib/active_merchant/billing/gateways/sage.rb +10 -5
- data/lib/active_merchant/billing/gateways/sage_pay.rb +1 -0
- data/lib/active_merchant/billing/gateways/transnational.rb +239 -0
- data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +9 -4
- data/lib/active_merchant/billing/integrations/direc_pay/status.rb +1 -1
- data/lib/active_merchant/billing/integrations/direc_pay.rb +1 -1
- data/lib/active_merchant/billing/integrations/dwolla/common.rb +21 -0
- data/lib/active_merchant/billing/integrations/dwolla/helper.rb +15 -6
- data/lib/active_merchant/billing/integrations/dwolla/notification.rb +11 -6
- data/lib/active_merchant/billing/integrations/dwolla/return.rb +12 -4
- data/lib/active_merchant/billing/integrations/dwolla.rb +5 -12
- data/lib/active_merchant/billing/integrations/notification.rb +13 -8
- data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +13 -1
- data/lib/active_merchant/billing/integrations/payu_in/helper.rb +74 -0
- data/lib/active_merchant/billing/integrations/payu_in/notification.rb +167 -0
- data/lib/active_merchant/billing/integrations/payu_in/return.rb +53 -0
- data/lib/active_merchant/billing/integrations/payu_in.rb +43 -0
- data/lib/active_merchant/billing/integrations/quickpay/notification.rb +68 -5
- data/lib/active_merchant/billing/integrations/rbkmoney/helper.rb +23 -0
- data/lib/active_merchant/billing/integrations/rbkmoney/notification.rb +91 -0
- data/lib/active_merchant/billing/integrations/rbkmoney.rb +17 -0
- data/lib/active_merchant/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +72 -62
- 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, '
|
|
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
|
-
#
|
|
286
|
+
# Refund a previous transaction.
|
|
287
287
|
#
|
|
288
288
|
# Note: See run_transaction for additional options.
|
|
289
289
|
#
|
|
290
|
-
def
|
|
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].
|
|
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.
|
|
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.
|
|
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['
|
|
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
|
-
|
|
45
|
-
|
|
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['
|
|
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
|
-
|
|
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
|
|
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
|