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,194 @@
|
|
1
|
+
module OffsitePayments #:nodoc:
|
2
|
+
module Integrations #:nodoc:
|
3
|
+
module PayflowLink
|
4
|
+
mattr_accessor :service_url
|
5
|
+
self.service_url = 'https://payflowlink.paypal.com'
|
6
|
+
|
7
|
+
def self.notification(post, options = {})
|
8
|
+
Notification.new(post)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.return(query_string, options = {})
|
12
|
+
OffsitePayments::Return.new(query_string)
|
13
|
+
end
|
14
|
+
|
15
|
+
class Helper < OffsitePayments::Helper
|
16
|
+
include ActiveMerchant::PostsData
|
17
|
+
|
18
|
+
def initialize(order, account, options = {})
|
19
|
+
super
|
20
|
+
add_field('login', account)
|
21
|
+
add_field('echodata', 'True')
|
22
|
+
add_field('user2', self.test?)
|
23
|
+
add_field('invoice', order)
|
24
|
+
add_field('vendor', account)
|
25
|
+
add_field('user', options[:credential4].presence || account)
|
26
|
+
add_field('trxtype', options[:transaction_type] || 'S')
|
27
|
+
end
|
28
|
+
|
29
|
+
mapping :account, 'login'
|
30
|
+
mapping :credential2, 'pwd'
|
31
|
+
mapping :credential3, 'partner'
|
32
|
+
mapping :order, 'user1'
|
33
|
+
|
34
|
+
mapping :amount, 'amt'
|
35
|
+
|
36
|
+
|
37
|
+
mapping :billing_address, :city => 'city',
|
38
|
+
:address => 'address',
|
39
|
+
:state => 'state',
|
40
|
+
:zip => 'zip',
|
41
|
+
:country => 'country',
|
42
|
+
:phone => 'phone',
|
43
|
+
:name => 'name'
|
44
|
+
|
45
|
+
mapping :customer, { :first_name => 'first_name', :last_name => 'last_name' }
|
46
|
+
|
47
|
+
def description(value)
|
48
|
+
add_field('description', normalize("#{value}").delete("#"))
|
49
|
+
end
|
50
|
+
|
51
|
+
def customer(params = {})
|
52
|
+
add_field(mappings[:customer][:first_name], params[:first_name])
|
53
|
+
add_field(mappings[:customer][:last_name], params[:last_name])
|
54
|
+
end
|
55
|
+
|
56
|
+
def billing_address(params = {})
|
57
|
+
# Get the country code in the correct format
|
58
|
+
# Use what we were given if we can't find anything
|
59
|
+
country_code = lookup_country_code(params.delete(:country))
|
60
|
+
add_field(mappings[:billing_address][:country], country_code)
|
61
|
+
|
62
|
+
add_field(mappings[:billing_address][:address], [params.delete(:address1), params.delete(:address2)].compact.join(' '))
|
63
|
+
|
64
|
+
province_code = params.delete(:state)
|
65
|
+
add_field(mappings[:billing_address][:state], province_code.blank? ? 'N/A' : province_code.upcase)
|
66
|
+
|
67
|
+
# Everything else
|
68
|
+
params.each do |k, v|
|
69
|
+
field = mappings[:billing_address][k]
|
70
|
+
add_field(field, v) unless field.nil?
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def form_fields
|
75
|
+
token, token_id = request_secure_token
|
76
|
+
|
77
|
+
{"securetoken" => token, "securetokenid" => token_id, "mode" => test? ? "test" : "live"}
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def secure_token_id
|
83
|
+
@secure_token_id ||= SecureRandom.hex(16)
|
84
|
+
end
|
85
|
+
|
86
|
+
def secure_token_url
|
87
|
+
test? ? "https://pilot-payflowpro.paypal.com" : "https://payflowpro.paypal.com"
|
88
|
+
end
|
89
|
+
|
90
|
+
def request_secure_token
|
91
|
+
@fields["securetokenid"] = secure_token_id
|
92
|
+
@fields["createsecuretoken"] = "Y"
|
93
|
+
|
94
|
+
fields = @fields.collect {|key, value| "#{key}[#{value.length}]=#{value}" }.join("&")
|
95
|
+
|
96
|
+
response = ssl_post(secure_token_url, fields)
|
97
|
+
|
98
|
+
parse_response(response)
|
99
|
+
end
|
100
|
+
|
101
|
+
def parse_response(response)
|
102
|
+
response = response.split("&").inject({}) do |hash, param|
|
103
|
+
key, value = param.split("=")
|
104
|
+
hash[key] = value
|
105
|
+
hash
|
106
|
+
end
|
107
|
+
|
108
|
+
[response['SECURETOKEN'], response['SECURETOKENID']] if response['RESPMSG'] && response['RESPMSG'].downcase == "approved"
|
109
|
+
end
|
110
|
+
|
111
|
+
def normalize(text)
|
112
|
+
return unless text
|
113
|
+
|
114
|
+
if ActiveSupport::Inflector.method(:transliterate).arity == -2
|
115
|
+
ActiveSupport::Inflector.transliterate(text,'')
|
116
|
+
elsif RUBY_VERSION >= '1.9'
|
117
|
+
text.gsub(/[^\x00-\x7F]+/, '')
|
118
|
+
else
|
119
|
+
ActiveSupport::Inflector.transliterate(text).to_s
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class Notification < OffsitePayments::Notification
|
125
|
+
|
126
|
+
# Was the transaction complete?
|
127
|
+
def complete?
|
128
|
+
status == "Completed"
|
129
|
+
end
|
130
|
+
|
131
|
+
# When was this payment received by the client.
|
132
|
+
# sometimes it can happen that we get the notification much later.
|
133
|
+
# One possible scenario is that our web application was down. In this case paypal tries several
|
134
|
+
# times an hour to inform us about the notification
|
135
|
+
def received_at
|
136
|
+
DateTime.parse(params['TRANSTIME']) if params['TRANSTIME']
|
137
|
+
rescue ArgumentError
|
138
|
+
nil
|
139
|
+
end
|
140
|
+
|
141
|
+
def status
|
142
|
+
params['RESPMSG']
|
143
|
+
end
|
144
|
+
|
145
|
+
# Id of this transaction (paypal number)
|
146
|
+
def transaction_id
|
147
|
+
params['PNREF']
|
148
|
+
end
|
149
|
+
|
150
|
+
# What type of transaction are we dealing with?
|
151
|
+
def type
|
152
|
+
params['TYPE']
|
153
|
+
end
|
154
|
+
|
155
|
+
# the money amount we received in X.2 decimal.
|
156
|
+
def gross
|
157
|
+
params['AMT']
|
158
|
+
end
|
159
|
+
|
160
|
+
# What currency have we been dealing with
|
161
|
+
def currency
|
162
|
+
nil
|
163
|
+
end
|
164
|
+
|
165
|
+
def status
|
166
|
+
params['RESULT'] == '0' ? 'Completed' : 'Failed'
|
167
|
+
end
|
168
|
+
|
169
|
+
# This is the item number which we submitted to paypal
|
170
|
+
def item_id
|
171
|
+
params['USER1']
|
172
|
+
end
|
173
|
+
|
174
|
+
# This is the invoice which you passed to paypal
|
175
|
+
def invoice
|
176
|
+
params['INVNUM']
|
177
|
+
end
|
178
|
+
|
179
|
+
# Was this a test transaction?
|
180
|
+
def test?
|
181
|
+
params['USER2'] == 'true'
|
182
|
+
end
|
183
|
+
|
184
|
+
def account
|
185
|
+
params["ACCT"]
|
186
|
+
end
|
187
|
+
|
188
|
+
def acknowledge(authcode = nil)
|
189
|
+
true
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,362 @@
|
|
1
|
+
module OffsitePayments #:nodoc:
|
2
|
+
module Integrations #:nodoc:
|
3
|
+
module Paypal
|
4
|
+
# Overwrite this if you want to change the Paypal test url
|
5
|
+
mattr_accessor :test_url
|
6
|
+
self.test_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr'
|
7
|
+
|
8
|
+
# Overwrite this if you want to change the Paypal production url
|
9
|
+
mattr_accessor :production_url
|
10
|
+
self.production_url = 'https://www.paypal.com/cgi-bin/webscr'
|
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, options = {})
|
25
|
+
Notification.new(post)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.return(query_string, options = {})
|
29
|
+
Return.new(query_string)
|
30
|
+
end
|
31
|
+
|
32
|
+
class Helper < OffsitePayments::Helper
|
33
|
+
CANADIAN_PROVINCES = { 'AB' => 'Alberta',
|
34
|
+
'BC' => 'British Columbia',
|
35
|
+
'MB' => 'Manitoba',
|
36
|
+
'NB' => 'New Brunswick',
|
37
|
+
'NL' => 'Newfoundland',
|
38
|
+
'NS' => 'Nova Scotia',
|
39
|
+
'NU' => 'Nunavut',
|
40
|
+
'NT' => 'Northwest Territories',
|
41
|
+
'ON' => 'Ontario',
|
42
|
+
'PE' => 'Prince Edward Island',
|
43
|
+
'QC' => 'Quebec',
|
44
|
+
'SK' => 'Saskatchewan',
|
45
|
+
'YT' => 'Yukon'
|
46
|
+
}
|
47
|
+
# See https://www.paypal.com/IntegrationCenter/ic_std-variable-reference.html for details on the following options.
|
48
|
+
mapping :order, [ 'item_number', 'custom' ]
|
49
|
+
|
50
|
+
def initialize(order, account, options = {})
|
51
|
+
super
|
52
|
+
add_field('cmd', '_ext-enter')
|
53
|
+
add_field('redirect_cmd', '_xclick')
|
54
|
+
add_field('quantity', 1)
|
55
|
+
add_field('item_name', 'Store purchase')
|
56
|
+
add_field('no_shipping', '1')
|
57
|
+
add_field('no_note', '1')
|
58
|
+
add_field('charset', 'utf-8')
|
59
|
+
add_field('address_override', '0')
|
60
|
+
add_field('bn', application_id.to_s.slice(0,32)) unless application_id.blank?
|
61
|
+
end
|
62
|
+
|
63
|
+
mapping :amount, 'amount'
|
64
|
+
mapping :account, 'business'
|
65
|
+
mapping :currency, 'currency_code'
|
66
|
+
mapping :notify_url, 'notify_url'
|
67
|
+
mapping :return_url, 'return'
|
68
|
+
mapping :cancel_return_url, 'cancel_return'
|
69
|
+
mapping :invoice, 'invoice'
|
70
|
+
mapping :item_name, 'item_name'
|
71
|
+
mapping :quantity, 'quantity'
|
72
|
+
mapping :no_shipping, 'no_shipping'
|
73
|
+
mapping :no_note, 'no_note'
|
74
|
+
mapping :address_override, 'address_override'
|
75
|
+
|
76
|
+
mapping :application_id, 'bn'
|
77
|
+
|
78
|
+
mapping :customer, :first_name => 'first_name',
|
79
|
+
:last_name => 'last_name',
|
80
|
+
:email => 'email'
|
81
|
+
|
82
|
+
mapping :shipping_address, :city => 'city',
|
83
|
+
:address1 => 'address1',
|
84
|
+
:address2 => 'address2',
|
85
|
+
:state => 'state',
|
86
|
+
:zip => 'zip',
|
87
|
+
:country => 'country'
|
88
|
+
|
89
|
+
def shipping_address(params = {})
|
90
|
+
# Get the country code in the correct format
|
91
|
+
# Use what we were given if we can't find anything
|
92
|
+
country_code = lookup_country_code(params.delete(:country))
|
93
|
+
add_field(mappings[:shipping_address][:country], country_code)
|
94
|
+
|
95
|
+
if params.has_key?(:phone)
|
96
|
+
phone = params.delete(:phone).to_s
|
97
|
+
|
98
|
+
# Wipe all non digits
|
99
|
+
phone.gsub!(/\D+/, '')
|
100
|
+
|
101
|
+
if ['US', 'CA'].include?(country_code) && phone =~ /(\d{3})(\d{3})(\d{4})$/
|
102
|
+
add_field('night_phone_a', $1)
|
103
|
+
add_field('night_phone_b', $2)
|
104
|
+
add_field('night_phone_c', $3)
|
105
|
+
else
|
106
|
+
add_field('night_phone_b', phone)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
province_code = params.delete(:state)
|
111
|
+
|
112
|
+
case country_code
|
113
|
+
when 'CA'
|
114
|
+
add_field(mappings[:shipping_address][:state], CANADIAN_PROVINCES[province_code.upcase]) unless province_code.nil?
|
115
|
+
when 'US'
|
116
|
+
add_field(mappings[:shipping_address][:state], province_code)
|
117
|
+
else
|
118
|
+
add_field(mappings[:shipping_address][:state], province_code.blank? ? 'N/A' : province_code)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Everything else
|
122
|
+
params.each do |k, v|
|
123
|
+
field = mappings[:shipping_address][k]
|
124
|
+
add_field(field, v) unless field.nil?
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
mapping :tax, 'tax'
|
129
|
+
mapping :shipping, 'shipping'
|
130
|
+
mapping :cmd, 'cmd'
|
131
|
+
mapping :custom, 'custom'
|
132
|
+
mapping :src, 'src'
|
133
|
+
mapping :sra, 'sra'
|
134
|
+
%w(a p t).each do |l|
|
135
|
+
(1..3).each do |i|
|
136
|
+
mapping "#{l}#{i}".to_sym, "#{l}#{i}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Parser and handler for incoming Instant payment notifications from paypal.
|
142
|
+
# The Example shows a typical handler in a rails application. Note that this
|
143
|
+
# is an example, please read the Paypal API documentation for all the details
|
144
|
+
# on creating a safe payment controller.
|
145
|
+
#
|
146
|
+
# Example
|
147
|
+
#
|
148
|
+
# class BackendController < ApplicationController
|
149
|
+
# include OffsitePayments::Integrations
|
150
|
+
#
|
151
|
+
# def paypal_ipn
|
152
|
+
# notify = Paypal::Notification.new(request.raw_post)
|
153
|
+
#
|
154
|
+
# if notify.masspay?
|
155
|
+
# masspay_items = notify.items
|
156
|
+
# end
|
157
|
+
#
|
158
|
+
# order = Order.find(notify.item_id)
|
159
|
+
#
|
160
|
+
# if notify.acknowledge
|
161
|
+
# begin
|
162
|
+
#
|
163
|
+
# if notify.complete? and order.total == notify.amount
|
164
|
+
# order.status = 'success'
|
165
|
+
#
|
166
|
+
# shop.ship(order)
|
167
|
+
# else
|
168
|
+
# logger.error("Failed to verify Paypal's notification, please investigate")
|
169
|
+
# end
|
170
|
+
#
|
171
|
+
# rescue => e
|
172
|
+
# order.status = 'failed'
|
173
|
+
# raise
|
174
|
+
# ensure
|
175
|
+
# order.save
|
176
|
+
# end
|
177
|
+
# end
|
178
|
+
#
|
179
|
+
# render :nothing
|
180
|
+
# end
|
181
|
+
# end
|
182
|
+
class Notification < OffsitePayments::Notification
|
183
|
+
include ActiveMerchant::PostsData
|
184
|
+
|
185
|
+
def initialize(post, options = {})
|
186
|
+
super
|
187
|
+
extend MassPayNotification if masspay?
|
188
|
+
end
|
189
|
+
|
190
|
+
# Was the transaction complete?
|
191
|
+
def complete?
|
192
|
+
status == "Completed"
|
193
|
+
end
|
194
|
+
|
195
|
+
# Is it a masspay notification?
|
196
|
+
def masspay?
|
197
|
+
type == "masspay"
|
198
|
+
end
|
199
|
+
|
200
|
+
# When was this payment received by the client.
|
201
|
+
# sometimes it can happen that we get the notification much later.
|
202
|
+
# One possible scenario is that our web application was down. In this case paypal tries several
|
203
|
+
# times an hour to inform us about the notification
|
204
|
+
def received_at
|
205
|
+
parsed_time_fields = DateTime._strptime(params['payment_date'], "%H:%M:%S %b %d, %Y %Z")
|
206
|
+
Time.gm(
|
207
|
+
parsed_time_fields[:year],
|
208
|
+
parsed_time_fields[:mon],
|
209
|
+
parsed_time_fields[:mday],
|
210
|
+
parsed_time_fields[:hour],
|
211
|
+
parsed_time_fields[:min],
|
212
|
+
parsed_time_fields[:sec]
|
213
|
+
) - Time.zone_offset(parsed_time_fields[:zone])
|
214
|
+
end
|
215
|
+
|
216
|
+
# Status of transaction. List of possible values:
|
217
|
+
# <tt>Canceled-Reversal</tt>::
|
218
|
+
# <tt>Completed</tt>::
|
219
|
+
# <tt>Denied</tt>::
|
220
|
+
# <tt>Expired</tt>::
|
221
|
+
# <tt>Failed</tt>::
|
222
|
+
# <tt>In-Progress</tt>::
|
223
|
+
# <tt>Partially-Refunded</tt>::
|
224
|
+
# <tt>Pending</tt>::
|
225
|
+
# <tt>Processed</tt>::
|
226
|
+
# <tt>Refunded</tt>::
|
227
|
+
# <tt>Reversed</tt>::
|
228
|
+
# <tt>Voided</tt>::
|
229
|
+
def status
|
230
|
+
params['payment_status']
|
231
|
+
end
|
232
|
+
|
233
|
+
# Id of this transaction (paypal number)
|
234
|
+
def transaction_id
|
235
|
+
params['txn_id']
|
236
|
+
end
|
237
|
+
|
238
|
+
# What type of transaction are we dealing with?
|
239
|
+
# "cart" "send_money" "web_accept" are possible here.
|
240
|
+
def type
|
241
|
+
params['txn_type']
|
242
|
+
end
|
243
|
+
|
244
|
+
# the money amount we received in X.2 decimal.
|
245
|
+
def gross
|
246
|
+
params['mc_gross']
|
247
|
+
end
|
248
|
+
|
249
|
+
# the markup paypal charges for the transaction
|
250
|
+
def fee
|
251
|
+
params['mc_fee']
|
252
|
+
end
|
253
|
+
|
254
|
+
# What currency have we been dealing with
|
255
|
+
def currency
|
256
|
+
params['mc_currency']
|
257
|
+
end
|
258
|
+
|
259
|
+
# This is the item number which we submitted to paypal
|
260
|
+
# The custom field is also mapped to item_id because PayPal
|
261
|
+
# doesn't return item_number in dispute notifications
|
262
|
+
def item_id
|
263
|
+
params['item_number'] || params['custom']
|
264
|
+
end
|
265
|
+
|
266
|
+
# This is the invoice which you passed to paypal
|
267
|
+
def invoice
|
268
|
+
params['invoice']
|
269
|
+
end
|
270
|
+
|
271
|
+
# Was this a test transaction?
|
272
|
+
def test?
|
273
|
+
params['test_ipn'] == '1'
|
274
|
+
end
|
275
|
+
|
276
|
+
def account
|
277
|
+
params['business'] || params['receiver_email']
|
278
|
+
end
|
279
|
+
|
280
|
+
# Acknowledge the transaction to paypal. This method has to be called after a new
|
281
|
+
# ipn arrives. Paypal will verify that all the information we received are correct and will return a
|
282
|
+
# ok or a fail.
|
283
|
+
#
|
284
|
+
# Example:
|
285
|
+
#
|
286
|
+
# def paypal_ipn
|
287
|
+
# notify = PaypalNotification.new(request.raw_post)
|
288
|
+
#
|
289
|
+
# if notify.acknowledge
|
290
|
+
# ... process order ... if notify.complete?
|
291
|
+
# else
|
292
|
+
# ... log possible hacking attempt ...
|
293
|
+
# end
|
294
|
+
def acknowledge(authcode = nil)
|
295
|
+
payload = raw
|
296
|
+
|
297
|
+
response = ssl_post(Paypal.service_url + '?cmd=_notify-validate', payload,
|
298
|
+
'Content-Length' => "#{payload.size}",
|
299
|
+
'User-Agent' => "Active Merchant -- http://activemerchant.org"
|
300
|
+
)
|
301
|
+
|
302
|
+
raise StandardError.new("Faulty paypal result: #{response}") unless ["VERIFIED", "INVALID"].include?(response)
|
303
|
+
|
304
|
+
response == "VERIFIED"
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
module MassPayNotification
|
309
|
+
# Mass pay returns a collection of MassPay Items, so inspect items to get the values
|
310
|
+
def transaction_id
|
311
|
+
end
|
312
|
+
|
313
|
+
# Mass pay returns a collection of MassPay Items, so inspect items to get the values
|
314
|
+
def gross
|
315
|
+
end
|
316
|
+
|
317
|
+
# Mass pay returns a collection of MassPay Items, so inspect items to get the values
|
318
|
+
def fee
|
319
|
+
end
|
320
|
+
|
321
|
+
# Mass pay returns a collection of MassPay Items, so inspect items to get the values
|
322
|
+
def currency
|
323
|
+
end
|
324
|
+
|
325
|
+
# Mass pay returns a collection of MassPay Items, so inspect items to get the values
|
326
|
+
def item_id
|
327
|
+
end
|
328
|
+
|
329
|
+
# Mass pay returns a collection of MassPay Items, so inspect items to get the values
|
330
|
+
def account
|
331
|
+
end
|
332
|
+
|
333
|
+
# Collection of notification items returned for MassPay transactions
|
334
|
+
def items
|
335
|
+
@items ||= (1..number_of_mass_pay_items).map do |item_number|
|
336
|
+
MassPayItem.new(
|
337
|
+
params["masspay_txn_id_#{item_number}"],
|
338
|
+
params["mc_gross_#{item_number}"],
|
339
|
+
params["mc_fee_#{item_number}"],
|
340
|
+
params["mc_currency_#{item_number}"],
|
341
|
+
params["unique_id_#{item_number}"],
|
342
|
+
params["receiver_email_#{item_number}"],
|
343
|
+
params["status_#{item_number}"]
|
344
|
+
)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
private
|
349
|
+
|
350
|
+
def number_of_mass_pay_items
|
351
|
+
@number_of_mass_pay_items ||= params.keys.select { |k| k.start_with? 'masspay_txn_id' }.size
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
class MassPayItem < Struct.new(:transaction_id, :gross, :fee, :currency, :item_id, :account, :status)
|
356
|
+
end
|
357
|
+
|
358
|
+
class Return < OffsitePayments::Return
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|