offsite_payments 2.0.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 (59) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +70 -0
  4. data/lib/offsite_payments.rb +46 -0
  5. data/lib/offsite_payments/action_view_helper.rb +72 -0
  6. data/lib/offsite_payments/helper.rb +119 -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/direc_pay.rb +339 -0
  15. data/lib/offsite_payments/integrations/directebanking.rb +237 -0
  16. data/lib/offsite_payments/integrations/doku.rb +171 -0
  17. data/lib/offsite_payments/integrations/dotpay.rb +166 -0
  18. data/lib/offsite_payments/integrations/dwolla.rb +160 -0
  19. data/lib/offsite_payments/integrations/e_payment_plans.rb +146 -0
  20. data/lib/offsite_payments/integrations/easy_pay.rb +137 -0
  21. data/lib/offsite_payments/integrations/epay.rb +161 -0
  22. data/lib/offsite_payments/integrations/first_data.rb +133 -0
  23. data/lib/offsite_payments/integrations/gestpay.rb +201 -0
  24. data/lib/offsite_payments/integrations/hi_trust.rb +179 -0
  25. data/lib/offsite_payments/integrations/ipay88.rb +240 -0
  26. data/lib/offsite_payments/integrations/klarna.rb +291 -0
  27. data/lib/offsite_payments/integrations/liqpay.rb +216 -0
  28. data/lib/offsite_payments/integrations/maksuturva.rb +231 -0
  29. data/lib/offsite_payments/integrations/mollie_ideal.rb +213 -0
  30. data/lib/offsite_payments/integrations/moneybookers.rb +199 -0
  31. data/lib/offsite_payments/integrations/nochex.rb +228 -0
  32. data/lib/offsite_payments/integrations/pag_seguro.rb +255 -0
  33. data/lib/offsite_payments/integrations/paxum.rb +114 -0
  34. data/lib/offsite_payments/integrations/pay_fast.rb +269 -0
  35. data/lib/offsite_payments/integrations/paydollar.rb +142 -0
  36. data/lib/offsite_payments/integrations/payflow_link.rb +194 -0
  37. data/lib/offsite_payments/integrations/paypal.rb +362 -0
  38. data/lib/offsite_payments/integrations/paypal_payments_advanced.rb +23 -0
  39. data/lib/offsite_payments/integrations/paysbuy.rb +71 -0
  40. data/lib/offsite_payments/integrations/payu_in.rb +266 -0
  41. data/lib/offsite_payments/integrations/payu_in_paisa.rb +46 -0
  42. data/lib/offsite_payments/integrations/platron.rb +153 -0
  43. data/lib/offsite_payments/integrations/pxpay.rb +271 -0
  44. data/lib/offsite_payments/integrations/quickpay.rb +232 -0
  45. data/lib/offsite_payments/integrations/rbkmoney.rb +110 -0
  46. data/lib/offsite_payments/integrations/robokassa.rb +154 -0
  47. data/lib/offsite_payments/integrations/sage_pay_form.rb +425 -0
  48. data/lib/offsite_payments/integrations/two_checkout.rb +332 -0
  49. data/lib/offsite_payments/integrations/universal.rb +180 -0
  50. data/lib/offsite_payments/integrations/valitor.rb +200 -0
  51. data/lib/offsite_payments/integrations/verkkomaksut.rb +143 -0
  52. data/lib/offsite_payments/integrations/web_pay.rb +186 -0
  53. data/lib/offsite_payments/integrations/webmoney.rb +119 -0
  54. data/lib/offsite_payments/integrations/wirecard_checkout_page.rb +359 -0
  55. data/lib/offsite_payments/integrations/world_pay.rb +273 -0
  56. data/lib/offsite_payments/notification.rb +71 -0
  57. data/lib/offsite_payments/return.rb +37 -0
  58. data/lib/offsite_payments/version.rb +3 -0
  59. metadata +270 -0
@@ -0,0 +1,114 @@
1
+ module OffsitePayments #:nodoc:
2
+ module Integrations #:nodoc:
3
+ # Documentation:
4
+ # https://www.paxum.com/payment_docs/page.php?name=apiIntroduction
5
+ module Paxum
6
+ mattr_accessor :test_url
7
+ self.test_url = 'https://paxum.com/payment/phrame.php?action=displayProcessPaymentLogin'
8
+
9
+ mattr_accessor :production_url
10
+ self.production_url = 'https://paxum.com/payment/phrame.php?action=displayProcessPaymentLogin'
11
+
12
+ mattr_accessor :signature_parameter_name
13
+ self.signature_parameter_name = 'key'
14
+
15
+ def self.service_url
16
+ mode = OffsitePayments.mode
17
+ case mode
18
+ when :production
19
+ self.production_url
20
+ when :test
21
+ self.test_url
22
+ else
23
+ raise StandardError, "Integration mode set to an invalid value: #{mode}"
24
+ end
25
+ end
26
+
27
+ def self.helper(order, account, options = {})
28
+ Helper.new(order, account, options)
29
+ end
30
+
31
+ def self.notification(query_string, options = {})
32
+ Notification.new(query_string, options)
33
+ end
34
+
35
+ module Common
36
+ def generate_signature_string
37
+ @raw_post.slice!(0) if @raw_post.starts_with?("&")
38
+ @raw_post = CGI.unescape(@raw_post)
39
+ @raw_post = "&#{@raw_post}" unless @raw_post.starts_with?("&")
40
+ arr = @raw_post.split('&')
41
+ arr.delete(arr.last)
42
+ data = arr.join('&')
43
+
44
+ (data + secret)
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
+ @paxum_options = options.dup
57
+ options.delete(:description)
58
+ options.delete(:fail_url)
59
+ options.delete(:success_url)
60
+ options.delete(:result_url)
61
+ super
62
+ add_field "button_type_id", "1"
63
+ add_field "variables", "notify_url=#{@paxum_options[:result_url]}"
64
+ @paxum_options.each do |key, value|
65
+ add_field mappings[key], value
66
+ end
67
+ end
68
+
69
+ def form_fields
70
+ @fields
71
+ end
72
+
73
+ def params
74
+ @fields
75
+ end
76
+
77
+ mapping :account, 'business_email'
78
+ mapping :amount, 'amount'
79
+ mapping :currency, 'currency'
80
+ mapping :order, 'item_id'
81
+ mapping :description, 'item_name'
82
+ mapping :fail_url, 'cancel_url'
83
+ mapping :success_url, 'finish_url'
84
+ mapping :result_url, 'notify_url'
85
+ end
86
+
87
+ class Notification < OffsitePayments::Notification
88
+ include Common
89
+
90
+ def initialize(post, options = {})
91
+ @raw_post = post.dup
92
+ post.slice!(0)
93
+ super
94
+ end
95
+
96
+ def self.recognizes?(params)
97
+ (params.has_key?('transaction_item_id') && params.has_key?('transaction_amount'))
98
+ end
99
+
100
+ def security_key
101
+ params["key"]
102
+ end
103
+
104
+ def secret
105
+ @options[:secret]
106
+ end
107
+
108
+ def acknowledge(authcode = nil)
109
+ (security_key == generate_signature)
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,269 @@
1
+ module OffsitePayments #:nodoc:
2
+ module Integrations #:nodoc:
3
+ # Documentation:
4
+ # https://www.payfast.co.za/s/std/integration-guide
5
+ module PayFast
6
+ # Overwrite this if you want to change the PayFast sandbox url
7
+ mattr_accessor :process_test_url
8
+ self.process_test_url = 'https://sandbox.payfast.co.za/eng/process'
9
+
10
+ # Overwrite this if you want to change the PayFast production url
11
+ mattr_accessor :process_production_url
12
+ self.process_production_url = 'https://www.payfast.co.za/eng/process'
13
+
14
+ # Overwrite this if you want to change the PayFast sandbox url
15
+ mattr_accessor :validate_test_url
16
+ self.validate_test_url = 'https://sandbox.payfast.co.za/eng/query/validate'
17
+
18
+ # Overwrite this if you want to change the PayFast production url
19
+ mattr_accessor :validate_production_url
20
+ self.validate_production_url = 'https://www.payfast.co.za/eng/query/validate'
21
+
22
+ mattr_accessor :signature_parameter_name
23
+ self.signature_parameter_name = 'signature'
24
+
25
+ def self.service_url
26
+ mode = OffsitePayments.mode
27
+ case mode
28
+ when :production
29
+ self.process_production_url
30
+ when :test
31
+ self.process_test_url
32
+ else
33
+ raise StandardError, "Integration mode set to an invalid value: #{mode}"
34
+ end
35
+ end
36
+
37
+ def self.validate_service_url
38
+ mode = OffsitePayments.mode
39
+ case mode
40
+ when :production
41
+ self.validate_production_url
42
+ when :test
43
+ self.validate_test_url
44
+ else
45
+ raise StandardError, "Integration mode set to an invalid value: #{mode}"
46
+ end
47
+ end
48
+
49
+ def self.helper(order, account, options = {})
50
+ Helper.new(order, account, options)
51
+ end
52
+
53
+ def self.notification(query_string, options = {})
54
+ Notification.new(query_string, options)
55
+ end
56
+
57
+ def self.return(post, options = {})
58
+ Return.new(post, options)
59
+ end
60
+
61
+ module Common
62
+ def generate_signature(type)
63
+ string = case type
64
+ when :request
65
+ request_signature_string
66
+ when :notify
67
+ notify_signature_string
68
+ end
69
+
70
+ Digest::MD5.hexdigest(string)
71
+ end
72
+
73
+ def request_attributes
74
+ [:merchant_id, :merchant_key, :return_url, :cancel_url,
75
+ :notify_url, :name_first, :name_last, :email_address,
76
+ :payment_id, :amount, :item_name, :item_description,
77
+ :custom_str1, :custom_str2, :custom_str3, :custom_str4,
78
+ :custom_str5, :custom_int1, :custom_int2, :custom_int3,
79
+ :custom_int4, :custom_int5, :email_confirmation,
80
+ :confirmation_address]
81
+ end
82
+
83
+ def request_signature_string
84
+ request_attributes.map do |attr|
85
+ "#{mappings[attr]}=#{CGI.escape(@fields[mappings[attr]])}" if @fields[mappings[attr]].present?
86
+ end.compact.join('&')
87
+ end
88
+
89
+ def notify_signature_string
90
+ params.map do |key, value|
91
+ "#{key}=#{CGI.escape(value)}" unless key == PayFast.signature_parameter_name
92
+ end.compact.join('&')
93
+ end
94
+ end
95
+
96
+ class Helper < OffsitePayments::Helper
97
+ include Common
98
+
99
+ def initialize(order, account, options = {})
100
+ super
101
+ add_field('merchant_id', account)
102
+ add_field('merchant_key', options.delete(:credential2))
103
+ add_field('m_payment_id', order)
104
+ end
105
+
106
+ def form_fields
107
+ @fields
108
+ end
109
+
110
+ def params
111
+ @fields
112
+ end
113
+
114
+ mapping :merchant_id, 'merchant_id'
115
+ mapping :merchant_key, 'merchant_key'
116
+ mapping :return_url, 'return_url'
117
+ mapping :cancel_return_url, 'cancel_url'
118
+ mapping :notify_url, 'notify_url'
119
+ mapping :name_first, 'name_first'
120
+ mapping :name_last, 'name_last'
121
+ mapping :email_address, 'email_address'
122
+ mapping :payment_id, 'm_payment_id'
123
+ mapping :amount, 'amount'
124
+ mapping :item_name, 'item_name'
125
+ mapping :description, 'item_name'
126
+
127
+ mapping :customer, :first_name => 'name_first',
128
+ :last_name => 'name_last',
129
+ :email => 'email_address',
130
+ :phone => 'phone'
131
+
132
+ 5.times { |i| mapping :"custom_str#{i}", "custom_str#{i}" }
133
+ 5.times { |i| mapping :"custom_int#{i}", "custom_int#{i}" }
134
+
135
+ mapping :email_confirmation, 'email_confirmation'
136
+ mapping :confirmation_address, 'confirmation_address'
137
+ end
138
+
139
+ # Parser and handler for incoming ITN from PayFast.
140
+ # The Example shows a typical handler in a rails application.
141
+ #
142
+ # Example
143
+ #
144
+ # class BackendController < ApplicationController
145
+ # include OffsitePayments::Integrations
146
+ #
147
+ # def pay_fast_itn
148
+ # notify = PayFast::Notification.new(request.raw_post)
149
+ #
150
+ # order = Order.find(notify.item_id)
151
+ #
152
+ # if notify.acknowledge
153
+ # begin
154
+ #
155
+ # if notify.complete? and order.total == notify.amount
156
+ # order.status = 'success'
157
+ #
158
+ # shop.ship(order)
159
+ # else
160
+ # logger.error("Failed to verify Paypal's notification, please investigate")
161
+ # end
162
+ #
163
+ # rescue => e
164
+ # order.status = 'failed'
165
+ # raise
166
+ # ensure
167
+ # order.save
168
+ # end
169
+ # end
170
+ #
171
+ # render :nothing
172
+ # end
173
+ # end
174
+ class Notification < OffsitePayments::Notification
175
+ include ActiveMerchant::PostsData
176
+ include Common
177
+
178
+ # Was the transaction complete?
179
+ def complete?
180
+ status == "Completed"
181
+ end
182
+
183
+ # Status of transaction. List of possible values:
184
+ # <tt>COMPLETE</tt>::
185
+ def status
186
+ if params['payment_status'] == "COMPLETE"
187
+ "Completed"
188
+ else
189
+ "Failed"
190
+ end
191
+ end
192
+
193
+ # Id of this transaction (uniq PayFast transaction id)
194
+ def transaction_id
195
+ params['pf_payment_id']
196
+ end
197
+
198
+ # Id of this transaction (uniq Shopify transaction id)
199
+ def item_id
200
+ params['m_payment_id']
201
+ end
202
+
203
+ # The total amount which the payer paid.
204
+ def gross
205
+ params['amount_gross']
206
+ end
207
+
208
+ # The total in fees which was deducted from the amount.
209
+ def fee
210
+ params['amount_fee']
211
+ end
212
+
213
+ # The net amount credited to the receiver's account.
214
+ def amount
215
+ params['amount_net']
216
+ end
217
+
218
+ # The name of the item being charged for.
219
+ def item_name
220
+ params['item_name']
221
+ end
222
+
223
+ # The Merchant ID as given by the PayFast system. Used to uniquely identify the receiver's account.
224
+ def merchant_id
225
+ params['merchant_id']
226
+ end
227
+
228
+ def currency
229
+ nil
230
+ end
231
+
232
+ # Generated hash depends on params order so use OrderedHash instead of Hash
233
+ def empty!
234
+ super
235
+ @params = ActiveSupport::OrderedHash.new
236
+ end
237
+
238
+ # Acknowledge the transaction to PayFast. This method has to be called after a new
239
+ # ITN arrives. PayFast will verify that all the information we received are correct and will return a
240
+ # VERIFIED or INVALID status.
241
+ #
242
+ # Example:
243
+ #
244
+ # def pay_fast_itn
245
+ # notify = PayFastNotification.new(request.raw_post)
246
+ #
247
+ # if notify.acknowledge
248
+ # ... process order ... if notify.complete?
249
+ # else
250
+ # ... log possible hacking attempt ...
251
+ # end
252
+ def acknowledge(authcode = nil)
253
+ if params[PayFast.signature_parameter_name] == generate_signature(:notify)
254
+ response = ssl_post(PayFast.validate_service_url, notify_signature_string,
255
+ 'Content-Type' => "application/x-www-form-urlencoded",
256
+ 'Content-Length' => "#{notify_signature_string.size}"
257
+ )
258
+ raise StandardError.new("Faulty PayFast result: #{response}") unless ['VALID', 'INVALID'].include?(response)
259
+
260
+ response == "VALID"
261
+ end
262
+ end
263
+ end
264
+
265
+ class Return < OffsitePayments::Return
266
+ end
267
+ end
268
+ end
269
+ end
@@ -0,0 +1,142 @@
1
+ module OffsitePayments #:nodoc:
2
+ module Integrations #:nodoc:
3
+ module Paydollar
4
+ CURRENCY_MAP = {
5
+ 'AED' => '784',
6
+ 'AUD' => '036',
7
+ 'BND' => '096',
8
+ 'CAD' => '124',
9
+ 'CNY' => '156',
10
+ 'EUR' => '978',
11
+ 'GBP' => '826',
12
+ 'HKD' => '344',
13
+ 'IDR' => '360',
14
+ 'JPY' => '392',
15
+ 'KRW' => '410',
16
+ 'MOP' => '446',
17
+ 'MYR' => '458',
18
+ 'NZD' => '554',
19
+ 'PHP' => '608',
20
+ 'SAR' => '682',
21
+ 'SGD' => '702',
22
+ 'THB' => '764',
23
+ 'TWD' => '901',
24
+ 'USD' => '840',
25
+ }
26
+
27
+ def self.service_url
28
+ case OffsitePayments.mode
29
+ when :production
30
+ 'https://www.paydollar.com/b2c2/eng/payment/payForm.jsp'
31
+ when :test
32
+ 'https://test.paydollar.com/b2cDemo/eng/payment/payForm.jsp'
33
+ else
34
+ raise StandardError, "Integration mode set to an invalid value: #{mode}"
35
+ end
36
+ end
37
+
38
+ def self.notification(post, options = {})
39
+ Notification.new(post, options)
40
+ end
41
+
42
+ def self.return(query_string, options = {})
43
+ Return.new(query_string, options)
44
+ end
45
+
46
+ def self.sign(fields, secret)
47
+ Digest::SHA1.hexdigest(fields.push(secret).join('|'))
48
+ end
49
+
50
+ class Helper < OffsitePayments::Helper
51
+ def initialize(order, account, options = {})
52
+ super
53
+ add_field('payType', 'N') # normal sale and not just auth
54
+ @secret = options[:credential2]
55
+ end
56
+
57
+ def form_fields
58
+ @fields.merge('secureHash' => generate_secure_hash)
59
+ end
60
+
61
+ def generate_secure_hash
62
+ fields = [@fields[mappings[:account]],
63
+ @fields[mappings[:order]],
64
+ @fields[mappings[:currency]],
65
+ @fields[mappings[:amount]],
66
+ @fields['payType']]
67
+ Paydollar.sign(fields, @secret)
68
+ end
69
+
70
+ def currency=(currency_code)
71
+ add_field(mappings[:currency], CURRENCY_MAP[currency_code])
72
+ end
73
+
74
+ mapping :account, 'merchantId'
75
+ mapping :amount, 'amount'
76
+ mapping :order, 'orderRef'
77
+ mapping :currency, 'currCode'
78
+ mapping :return_url, 'successUrl'
79
+ mapping :cancel_return_url, ['cancelUrl','failUrl']
80
+ end
81
+
82
+ class Notification < OffsitePayments::Notification
83
+ def complete?
84
+ status == 'Completed'
85
+ end
86
+
87
+ def item_id
88
+ @params['Ref']
89
+ end
90
+
91
+ def currency
92
+ CURRENCY_MAP.key(@params['Cur'])
93
+ end
94
+
95
+ def gross
96
+ @params['Amt']
97
+ end
98
+
99
+ def transaction_id
100
+ @params['PayRef']
101
+ end
102
+
103
+ def status
104
+ case @params['successcode']
105
+ when '0' then 'Completed'
106
+ else 'Failed'
107
+ end
108
+ end
109
+
110
+ def acknowledge(authcode = nil)
111
+ # paydollar supports multiple signature keys, therefore we need to check if any
112
+ # of their signatures match ours
113
+ hash = @params['secureHash']
114
+ if !hash
115
+ return false
116
+ end
117
+ hash.split(',').include? generate_secure_hash
118
+ end
119
+
120
+ private
121
+
122
+ def generate_secure_hash
123
+ fields = [@params['src'],
124
+ @params['prc'],
125
+ @params['successcode'],
126
+ @params['Ref'],
127
+ @params['PayRef'],
128
+ @params['Cur'],
129
+ @params['Amt'],
130
+ @params['payerAuth']]
131
+ Paydollar.sign(fields, @options[:credential2])
132
+ end
133
+ end
134
+
135
+ class Return < OffsitePayments::Return
136
+ def success?
137
+ @params.has_key?('Ref')
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end