trado_paypal_module 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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