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