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,133 @@
1
+ module OffsitePayments #:nodoc:
2
+ module Integrations #:nodoc:
3
+ module FirstData
4
+ # Overwrite this if you want to change the ANS test url
5
+ mattr_accessor :test_url
6
+ self.test_url = 'https://demo.globalgatewaye4.firstdata.com/payment'
7
+
8
+ # Overwrite this if you want to change the ANS production url
9
+ mattr_accessor :production_url
10
+ self.production_url = 'https://checkout.globalgatewaye4.firstdata.com/payment'
11
+
12
+ def self.service_url
13
+ mode = OffsitePayments.mode
14
+ case mode
15
+ when :production
16
+ self.production_url
17
+ when :test
18
+ self.test_url
19
+ else
20
+ raise StandardError, "Integration mode set to an invalid value: #{mode}"
21
+ end
22
+ end
23
+
24
+ def self.notification(post)
25
+ Notification.new(post)
26
+ end
27
+
28
+ def self.return(query_string)
29
+ Return.new(query_string)
30
+ end
31
+
32
+ # First Data payment pages emulates the Authorize.Net SIM API. See
33
+ # OffsitePayments::Integrations::AuthorizeNetSim::Helper for
34
+ # more details.
35
+ #
36
+ # An example. Note the username as a parameter and transaction key you
37
+ # will want to use later.
38
+ #
39
+ # payment_service_for('order_id', 'first_data_payment_page_id', :service => :first_data, :amount => 157.0) do |service|
40
+ #
41
+ # # You must call setup_hash and invoice
42
+ #
43
+ # service.setup_hash :transaction_key => '8CP6zJ7uD875J6tY',
44
+ # :order_timestamp => 1206836763
45
+ # service.customer_id 8
46
+ # service.customer :first_name => 'g',
47
+ # :last_name => 'g',
48
+ # :email => 'g@g.com',
49
+ # :phone => '3'
50
+ # service.billing_address :zip => 'g',
51
+ # :country => 'United States of America',
52
+ # :address => 'g'
53
+ #
54
+ # service.ship_to_address :first_name => 'g',
55
+ # :last_name => 'g',
56
+ # :city => '',
57
+ # :address => 'g',
58
+ # :address2 => '',
59
+ # :state => address.state,
60
+ # :country => 'United States of America',
61
+ # :zip => 'g'
62
+ #
63
+ # service.invoice "516428355" # your invoice number
64
+ # # The end-user is presented with the HTML produced by the notify_url
65
+ # # (using the First Data Receipt Link feature).
66
+ # service.return_url "http://mysite/first_data_receipt_generator_page"
67
+ # service.payment_header 'My store name'
68
+ # service.add_line_item :name => 'item name', :quantity => 1, :unit_price => 0
69
+ # service.test_request 'true' # only if it's just a test
70
+ # service.shipping '25.0'
71
+ # # Tell it to display a "0" line item for shipping, with the price in
72
+ # # the name, otherwise it isn't shown at all, leaving the end user to
73
+ # # wonder why the total is different than the sum of the line items.
74
+ # service.add_shipping_as_line_item
75
+ # server.add_tax_as_line_item # same with tax
76
+ # # See the helper.rb file for various custom fields
77
+ # end
78
+ class Helper < OffsitePayments::Integrations::AuthorizeNetSim::Helper
79
+ # Configure notify_url to use the "Relay Response" feature
80
+ mapping :notify_url, 'x_relay_url'
81
+
82
+ # Configure return_url to use the "Receipt Link" feature
83
+ mapping :return_url, 'x_receipt_link_url'
84
+ end
85
+
86
+ # First Data payment pages emulates the Authorize.Net SIM API. See
87
+ # OffsitePayments::Integrations::FirstData::Notification for
88
+ # more details.
89
+ #
90
+ # # Example:
91
+ # parser = FirstData::Notification.new(request.raw_post)
92
+ # passed = parser.complete?
93
+ #
94
+ # order = Order.find_by_order_number(parser.invoice_num)
95
+ #
96
+ # unless order
97
+ # @message = 'Error--unable to find your transaction! Please contact us directly.'
98
+ # return render :partial => 'first_data_payment_response'
99
+ # end
100
+ #
101
+ # if order.total != parser.gross.to_f
102
+ # logger.error "First Data said they paid for #{parser.gross} and it should have been #{order.total}!"
103
+ # passed = false
104
+ # end
105
+ #
106
+ # # Theoretically, First Data will *never* pass us the same transaction
107
+ # # ID twice, but we can double check that... by using
108
+ # # parser.transaction_id, and checking against previous orders' transaction
109
+ # # id's (which you can save when the order is completed)....
110
+ # unless parser.acknowledge FIRST_DATA_TRANSACTION_KEY, FIRST_DATA_RESPONSE_KEY
111
+ # passed = false
112
+ # logger.error "ALERT POSSIBLE FRAUD ATTEMPT"
113
+ # end
114
+ #
115
+ # unless parser.cavv_matches? and parser.avs_code_matches?
116
+ # logger.error 'Warning--non matching CC!' + params.inspect
117
+ # # Could fail them here, as well (recommended)...
118
+ # end
119
+ #
120
+ # if passed
121
+ # # Set up your session, and render something that will redirect them to
122
+ # # your site, most likely.
123
+ # else
124
+ # # Render failure or redirect them to your site where you will render failure
125
+ # end
126
+ class Notification < OffsitePayments::Integrations::AuthorizeNetSim::Notification
127
+ def acknowledge(response_key, payment_page_id)
128
+ Digest::MD5.hexdigest(response_key + payment_page_id + params['x_trans_id'] + sprintf('%.2f', gross)) == params['x_MD5_Hash'].downcase
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,201 @@
1
+ # With help from Giovanni Intini and his code for RGestPay - http://medlar.it/it/progetti/rgestpay
2
+
3
+ module OffsitePayments #:nodoc:
4
+ module Integrations #:nodoc:
5
+ module Gestpay
6
+ mattr_accessor :service_url
7
+ self.service_url = 'https://ecomm.sella.it/gestpay/pagam.asp'
8
+
9
+ def self.notification(post, options = {})
10
+ Notification.new(post)
11
+ end
12
+
13
+ def self.return(query_string, options = {})
14
+ Return.new(query_string)
15
+ end
16
+
17
+ module Common
18
+ GestpayEncryptionResponseError = Class.new(StandardError)
19
+
20
+ VERSION = "2.0"
21
+ ENCRYPTION_PATH = "/CryptHTTPS/Encrypt.asp"
22
+ DECRYPTION_PATH = "/CryptHTTPS/Decrypt.asp"
23
+ DELIMITER = '*P1*'
24
+
25
+ CURRENCY_MAPPING = {
26
+ 'EUR' => '242',
27
+ 'ITL' => '18',
28
+ 'BRL' => '234',
29
+ 'USD' => '1',
30
+ 'JPY' => '71',
31
+ 'HKD' => '103'
32
+ }
33
+
34
+
35
+
36
+ def parse_response(response)
37
+ case response
38
+ when /#cryptstring#(.*)#\/cryptstring#/, /#decryptstring#(.*)#\/decryptstring#/
39
+ $1
40
+ when /#error#(.*)#\/error#/
41
+ raise GestpayEncryptionResponseError, "An error occurred retrieving the encrypted string from GestPay: #{$1}"
42
+ else
43
+ raise GestpayEncryptionResponseError, "No response was received by GestPay"
44
+ end
45
+ end
46
+
47
+ def ssl_get(url, path)
48
+ uri = URI.parse(url)
49
+ site = Net::HTTP.new(uri.host, uri.port)
50
+ site.use_ssl = true
51
+ site.verify_mode = OpenSSL::SSL::VERIFY_NONE
52
+ site.get(path).body
53
+ end
54
+ end
55
+
56
+ class Helper < OffsitePayments::Helper
57
+ include Common
58
+ # Valid language codes
59
+ # Italian => 1
60
+ # English => 2
61
+ # Spanish => 3
62
+ # French => 4
63
+ # Tedesco => 5
64
+ def initialize(order, account, options = {})
65
+ super
66
+ add_field('PAY1_IDLANGUAGE', 2)
67
+ end
68
+
69
+ mapping :account, 'ShopLogin'
70
+
71
+ mapping :amount, 'PAY1_AMOUNT'
72
+ mapping :currency, 'PAY1_UICCODE'
73
+
74
+ mapping :order, 'PAY1_SHOPTRANSACTIONID'
75
+
76
+ # Buyer name PAY1_CHNAME
77
+ mapping :customer, :email => 'PAY1_CHEMAIL'
78
+
79
+ mapping :credit_card, :number => 'PAY1_CARDNUMBER',
80
+ :expiry_month => 'PAY1_EXPMONTH',
81
+ :expiry_year => 'PAY1_EXPYEAR',
82
+ :verification_value => 'PAY1_CVV'
83
+
84
+ def customer(params = {})
85
+ add_field(mappings[:customer][:email], params[:email])
86
+ add_field('PAY1_CHNAME', "#{params[:first_name]} #{params[:last_name]}")
87
+ end
88
+
89
+ def currency=(currency_code)
90
+ code = CURRENCY_MAPPING[currency_code]
91
+ raise ActionViewHelperError, "Invalid currency code #{currency_code} specified" if code.nil?
92
+
93
+ add_field(mappings[:currency], code)
94
+ end
95
+
96
+ def form_fields
97
+ @encrypted_data ||= get_encrypted_string
98
+
99
+ {
100
+ 'a' => @fields['ShopLogin'],
101
+ 'b' => @encrypted_data
102
+ }
103
+ end
104
+
105
+ def get_encrypted_string
106
+ response = ssl_get(Gestpay.service_url, encryption_query_string)
107
+ parse_response(response)
108
+ rescue GestpayEncryptionResponseError => e
109
+ raise ActionViewHelperError.new(e)
110
+ end
111
+
112
+ def encryption_query_string
113
+ fields = ['PAY1_AMOUNT', 'PAY1_SHOPTRANSACTIONID', 'PAY1_UICCODE']
114
+
115
+ encoded_params = fields.collect{ |field| "#{field}=#{CGI.escape(@fields[field])}" }.join(DELIMITER)
116
+
117
+ "#{ENCRYPTION_PATH}?a=" + CGI.escape(@fields['ShopLogin']) + "&b=" + encoded_params + "&c=" + CGI.escape(VERSION)
118
+ end
119
+ end
120
+
121
+ class Notification < OffsitePayments::Notification
122
+ include Common
123
+
124
+ def complete?
125
+ status == 'Completed'
126
+ end
127
+
128
+ # The important param
129
+ def item_id
130
+ params['PAY1_SHOPTRANSACTIONID']
131
+ end
132
+
133
+ def transaction_id
134
+ params['PAY1_BANKTRANSACTIONID']
135
+ end
136
+
137
+ # the money amount we received in X.2 decimal.
138
+ def gross
139
+ params['PAY1_AMOUNT']
140
+ end
141
+
142
+ def currency
143
+ # Ruby 1.9 compat
144
+ method = CURRENCY_MAPPING.respond_to?(:key) ? :key : :index
145
+ CURRENCY_MAPPING.send(method, params['PAY1_UICCODE'])
146
+ end
147
+
148
+ def test?
149
+ false
150
+ end
151
+
152
+ def status
153
+ case params['PAY1_TRANSACTIONRESULT']
154
+ when 'OK'
155
+ 'Completed'
156
+ else
157
+ 'Failed'
158
+ end
159
+ end
160
+
161
+ def acknowledge(authcode = nil)
162
+ true
163
+ end
164
+
165
+ private
166
+ # Take the posted data and move the relevant data into a hash
167
+ def parse(query_string)
168
+ @raw = query_string
169
+
170
+ return if query_string.blank?
171
+ encrypted_params = parse_delimited_string(query_string)
172
+
173
+ return if encrypted_params['a'].blank? || encrypted_params['b'].blank?
174
+ @params = decrypt_data(encrypted_params['a'], encrypted_params['b'])
175
+ end
176
+
177
+ def parse_delimited_string(string, delimiter = '&', unencode_cgi = false)
178
+ result = {}
179
+ for line in string.split(delimiter)
180
+ key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
181
+ result[key] = unencode_cgi ? CGI.unescape(value) : value
182
+ end
183
+ result
184
+ end
185
+
186
+ def decrypt_data(shop_login, encrypted_string)
187
+ response = ssl_get(Gestpay.service_url, decryption_query_string(shop_login, encrypted_string))
188
+ encoded_response = parse_response(response)
189
+ parse_delimited_string(encoded_response, DELIMITER, true)
190
+ end
191
+
192
+ def decryption_query_string(shop_login, encrypted_string)
193
+ "#{DECRYPTION_PATH}?a=" + CGI.escape(shop_login) + "&b=" + encrypted_string + "&c=" + CGI.escape(VERSION)
194
+ end
195
+ end
196
+
197
+ class Return < OffsitePayments::Return
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,179 @@
1
+ module OffsitePayments #:nodoc:
2
+ module Integrations #:nodoc:
3
+ module HiTrust
4
+ TEST_URL = 'https://testtrustlink.hitrust.com.tw/TrustLink/TrxReqForJava'
5
+ LIVE_URL = 'https://trustlink.hitrust.com.tw/TrustLink/TrxReqForJava'
6
+
7
+ def self.service_url
8
+ OffsitePayments.mode == :test ? TEST_URL : LIVE_URL
9
+ end
10
+
11
+ def self.notification(post, options = {})
12
+ Notification.new(post)
13
+ end
14
+
15
+ def self.return(query_string, options = {})
16
+ Return.new(query_string)
17
+ end
18
+
19
+ class Helper < OffsitePayments::Helper
20
+ # Transaction types
21
+ # * Auth
22
+ # * AuthRe
23
+ # * Capture
24
+ # * CaptureRe
25
+ # * Refund
26
+ # * RefundRe
27
+ # * Query
28
+ def initialize(order, account, options = {})
29
+ super
30
+ # Perform an authorization by default
31
+ add_field('Type', 'Auth')
32
+
33
+ # Capture the payment right away
34
+ add_field('depositflag', '1')
35
+
36
+ # Disable auto query - who knows what it does?
37
+ add_field('queryflag', '1')
38
+
39
+ add_field('orderdesc', 'Store purchase')
40
+ end
41
+
42
+ mapping :account, 'storeid'
43
+ mapping :amount, 'amount'
44
+
45
+ def amount=(money)
46
+ cents = money.respond_to?(:cents) ? money.cents : money
47
+ raise ArgumentError, "amount must be a Money object or an integer" if money.is_a?(String)
48
+ raise ActionViewHelperError, "amount must be greater than $0.00" if cents.to_i <= 0
49
+
50
+ add_field(mappings[:amount], cents)
51
+ end
52
+ # Supported currencies include:
53
+ # * CNY:Chinese Yuan (Renminbi)
54
+ # * TWD:New Taiwan Dollar
55
+ # * HKD:Hong Kong Dollar
56
+ # * USD:US Dollar
57
+ # * AUD:Austrian Dollar
58
+ mapping :currency, 'currency'
59
+
60
+ mapping :order, 'ordernumber'
61
+ mapping :description, 'orderdesc'
62
+
63
+ mapping :notify_url, 'merUpdateURL'
64
+ mapping :return_url, 'returnURL'
65
+ end
66
+
67
+ class Notification < OffsitePayments::Notification
68
+ SUCCESS = '00'
69
+
70
+ self.production_ips = [ '203.75.242.8' ]
71
+
72
+ def complete?
73
+ status == 'Completed'
74
+ end
75
+
76
+ def transaction_id
77
+ params['authRRN']
78
+ end
79
+
80
+ def item_id
81
+ params['ordernumber']
82
+ end
83
+
84
+ def received_at
85
+ Time.parse(params['orderdate']) rescue nil
86
+ end
87
+
88
+ def currency
89
+ params['currency']
90
+ end
91
+
92
+ def gross
93
+ sprintf("%.2f", gross_cents.to_f / 100)
94
+ end
95
+
96
+ def gross_cents
97
+ params['approveamount'].to_i
98
+ end
99
+
100
+ def account
101
+ params['storeid']
102
+ end
103
+
104
+ def status
105
+ params['retcode'] == SUCCESS ? 'Completed' : 'Failed'
106
+ end
107
+
108
+ def test?
109
+ OffsitePayments.mode == :test
110
+ end
111
+
112
+ def acknowledge
113
+ true
114
+ end
115
+ end
116
+
117
+ class Return < OffsitePayments::Return
118
+ SUCCESS = "00"
119
+ CODES = { "00" => "Operation completed successfully",
120
+ "-1" => "Unable to initialize winsock dll.",
121
+ "-2" => "Can't create stream socket.",
122
+ "-3" => "No Request Message.",
123
+ "-4" => "Can't connect to server.",
124
+ "-5" => "Send socket error.",
125
+ "-6" => "Couldn't receive data.",
126
+ "-7" => "Receive Broken message.",
127
+ "-8" => "Unable to initialize Envirnment.",
128
+ "-9" => "Can't Read Server RSA File.",
129
+ "-10" => "Can't Read Client RSA File.",
130
+ "-11" => "Web Server error.",
131
+ "-12" => "Receive Message type error.",
132
+ "-13" => "No Request Message.",
133
+ "-14" => "No Response Content.",
134
+ "-18" => "Merchant Update URL not found.",
135
+ "-19" => "Server URL not find Domain or IP.",
136
+ "-20" => "Server URL only can fill http or https.",
137
+ "-21" => "Server Config File open error.",
138
+ "-22" => "Server RSA Key File open error.",
139
+ "-23" => "Server RSA Key File read error.",
140
+ "-24" => "Server Config File have some errors, Please to check it.",
141
+ "-25" => "Merchant Config File open error.",
142
+ "-26" => "Merchant RSA Key File open error.",
143
+ "-27" => "Merchant RSA Key File read error.",
144
+ "-28" => "Merchant Config File has some errors, Please to check it.",
145
+ "-29" => "Server Type is unknown.",
146
+ "-30" => "Comm Type is unknown.",
147
+ "-31" => "Input Parameter [ORDERNO] is null or empty.",
148
+ "-32" => "Input Parameter [STOREID] is null or empty.",
149
+ "-33" => "Input Parameter [ORDERDESC] is null or empty.",
150
+ "-34" => "Input Parameter [CURRENCY] is null or empty.",
151
+ "-35" => "Input Parameter [AMOUNT] is null or empty.",
152
+ "-36" => "Input Parameter [ORDERURL] is null or empty.",
153
+ "-37" => "Input Parameter [RETURNURL] is null or empty.",
154
+ "-38" => "Input Parameter [DEPOSIT] is null or empty.",
155
+ "-39" => "Input Parameter [QUERYFLAG] is null or empty.",
156
+ "-40" => "Input Parameter [UPDATEURL] is null or empty.",
157
+ "-41" => "Input Parameter [MERUPDATEURL] is null or empty.",
158
+ "-42" => "Input Parameter [KEY] is null or empty.",
159
+ "-43" => "Input Parameter [MAC] is null or empty.",
160
+ "-44" => "Input Parameter [CIPHER] is null or empty.",
161
+ "-45" => "Input Parameter [TrxType] is wrong.",
162
+ "-100" => "TrustLink Server is closed. Or Merchant Server IP is not consistent with TrustLink Server setting.",
163
+ "-101" => "TrustLink Server receives NULL.",
164
+ "-308" => "Order Number already exists.",
165
+ "positive" => "Response from Bank. Please contact with Acquirer Bank Service or HiTRUST Call Center."
166
+ }
167
+
168
+ def success?
169
+ params['retcode'] == SUCCESS
170
+ end
171
+
172
+ def message
173
+ return CODES["positive"] if params['retcode'].to_i > 0
174
+ CODES[ params['retcode'] ]
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end