offsite_payments 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +70 -0
- data/lib/offsite_payments.rb +46 -0
- data/lib/offsite_payments/action_view_helper.rb +72 -0
- data/lib/offsite_payments/helper.rb +119 -0
- data/lib/offsite_payments/integrations.rb +14 -0
- data/lib/offsite_payments/integrations/a1agregator.rb +245 -0
- data/lib/offsite_payments/integrations/authorize_net_sim.rb +580 -0
- data/lib/offsite_payments/integrations/bit_pay.rb +150 -0
- data/lib/offsite_payments/integrations/bogus.rb +32 -0
- data/lib/offsite_payments/integrations/chronopay.rb +283 -0
- data/lib/offsite_payments/integrations/citrus.rb +227 -0
- data/lib/offsite_payments/integrations/direc_pay.rb +339 -0
- data/lib/offsite_payments/integrations/directebanking.rb +237 -0
- data/lib/offsite_payments/integrations/doku.rb +171 -0
- data/lib/offsite_payments/integrations/dotpay.rb +166 -0
- data/lib/offsite_payments/integrations/dwolla.rb +160 -0
- data/lib/offsite_payments/integrations/e_payment_plans.rb +146 -0
- data/lib/offsite_payments/integrations/easy_pay.rb +137 -0
- data/lib/offsite_payments/integrations/epay.rb +161 -0
- data/lib/offsite_payments/integrations/first_data.rb +133 -0
- data/lib/offsite_payments/integrations/gestpay.rb +201 -0
- data/lib/offsite_payments/integrations/hi_trust.rb +179 -0
- data/lib/offsite_payments/integrations/ipay88.rb +240 -0
- data/lib/offsite_payments/integrations/klarna.rb +291 -0
- data/lib/offsite_payments/integrations/liqpay.rb +216 -0
- data/lib/offsite_payments/integrations/maksuturva.rb +231 -0
- data/lib/offsite_payments/integrations/mollie_ideal.rb +213 -0
- data/lib/offsite_payments/integrations/moneybookers.rb +199 -0
- data/lib/offsite_payments/integrations/nochex.rb +228 -0
- data/lib/offsite_payments/integrations/pag_seguro.rb +255 -0
- data/lib/offsite_payments/integrations/paxum.rb +114 -0
- data/lib/offsite_payments/integrations/pay_fast.rb +269 -0
- data/lib/offsite_payments/integrations/paydollar.rb +142 -0
- data/lib/offsite_payments/integrations/payflow_link.rb +194 -0
- data/lib/offsite_payments/integrations/paypal.rb +362 -0
- data/lib/offsite_payments/integrations/paypal_payments_advanced.rb +23 -0
- data/lib/offsite_payments/integrations/paysbuy.rb +71 -0
- data/lib/offsite_payments/integrations/payu_in.rb +266 -0
- data/lib/offsite_payments/integrations/payu_in_paisa.rb +46 -0
- data/lib/offsite_payments/integrations/platron.rb +153 -0
- data/lib/offsite_payments/integrations/pxpay.rb +271 -0
- data/lib/offsite_payments/integrations/quickpay.rb +232 -0
- data/lib/offsite_payments/integrations/rbkmoney.rb +110 -0
- data/lib/offsite_payments/integrations/robokassa.rb +154 -0
- data/lib/offsite_payments/integrations/sage_pay_form.rb +425 -0
- data/lib/offsite_payments/integrations/two_checkout.rb +332 -0
- data/lib/offsite_payments/integrations/universal.rb +180 -0
- data/lib/offsite_payments/integrations/valitor.rb +200 -0
- data/lib/offsite_payments/integrations/verkkomaksut.rb +143 -0
- data/lib/offsite_payments/integrations/web_pay.rb +186 -0
- data/lib/offsite_payments/integrations/webmoney.rb +119 -0
- data/lib/offsite_payments/integrations/wirecard_checkout_page.rb +359 -0
- data/lib/offsite_payments/integrations/world_pay.rb +273 -0
- data/lib/offsite_payments/notification.rb +71 -0
- data/lib/offsite_payments/return.rb +37 -0
- data/lib/offsite_payments/version.rb +3 -0
- metadata +270 -0
@@ -0,0 +1,199 @@
|
|
1
|
+
module OffsitePayments #:nodoc:
|
2
|
+
module Integrations #:nodoc:
|
3
|
+
module Moneybookers
|
4
|
+
mattr_accessor :production_url
|
5
|
+
self.production_url = 'https://www.moneybookers.com/app/payment.pl'
|
6
|
+
|
7
|
+
def self.service_url
|
8
|
+
self.production_url
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.notification(post, options)
|
12
|
+
Notification.new(post, options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.return(post, options = {})
|
16
|
+
Return.new(post, options)
|
17
|
+
end
|
18
|
+
|
19
|
+
class Helper < OffsitePayments::Helper
|
20
|
+
mapping :account, 'pay_to_email'
|
21
|
+
mapping :order, 'transaction_id'
|
22
|
+
mapping :amount, 'amount'
|
23
|
+
mapping :currency, 'currency'
|
24
|
+
|
25
|
+
mapping :customer,
|
26
|
+
:first_name => 'firstname',
|
27
|
+
:last_name => 'lastname',
|
28
|
+
:email => 'pay_from_email',
|
29
|
+
:phone => 'phone_number'
|
30
|
+
|
31
|
+
mapping :billing_address,
|
32
|
+
:city => 'city',
|
33
|
+
:address1 => 'address',
|
34
|
+
:address2 => 'address2',
|
35
|
+
:state => 'state',
|
36
|
+
:zip => 'postal_code',
|
37
|
+
:country => 'country'
|
38
|
+
|
39
|
+
mapping :notify_url, 'status_url'
|
40
|
+
mapping :return_url, 'return_url'
|
41
|
+
mapping :cancel_return_url, 'cancel_url'
|
42
|
+
mapping :description, 'detail1_text'
|
43
|
+
|
44
|
+
MAPPED_COUNTRY_CODES = {
|
45
|
+
'SE' => 'SV',
|
46
|
+
'DK' => 'DA'
|
47
|
+
}
|
48
|
+
|
49
|
+
SUPPORTED_COUNTRY_CODES = [
|
50
|
+
'FI', 'DE', 'ES', 'FR',
|
51
|
+
'IT','PL', 'GR', 'RO',
|
52
|
+
'RU', 'TR', 'CN', 'CZ', 'NL'
|
53
|
+
]
|
54
|
+
|
55
|
+
def initialize(order, account, options = {})
|
56
|
+
super
|
57
|
+
add_tracking_token
|
58
|
+
add_default_parameters
|
59
|
+
add_seller_details(options)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def add_tracking_token
|
65
|
+
return if application_id.blank? || application_id == 'ActiveMerchant'
|
66
|
+
|
67
|
+
add_field('merchant_fields', 'platform')
|
68
|
+
add_field('platform', application_id)
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_default_parameters
|
72
|
+
add_field('hide_login', 1)
|
73
|
+
end
|
74
|
+
|
75
|
+
def add_seller_details(options)
|
76
|
+
add_field('recipient_description', options[:account_name]) if options[:account_name]
|
77
|
+
add_field('country', lookup_country_code(options[:country], :alpha3)) if options[:country]
|
78
|
+
add_field('language', locale_code(options[:country])) if options[:country]
|
79
|
+
end
|
80
|
+
|
81
|
+
def locale_code(country_code)
|
82
|
+
return country_code if SUPPORTED_COUNTRY_CODES.include?(country_code)
|
83
|
+
MAPPED_COUNTRY_CODES[country_code] || 'EN'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class Notification < OffsitePayments::Notification
|
88
|
+
def complete?
|
89
|
+
status == 'Completed'
|
90
|
+
end
|
91
|
+
|
92
|
+
# ‘2’ Processed – This status is sent when the transaction is processed and the funds have been received on your Moneybookers account.
|
93
|
+
# ‘0’ Pending – This status is sent when the customers pays via the pending bank transfer option. Such transactions will auto-process IF the bank transfer is received by Moneybookers. We strongly recommend that you do NOT process the order/transaction in your system upon receipt of a pending status from Moneybookers.
|
94
|
+
# ‘-1’ Cancelled – Pending transactions can either be cancelled manually by the sender in their online account history or they will auto-cancel after 14 days if still pending.
|
95
|
+
# ‘-2’ Failed – This status is sent when the customer tries to pay via Credit Card or Direct Debit but our provider declines the transaction. If you do not accept Credit Card or Direct Debit payments via Moneybookers (see page 17) then you will never receive the failed status.
|
96
|
+
# ‘-3’ Chargeback – This status could be received only if your account is configured to receive chargebacks. If this is the case, whenever a chargeback is received by Moneybookers, a -3 status will be posted on the status_url for the reversed transaction.
|
97
|
+
def status
|
98
|
+
case status_code
|
99
|
+
when '2'
|
100
|
+
'Completed'
|
101
|
+
when '0'
|
102
|
+
'Pending'
|
103
|
+
when '-1'
|
104
|
+
'Cancelled'
|
105
|
+
when '-2'
|
106
|
+
'Failed'
|
107
|
+
when '-3'
|
108
|
+
'Reversed'
|
109
|
+
else
|
110
|
+
'Error'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def status_code
|
115
|
+
params['status']
|
116
|
+
end
|
117
|
+
|
118
|
+
def item_id
|
119
|
+
params['transaction_id']
|
120
|
+
end
|
121
|
+
|
122
|
+
def transaction_id
|
123
|
+
params['mb_transaction_id']
|
124
|
+
end
|
125
|
+
|
126
|
+
# When was this payment received by the client.
|
127
|
+
def received_at
|
128
|
+
nil
|
129
|
+
end
|
130
|
+
|
131
|
+
def payer_email
|
132
|
+
params['pay_from_email']
|
133
|
+
end
|
134
|
+
|
135
|
+
def receiver_email
|
136
|
+
params['pay_to_email']
|
137
|
+
end
|
138
|
+
|
139
|
+
def md5sig
|
140
|
+
params['md5sig']
|
141
|
+
end
|
142
|
+
|
143
|
+
#Unique ID from the merchant's Moneybookers.com account, needed for calculatinon of md5 sig
|
144
|
+
def merchant_id
|
145
|
+
params['merchant_id']
|
146
|
+
end
|
147
|
+
|
148
|
+
# currency of the payment as posted by the merchant on the entry form
|
149
|
+
def currency
|
150
|
+
params['currency']
|
151
|
+
end
|
152
|
+
|
153
|
+
# amount of the payment as posted by the merchant on the entry form (ex. 39.60/39.6/39)
|
154
|
+
def gross
|
155
|
+
params['amount']
|
156
|
+
end
|
157
|
+
|
158
|
+
# currency of mb_amount, will always be the same as the currency of the beneficiary's account at Moneybookers.com
|
159
|
+
def merchant_currency
|
160
|
+
params['mb_currency']
|
161
|
+
end
|
162
|
+
|
163
|
+
# total amount of the payment in Merchants currency (ex 25.46/25.4/25)
|
164
|
+
def merchant_amount
|
165
|
+
params['mb_amount']
|
166
|
+
end
|
167
|
+
|
168
|
+
# Was this a test transaction?
|
169
|
+
def test?
|
170
|
+
false
|
171
|
+
end
|
172
|
+
|
173
|
+
def secret
|
174
|
+
@options[:credential2]
|
175
|
+
end
|
176
|
+
|
177
|
+
# Acknowledge the transaction to MoneyBooker. This method has to be called after a new
|
178
|
+
# apc arrives. It will verify that all the information we received is correct and will return a
|
179
|
+
# ok or a fail. The secret (second credential) has to be provided in the parameter :credential2
|
180
|
+
# when instantiating the Notification object.
|
181
|
+
#
|
182
|
+
# Example:
|
183
|
+
#
|
184
|
+
# def ipn
|
185
|
+
# notify = Moneybookers.notification(request.raw_post, :credential2 => 'secret')
|
186
|
+
#
|
187
|
+
# if notify.acknowledge
|
188
|
+
# ... process order ... if notify.complete?
|
189
|
+
# else
|
190
|
+
# ... log possible hacking attempt ...
|
191
|
+
# end
|
192
|
+
def acknowledge(authcode = nil)
|
193
|
+
fields = [merchant_id, item_id, Digest::MD5.hexdigest(secret.to_s).upcase, merchant_amount, merchant_currency, status_code].join
|
194
|
+
md5sig == Digest::MD5.hexdigest(fields).upcase
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,228 @@
|
|
1
|
+
module OffsitePayments #:nodoc:
|
2
|
+
module Integrations #:nodoc:
|
3
|
+
# To start with Nochex, follow the instructions for installing
|
4
|
+
# ActiveMerchant as a plugin, as described on
|
5
|
+
# http://www.activemerchant.org/.
|
6
|
+
#
|
7
|
+
# The plugin will automatically add the ActionView helper for
|
8
|
+
# ActiveMerchant, which will allow you to make the Nochex payments.
|
9
|
+
# The idea behind the helper is that it generates an invisible
|
10
|
+
# forwarding screen that will automatically redirect the user.
|
11
|
+
# So you would collect all the information about the order and then
|
12
|
+
# simply render the hidden form, which redirects the user to Nochex.
|
13
|
+
#
|
14
|
+
# The syntax of the helper is as follows:
|
15
|
+
#
|
16
|
+
# <% payment_service_for 'order id', 'nochex_user_id',
|
17
|
+
# :amount => 50.00,
|
18
|
+
# :service => :nochex,
|
19
|
+
# :html => { :id => 'nochex-form' } do |service| %>
|
20
|
+
#
|
21
|
+
# <% service.customer :first_name => 'Cody',
|
22
|
+
# :last_name => 'Fauser',
|
23
|
+
# :phone => '(555)555-5555',
|
24
|
+
# :email => 'cody@example.com' %>
|
25
|
+
#
|
26
|
+
# <% service.billing_address :city => 'Ottawa',
|
27
|
+
# :address1 => '21 Snowy Brook Lane',
|
28
|
+
# :address2 => 'Apt. 36',
|
29
|
+
# :state => 'ON',
|
30
|
+
# :country => 'CA',
|
31
|
+
# :zip => 'K1J1E5' %>
|
32
|
+
#
|
33
|
+
# <% service.invoice '#1000' %>
|
34
|
+
# <% service.shipping '0.00' %>
|
35
|
+
# <% service.tax '0.00' %>
|
36
|
+
#
|
37
|
+
# <% service.notify_url url_for(:action => 'notify', :only_path => false) %>
|
38
|
+
# <% service.return_url url_for(:action => 'done', :only_path => false) %>
|
39
|
+
# <% service.cancel_return_url 'http://mystore.com' %>
|
40
|
+
# <% end %>
|
41
|
+
#
|
42
|
+
# The notify_url is the URL that the Nochex IPN will be sent. You can
|
43
|
+
# handle the notification in your controller action as follows:
|
44
|
+
#
|
45
|
+
# class NotificationController < ApplicationController
|
46
|
+
# include OffsitePayments::Integrations
|
47
|
+
#
|
48
|
+
# def notify
|
49
|
+
# notification = Nochex::Notification.new(request.raw_post)
|
50
|
+
#
|
51
|
+
# begin
|
52
|
+
# # Acknowledge notification with Nochex
|
53
|
+
# raise StandardError, 'Illegal Notification' unless notification.acknowledge
|
54
|
+
# # Process the payment
|
55
|
+
# rescue => e
|
56
|
+
# logger.warn("Illegal notification received: #{e.message}")
|
57
|
+
# ensure
|
58
|
+
# head(:ok)
|
59
|
+
# end
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
module Nochex
|
63
|
+
mattr_accessor :service_url
|
64
|
+
self.service_url = 'https://secure.nochex.com'
|
65
|
+
|
66
|
+
mattr_accessor :notification_confirmation_url
|
67
|
+
self.notification_confirmation_url = 'https://www.nochex.com/nochex.dll/apc/apc'
|
68
|
+
|
69
|
+
# Simply a convenience method that returns a new
|
70
|
+
# OffsitePayments::Integrations::Nochex::Notification
|
71
|
+
def self.notification(post, options = {})
|
72
|
+
Notification.new(post)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.return(query_string, options = {})
|
76
|
+
Return.new(query_string)
|
77
|
+
end
|
78
|
+
|
79
|
+
class Helper < OffsitePayments::Helper
|
80
|
+
# Required Parameters
|
81
|
+
# email
|
82
|
+
# amount
|
83
|
+
mapping :account, 'email'
|
84
|
+
mapping :amount, 'amount'
|
85
|
+
|
86
|
+
# Set the field status = test for testing with accounts:
|
87
|
+
# Account Password
|
88
|
+
# test1@nochex.com 123456
|
89
|
+
# test2@nochex.com 123456
|
90
|
+
# def initialize(order, account, options = {})
|
91
|
+
# super
|
92
|
+
# add_field('status', 'test')
|
93
|
+
# end
|
94
|
+
|
95
|
+
# Need to format the amount to have 2 decimal places
|
96
|
+
def amount=(money)
|
97
|
+
cents = money.respond_to?(:cents) ? money.cents : money
|
98
|
+
raise ArgumentError, "amount must be a Money object or an integer" if money.is_a?(String)
|
99
|
+
raise ActionViewHelperError, "amount must be greater than $0.00" if cents.to_i <= 0
|
100
|
+
|
101
|
+
add_field mappings[:amount], sprintf("%.2f", cents.to_f/100)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Optional Parameters
|
105
|
+
# ordernumber
|
106
|
+
mapping :order, 'ordernumber'
|
107
|
+
|
108
|
+
# firstname
|
109
|
+
# lastname
|
110
|
+
# email_address_sender
|
111
|
+
mapping :customer, :first_name => 'firstname',
|
112
|
+
:last_name => 'lastname',
|
113
|
+
:email => 'email_address_sender'
|
114
|
+
|
115
|
+
# town
|
116
|
+
# firstline
|
117
|
+
# county
|
118
|
+
# postcode
|
119
|
+
mapping :billing_address, :city => 'town',
|
120
|
+
:address1 => 'firstline',
|
121
|
+
:state => 'county',
|
122
|
+
:zip => 'postcode'
|
123
|
+
|
124
|
+
# responderurl
|
125
|
+
mapping :notify_url, 'responderurl'
|
126
|
+
|
127
|
+
# returnurl
|
128
|
+
mapping :return_url, 'returnurl'
|
129
|
+
|
130
|
+
# cancelurl
|
131
|
+
mapping :cancel_return_url, 'cancelurl'
|
132
|
+
|
133
|
+
# description
|
134
|
+
mapping :description, 'description'
|
135
|
+
|
136
|
+
# Currently unmapped
|
137
|
+
# logo
|
138
|
+
end
|
139
|
+
|
140
|
+
# Parser and handler for incoming Automatic Payment Confirmations from Nochex.
|
141
|
+
class Notification < OffsitePayments::Notification
|
142
|
+
include ActiveMerchant::PostsData
|
143
|
+
|
144
|
+
def complete?
|
145
|
+
status == 'Completed'
|
146
|
+
end
|
147
|
+
|
148
|
+
# Id of the order we passed to Nochex
|
149
|
+
def item_id
|
150
|
+
params['order_id']
|
151
|
+
end
|
152
|
+
|
153
|
+
def transaction_id
|
154
|
+
params['transaction_id']
|
155
|
+
end
|
156
|
+
|
157
|
+
def currency
|
158
|
+
'GBP'
|
159
|
+
end
|
160
|
+
|
161
|
+
# When was this payment received by the client.
|
162
|
+
def received_at
|
163
|
+
# U.K. Format: 27/09/2006 22:30:54
|
164
|
+
return if params['transaction_date'].blank?
|
165
|
+
time = params['transaction_date'].scan(/\d+/)
|
166
|
+
Time.utc(time[2], time[1], time[0], time[3], time[4], time[5])
|
167
|
+
end
|
168
|
+
|
169
|
+
def payer_email
|
170
|
+
params['from_email']
|
171
|
+
end
|
172
|
+
|
173
|
+
def receiver_email
|
174
|
+
params['to_email']
|
175
|
+
end
|
176
|
+
|
177
|
+
def security_key
|
178
|
+
params['security_key']
|
179
|
+
end
|
180
|
+
|
181
|
+
# the money amount we received in X.2 decimal.
|
182
|
+
def gross
|
183
|
+
sprintf("%.2f", params['amount'].to_f)
|
184
|
+
end
|
185
|
+
|
186
|
+
# Was this a test transaction?
|
187
|
+
def test?
|
188
|
+
params['status'] == 'test'
|
189
|
+
end
|
190
|
+
|
191
|
+
def status
|
192
|
+
'Completed'
|
193
|
+
end
|
194
|
+
|
195
|
+
# Acknowledge the transaction to Nochex. This method has to be called after a new
|
196
|
+
# apc arrives. Nochex will verify that all the information we received are correct and will return a
|
197
|
+
# ok or a fail. This is very similar to the PayPal IPN scheme.
|
198
|
+
#
|
199
|
+
# Example:
|
200
|
+
#
|
201
|
+
# def nochex_ipn
|
202
|
+
# notify = NochexNotification.new(request.raw_post)
|
203
|
+
#
|
204
|
+
# if notify.acknowledge
|
205
|
+
# ... process order ... if notify.complete?
|
206
|
+
# else
|
207
|
+
# ... log possible hacking attempt ...
|
208
|
+
# end
|
209
|
+
def acknowledge(authcode = nil)
|
210
|
+
payload = raw
|
211
|
+
|
212
|
+
response = ssl_post(Nochex.notification_confirmation_url, payload,
|
213
|
+
'Content-Length' => "#{payload.size}",
|
214
|
+
'User-Agent' => "Active Merchant -- http://activemerchant.org",
|
215
|
+
'Content-Type' => "application/x-www-form-urlencoded"
|
216
|
+
)
|
217
|
+
|
218
|
+
raise StandardError.new("Faulty Nochex result: #{response}") unless ["AUTHORISED", "DECLINED"].include?(response)
|
219
|
+
|
220
|
+
response == "AUTHORISED"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
class Return < OffsitePayments::Return
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
module OffsitePayments #:nodoc:
|
2
|
+
module Integrations #:nodoc:
|
3
|
+
module PagSeguro
|
4
|
+
mattr_accessor :service_production_url
|
5
|
+
self.service_production_url = 'https://pagseguro.uol.com.br/v2/checkout/payment.html'
|
6
|
+
|
7
|
+
mattr_accessor :service_test_url
|
8
|
+
self.service_test_url = 'https://sandbox.pagseguro.uol.com.br/v2/checkout/payment.html'
|
9
|
+
|
10
|
+
mattr_accessor :invoicing_production_url
|
11
|
+
self.invoicing_production_url = 'https://ws.pagseguro.uol.com.br/v2/checkout/'
|
12
|
+
|
13
|
+
mattr_accessor :invoicing_test_url
|
14
|
+
self.invoicing_test_url = 'https://ws.sandbox.pagseguro.uol.com.br/v2/checkout/'
|
15
|
+
|
16
|
+
mattr_accessor :notification_production_url
|
17
|
+
self.notification_production_url = 'https://ws.pagseguro.uol.com.br/v2/transactions/notifications/'
|
18
|
+
|
19
|
+
mattr_accessor :notification_test_url
|
20
|
+
self.notification_test_url = 'https://ws.sandbox.pagseguro.uol.com.br/v2/transactions/notifications/'
|
21
|
+
|
22
|
+
def self.service_url
|
23
|
+
test? ? service_test_url : service_production_url
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.invoicing_url
|
27
|
+
test? ? invoicing_test_url : invoicing_production_url
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.notification_url
|
31
|
+
test? ? notification_test_url : notification_production_url
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.notification(query_string, options = {})
|
35
|
+
Notification.new(query_string, options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.return(query_string, options = {})
|
39
|
+
Return.new(query_string, options)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.test?
|
43
|
+
OffsitePayments.mode == :test
|
44
|
+
end
|
45
|
+
|
46
|
+
class Helper < OffsitePayments::Helper
|
47
|
+
def initialize(order_id, account, options)
|
48
|
+
super
|
49
|
+
@account = account
|
50
|
+
|
51
|
+
add_field('itemAmount1', sprintf("%0.02f", options[:amount]))
|
52
|
+
add_field('itemId1', '1')
|
53
|
+
add_field('itemQuantity1', '1')
|
54
|
+
add_field('shippingType', '3')
|
55
|
+
add_field('currency', 'BRL')
|
56
|
+
end
|
57
|
+
|
58
|
+
mapping :account, 'email'
|
59
|
+
mapping :credential2, 'token'
|
60
|
+
|
61
|
+
mapping :order, 'reference'
|
62
|
+
|
63
|
+
mapping :billing_address, :city => 'shippingAddressCity',
|
64
|
+
:address1 => 'shippingAddressStreet',
|
65
|
+
:address2 => 'shippingAddressNumber',
|
66
|
+
:state => 'shippingAddressState',
|
67
|
+
:zip => 'shippingAddressPostalCode',
|
68
|
+
:country => 'shippingAddressCountry'
|
69
|
+
|
70
|
+
mapping :notify_url, 'notificationURL'
|
71
|
+
mapping :return_url, 'redirectURL'
|
72
|
+
mapping :description, 'itemDescription1'
|
73
|
+
|
74
|
+
def form_fields
|
75
|
+
invoice_id = fetch_token
|
76
|
+
|
77
|
+
{"code" => invoice_id}
|
78
|
+
end
|
79
|
+
|
80
|
+
def shipping(value)
|
81
|
+
add_field("shippingCost", sprintf("%0.02f", value))
|
82
|
+
end
|
83
|
+
|
84
|
+
def customer(params = {})
|
85
|
+
phone = area_code_and_number(params[:phone])
|
86
|
+
full_name = remove_excessive_whitespace("#{params[:first_name]} #{params[:last_name]}")
|
87
|
+
|
88
|
+
add_field("senderAreaCode", phone[0])
|
89
|
+
add_field("senderPhone", phone[1])
|
90
|
+
add_field("senderEmail", params[:email])
|
91
|
+
add_field('senderName', full_name)
|
92
|
+
end
|
93
|
+
|
94
|
+
def fetch_token
|
95
|
+
uri = URI.parse(PagSeguro.invoicing_url)
|
96
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
97
|
+
http.use_ssl = true
|
98
|
+
|
99
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
100
|
+
request.content_type = "application/x-www-form-urlencoded"
|
101
|
+
request.set_form_data @fields
|
102
|
+
|
103
|
+
response = http.request(request)
|
104
|
+
xml = Nokogiri::XML.parse(response.body)
|
105
|
+
|
106
|
+
check_for_errors(response, xml)
|
107
|
+
|
108
|
+
extract_token(xml)
|
109
|
+
rescue Timeout::Error, Errno::ECONNRESET => e
|
110
|
+
raise ActionViewHelperError, "Erro ao conectar-se ao PagSeguro. Por favor, tente novamente."
|
111
|
+
end
|
112
|
+
|
113
|
+
def area_code_and_number(phone)
|
114
|
+
phone.gsub!(/[^\d]/, '')
|
115
|
+
|
116
|
+
ddd = phone.slice(0..1)
|
117
|
+
number = phone.slice(2..12)
|
118
|
+
|
119
|
+
[ddd, number]
|
120
|
+
end
|
121
|
+
|
122
|
+
def check_for_errors(response, xml)
|
123
|
+
return if response.code == "200"
|
124
|
+
|
125
|
+
case response.code
|
126
|
+
when "400"
|
127
|
+
raise ActionViewHelperError, humanize_errors(xml)
|
128
|
+
when "401"
|
129
|
+
raise ActionViewHelperError, "Token do PagSeguro inválido."
|
130
|
+
else
|
131
|
+
raise ActiveMerchant::ResponseError, response
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def extract_token(xml)
|
136
|
+
xml.css("code").text
|
137
|
+
end
|
138
|
+
|
139
|
+
def humanize_errors(xml)
|
140
|
+
# reference: https://pagseguro.uol.com.br/v2/guia-de-integracao/codigos-de-erro.html
|
141
|
+
|
142
|
+
xml.css("errors").children.map do |error|
|
143
|
+
case error.css('code').text
|
144
|
+
when "11013"
|
145
|
+
"Código de área inválido"
|
146
|
+
when "11014"
|
147
|
+
"Número de telefone inválido. Formato esperado: (DD) XXXX-XXXX"
|
148
|
+
when "11017"
|
149
|
+
"Código postal (CEP) inválido."
|
150
|
+
else
|
151
|
+
error.css('message').text
|
152
|
+
end
|
153
|
+
end.join(", ")
|
154
|
+
end
|
155
|
+
|
156
|
+
def remove_excessive_whitespace(text)
|
157
|
+
text.gsub(/\s{2,}/, ' ').strip
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class Notification < OffsitePayments::Notification
|
162
|
+
def initialize(post, options = {})
|
163
|
+
notify_code = parse_http_query(post)["notificationCode"]
|
164
|
+
email = options[:credential1]
|
165
|
+
token = options[:credential2]
|
166
|
+
|
167
|
+
uri = URI.join(PagSeguro.notification_url, notify_code)
|
168
|
+
parse_xml(web_get(uri, email: email, token: token))
|
169
|
+
end
|
170
|
+
|
171
|
+
def complete?
|
172
|
+
status == "Completed"
|
173
|
+
end
|
174
|
+
|
175
|
+
def item_id
|
176
|
+
params["transaction"]["reference"]
|
177
|
+
end
|
178
|
+
|
179
|
+
def transaction_id
|
180
|
+
params["transaction"]["code"]
|
181
|
+
end
|
182
|
+
|
183
|
+
def received_at
|
184
|
+
params["transaction"]["date"]
|
185
|
+
end
|
186
|
+
|
187
|
+
def payer_email
|
188
|
+
params["sender"]["email"]
|
189
|
+
end
|
190
|
+
|
191
|
+
def gross
|
192
|
+
params["transaction"]["grossAmount"]
|
193
|
+
end
|
194
|
+
|
195
|
+
def currency
|
196
|
+
"BRL"
|
197
|
+
end
|
198
|
+
|
199
|
+
def payment_method_type
|
200
|
+
params["transaction"]["paymentMethod"]["type"]
|
201
|
+
end
|
202
|
+
|
203
|
+
def payment_method_code
|
204
|
+
params["transaction"]["paymentMethod"]["code"]
|
205
|
+
end
|
206
|
+
|
207
|
+
def status
|
208
|
+
case params["transaction"]["status"]
|
209
|
+
when "1", "2"
|
210
|
+
"Pending"
|
211
|
+
when "3"
|
212
|
+
"Completed"
|
213
|
+
when "4"
|
214
|
+
"Available"
|
215
|
+
when "5"
|
216
|
+
"Dispute"
|
217
|
+
when "6"
|
218
|
+
"Reversed"
|
219
|
+
when "7"
|
220
|
+
"Failed"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
# There's no acknowledge for PagSeguro
|
225
|
+
def acknowledge
|
226
|
+
true
|
227
|
+
end
|
228
|
+
|
229
|
+
private
|
230
|
+
|
231
|
+
def web_get(uri, params)
|
232
|
+
uri.query = URI.encode_www_form(params)
|
233
|
+
|
234
|
+
response = Net::HTTP.get_response(uri)
|
235
|
+
response.body
|
236
|
+
end
|
237
|
+
|
238
|
+
# Take the posted data and move the relevant data into a hash
|
239
|
+
def parse_xml(post)
|
240
|
+
@params = Hash.from_xml(post)
|
241
|
+
end
|
242
|
+
|
243
|
+
def parse_http_query(post)
|
244
|
+
@raw = post
|
245
|
+
params = {}
|
246
|
+
for line in post.split('&')
|
247
|
+
key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
|
248
|
+
params[key] = value
|
249
|
+
end
|
250
|
+
params
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|