offsite_payments 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,271 @@
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
+ end
62
+
63
+ def form_method
64
+ "GET"
65
+ end
66
+
67
+ def form_fields
68
+ redirect_parameters
69
+ end
70
+
71
+ private
72
+ def generate_request
73
+ xml = REXML::Document.new
74
+ root = xml.add_element('GenerateRequest')
75
+
76
+ token_parameters.each do | k, v |
77
+ next if v.blank?
78
+
79
+ v = v.to_s.slice(0, 50) if k == "MerchantReference"
80
+ root.add_element(k).text = v
81
+ end
82
+
83
+ xml.to_s
84
+ end
85
+
86
+ def parse_response(raw_response)
87
+ xml = REXML::Document.new(raw_response)
88
+ root = REXML::XPath.first(xml, "//Request")
89
+ valid = root.attributes["valid"]
90
+ redirect = root.elements["URI"].try(:text)
91
+ valid, redirect = "0", root.elements["ResponseText"].try(:text) unless redirect
92
+
93
+ # example valid response:
94
+ # <Request valid="1"><URI>https://sec.paymentexpress.com/pxpay/pxpay.aspx?userid=PxpayUser&amp;request=REQUEST_TOKEN</URI></Request>
95
+ # <Request valid='1'><Reco>IP</Reco><ResponseText>Invalid Access Info</ResponseText></Request>
96
+
97
+ # example invalid response:
98
+ # <Request valid="0"><URI>Invalid TxnType</URI></Request>
99
+
100
+ {:valid => valid, :redirect => redirect}
101
+ end
102
+ end
103
+
104
+ class Notification < OffsitePayments::Notification
105
+ include ActiveMerchant::PostsData
106
+ include ActiveMerchant::RequiresParameters
107
+
108
+ def initialize(query_string, options={})
109
+ # PxPay appends ?result=...&userid=... to whatever return_url was specified, even if that URL ended with a ?query.
110
+ # So switch the first ? if present to a &
111
+ query_string[/\?/] = '&' if query_string[/\?/]
112
+ super
113
+
114
+ @encrypted_params = @params
115
+ @params = {}
116
+
117
+ requires! @encrypted_params, "result"
118
+ requires! @options, :credential1, :credential2
119
+
120
+ decrypt_transaction_result(@encrypted_params["result"])
121
+ end
122
+
123
+ # was the notification a validly formed request?
124
+ def acknowledge(authcode = nil)
125
+ @valid == '1'
126
+ end
127
+
128
+ def status
129
+ return 'Failed' unless success?
130
+ return 'Completed' if complete?
131
+ 'Error'
132
+ end
133
+
134
+ def complete?
135
+ @params['TxnType'] == 'Purchase' && success?
136
+ end
137
+
138
+ def cancelled?
139
+ !success?
140
+ end
141
+
142
+ # for field definitions see
143
+ # http://www.paymentexpress.com/Technical_Resources/Ecommerce_Hosted/PxPay
144
+
145
+ def success?
146
+ @params['Success'] == '1'
147
+ end
148
+
149
+ def gross
150
+ @params['AmountSettlement']
151
+ end
152
+
153
+ def currency
154
+ @params['CurrencySettlement']
155
+ end
156
+
157
+ def account
158
+ @params['userid']
159
+ end
160
+
161
+ def item_id
162
+ @params['MerchantReference']
163
+ end
164
+
165
+ def currency_input
166
+ @params['CurrencyInput']
167
+ end
168
+
169
+ def auth_code
170
+ @params['AuthCode']
171
+ end
172
+
173
+ def card_type
174
+ @params['CardName']
175
+ end
176
+
177
+ def card_holder_name
178
+ @params['CardHolderName']
179
+ end
180
+
181
+ def card_number
182
+ @params['CardNumber']
183
+ end
184
+
185
+ def expiry_date
186
+ @params['DateExpiry']
187
+ end
188
+
189
+ def client_ip
190
+ @params['ClientInfo']
191
+ end
192
+
193
+ def order_id
194
+ item_id
195
+ end
196
+
197
+ def payer_email
198
+ @params['EmailAddress']
199
+ end
200
+
201
+ def transaction_id
202
+ @params['DpsTxnRef']
203
+ end
204
+
205
+ def settlement_date
206
+ @params['DateSettlement']
207
+ end
208
+
209
+ # Indication of the uniqueness of a card number
210
+ def txn_mac
211
+ @params['TxnMac']
212
+ end
213
+
214
+ def message
215
+ @params['ResponseText']
216
+ end
217
+
218
+ def optional_data
219
+ [@params['TxnData1'],@fields['TxnData2'],@fields['TxnData3']]
220
+ end
221
+
222
+ # When was this payment was received by the client.
223
+ def received_at
224
+ settlement_date
225
+ end
226
+
227
+ # Was this a test transaction?
228
+ def test?
229
+ nil
230
+ end
231
+
232
+ private
233
+
234
+ def decrypt_transaction_result(encrypted_result)
235
+ request_xml = REXML::Document.new
236
+ root = request_xml.add_element('ProcessResponse')
237
+
238
+ root.add_element('PxPayUserId').text = @options[:credential1]
239
+ root.add_element('PxPayKey').text = @options[:credential2]
240
+ root.add_element('Response').text = encrypted_result
241
+
242
+ @raw = ssl_post(Pxpay.token_url, request_xml.to_s)
243
+
244
+ response_xml = REXML::Document.new(@raw)
245
+ root = REXML::XPath.first(response_xml)
246
+ @valid = root.attributes["valid"]
247
+ @params = {}
248
+ root.elements.each { |e| @params[e.name] = e.text }
249
+ end
250
+ end
251
+
252
+ class Return < OffsitePayments::Return
253
+ def initialize(query_string, options={})
254
+ @notification = Notification.new(query_string, options)
255
+ end
256
+
257
+ def success?
258
+ @notification && @notification.complete?
259
+ end
260
+
261
+ def cancelled?
262
+ @notification && @notification.cancelled?
263
+ end
264
+
265
+ def message
266
+ @notification.message
267
+ end
268
+ end
269
+ end
270
+ end
271
+ 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