trado_paypal_module 0.9.1

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 (53) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +34 -0
  4. data/app/controllers/trado_paypal_module/ipn_controller.rb +26 -0
  5. data/app/controllers/trado_paypal_module/paypal_controller.rb +36 -0
  6. data/config/routes.rb +3 -0
  7. data/lib/generators/templates/controller.rb +6 -0
  8. data/lib/generators/templates/helper.rb +6 -0
  9. data/lib/generators/templates/migration.rb +13 -0
  10. data/lib/generators/trado_paypal_module/install_generator.rb +91 -0
  11. data/lib/tasks/trado_paypal_module_tasks.rake +4 -0
  12. data/lib/trado_paypal_module.rb +12 -0
  13. data/lib/trado_paypal_module/active_record.rb +15 -0
  14. data/lib/trado_paypal_module/engine.rb +6 -0
  15. data/lib/trado_paypal_module/paypaler.rb +219 -0
  16. data/lib/trado_paypal_module/version.rb +3 -0
  17. data/test/dummy/README.rdoc +28 -0
  18. data/test/dummy/Rakefile +6 -0
  19. data/test/dummy/app/assets/javascripts/application.js +13 -0
  20. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  21. data/test/dummy/app/controllers/application_controller.rb +5 -0
  22. data/test/dummy/app/helpers/application_helper.rb +2 -0
  23. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  24. data/test/dummy/bin/bundle +3 -0
  25. data/test/dummy/bin/rails +4 -0
  26. data/test/dummy/bin/rake +4 -0
  27. data/test/dummy/bin/setup +29 -0
  28. data/test/dummy/config.ru +4 -0
  29. data/test/dummy/config/application.rb +26 -0
  30. data/test/dummy/config/boot.rb +5 -0
  31. data/test/dummy/config/database.yml +25 -0
  32. data/test/dummy/config/environment.rb +5 -0
  33. data/test/dummy/config/environments/development.rb +41 -0
  34. data/test/dummy/config/environments/production.rb +79 -0
  35. data/test/dummy/config/environments/test.rb +42 -0
  36. data/test/dummy/config/initializers/assets.rb +11 -0
  37. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  38. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  39. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  40. data/test/dummy/config/initializers/inflections.rb +16 -0
  41. data/test/dummy/config/initializers/mime_types.rb +4 -0
  42. data/test/dummy/config/initializers/session_store.rb +3 -0
  43. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  44. data/test/dummy/config/locales/en.yml +23 -0
  45. data/test/dummy/config/routes.rb +56 -0
  46. data/test/dummy/config/secrets.yml +22 -0
  47. data/test/dummy/public/404.html +67 -0
  48. data/test/dummy/public/422.html +67 -0
  49. data/test/dummy/public/500.html +66 -0
  50. data/test/dummy/public/favicon.ico +0 -0
  51. data/test/test_helper.rb +20 -0
  52. data/test/trado_paypal_module_test.rb +7 -0
  53. metadata +173 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: eb0fc1e85e04eec3a1950232e9d16b9209263dba
4
+ data.tar.gz: 2865fc5e70d08593d5fa176c9be02582f0fa73bc
5
+ SHA512:
6
+ metadata.gz: 9ce411a3afd6fd97697e65cb7d6f24c130d75b94da7b4326fafadaa5ac8e01db4f8d49a5310a39c7ec67978d961397ead41b8c34a58592f37193fe31baec63ee
7
+ data.tar.gz: 388365d0b59ccfa689da49dc8876a12c2b226c31d1785e34af14f5dfdf3fe52707db304f98243bc2bf122775f224498d287ca7cb46549aca448f49a2c1ff20e2
@@ -0,0 +1,20 @@
1
+ Copyright 2016 Tom Dallimore
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,34 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'TradoPaypalModule'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+
19
+
20
+
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'lib'
28
+ t.libs << 'test'
29
+ t.pattern = 'test/**/*_test.rb'
30
+ t.verbose = false
31
+ end
32
+
33
+
34
+ task default: :test
@@ -0,0 +1,26 @@
1
+ class TradoPaypalModule::IpnController < ApplicationController
2
+ skip_before_action :authenticate_user!
3
+
4
+ # TODO: Find out why this is throwing an error.
5
+ include ActiveMerchant::Billing::Integrations
6
+
7
+ # Handler for incoming Instant Payment Notifications from paypal about orders
8
+ def update
9
+ notify = Paypal::Notification.new(request.raw_post)
10
+
11
+ if notify.acknowledge
12
+ transaction = Transaction.where(order_id: notify.params['invoice']).first
13
+ if notify.complete? and transaction.gross_amount.to_s == notify.params['mc_gross']
14
+ transaction.fee = notify.params['mc_fee']
15
+ transaction.completed!
16
+ else
17
+ transaction.failed!
18
+ end
19
+ if transaction.save
20
+ Mailatron4000::Orders.confirmation_email(transaction.order) rescue Rails.logger.warn("PayPal IPN: Order #{transaction.order.id} confirmation email failed to send")
21
+ end
22
+ end
23
+
24
+ render nothing: true
25
+ end
26
+ end
@@ -0,0 +1,36 @@
1
+ class TradoPaypalModule::PaypalController < ApplicationController
2
+ skip_before_action :authenticate_user!
3
+ include CartBuilder
4
+
5
+ def confirm
6
+ set_order
7
+ set_cart_totals
8
+ set_grouped_countries
9
+ set_browser_data
10
+ @order.attributes = params[:order]
11
+ if @order.save
12
+ @order.calculate(current_cart, Store.tax_rate)
13
+ generate_payment_url
14
+ if @redirect_url.nil?
15
+ flash_message :error, 'An error ocurred with your order. Please try again.'
16
+ Rails.logger.error "PayPal: Unable to generate redirect URL."
17
+ redirect_to checkout_carts_url
18
+ else
19
+ redirect_to @redirect_url
20
+ end
21
+ else
22
+ flash_message :error, 'An error ocurred with your order. Please try again.'
23
+ render theme_presenter.page_template_path('carts/checkout'), layout: theme_presenter.layout_template_path
24
+ end
25
+ rescue ActiveMerchant::ConnectionError
26
+ flash_message :error, 'An error ocurred with your order. Please try again.'
27
+ Rails.logger.error "PayPal: API is temporarily unavailable."
28
+ redirect_to checkout_carts_url
29
+ end
30
+
31
+ private
32
+
33
+ def generate_payment_url
34
+ @redirect_url = Store::PayProvider.new(cart: current_cart, order: @order, provider: @order.payment_type, ip_address: request.remote_ip).build
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ TradoPaypalModule::Engine.routes.draw do
2
+ post 'ipn', to: 'trado_paypal_module/ipn#update', as: 'paypal_ipn'
3
+ end
@@ -0,0 +1,6 @@
1
+ class Carts::PaypalController < TradoPaypalModule::PaypalController
2
+
3
+ def confirm
4
+ super
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module PaypalHelper
2
+
3
+ def paypal_form_tag f
4
+ raw("<div class='paypal-form-wrapper'>#{f.radio_button(:payment_type, 'paypal', checked: true)}#{image_tag('paypal-icon.png')}</div>")
5
+ end
6
+ end
@@ -0,0 +1,13 @@
1
+ class AddPaypalAttributes < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :transactions, :paypal_id, :string
4
+ add_column :orders, :paypal_express_token, :string
5
+ add_column :orders, :paypal_express_payer_id, :string
6
+ end
7
+
8
+ def self.down
9
+ remove_column :transactions, :paypal_id
10
+ remove_column :orders, :paypal_express_token
11
+ remove_column :orders, :paypal_express_payer_id
12
+ end
13
+ end
@@ -0,0 +1,91 @@
1
+ module TradoPaypalModule
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("../../templates", __FILE__)
5
+
6
+ def copy_migration
7
+ unless paypal_migration_already_exists?
8
+ timestamp_number = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
9
+ copy_file "migration.rb", "db/migrate/#{timestamp_number}_add_paypal_attributes.rb"
10
+ end
11
+ end
12
+
13
+ def copy_helper
14
+ template "helper.rb", "app/helpers/paypal_helper.rb"
15
+ end
16
+
17
+ def copy_controller
18
+ template "controller.rb", "app/controllers/carts/paypal_controller.rb"
19
+ end
20
+
21
+ def setup_routes
22
+ route_content = <<-CONTENT
23
+
24
+ mount TradoPaypalModule::Engine => '/paypal'
25
+ CONTENT
26
+ inject_into_file "config/routes.rb", route_content, after: "Trado::Application.routes.draw do"
27
+ end
28
+
29
+ def assign_model_concerns
30
+ order_content = <<-CONTENT
31
+
32
+ has_order_paypal
33
+ CONTENT
34
+ transaction_content = <<-CONTENT
35
+
36
+ has_transaction_paypal
37
+ CONTENT
38
+
39
+ inject_into_file "app/models/order.rb", order_content, after: "class Order < ActiveRecord::Base"
40
+ inject_into_file "app/models/transaction.rb", transaction_content, after: "class Transaction < ActiveRecord::Base"
41
+ end
42
+
43
+ def setup_env_configs
44
+ development_content = <<-CONTENT
45
+
46
+ # PayPal settings
47
+ config.after_initialize do
48
+ ActiveMerchant::Billing::Base.mode = :test
49
+ paypal_options = {
50
+ login: Rails.application.secrets.paypal_login,
51
+ password: Rails.application.secrets.paypal_password,
52
+ signature: Rails.application.secrets.paypal_signature
53
+ }
54
+ ::EXPRESS_GATEWAY = ActiveMerchant::Billing::PaypalExpressGateway.new(paypal_options)
55
+ end
56
+ CONTENT
57
+
58
+ test_content = <<-CONTENT
59
+
60
+ # PayPal settings
61
+ config.after_initialize do
62
+ ActiveMerchant::Billing::Base.mode = :test
63
+ ::EXPRESS_GATEWAY = ActiveMerchant::Billing::BogusGateway.new
64
+ end
65
+ CONTENT
66
+
67
+ production_content = <<-CONTENT
68
+
69
+ # PayPal settings
70
+ config.after_initialize do
71
+ paypal_options = {
72
+ login: Rails.application.secrets.paypal_login,
73
+ password: Rails.application.secrets.paypal_password,
74
+ signature: Rails.application.secrets.paypal_signature
75
+ }
76
+ ::EXPRESS_GATEWAY = ActiveMerchant::Billing::PaypalExpressGateway.new(paypal_options)
77
+ end
78
+ CONTENT
79
+ inject_into_file "config/environments/development.rb", development_content, after: "Trado::Application.configure do"
80
+ inject_into_file "config/environments/test.rb", test_content, after: "Trado::Application.configure do"
81
+ inject_into_file "config/environments/production.rb", production_content, after: "Trado::Application.configure do"
82
+ end
83
+
84
+ private
85
+
86
+ def paypal_migration_already_exists?
87
+ Dir.glob("#{File.join(destination_root, File.join("db", "migrate"))}/[0-9]*_*.rb").grep(/\d+_add_paypal_attributes.rb$/).first
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :trado_paypal_module do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,12 @@
1
+ module TradoPaypalModule
2
+ end
3
+
4
+ require 'activemerchant'
5
+ require 'offsite_payments'
6
+
7
+ require 'trado_paypal_module/engine'
8
+ require 'trado_paypal_module/version'
9
+ require 'trado_paypal_module/active_record'
10
+ require 'trado_paypal_module/paypaler'
11
+
12
+ ActiveRecord::Base.send(:include, TradoPaypalModule::ActiveRecord)
@@ -0,0 +1,15 @@
1
+ module TradoPaypalModule
2
+ module ActiveRecord
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def has_order_paypal
7
+ attr_accessible :paypal_express_token, :paypal_express_payer_id
8
+ end
9
+
10
+ def has_transaction_paypal
11
+ attr_accessible :paypal_id
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ require 'rails'
2
+
3
+ module TradoPaypalModule
4
+ class Engine < Rails::Engine
5
+ end
6
+ end
@@ -0,0 +1,219 @@
1
+ require_dependency 'lib/payatron_4000'
2
+
3
+ module TradoPaypalModule
4
+
5
+ class Paypaler
6
+
7
+ # Builds the a PayPal purchase request from the order data
8
+ # If successful, redirect to PayPal for the user to login
9
+ # If unsuccessful, redirect to failed order page
10
+ #
11
+ # @param cart [Object]
12
+ # @param order [Object]
13
+ # @param ip_address [String]
14
+ # @return [String] redirect url
15
+ def self.build cart, order, ip_address
16
+ response = EXPRESS_GATEWAY.setup_purchase(
17
+ Store::Price.new(price: order.gross_amount, tax_type: 'net').singularize,
18
+ TradoPaypalModule::Paypaler.express_setup_options(
19
+ order,
20
+ cart,
21
+ ip_address,
22
+ Rails.application.routes.url_helpers.confirm_order_url(order, host: Trado::Application.config.action_mailer.default_url_options[:host]),
23
+ Rails.application.routes.url_helpers.mycart_carts_url(host: Trado::Application.config.action_mailer.default_url_options[:host])
24
+ )
25
+ )
26
+ if response.success?
27
+ return EXPRESS_GATEWAY.redirect_url_for(response.token)
28
+ else
29
+ TradoPaypalModule::Paypaler.failed(response, order)
30
+ Payatron4000.decommission_order(order)
31
+ return Rails.application.routes.url_helpers.failed_order_url(order, host: Trado::Application.config.action_mailer.default_url_options[:host])
32
+ end
33
+ end
34
+
35
+ # Creates the payment information object for PayPal to parse in the login
36
+ #
37
+ # @param order [Object]
38
+ # @param cart [Object]
39
+ # @param ip_address [String]
40
+ # @param return_url [String]
41
+ # @param cancel_url [String]
42
+ # @return [Object] order data from the store for PayPal
43
+ def self.express_setup_options order, cart, ip_address, return_url, cancel_url
44
+ {
45
+ :subtotal => Store::Price.new(price: (order.net_amount - order.delivery.price), tax_type: 'net').singularize,
46
+ :shipping => Store::Price.new(price: order.delivery.price, tax_type: 'net').singularize,
47
+ :tax => Store::Price.new(price: order.tax_amount, tax_type: 'net').singularize,
48
+ :handling => 0,
49
+ :order_id => order.id,
50
+ :items => TradoPaypalModule::Paypaler.express_items(cart.cart_items),
51
+ :address_override => 1,
52
+ :shipping_address => order.delivery_address.full_address,
53
+ :req_confirm_shipping => 0,
54
+ :ip => ip_address,
55
+ :return_url => return_url,
56
+ :cancel_return_url => cancel_url,
57
+ :currency => Store.settings.currency_code,
58
+ }
59
+ end
60
+
61
+ # Creates the payment information object for PayPal to parse in the confirmation step and complete the purchase
62
+ #
63
+ # @param order [Object]
64
+ # @return [Object] current customer order
65
+ def self.express_purchase_options order, ip_address
66
+ {
67
+ :subtotal => Store::Price.new(price: (order.net_amount - order.delivery.price), tax_type: 'net').singularize,
68
+ :shipping => Store::Price.new(price: order.delivery.price, tax_type: 'net').singularize,
69
+ :tax => Store::Price.new(price: order.tax_amount, tax_type: 'net').singularize,
70
+ :handling => 0,
71
+ :items => TradoPaypalModule::Paypaler.express_items(order.order_items),
72
+ :token => order.paypal_express_token,
73
+ :payer_id => order.paypal_express_payer_id,
74
+ :currency => Store.settings.currency_code,
75
+ :ip => ip_address,
76
+ }
77
+ end
78
+
79
+ # Creates an aray of items which represent cart_items or order_items
80
+ # This is passed into the express_setup_options and express_purchase_options methods
81
+ #
82
+ # @return [Array] list of cart or order items for PayPal
83
+ def self.express_items items
84
+ items.collect do |item|
85
+ {
86
+ :name => "#{item.sku.product.name} (#{item.sku.variants.map{|v| v.name.titleize}.join(' / ')})",
87
+ :description => "#{item.sku.product.name} (#{item.sku.variants.map{|v| v.name.titleize}.join(' / ')})",
88
+ :amount => Store::Price.new(price: item.price, tax_type: 'net').singularize,
89
+ :quantity => item.quantity
90
+ }
91
+ end
92
+ end
93
+
94
+ # Assign PayPal token to order after user logs into their account
95
+ #
96
+ # @param token [String]
97
+ # @param payer_id [Integer]
98
+ # @param order [Object]
99
+ def self.assign_paypal_token token, payer_id, order
100
+ order.paypal_express_token = token
101
+ order.paypal_express_payer_id = payer_id
102
+ order.save(validate: false)
103
+ end
104
+
105
+ # Completes the order process by communicating with PayPal; receives a response and in turn creates the relevant transaction records,
106
+ # sends a confirmation email and redirects the user.
107
+ #
108
+ # @param order [Object]
109
+ # @param session [Object
110
+ def self.complete order, session, ip_address
111
+ order.transfer(order.cart)
112
+ response = EXPRESS_GATEWAY.purchase(Store::Price.new(price: order.gross_amount, tax_type: 'net').singularize,
113
+ TradoPaypalModule::Paypaler.express_purchase_options(order, ip_address)
114
+ )
115
+ if response.success?
116
+ TradoPaypalModule::Paypaler.successful(response, order)
117
+ Payatron4000.destroy_cart(session)
118
+ Payatron4000.decommission_order(order)
119
+ order.reload
120
+ Mailatron4000::Orders.confirmation_email(order)
121
+ return Rails.application.routes.url_helpers.success_order_url(order, host: Trado::Application.config.action_mailer.default_url_options[:host])
122
+ else
123
+ TradoPaypalModule::Paypaler.failed(response, order)
124
+ order.reload
125
+ Mailatron4000::Orders.confirmation_email(order)
126
+ return Rails.application.routes.url_helpers.failed_order_url(order, host: Trado::Application.config.action_mailer.default_url_options[:host])
127
+ end
128
+ end
129
+
130
+ # Upon successfully completing an order with a PayPal payment option a new transaction record is created, stock is updated for the relevant SKU
131
+ #
132
+ # @param response [Object]
133
+ # @param order [Object]
134
+ def self.successful response, order
135
+ Transaction.new( :fee => response.params['PaymentInfo']['FeeAmount'],
136
+ :order_id => order.id,
137
+ :payment_status => response.params['PaymentInfo']['PaymentStatus'].downcase,
138
+ :transaction_type => 'Credit',
139
+ :tax_amount => response.params['PaymentInfo']['TaxAmount'],
140
+ :paypal_id => response.params['PaymentInfo']['TransactionID'],
141
+ :payment_type => 'paypal',
142
+ :net_amount => response.params['PaymentInfo']['GrossAmount'].to_d - response.params['PaymentInfo']['TaxAmount'].to_d,
143
+ :gross_amount => response.params['PaymentInfo']['GrossAmount'],
144
+ :status_reason => response.params['PaymentInfo']['PendingReason']
145
+ ).save(validate: false)
146
+ Payatron4000.update_stock(order)
147
+ Payatron4000.increment_product_order_count(order.products)
148
+ end
149
+
150
+
151
+ # When an order has failed to complete, a new transaction record is created with a logged status reason
152
+ #
153
+ # @param response [Object]
154
+ # @param order [Object]
155
+ def self.failed response, order
156
+ Transaction.new( :fee => 0,
157
+ :gross_amount => order.gross_amount,
158
+ :order_id => order.id,
159
+ :payment_status => 'failed',
160
+ :transaction_type => 'Credit',
161
+ :tax_amount => order.tax_amount,
162
+ :paypal_id => nil,
163
+ :payment_type => 'paypal',
164
+ :net_amount => order.net_amount,
165
+ :status_reason => response.message,
166
+ :error_code => response.params["error_codes"].to_i
167
+ ).save(validate: false)
168
+ Payatron4000.increment_product_order_count(order.products)
169
+ end
170
+
171
+ # A list of available currency codes for the PayPal payment system
172
+ #
173
+ # @return [Array] available currency codes
174
+ def self.currency_codes
175
+ return [
176
+ "AUD",
177
+ "CAD",
178
+ "CZK",
179
+ "DKK",
180
+ "EUR",
181
+ "HKD",
182
+ "HUF",
183
+ "ILS",
184
+ "JPY",
185
+ "MXN",
186
+ "NOK",
187
+ "NZD",
188
+ "PHP",
189
+ "PLN",
190
+ "GBP",
191
+ "RUB",
192
+ "SGD",
193
+ "SEK",
194
+ "CHF",
195
+ "TWD",
196
+ "THB",
197
+ "USD"
198
+ ]
199
+ end
200
+
201
+ # A list of fatal error codes for an order
202
+ # If the passed in error code parameter is included in the fatal codes array, return true
203
+ #
204
+ # @param error_code [Integer] payment error code
205
+ # @return [Boolean]
206
+ def self.fatal_error_code? error_code
207
+ @fatal_codes =
208
+ [
209
+ 10412, # PayPal: Payment has already been made for this InvoiceID.
210
+ 10415 # PayPal: A successful transaction has already been completed for this token.
211
+ ]
212
+ return @fatal_codes.include?(error_code) ? true : false
213
+ end
214
+
215
+ def self.valid_tokens? params
216
+ params[:token].present? && params[:PayerID].present?
217
+ end
218
+ end
219
+ end