better_offsite_payments 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +76 -0
  4. data/lib/offsite_payments.rb +39 -0
  5. data/lib/offsite_payments/action_view_helper.rb +72 -0
  6. data/lib/offsite_payments/helper.rb +120 -0
  7. data/lib/offsite_payments/integrations.rb +14 -0
  8. data/lib/offsite_payments/integrations/a1agregator.rb +245 -0
  9. data/lib/offsite_payments/integrations/authorize_net_sim.rb +580 -0
  10. data/lib/offsite_payments/integrations/bit_pay.rb +150 -0
  11. data/lib/offsite_payments/integrations/bogus.rb +32 -0
  12. data/lib/offsite_payments/integrations/chronopay.rb +283 -0
  13. data/lib/offsite_payments/integrations/citrus.rb +227 -0
  14. data/lib/offsite_payments/integrations/coinbase.rb +172 -0
  15. data/lib/offsite_payments/integrations/direc_pay.rb +332 -0
  16. data/lib/offsite_payments/integrations/directebanking.rb +237 -0
  17. data/lib/offsite_payments/integrations/doku.rb +171 -0
  18. data/lib/offsite_payments/integrations/dotpay.rb +166 -0
  19. data/lib/offsite_payments/integrations/dwolla.rb +160 -0
  20. data/lib/offsite_payments/integrations/e_payment_plans.rb +146 -0
  21. data/lib/offsite_payments/integrations/easy_pay.rb +137 -0
  22. data/lib/offsite_payments/integrations/epay.rb +161 -0
  23. data/lib/offsite_payments/integrations/first_data.rb +133 -0
  24. data/lib/offsite_payments/integrations/gestpay.rb +205 -0
  25. data/lib/offsite_payments/integrations/hi_trust.rb +179 -0
  26. data/lib/offsite_payments/integrations/ipay88.rb +251 -0
  27. data/lib/offsite_payments/integrations/klarna.rb +275 -0
  28. data/lib/offsite_payments/integrations/liqpay.rb +216 -0
  29. data/lib/offsite_payments/integrations/maksuturva.rb +231 -0
  30. data/lib/offsite_payments/integrations/megakassa.rb +184 -0
  31. data/lib/offsite_payments/integrations/mollie.rb +32 -0
  32. data/lib/offsite_payments/integrations/mollie_ideal.rb +194 -0
  33. data/lib/offsite_payments/integrations/mollie_mistercash.rb +143 -0
  34. data/lib/offsite_payments/integrations/molpay.rb +193 -0
  35. data/lib/offsite_payments/integrations/moneybookers.rb +199 -0
  36. data/lib/offsite_payments/integrations/nochex.rb +228 -0
  37. data/lib/offsite_payments/integrations/pag_seguro.rb +268 -0
  38. data/lib/offsite_payments/integrations/paxum.rb +114 -0
  39. data/lib/offsite_payments/integrations/pay_fast.rb +269 -0
  40. data/lib/offsite_payments/integrations/paydollar.rb +142 -0
  41. data/lib/offsite_payments/integrations/payflow_link.rb +194 -0
  42. data/lib/offsite_payments/integrations/paypal.rb +362 -0
  43. data/lib/offsite_payments/integrations/paypal_payments_advanced.rb +23 -0
  44. data/lib/offsite_payments/integrations/paysbuy.rb +71 -0
  45. data/lib/offsite_payments/integrations/payu_in.rb +276 -0
  46. data/lib/offsite_payments/integrations/payu_in_paisa.rb +46 -0
  47. data/lib/offsite_payments/integrations/platron.rb +153 -0
  48. data/lib/offsite_payments/integrations/pxpay.rb +273 -0
  49. data/lib/offsite_payments/integrations/quickpay.rb +232 -0
  50. data/lib/offsite_payments/integrations/rbkmoney.rb +110 -0
  51. data/lib/offsite_payments/integrations/realex_offsite.rb +317 -0
  52. data/lib/offsite_payments/integrations/robokassa.rb +154 -0
  53. data/lib/offsite_payments/integrations/sage_pay_form.rb +431 -0
  54. data/lib/offsite_payments/integrations/two_checkout.rb +329 -0
  55. data/lib/offsite_payments/integrations/universal.rb +190 -0
  56. data/lib/offsite_payments/integrations/valitor.rb +200 -0
  57. data/lib/offsite_payments/integrations/verkkomaksut.rb +143 -0
  58. data/lib/offsite_payments/integrations/web_pay.rb +186 -0
  59. data/lib/offsite_payments/integrations/webmoney.rb +119 -0
  60. data/lib/offsite_payments/integrations/wirecard_checkout_page.rb +359 -0
  61. data/lib/offsite_payments/integrations/world_pay.rb +280 -0
  62. data/lib/offsite_payments/integrations/yandex_money.rb +175 -0
  63. data/lib/offsite_payments/notification.rb +71 -0
  64. data/lib/offsite_payments/return.rb +37 -0
  65. data/lib/offsite_payments/version.rb +3 -0
  66. metadata +297 -0
@@ -0,0 +1,110 @@
1
+ module OffsitePayments #:nodoc:
2
+ module Integrations #:nodoc:
3
+ module Rbkmoney
4
+ mattr_accessor :service_url
5
+ self.service_url = 'https://rbkmoney.ru/acceptpurchase.aspx'
6
+
7
+ def self.notification(*args)
8
+ Notification.new(*args)
9
+ end
10
+
11
+ class Helper < OffsitePayments::Helper
12
+ mapping :account, 'eshopId'
13
+ mapping :amount, 'recipientAmount'
14
+
15
+ # NOTE: rbkmoney uses outdated currency code 'RUR'
16
+ mapping :currency, 'recipientCurrency'
17
+
18
+ mapping :order, 'orderId'
19
+
20
+ mapping :customer, :email => 'user_email'
21
+
22
+ mapping :credential2, 'serviceName'
23
+ mapping :credential3, 'successUrl'
24
+ mapping :credential4, 'failUrl'
25
+ end
26
+
27
+ class Notification < OffsitePayments::Notification
28
+ %w(
29
+ eshopId
30
+ paymentId
31
+ orderId
32
+ eshopAccount
33
+ serviceName
34
+ recipientAmount
35
+ recipientCurrency
36
+ paymentStatus
37
+ userName
38
+ userEmail
39
+ paymentData
40
+ secretKey
41
+ hash
42
+ ).each do |param_name|
43
+ define_method(param_name.underscore){ params[param_name] }
44
+ end
45
+
46
+ def complete?
47
+ (payment_status == '5')
48
+ end
49
+
50
+ def test?
51
+ false
52
+ end
53
+
54
+ def status
55
+ case payment_status
56
+ when '3'
57
+ 'pending'
58
+ when '5'
59
+ 'completed'
60
+ else 'unknown'
61
+ end
62
+ end
63
+
64
+ def user_fields
65
+ params.inject({}) do |fields, (k,v)|
66
+ if /\AuserField_[\d+]\z/.match(k)
67
+ fields[k] = v
68
+ end
69
+ fields
70
+ end
71
+ end
72
+
73
+ alias_method :client_id, :eshop_id
74
+ alias_method :item_id, :order_id
75
+ alias_method :transaction_id, :payment_id
76
+ alias_method :received_at, :payment_data
77
+ alias_method :payer_email, :user_email
78
+ alias_method :gross, :recipient_amount
79
+ alias_method :currency, :recipient_currency
80
+
81
+ def acknowledge(authcode = nil)
82
+ string = [
83
+ eshop_id,
84
+ order_id,
85
+ service_name,
86
+ eshop_account,
87
+ recipient_amount,
88
+ recipient_currency,
89
+ payment_status,
90
+ user_name,
91
+ user_email,
92
+ payment_data,
93
+ @options[:secret]
94
+ ].join '::'
95
+
96
+ signature = case hash.to_s.length
97
+ when 32
98
+ Digest::MD5.hexdigest(string)
99
+ when 128
100
+ Digest::SHA512.hexdigest(string)
101
+ else
102
+ return false
103
+ end
104
+
105
+ signature == hash
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,317 @@
1
+ module OffsitePayments #:nodoc:
2
+ module Integrations #:nodoc:
3
+ module RealexOffsite
4
+ mattr_accessor :production_url
5
+ mattr_accessor :test_url
6
+ self.production_url = 'https://epage.payandshop.com/epage.cgi'
7
+ self.test_url = 'https://hpp.sandbox.realexpayments.com/pay'
8
+
9
+ def self.helper(order, account, options={})
10
+ Helper.new(order, account, options)
11
+ end
12
+
13
+ def self.notification(query_string, options={})
14
+ Notification.new(query_string, options)
15
+ end
16
+
17
+ def self.return(query_string, options={})
18
+ Return.new(query_string, options)
19
+ end
20
+
21
+ def self.service_url
22
+ mode = OffsitePayments.mode
23
+ case mode
24
+ when :production
25
+ self.production_url
26
+ when :test
27
+ self.test_url
28
+ else
29
+ raise StandardError, "Integration mode set to an invalid value: #{mode}"
30
+ end
31
+ end
32
+
33
+ module Common
34
+ CURRENCY_SPECIAL_MINOR_UNITS = {
35
+ 'BIF' => 0,
36
+ 'BYR' => 0,
37
+ 'CLF' => 0,
38
+ 'CLP' => 0,
39
+ 'CVE' => 0,
40
+ 'DJF' => 0,
41
+ 'GNF' => 0,
42
+ 'HUF' => 0,
43
+ 'ISK' => 0,
44
+ 'JPY' => 0,
45
+ 'KMF' => 0,
46
+ 'KRW' => 0,
47
+ 'PYG' => 0,
48
+ 'RWF' => 0,
49
+ 'UGX' => 0,
50
+ 'UYI' => 0,
51
+ 'VND' => 0,
52
+ 'VUV' => 0,
53
+ 'XAF' => 0,
54
+ 'XOF' => 0,
55
+ 'XPF' => 0,
56
+ 'BHD' => 3,
57
+ 'IQD' => 3,
58
+ 'JOD' => 3,
59
+ 'KWD' => 3,
60
+ 'LYD' => 3,
61
+ 'OMR' => 3,
62
+ 'TND' => 3,
63
+ 'COU' => 4
64
+ }
65
+
66
+ def create_signature(fields, secret)
67
+ data = fields.join('.')
68
+ digest = Digest::SHA1.hexdigest(data)
69
+ signed = "#{digest}.#{secret}"
70
+ Digest::SHA1.hexdigest(signed)
71
+ end
72
+
73
+ # Realex accepts currency amounts as an integer in the lowest value
74
+ # e.g.
75
+ # format_amount(110.56, 'GBP')
76
+ # => 11056
77
+ def format_amount(amount, currency)
78
+ units = CURRENCY_SPECIAL_MINOR_UNITS[currency] || 2
79
+ multiple = 10**units
80
+ return (amount.to_f * multiple.to_f).to_i
81
+ end
82
+
83
+ # Realex returns currency amount as an integer
84
+ def format_amount_as_float(amount, currency)
85
+ units = CURRENCY_SPECIAL_MINOR_UNITS[currency] || 2
86
+ divisor = 10**units
87
+ return (amount.to_f / divisor.to_f)
88
+ end
89
+
90
+ def extract_digits(value)
91
+ value.scan(/\d+/).join('')
92
+ end
93
+
94
+ def extract_avs_code(params={})
95
+ [extract_digits(params[:zip]), extract_digits(params[:address1])].join('|')
96
+ end
97
+
98
+ end
99
+
100
+ class Helper < OffsitePayments::Helper
101
+ include Common
102
+
103
+ def initialize(order, account, options = {})
104
+ @timestamp = Time.now.strftime('%Y%m%d%H%M%S')
105
+ @currency = options[:currency]
106
+ @merchant_id = account
107
+ @sub_account = options[:credential2]
108
+ @secret = options[:credential3]
109
+ super
110
+ # Credentials
111
+ add_field 'MERCHANT_ID', @merchant_id
112
+ add_field 'ACCOUNT', @sub_account
113
+ # Defaults
114
+ add_field 'AUTO_SETTLE_FLAG', '1'
115
+ add_field 'RETURN_TSS', '1'
116
+ add_field 'TIMESTAMP', @timestamp
117
+ # Realex does not send back CURRENCY param in response
118
+ # however it does echo any other param so we send it twice.
119
+ add_field 'X-CURRENCY', @currency
120
+ add_field 'X-TEST', @test.to_s
121
+ add_field 'ORDER_ID', "#{order}#{@timestamp.to_i}"
122
+ end
123
+
124
+ def form_fields
125
+ sign_fields
126
+ end
127
+
128
+ def amount=(amount)
129
+ add_field 'AMOUNT', format_amount(amount, @currency)
130
+ end
131
+
132
+ def billing_address(params={})
133
+ add_field(mappings[:billing_address][:zip], extract_avs_code(params))
134
+ add_field(mappings[:billing_address][:country], lookup_country_code(params[:country]))
135
+ end
136
+
137
+ def shipping_address(params={})
138
+ add_field(mappings[:shipping_address][:zip], extract_avs_code(params))
139
+ add_field(mappings[:shipping_address][:country], lookup_country_code(params[:country]))
140
+ end
141
+
142
+ def sign_fields
143
+ @fields.merge!('SHA1HASH' => generate_signature)
144
+ end
145
+
146
+ def generate_signature
147
+ fields_to_sign = []
148
+ ['TIMESTAMP', 'MERCHANT_ID', 'ORDER_ID', 'AMOUNT', 'CURRENCY'].each do |field|
149
+ fields_to_sign << @fields[field]
150
+ end
151
+
152
+ create_signature(fields_to_sign, @secret)
153
+ end
154
+
155
+ # Realex Required Fields
156
+ mapping :currency, 'CURRENCY'
157
+
158
+ mapping :order, 'CHECKOUT_ID'
159
+ mapping :amount, 'AMOUNT'
160
+ mapping :notify_url, 'MERCHANT_RESPONSE_URL'
161
+ mapping :return_url, 'MERCHANT_RETURN_URL'
162
+
163
+ # Realex Optional fields
164
+ mapping :customer, :email => 'CUST_NUM'
165
+
166
+ mapping :shipping_address, :zip => 'SHIPPING_CODE',
167
+ :country => 'SHIPPING_CO'
168
+ mapping :billing_address, :zip => 'BILLING_CODE',
169
+ :country => 'BILLING_CO'
170
+ end
171
+
172
+ class Notification < OffsitePayments::Notification
173
+ include Common
174
+ def initialize(post, options={})
175
+ super
176
+ @secret = options[:credential3]
177
+ end
178
+
179
+ # Required Notification methods to define
180
+ def acknowledge(authcode = nil)
181
+ verified?
182
+ end
183
+
184
+ def item_id
185
+ checkout_id
186
+ end
187
+
188
+ def transaction_id
189
+ pasref
190
+ end
191
+
192
+ def test?
193
+ params['X-TEST']
194
+ end
195
+
196
+ def status
197
+ if result == '00'
198
+ 'Completed'
199
+ else
200
+ 'Invalid'
201
+ end
202
+ end
203
+
204
+ # Realex does not send back the currency param by default
205
+ # we have sent this additional parameter
206
+ def currency
207
+ params['X-CURRENCY']
208
+ end
209
+
210
+ def gross
211
+ format_amount_as_float(params['AMOUNT'], currency)
212
+ end
213
+
214
+ def complete?
215
+ verified? && status == 'Completed'
216
+ end
217
+
218
+ # Fields for Realex signature verification
219
+ def timestamp
220
+ params['TIMESTAMP']
221
+ end
222
+
223
+ def merchant_id
224
+ params['MERCHANT_ID']
225
+ end
226
+
227
+ def checkout_id
228
+ params['CHECKOUT_ID']
229
+ end
230
+
231
+ def order_id
232
+ params['ORDER_ID']
233
+ end
234
+
235
+ def result
236
+ params['RESULT']
237
+ end
238
+
239
+ def message
240
+ params['MESSAGE']
241
+ end
242
+
243
+ def pasref
244
+ params['PASREF']
245
+ end
246
+
247
+ def authcode
248
+ params['AUTHCODE']
249
+ end
250
+
251
+ def signature
252
+ params['SHA1HASH']
253
+ end
254
+
255
+ def calculated_signature
256
+ fields = [timestamp, merchant_id, order_id, result, message, pasref, authcode]
257
+ create_signature(fields, @secret)
258
+ end
259
+
260
+ def verified?
261
+ signature == calculated_signature
262
+ end
263
+
264
+ # Extra data (available from Realex)
265
+ def cvn_result
266
+ params['CVNRESULT']
267
+ end
268
+
269
+ def avs_postcode_result
270
+ params['AVSPOSTCODERESULT']
271
+ end
272
+
273
+ def avs_address_result
274
+ params['AVSADDRESSRESULT']
275
+ end
276
+
277
+ def pasref
278
+ params['PASREF']
279
+ end
280
+
281
+ def eci
282
+ params['ECI']
283
+ end
284
+
285
+ def cavv
286
+ params['CAVV']
287
+ end
288
+
289
+ def xid
290
+ params['XID']
291
+ end
292
+
293
+ end
294
+
295
+ class Return < OffsitePayments::Return
296
+ def initialize(data, options)
297
+ super
298
+ @notification = Notification.new(data, options)
299
+ end
300
+
301
+ def success?
302
+ notification.complete?
303
+ end
304
+
305
+ # TODO: realex does not provide a separate cancelled endpoint
306
+ def cancelled?
307
+ false
308
+ end
309
+
310
+ def message
311
+ notification.message
312
+ end
313
+ end
314
+
315
+ end
316
+ end
317
+ end
@@ -0,0 +1,154 @@
1
+ module OffsitePayments #:nodoc:
2
+ module Integrations #:nodoc:
3
+ # Documentation: http://robokassa.ru/Doc/En/Interface.aspx
4
+ module Robokassa
5
+ # Overwrite this if you want to change the Robokassa test url
6
+ mattr_accessor :test_url
7
+ self.test_url = 'http://test.robokassa.ru/Index.aspx'
8
+
9
+ # Overwrite this if you want to change the Robokassa production url
10
+ mattr_accessor :production_url
11
+ self.production_url = 'https://merchant.roboxchange.com/Index.aspx'
12
+
13
+ mattr_accessor :signature_parameter_name
14
+ self.signature_parameter_name = 'SignatureValue'
15
+
16
+ def self.service_url
17
+ mode = OffsitePayments.mode
18
+ case mode
19
+ when :production
20
+ self.production_url
21
+ when :test
22
+ self.test_url
23
+ else
24
+ raise StandardError, "Integration mode set to an invalid value: #{mode}"
25
+ end
26
+ end
27
+
28
+ def self.helper(order, account, options = {})
29
+ Helper.new(order, account, options)
30
+ end
31
+
32
+ def self.notification(query_string, options = {})
33
+ Notification.new(query_string, options)
34
+ end
35
+
36
+ def self.return(query_string)
37
+ Return.new(query_string)
38
+ end
39
+
40
+ module Common
41
+ def generate_signature_string
42
+ custom_param_keys = params.keys.select {|key| key =~ /^shp/}.sort
43
+ custom_params = custom_param_keys.map {|key| "#{key}=#{params[key]}"}
44
+ [main_params, secret, custom_params.compact].flatten.join(':')
45
+ end
46
+
47
+ def generate_signature
48
+ Digest::MD5.hexdigest(generate_signature_string)
49
+ end
50
+ end
51
+
52
+ class Helper < OffsitePayments::Helper
53
+ include Common
54
+
55
+ def initialize(order, account, options = {})
56
+ @md5secret = options.delete(:secret)
57
+ super
58
+ end
59
+
60
+ def form_fields
61
+ @fields.merge(OffsitePayments::Integrations::Robokassa.signature_parameter_name => generate_signature)
62
+ end
63
+
64
+ def main_params
65
+ [:account, :amount, :order].map {|key| @fields[mappings[key]]}
66
+ end
67
+
68
+ def params
69
+ @fields
70
+ end
71
+
72
+ def secret
73
+ @md5secret
74
+ end
75
+
76
+ def method_missing(method_id, *args)
77
+ method_id = method_id.to_s.gsub(/=$/, '')
78
+
79
+ # support for robokassa custom parameters
80
+ if method_id =~ /^shp/
81
+ add_field method_id, args.last
82
+ end
83
+
84
+ super
85
+ end
86
+
87
+ mapping :account, 'MrchLogin'
88
+ mapping :amount, 'OutSum'
89
+ mapping :currency, 'IncCurrLabel'
90
+ mapping :order, 'InvId'
91
+ mapping :description, 'Desc'
92
+ mapping :email, 'Email'
93
+ end
94
+
95
+ class Notification < OffsitePayments::Notification
96
+ include Common
97
+
98
+ def self.recognizes?(params)
99
+ params.has_key?('InvId') && params.has_key?('OutSum')
100
+ end
101
+
102
+ def complete?
103
+ true
104
+ end
105
+
106
+ def amount
107
+ BigDecimal.new(gross)
108
+ end
109
+
110
+ def item_id
111
+ params['InvId']
112
+ end
113
+
114
+ def security_key
115
+ params[OffsitePayments::Integrations::Robokassa.signature_parameter_name].to_s.downcase
116
+ end
117
+
118
+ def gross
119
+ params['OutSum']
120
+ end
121
+
122
+ def status
123
+ 'success'
124
+ end
125
+
126
+ def secret
127
+ @options[:secret]
128
+ end
129
+
130
+ def main_params
131
+ [gross, item_id]
132
+ end
133
+
134
+ def acknowledge(authcode = nil)
135
+ security_key == generate_signature
136
+ end
137
+
138
+ def success_response(*args)
139
+ "OK#{item_id}"
140
+ end
141
+ end
142
+
143
+ class Return < OffsitePayments::Return
144
+ def item_id
145
+ @params['InvId']
146
+ end
147
+
148
+ def amount
149
+ @params['OutSum']
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end