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.
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