koffsite_payments 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +13 -0
  4. data/lib/offsite_payments.rb +48 -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/coinbase.rb +166 -0
  15. data/lib/offsite_payments/integrations/direc_pay.rb +339 -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 +203 -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 +291 -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/mollie_ideal.rb +216 -0
  31. data/lib/offsite_payments/integrations/moneybookers.rb +199 -0
  32. data/lib/offsite_payments/integrations/nochex.rb +228 -0
  33. data/lib/offsite_payments/integrations/pag_seguro.rb +268 -0
  34. data/lib/offsite_payments/integrations/paxum.rb +114 -0
  35. data/lib/offsite_payments/integrations/pay_fast.rb +269 -0
  36. data/lib/offsite_payments/integrations/pay_u_latam.rb +246 -0
  37. data/lib/offsite_payments/integrations/paydollar.rb +142 -0
  38. data/lib/offsite_payments/integrations/payflow_link.rb +194 -0
  39. data/lib/offsite_payments/integrations/paypal.rb +362 -0
  40. data/lib/offsite_payments/integrations/paypal_payments_advanced.rb +23 -0
  41. data/lib/offsite_payments/integrations/paysbuy.rb +71 -0
  42. data/lib/offsite_payments/integrations/payu_in.rb +266 -0
  43. data/lib/offsite_payments/integrations/payu_in_paisa.rb +46 -0
  44. data/lib/offsite_payments/integrations/platron.rb +153 -0
  45. data/lib/offsite_payments/integrations/pxpay.rb +273 -0
  46. data/lib/offsite_payments/integrations/quickpay.rb +232 -0
  47. data/lib/offsite_payments/integrations/rbkmoney.rb +110 -0
  48. data/lib/offsite_payments/integrations/robokassa.rb +154 -0
  49. data/lib/offsite_payments/integrations/sage_pay_form.rb +425 -0
  50. data/lib/offsite_payments/integrations/two_checkout.rb +329 -0
  51. data/lib/offsite_payments/integrations/universal.rb +181 -0
  52. data/lib/offsite_payments/integrations/valitor.rb +200 -0
  53. data/lib/offsite_payments/integrations/verkkomaksut.rb +143 -0
  54. data/lib/offsite_payments/integrations/web_pay.rb +186 -0
  55. data/lib/offsite_payments/integrations/webmoney.rb +119 -0
  56. data/lib/offsite_payments/integrations/wirecard_checkout_page.rb +359 -0
  57. data/lib/offsite_payments/integrations/world_pay.rb +273 -0
  58. data/lib/offsite_payments/notification.rb +71 -0
  59. data/lib/offsite_payments/return.rb +37 -0
  60. data/lib/offsite_payments/version.rb +3 -0
  61. metadata +268 -0
@@ -0,0 +1,273 @@
1
+ require 'rexml/document'
2
+
3
+ module OffsitePayments #:nodoc:
4
+ module Integrations #:nodoc:
5
+ module Pxpay
6
+ def self.token_url
7
+ 'https://sec.paymentexpress.com/pxpay/pxaccess.aspx'
8
+ end
9
+
10
+ def self.notification(post, options={})
11
+ Notification.new(post, options)
12
+ end
13
+
14
+ def self.return(query_string, options={})
15
+ Return.new(query_string, options)
16
+ end
17
+
18
+ class Helper < OffsitePayments::Helper
19
+ include ActiveMerchant::PostsData
20
+
21
+ attr_reader :token_parameters, :redirect_parameters
22
+
23
+ def initialize(order, account, options = {})
24
+ @token_parameters = {
25
+ 'PxPayUserId' => account,
26
+ 'PxPayKey' => options[:credential2],
27
+ 'CurrencyInput' => options[:currency],
28
+ 'MerchantReference' => order,
29
+ 'EmailAddress' => options[:customer_email],
30
+ 'TxnData1' => options[:custom1],
31
+ 'TxnData2' => options[:custom2],
32
+ 'TxnData3' => options[:custom3],
33
+ 'AmountInput' => "%.2f" % options[:amount].to_f.round(2),
34
+ 'EnableAddBillCard' => '0',
35
+ 'TxnType' => 'Purchase',
36
+ 'UrlSuccess' => options[:return_url],
37
+ 'UrlFail' => options[:return_url]
38
+ }
39
+ @redirect_parameters = {}
40
+
41
+ super
42
+
43
+ raise ArgumentError, "error - must specify return_url" if token_parameters['UrlSuccess'].blank?
44
+ raise ArgumentError, "error - must specify cancel_return_url" if token_parameters['UrlFail'].blank?
45
+ end
46
+
47
+ def credential_based_url
48
+ raw_response = ssl_post(Pxpay.token_url, generate_request)
49
+ result = parse_response(raw_response)
50
+
51
+ raise ActionViewHelperError, "error - failed to get token - message was #{result[:redirect]}" unless result[:valid] == "1"
52
+
53
+ url = URI.parse(result[:redirect])
54
+
55
+ if url.query
56
+ @redirect_parameters = CGI.parse(url.query)
57
+ url.query = nil
58
+ end
59
+
60
+ url.to_s
61
+ rescue ActiveMerchant::ConnectionError
62
+ raise ActionViewHelperError, "A connection error occurred while contacting the payment gateway. Please try again."
63
+ end
64
+
65
+ def form_method
66
+ "GET"
67
+ end
68
+
69
+ def form_fields
70
+ redirect_parameters
71
+ end
72
+
73
+ private
74
+ def generate_request
75
+ xml = REXML::Document.new
76
+ root = xml.add_element('GenerateRequest')
77
+
78
+ token_parameters.each do | k, v |
79
+ next if v.blank?
80
+
81
+ v = v.to_s.slice(0, 50) if k == "MerchantReference"
82
+ root.add_element(k).text = v
83
+ end
84
+
85
+ xml.to_s
86
+ end
87
+
88
+ def parse_response(raw_response)
89
+ xml = REXML::Document.new(raw_response)
90
+ root = REXML::XPath.first(xml, "//Request")
91
+ valid = root.attributes["valid"]
92
+ redirect = root.elements["URI"].try(:text)
93
+ valid, redirect = "0", root.elements["ResponseText"].try(:text) unless redirect
94
+
95
+ # example valid response:
96
+ # <Request valid="1"><URI>https://sec.paymentexpress.com/pxpay/pxpay.aspx?userid=PxpayUser&amp;request=REQUEST_TOKEN</URI></Request>
97
+ # <Request valid='1'><Reco>IP</Reco><ResponseText>Invalid Access Info</ResponseText></Request>
98
+
99
+ # example invalid response:
100
+ # <Request valid="0"><URI>Invalid TxnType</URI></Request>
101
+
102
+ {:valid => valid, :redirect => redirect}
103
+ end
104
+ end
105
+
106
+ class Notification < OffsitePayments::Notification
107
+ include ActiveMerchant::PostsData
108
+ include ActiveMerchant::RequiresParameters
109
+
110
+ def initialize(query_string, options={})
111
+ # PxPay appends ?result=...&userid=... to whatever return_url was specified, even if that URL ended with a ?query.
112
+ # So switch the first ? if present to a &
113
+ query_string[/\?/] = '&' if query_string[/\?/]
114
+ super
115
+
116
+ @encrypted_params = @params
117
+ @params = {}
118
+
119
+ requires! @encrypted_params, "result"
120
+ requires! @options, :credential1, :credential2
121
+
122
+ decrypt_transaction_result(@encrypted_params["result"])
123
+ end
124
+
125
+ # was the notification a validly formed request?
126
+ def acknowledge(authcode = nil)
127
+ @valid == '1'
128
+ end
129
+
130
+ def status
131
+ return 'Failed' unless success?
132
+ return 'Completed' if complete?
133
+ 'Error'
134
+ end
135
+
136
+ def complete?
137
+ @params['TxnType'] == 'Purchase' && success?
138
+ end
139
+
140
+ def cancelled?
141
+ !success?
142
+ end
143
+
144
+ # for field definitions see
145
+ # http://www.paymentexpress.com/Technical_Resources/Ecommerce_Hosted/PxPay
146
+
147
+ def success?
148
+ @params['Success'] == '1'
149
+ end
150
+
151
+ def gross
152
+ @params['AmountSettlement']
153
+ end
154
+
155
+ def currency
156
+ @params['CurrencySettlement']
157
+ end
158
+
159
+ def account
160
+ @params['userid']
161
+ end
162
+
163
+ def item_id
164
+ @params['MerchantReference']
165
+ end
166
+
167
+ def currency_input
168
+ @params['CurrencyInput']
169
+ end
170
+
171
+ def auth_code
172
+ @params['AuthCode']
173
+ end
174
+
175
+ def card_type
176
+ @params['CardName']
177
+ end
178
+
179
+ def card_holder_name
180
+ @params['CardHolderName']
181
+ end
182
+
183
+ def card_number
184
+ @params['CardNumber']
185
+ end
186
+
187
+ def expiry_date
188
+ @params['DateExpiry']
189
+ end
190
+
191
+ def client_ip
192
+ @params['ClientInfo']
193
+ end
194
+
195
+ def order_id
196
+ item_id
197
+ end
198
+
199
+ def payer_email
200
+ @params['EmailAddress']
201
+ end
202
+
203
+ def transaction_id
204
+ @params['DpsTxnRef']
205
+ end
206
+
207
+ def settlement_date
208
+ @params['DateSettlement']
209
+ end
210
+
211
+ # Indication of the uniqueness of a card number
212
+ def txn_mac
213
+ @params['TxnMac']
214
+ end
215
+
216
+ def message
217
+ @params['ResponseText']
218
+ end
219
+
220
+ def optional_data
221
+ [@params['TxnData1'],@fields['TxnData2'],@fields['TxnData3']]
222
+ end
223
+
224
+ # When was this payment was received by the client.
225
+ def received_at
226
+ settlement_date
227
+ end
228
+
229
+ # Was this a test transaction?
230
+ def test?
231
+ nil
232
+ end
233
+
234
+ private
235
+
236
+ def decrypt_transaction_result(encrypted_result)
237
+ request_xml = REXML::Document.new
238
+ root = request_xml.add_element('ProcessResponse')
239
+
240
+ root.add_element('PxPayUserId').text = @options[:credential1]
241
+ root.add_element('PxPayKey').text = @options[:credential2]
242
+ root.add_element('Response').text = encrypted_result
243
+
244
+ @raw = ssl_post(Pxpay.token_url, request_xml.to_s)
245
+
246
+ response_xml = REXML::Document.new(@raw)
247
+ root = REXML::XPath.first(response_xml)
248
+ @valid = root.attributes["valid"]
249
+ @params = {}
250
+ root.elements.each { |e| @params[e.name] = e.text }
251
+ end
252
+ end
253
+
254
+ class Return < OffsitePayments::Return
255
+ def initialize(query_string, options={})
256
+ @notification = Notification.new(query_string, options)
257
+ end
258
+
259
+ def success?
260
+ @notification && @notification.complete?
261
+ end
262
+
263
+ def cancelled?
264
+ @notification && @notification.cancelled?
265
+ end
266
+
267
+ def message
268
+ @notification.message
269
+ end
270
+ end
271
+ end
272
+ end
273
+ end
@@ -0,0 +1,232 @@
1
+ module OffsitePayments #:nodoc:
2
+ module Integrations #:nodoc:
3
+ module Quickpay
4
+ mattr_accessor :service_url
5
+ self.service_url = 'https://secure.quickpay.dk/form/'
6
+
7
+ def self.notification(post, options = {})
8
+ Notification.new(post)
9
+ end
10
+
11
+ def self.return(post, options = {})
12
+ Return.new(post, options)
13
+ end
14
+
15
+ class Helper < OffsitePayments::Helper
16
+ def initialize(order, account, options = {})
17
+ md5secret options.delete(:credential2)
18
+ super
19
+ add_field('protocol', '7')
20
+ add_field('msgtype', 'authorize')
21
+ add_field('language', 'da')
22
+ add_field('autocapture', 0)
23
+ add_field('testmode', test? ? 1 : 0)
24
+ add_field('ordernumber', format_order_number(order))
25
+ end
26
+
27
+ def md5secret(value)
28
+ @md5secret = value
29
+ end
30
+
31
+ def form_fields
32
+ @fields.merge('md5check' => generate_md5check)
33
+ end
34
+
35
+ def generate_md5string
36
+ MD5_CHECK_FIELDS.map {|key| @fields[key.to_s]} * "" + @md5secret
37
+ end
38
+
39
+ def generate_md5check
40
+ Digest::MD5.hexdigest(generate_md5string)
41
+ end
42
+
43
+ # Limited to 20 digits max
44
+ def format_order_number(number)
45
+ number.to_s.gsub(/[^\w]/, '').rjust(4, "0")[0...20]
46
+ end
47
+
48
+ MD5_CHECK_FIELDS = [
49
+ :protocol,
50
+ :msgtype,
51
+ :merchant,
52
+ :language,
53
+ :ordernumber,
54
+ :amount,
55
+ :currency,
56
+ :continueurl,
57
+ :cancelurl,
58
+ :callbackurl,
59
+ :autocapture,
60
+ :autofee,
61
+ :cardtypelock,
62
+ :description,
63
+ :group,
64
+ :testmode,
65
+ :splitpayment,
66
+ :forcemobile,
67
+ :deadline,
68
+ :cardhash
69
+ ]
70
+
71
+ mapping :protocol, 'protocol'
72
+ mapping :msgtype, 'msgtype'
73
+ mapping :account, 'merchant'
74
+ mapping :language, 'language'
75
+ mapping :amount, 'amount'
76
+ mapping :currency, 'currency'
77
+
78
+ mapping :return_url, 'continueurl'
79
+ mapping :cancel_return_url, 'cancelurl'
80
+ mapping :notify_url, 'callbackurl'
81
+
82
+ mapping :autocapture, 'autocapture'
83
+ mapping :autofee, 'autofee'
84
+ mapping :cardtypelock, 'cardtypelock'
85
+
86
+ mapping :ipaddress, 'ipaddress'
87
+
88
+ mapping :description, 'description'
89
+ mapping :group, 'group'
90
+ mapping :testmode, 'testmode'
91
+
92
+ mapping :splitpayment, 'splitpayment'
93
+ mapping :forcemobile, 'forcemobile'
94
+ mapping :deadline, 'deadline'
95
+ mapping :cardhash, 'cardhash'
96
+
97
+ mapping :customer, ''
98
+ mapping :billing_address, {}
99
+ mapping :tax, ''
100
+ mapping :shipping, ''
101
+ end
102
+
103
+ class Notification < OffsitePayments::Notification
104
+ def complete?
105
+ status == '000'
106
+ end
107
+
108
+ def item_id
109
+ params['ordernumber']
110
+ end
111
+
112
+ def transaction_id
113
+ params['transaction']
114
+ end
115
+
116
+ def received_at
117
+ time = params['time']
118
+ # If time only contains 12 integers then it's pre v5 format
119
+ time = "20#{params['time']}" if /[0-9]{12}/.match(params['time'])
120
+ Time.parse(time)
121
+ end
122
+
123
+ def gross
124
+ "%.2f" % (gross_cents / 100.0)
125
+ end
126
+
127
+ def gross_cents
128
+ params['amount'].to_i
129
+ end
130
+
131
+ def status
132
+ params['qpstat']
133
+ end
134
+
135
+ def currency
136
+ params['currency']
137
+ end
138
+
139
+ # Provide access to raw fields from quickpay
140
+ %w(
141
+ msgtype
142
+ ordernumber
143
+ state
144
+ chstat
145
+ chstatmsg
146
+ qpstat
147
+ qpstatmsg
148
+ merchant
149
+ merchantemail
150
+ cardtype
151
+ cardnumber
152
+ cardhash
153
+ cardexpire
154
+ splitpayment
155
+ fraudprobability
156
+ fraudremarks
157
+ fraudreport
158
+ fee
159
+ ).each do |attr|
160
+ define_method(attr) do
161
+ params[attr]
162
+ end
163
+ end
164
+
165
+ MD5_CHECK_FIELDS = [
166
+ :msgtype,
167
+ :ordernumber,
168
+ :amount,
169
+ :currency,
170
+ :time,
171
+ :state,
172
+ :qpstat,
173
+ :qpstatmsg,
174
+ :chstat,
175
+ :chstatmsg,
176
+ :merchant,
177
+ :merchantemail,
178
+ :transaction,
179
+ :cardtype,
180
+ :cardnumber,
181
+ :cardhash,
182
+ :cardexpire,
183
+ :splitpayment,
184
+ :fraudprobability,
185
+ :fraudremarks,
186
+ :fraudreport,
187
+ :fee
188
+ ]
189
+
190
+ def generate_md5string
191
+ MD5_CHECK_FIELDS.map { |key| params[key.to_s] } * "" + @options[:credential2].to_s
192
+ end
193
+
194
+ def generate_md5check
195
+ Digest::MD5.hexdigest(generate_md5string)
196
+ end
197
+
198
+ # Quickpay doesn't do acknowledgements of callback notifications
199
+ # Instead it uses and MD5 hash of all parameters
200
+ def acknowledge(authcode = nil)
201
+ generate_md5check == params['md5check']
202
+ end
203
+
204
+ # Take the posted data and move the relevant data into a hash
205
+ def parse(post)
206
+ # 30 + 12
207
+ #------------------------------8a827a0e6829
208
+ #Content-Disposition: form-data; name="msgtype"
209
+ #
210
+ #subscribe
211
+ #------------------------------8a827a0e6829
212
+ #Content-Disposition: form-data; name="ordernumber"
213
+ #
214
+ #BILP94406
215
+
216
+ if post =~ /-{20,40}\w{6,24}/
217
+ @raw = post.to_s
218
+ post.split(/-{20,40}\w{6,24}[\n\r]*/m).each do |part|
219
+ part.scan(/([^\n\r]+)[\n\r]+([^\n\r]*)/m) do |header, value|
220
+ if header.match(/name=["'](.*)["']/)
221
+ params[$1] = value.strip
222
+ end
223
+ end
224
+ end
225
+ else
226
+ super
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
232
+ end