better_offsite_payments 2.3.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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +76 -0
- data/lib/offsite_payments.rb +39 -0
- data/lib/offsite_payments/action_view_helper.rb +72 -0
- data/lib/offsite_payments/helper.rb +120 -0
- data/lib/offsite_payments/integrations.rb +14 -0
- data/lib/offsite_payments/integrations/a1agregator.rb +245 -0
- data/lib/offsite_payments/integrations/authorize_net_sim.rb +580 -0
- data/lib/offsite_payments/integrations/bit_pay.rb +150 -0
- data/lib/offsite_payments/integrations/bogus.rb +32 -0
- data/lib/offsite_payments/integrations/chronopay.rb +283 -0
- data/lib/offsite_payments/integrations/citrus.rb +227 -0
- data/lib/offsite_payments/integrations/coinbase.rb +172 -0
- data/lib/offsite_payments/integrations/direc_pay.rb +332 -0
- data/lib/offsite_payments/integrations/directebanking.rb +237 -0
- data/lib/offsite_payments/integrations/doku.rb +171 -0
- data/lib/offsite_payments/integrations/dotpay.rb +166 -0
- data/lib/offsite_payments/integrations/dwolla.rb +160 -0
- data/lib/offsite_payments/integrations/e_payment_plans.rb +146 -0
- data/lib/offsite_payments/integrations/easy_pay.rb +137 -0
- data/lib/offsite_payments/integrations/epay.rb +161 -0
- data/lib/offsite_payments/integrations/first_data.rb +133 -0
- data/lib/offsite_payments/integrations/gestpay.rb +205 -0
- data/lib/offsite_payments/integrations/hi_trust.rb +179 -0
- data/lib/offsite_payments/integrations/ipay88.rb +251 -0
- data/lib/offsite_payments/integrations/klarna.rb +275 -0
- data/lib/offsite_payments/integrations/liqpay.rb +216 -0
- data/lib/offsite_payments/integrations/maksuturva.rb +231 -0
- data/lib/offsite_payments/integrations/megakassa.rb +184 -0
- data/lib/offsite_payments/integrations/mollie.rb +32 -0
- data/lib/offsite_payments/integrations/mollie_ideal.rb +194 -0
- data/lib/offsite_payments/integrations/mollie_mistercash.rb +143 -0
- data/lib/offsite_payments/integrations/molpay.rb +193 -0
- data/lib/offsite_payments/integrations/moneybookers.rb +199 -0
- data/lib/offsite_payments/integrations/nochex.rb +228 -0
- data/lib/offsite_payments/integrations/pag_seguro.rb +268 -0
- data/lib/offsite_payments/integrations/paxum.rb +114 -0
- data/lib/offsite_payments/integrations/pay_fast.rb +269 -0
- data/lib/offsite_payments/integrations/paydollar.rb +142 -0
- data/lib/offsite_payments/integrations/payflow_link.rb +194 -0
- data/lib/offsite_payments/integrations/paypal.rb +362 -0
- data/lib/offsite_payments/integrations/paypal_payments_advanced.rb +23 -0
- data/lib/offsite_payments/integrations/paysbuy.rb +71 -0
- data/lib/offsite_payments/integrations/payu_in.rb +276 -0
- data/lib/offsite_payments/integrations/payu_in_paisa.rb +46 -0
- data/lib/offsite_payments/integrations/platron.rb +153 -0
- data/lib/offsite_payments/integrations/pxpay.rb +273 -0
- data/lib/offsite_payments/integrations/quickpay.rb +232 -0
- data/lib/offsite_payments/integrations/rbkmoney.rb +110 -0
- data/lib/offsite_payments/integrations/realex_offsite.rb +317 -0
- data/lib/offsite_payments/integrations/robokassa.rb +154 -0
- data/lib/offsite_payments/integrations/sage_pay_form.rb +431 -0
- data/lib/offsite_payments/integrations/two_checkout.rb +329 -0
- data/lib/offsite_payments/integrations/universal.rb +190 -0
- data/lib/offsite_payments/integrations/valitor.rb +200 -0
- data/lib/offsite_payments/integrations/verkkomaksut.rb +143 -0
- data/lib/offsite_payments/integrations/web_pay.rb +186 -0
- data/lib/offsite_payments/integrations/webmoney.rb +119 -0
- data/lib/offsite_payments/integrations/wirecard_checkout_page.rb +359 -0
- data/lib/offsite_payments/integrations/world_pay.rb +280 -0
- data/lib/offsite_payments/integrations/yandex_money.rb +175 -0
- data/lib/offsite_payments/notification.rb +71 -0
- data/lib/offsite_payments/return.rb +37 -0
- data/lib/offsite_payments/version.rb +3 -0
- metadata +297 -0
@@ -0,0 +1,280 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
module OffsitePayments #:nodoc:
|
3
|
+
module Integrations #:nodoc:
|
4
|
+
module WorldPay
|
5
|
+
mattr_accessor :production_url, :test_url
|
6
|
+
self.production_url = 'https://secure.worldpay.com/wcc/purchase'
|
7
|
+
self.test_url = 'https://secure-test.worldpay.com/wcc/purchase'
|
8
|
+
|
9
|
+
def self.service_url
|
10
|
+
case OffsitePayments.mode
|
11
|
+
when :production
|
12
|
+
self.production_url
|
13
|
+
when :test
|
14
|
+
self.test_url
|
15
|
+
else
|
16
|
+
raise StandardError, "Integration mode set to an invalid value: #{mode}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.notification(post, options = {})
|
21
|
+
Notification.new(post, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.return(post, options = {})
|
25
|
+
Return.new(post, options)
|
26
|
+
end
|
27
|
+
|
28
|
+
class Helper < OffsitePayments::Helper
|
29
|
+
mapping :account, 'instId'
|
30
|
+
mapping :amount, 'amount'
|
31
|
+
mapping :order, 'cartId'
|
32
|
+
mapping :currency, 'currency'
|
33
|
+
|
34
|
+
mapping :customer, :email => 'email',
|
35
|
+
:phone => 'tel'
|
36
|
+
|
37
|
+
mapping :billing_address, :zip => 'postcode',
|
38
|
+
:country => 'country'
|
39
|
+
|
40
|
+
mapping :description, 'desc'
|
41
|
+
mapping :notify_url, 'MC_callback'
|
42
|
+
mapping :return_url, 'MC_return'
|
43
|
+
|
44
|
+
# WorldPay supports two different test modes - :always_succeed and :always_fail
|
45
|
+
def initialize(order, account, options = {})
|
46
|
+
super
|
47
|
+
|
48
|
+
if OffsitePayments.mode == :test || options[:test]
|
49
|
+
test_mode = case options[:test]
|
50
|
+
when :always_fail
|
51
|
+
101
|
52
|
+
when false
|
53
|
+
0
|
54
|
+
else
|
55
|
+
100
|
56
|
+
end
|
57
|
+
add_field('testMode', test_mode.to_s)
|
58
|
+
elsif OffsitePayments.mode == :always_succeed
|
59
|
+
add_field('testMode', '100')
|
60
|
+
elsif OffsitePayments.mode == :always_fail
|
61
|
+
add_field('testMode', '101')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# WorldPay only supports a single address field so we
|
66
|
+
# have to concat together - lines are separated using
|
67
|
+
def billing_address(params={})
|
68
|
+
add_field(mappings[:billing_address][:zip], params[:zip])
|
69
|
+
add_field(mappings[:billing_address][:country], lookup_country_code(params[:country]))
|
70
|
+
|
71
|
+
address = [params[:address1], params[:address2], params[:city], params[:state]].compact
|
72
|
+
add_field('address', address.join(' '))
|
73
|
+
end
|
74
|
+
|
75
|
+
# WorldPay only supports a single name field so we have to concat
|
76
|
+
def customer(params={})
|
77
|
+
add_field(mappings[:customer][:email], params[:email])
|
78
|
+
add_field(mappings[:customer][:phone], params[:phone])
|
79
|
+
add_field('name', "#{params[:first_name]} #{params[:last_name]}")
|
80
|
+
end
|
81
|
+
|
82
|
+
# Support for a MD5 hash of selected fields to prevent tampering
|
83
|
+
# For further information read the tech note at the address below:
|
84
|
+
# http://support.worldpay.com/kb/integration_guides/junior/integration/help/tech_notes/sjig_tn_009.html
|
85
|
+
def encrypt(secret, fields = [:amount, :currency, :account, :order])
|
86
|
+
signature_fields = fields.collect{ |field| mappings[field] }
|
87
|
+
add_field('signatureFields', signature_fields.join(':'))
|
88
|
+
|
89
|
+
field_values = fields.collect{ |field| form_fields[mappings[field]] }
|
90
|
+
signature = "#{secret}:#{field_values.join(':')}"
|
91
|
+
add_field('signature', Digest::MD5.hexdigest(signature))
|
92
|
+
end
|
93
|
+
|
94
|
+
# Add a time window for which the payment can be completed. Read the link below for how they work
|
95
|
+
# http://support.worldpay.com/kb/integration_guides/junior/integration/help/appendicies/sjig_10100.html
|
96
|
+
def valid_from(from_time)
|
97
|
+
add_field('authValidFrom', from_time.to_i.to_s + '000')
|
98
|
+
end
|
99
|
+
|
100
|
+
def valid_to(to_time)
|
101
|
+
add_field('authValidTo', to_time.to_i.to_s + '000')
|
102
|
+
end
|
103
|
+
|
104
|
+
# WorldPay supports the passing of custom parameters prefixed with the following:
|
105
|
+
# C_ : These parameters can be used in the response pages hosted on WorldPay's site
|
106
|
+
# M_ : These parameters are passed through to the callback script (if enabled)
|
107
|
+
# MC_ or CM_ : These parameters are availble both in the response and callback contexts
|
108
|
+
def response_params(params={})
|
109
|
+
params.each{|k,v| add_field("C_#{k}",v)}
|
110
|
+
end
|
111
|
+
|
112
|
+
def callback_params(params={})
|
113
|
+
params.each{|k,v| add_field("M_#{k}",v)}
|
114
|
+
end
|
115
|
+
|
116
|
+
def combined_params(params={})
|
117
|
+
params.each{|k,v| add_field("MC_#{k}",v)}
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class Notification < OffsitePayments::Notification
|
122
|
+
def complete?
|
123
|
+
status == 'Completed'
|
124
|
+
end
|
125
|
+
|
126
|
+
def account
|
127
|
+
params['instId']
|
128
|
+
end
|
129
|
+
|
130
|
+
def item_id
|
131
|
+
params['cartId']
|
132
|
+
end
|
133
|
+
|
134
|
+
def transaction_id
|
135
|
+
params['transId']
|
136
|
+
end
|
137
|
+
|
138
|
+
# Time this payment was received by the client in UTC time.
|
139
|
+
def received_at
|
140
|
+
Time.at(params['transTime'].to_i / 1000).utc
|
141
|
+
end
|
142
|
+
|
143
|
+
# Callback password set in the WorldPay CMS
|
144
|
+
def security_key
|
145
|
+
params['callbackPW']
|
146
|
+
end
|
147
|
+
|
148
|
+
# the money amount we received in X.2 decimal.
|
149
|
+
def gross
|
150
|
+
params['authAmount']
|
151
|
+
end
|
152
|
+
|
153
|
+
def currency
|
154
|
+
params['authCurrency']
|
155
|
+
end
|
156
|
+
|
157
|
+
# Was this a test transaction?
|
158
|
+
def test?
|
159
|
+
params.key?('testMode') && params['testMode'] != '0'
|
160
|
+
end
|
161
|
+
|
162
|
+
def status
|
163
|
+
params['transStatus'] == 'Y' ? 'Completed' : 'Cancelled'
|
164
|
+
end
|
165
|
+
|
166
|
+
def name
|
167
|
+
params['name']
|
168
|
+
end
|
169
|
+
|
170
|
+
def address
|
171
|
+
params['address']
|
172
|
+
end
|
173
|
+
|
174
|
+
def postcode
|
175
|
+
params['postcode']
|
176
|
+
end
|
177
|
+
|
178
|
+
def country
|
179
|
+
params['country']
|
180
|
+
end
|
181
|
+
|
182
|
+
def phone_number
|
183
|
+
params['tel']
|
184
|
+
end
|
185
|
+
|
186
|
+
def fax_number
|
187
|
+
params['fax']
|
188
|
+
end
|
189
|
+
|
190
|
+
def email_address
|
191
|
+
params['email']
|
192
|
+
end
|
193
|
+
|
194
|
+
def card_type
|
195
|
+
params['cardType']
|
196
|
+
end
|
197
|
+
|
198
|
+
# WorldPay extended fraud checks returned as a 4 character string
|
199
|
+
# 1st char: Credit card CVV check
|
200
|
+
# 2nd char: Postcode AVS check
|
201
|
+
# 3rd char: Address AVS check
|
202
|
+
# 4th char: Country comparison check
|
203
|
+
# Possible values are:
|
204
|
+
# :not_supported - 0
|
205
|
+
# :not_checked - 1
|
206
|
+
# :matched - 2
|
207
|
+
# :not_matched - 4
|
208
|
+
# :partial_match - 8
|
209
|
+
def cvv_status
|
210
|
+
return avs_value_to_symbol(params['AVS'][0].chr)
|
211
|
+
end
|
212
|
+
|
213
|
+
def postcode_status
|
214
|
+
return avs_value_to_symbol(params['AVS'][1].chr)
|
215
|
+
end
|
216
|
+
|
217
|
+
def address_status
|
218
|
+
return avs_value_to_symbol(params['AVS'][2].chr)
|
219
|
+
end
|
220
|
+
|
221
|
+
def country_status
|
222
|
+
return avs_value_to_symbol(params['AVS'][3].chr)
|
223
|
+
end
|
224
|
+
|
225
|
+
def acknowledge(authcode = nil)
|
226
|
+
return true
|
227
|
+
end
|
228
|
+
|
229
|
+
# WorldPay supports the passing of custom parameters through to the callback script
|
230
|
+
def custom_params
|
231
|
+
return @custom_params ||= read_custom_params
|
232
|
+
end
|
233
|
+
|
234
|
+
# Check if the request comes from IP range 195.35.90.0 – 195.35.91.255
|
235
|
+
def valid_sender?(ip)
|
236
|
+
return true if OffsitePayments.mode == :test
|
237
|
+
IPAddr.new("195.35.90.0/23").include?(IPAddr.new(ip))
|
238
|
+
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
# Take the posted data and move the relevant data into a hash
|
243
|
+
def parse(post)
|
244
|
+
@raw = post
|
245
|
+
for line in post.split('&')
|
246
|
+
key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
|
247
|
+
params[key] = value
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# Read the custom params into a hash
|
252
|
+
def read_custom_params
|
253
|
+
custom = {}
|
254
|
+
params.each do |key, value|
|
255
|
+
if /\A(M_|MC_|CM_)/ === key
|
256
|
+
custom[key.gsub(/\A(M_|MC_|CM_)/, '').to_sym] = value
|
257
|
+
end
|
258
|
+
end
|
259
|
+
custom
|
260
|
+
end
|
261
|
+
|
262
|
+
# Convert a AVS value to a symbol - see above for more about AVS
|
263
|
+
def avs_value_to_symbol(value)
|
264
|
+
case value.to_s
|
265
|
+
when '8'
|
266
|
+
:partial_match
|
267
|
+
when '4'
|
268
|
+
:no_match
|
269
|
+
when '2'
|
270
|
+
:matched
|
271
|
+
when '1'
|
272
|
+
:not_checked
|
273
|
+
else
|
274
|
+
:not_supported
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module OffsitePayments #:nodoc:
|
4
|
+
module Integrations #:nodoc:
|
5
|
+
module YandexMoney
|
6
|
+
|
7
|
+
# Start integration with yandex.money here:
|
8
|
+
# https://money.yandex.ru/joinups
|
9
|
+
|
10
|
+
# Shop example:
|
11
|
+
# https://github.com/yurijmi/yandex_money_offsite_payments_demo
|
12
|
+
|
13
|
+
mattr_accessor :production_url, :test_url
|
14
|
+
|
15
|
+
self.production_url = 'https://money.yandex.ru/eshop.xml'
|
16
|
+
self.test_url = 'https://demomoney.yandex.ru/eshop.xml'
|
17
|
+
|
18
|
+
def self.service_url
|
19
|
+
case OffsitePayments.mode
|
20
|
+
when :production
|
21
|
+
self.production_url
|
22
|
+
when :test
|
23
|
+
self.test_url
|
24
|
+
else
|
25
|
+
raise StandardError, "Integration mode set to an invalid value: #{mode}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.notification(post)
|
30
|
+
Notification.new(post)
|
31
|
+
end
|
32
|
+
|
33
|
+
class Helper < OffsitePayments::Helper
|
34
|
+
mapping :account, 'customerNumber'
|
35
|
+
mapping :amount, 'sum'
|
36
|
+
mapping :order, 'orderNumber'
|
37
|
+
mapping :error_url, 'shopFailURL'
|
38
|
+
mapping :return_url, 'shopSuccessURL'
|
39
|
+
mapping :description, 'orderDetails'
|
40
|
+
|
41
|
+
mapping :customer, :email => 'cps_email',
|
42
|
+
:phone => 'cps_phone'
|
43
|
+
|
44
|
+
# additional yandex.money parameters
|
45
|
+
mapping :scid, 'scid'
|
46
|
+
mapping :shopId, 'shopId'
|
47
|
+
mapping :shopArticleId, 'shopArticleId'
|
48
|
+
end
|
49
|
+
|
50
|
+
class Notification < OffsitePayments::Notification
|
51
|
+
def initialize(post, options = {})
|
52
|
+
super
|
53
|
+
@response_code = '200'
|
54
|
+
end
|
55
|
+
|
56
|
+
def complete?
|
57
|
+
params['_raw_action'] == 'paymentAviso'
|
58
|
+
end
|
59
|
+
|
60
|
+
def item_id
|
61
|
+
params['_raw_orderNumber']
|
62
|
+
end
|
63
|
+
|
64
|
+
def transaction_id
|
65
|
+
params['_raw_invoiceId']
|
66
|
+
end
|
67
|
+
|
68
|
+
# When was this payment received by the client.
|
69
|
+
def received_at
|
70
|
+
params['_raw_orderCreatedDatetime']
|
71
|
+
end
|
72
|
+
|
73
|
+
def currency
|
74
|
+
params['_raw_orderSumCurrencyPaycash']
|
75
|
+
end
|
76
|
+
|
77
|
+
def payer_email
|
78
|
+
params['_raw_cps_email']
|
79
|
+
end
|
80
|
+
|
81
|
+
# the money amount we received in X.2 decimal.
|
82
|
+
def gross
|
83
|
+
params['_raw_orderSumAmount'].to_f
|
84
|
+
end
|
85
|
+
|
86
|
+
def customer_id
|
87
|
+
params['_raw_customerNumber']
|
88
|
+
end
|
89
|
+
|
90
|
+
def set_response(code)
|
91
|
+
@response_code = code
|
92
|
+
end
|
93
|
+
|
94
|
+
def get_response()
|
95
|
+
@response_code
|
96
|
+
end
|
97
|
+
|
98
|
+
# Was this a test transaction?
|
99
|
+
def test?
|
100
|
+
false
|
101
|
+
end
|
102
|
+
|
103
|
+
def status
|
104
|
+
case params['_raw_action']
|
105
|
+
when 'checkOrder'
|
106
|
+
'pending'
|
107
|
+
when 'paymentAviso'
|
108
|
+
'completed'
|
109
|
+
else 'unknown'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def response
|
114
|
+
shop_id = params['_raw_shopId']
|
115
|
+
method = params['_raw_action']
|
116
|
+
dt = Time.now.iso8601
|
117
|
+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
|
118
|
+
"<#{method}Response performedDatetime=\"#{dt}\" code=\"#{@response_code}\"" +
|
119
|
+
" invoiceId=\"#{transaction_id}\" shopId=\"#{shop_id}\"/>"
|
120
|
+
end
|
121
|
+
|
122
|
+
# Acknowledge the transaction to YandexMoney. This method has to be called after a new
|
123
|
+
# apc arrives. YandexMoney will verify that all the information we received are correct and will return a
|
124
|
+
# ok or a fail.
|
125
|
+
#
|
126
|
+
# Example:
|
127
|
+
#
|
128
|
+
# def ipn
|
129
|
+
# notify = YandexMoneyNotification.new(request.raw_post)
|
130
|
+
#
|
131
|
+
# if notify.acknowledge(authcode)
|
132
|
+
# if notify.complete?
|
133
|
+
# ... process order ...
|
134
|
+
# end
|
135
|
+
# else
|
136
|
+
# ... log possible hacking attempt ...
|
137
|
+
# end
|
138
|
+
# render text: notify.response
|
139
|
+
#
|
140
|
+
|
141
|
+
def acknowledge(authcode = nil)
|
142
|
+
string = [params['_raw_action'],
|
143
|
+
params['_raw_orderSumAmount'],
|
144
|
+
params['_raw_orderSumCurrencyPaycash'],
|
145
|
+
params['_raw_orderSumBankPaycash'],
|
146
|
+
params['_raw_shopId'],
|
147
|
+
params['_raw_invoiceId'],
|
148
|
+
params['_raw_customerNumber'],
|
149
|
+
authcode
|
150
|
+
].join(';')
|
151
|
+
|
152
|
+
digest = Digest::MD5.hexdigest(string)
|
153
|
+
res = params['_raw_md5'] == digest.upcase
|
154
|
+
if res
|
155
|
+
@response_code = '0'
|
156
|
+
else
|
157
|
+
@response_code = '1'
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
# Take the posted data and move the relevant data into a hash
|
164
|
+
def parse(post)
|
165
|
+
@raw = post.to_s
|
166
|
+
for line in @raw.split('&')
|
167
|
+
key, value = *line.scan( %r{^([A-Za-z0-9_.-]+)\=(.*)$} ).flatten
|
168
|
+
# to divide raw values from other
|
169
|
+
params['_raw_' + key] = CGI.unescape(value.to_s) if key.present?
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|