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