Class: EmployeeRecord
Overview
== Schema Information
Table name: employee_records(Employee profile and role flags used for rep classification.)
Database name: primary
id :integer not null, primary key
activities_per_day :integer
activities_per_day_priority_tiers :integer
author_bio :text
author_page :boolean default(FALSE), not null
bereavement_days :integer
calendly_link :string
call_block_a :string
call_block_b :string
certifications :text
default_dashboard :string(255)
department(Department label used for organizational filtering and analytics.) :string(30)
disable_self_assign :boolean default(FALSE)
disable_special_events_alerts :boolean default(FALSE), not null
employment_end_date :date
employment_start_date :date
full_bio :text
heatwave_preferences :json
hide_signature_call_text_me_directly :boolean default(FALSE)
hide_signature_pbx_extension :boolean default(FALSE)
hire_date :date
interesting_fact :text
is_visa_holder :boolean
job_description :text
job_title :string(100)
jury_duty_days :integer
kpi_activities :integer
kpi_live_chat :integer
kpi_outbound_calls :integer
kpi_sms :integer
kpi_support_cases :integer
local_sales_rep :boolean default(FALSE), not null
mba_inventory :string default([]), is an Array
menus :string is an Array
monitor_group_sms_numbers :boolean default(FALSE)
monitor_unlinked_extensions :boolean default(FALSE), not null
next_birthday :date
next_work_anniversary :date
payroll_identifier :string
primary_sales_rep(True when employee is classified as a primary sales rep.) :boolean default(FALSE), not null
pto_backup1 :string
pto_backup2 :string
pto_backup3 :string
release_date :date
scheduler_link_type :string default("hidden")
secondary_sales_rep :boolean default(FALSE), not null
show_calendly_link :boolean default(FALSE)
show_signature_photo :boolean default(FALSE)
signature :text
slug :string
std_days :integer
vacation_days :integer
visa_end_date :date
visa_start_date :date
visa_type :string
watch_list_ids :integer default([]), is an Array
watch_list_role_ids :integer default([]), is an Array
created_at :datetime not null
updated_at :datetime not null
backup_rep_id :integer
commission_structure_id :integer
creator_id :integer
party_id :integer not null
print_node_computer_id :integer
profile_picture_id :integer
signature_picture_id :integer
updater_id :integer
Indexes
employee_records_profile_picture_id_idx (profile_picture_id)
employee_records_signature_picture_id_idx (signature_picture_id)
idx_party_secondary_sales_rep (party_id,secondary_sales_rep)
index_employee_records_on_call_block_a (call_block_a)
index_employee_records_on_call_block_b (call_block_b)
index_employee_records_on_employment_end_date (employment_end_date)
index_employee_records_on_employment_start_date (employment_start_date)
index_employee_records_on_is_visa_holder (is_visa_holder)
index_employee_records_on_slug (slug) UNIQUE
index_employee_records_on_visa_end_date (visa_end_date)
index_employee_records_on_visa_start_date (visa_start_date)
index_employee_records_on_visa_type (visa_type)
Foreign Keys
fk_rails_... (party_id => parties.id) ON DELETE => cascade
fk_rails_... (profile_picture_id => digital_assets.id)
fk_rails_... (signature_picture_id => digital_assets.id)
Constant Summary
collapse
- DEFAULT_ACTIVITIES_PER_DAY_PRIORITY_TIERS =
90
- DEFAULT_ACTIVITIES_PER_DAY =
40
- MANAGER_SQL =
<<-EOS
exists(select 1 from accounts a
inner join accounts_roles ar on ar.account_id = a.id
inner join roles r on r.id = ar.role_id
inner join parties e on e.id = a.party_id and e.type = 'Employee'
where e.id = employee_records.party_id
and (r.name ILIKE '%manager%' or r.name ILIKE '%director%')
and e.inactive = false)
or exists(select 1 from employee_records er
where er.id = employee_records.id and er.party_id IN (select distinct e.parent_id
from parties e
where e.parent_id is not null))
EOS
- SALES_REP_SQL =
<<-EOS
exists(select 1 from accounts a
inner join accounts_roles ar on ar.account_id = a.id
inner join roles r on r.id = ar.role_id
inner join parties e on e.id = a.party_id and e.type = 'Employee'
where e.id = employee_records.party_id
and (r.name ILIKE '%sales%')
and e.inactive = false)
or exists(select 1 from employee_records er
where er.id = employee_records.id and er.party_id IN (select distinct e.parent_id
from parties e
where e.parent_id is not null))
EOS
- CALL_BLOCK_OPTIONS =
[%w[None none], %w[Morning morning], %w[Afternoon afternoon]]
- TYPES_OF_VISA =
[
['F-1 (Foreign academic student)', 'F-1 (Foreign academic student)'],
['H-1B (Temporary worker)', 'H-1B (Temporary worker)'],
['H-3 (Temporary worker)', 'H-3 (Temporary worker)'],
['J-1 (Exchange visitor)', 'J-1 (Exchange visitor)'],
['K-1 (Fiancé of a U.S. citizen)', 'K-1 (Fiancé of a U.S. citizen)']
]
- SCHEDULER_LINK_TYPES =
%w[hidden external heatwave].freeze
Models::Auditable::ALWAYS_IGNORED
Instance Attribute Summary collapse
#creator, #updater
Delegated Instance Attributes
collapse
Class Method Summary
collapse
Instance Method Summary
collapse
#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
#publish_event
Instance Attribute Details
#activities_per_day ⇒ Object
159
|
# File 'app/models/employee_record.rb', line 159
validates :activities_per_day, numericality: { greater_than_or_equal_to: 0 }
|
#activities_per_day_priority_tiers ⇒ Object
160
|
# File 'app/models/employee_record.rb', line 160
validates :activities_per_day_priority_tiers, numericality: { greater_than_or_equal_to: 0 }
|
#scheduler_link_type ⇒ Object
184
|
# File 'app/models/employee_record.rb', line 184
validates :scheduler_link_type, inclusion: { in: SCHEDULER_LINK_TYPES }, allow_nil: true
|
Class Method Details
.active_employees ⇒ ActiveRecord::Relation<EmployeeRecord>
A relation of EmployeeRecords that are active employees. Active Record Scope
170
|
# File 'app/models/employee_record.rb', line 170
scope :active_employees, -> { joins(:party).merge(Employee.active_employees) }
|
.active_employees_in_department(department) ⇒ Object
253
254
255
|
# File 'app/models/employee_record.rb', line 253
def self.active_employees_in_department(department)
active_employees.includes(:party).where(EmployeeRecord[:department].matches(department))
end
|
.department_select_options ⇒ Object
330
331
332
|
# File 'app/models/employee_record.rb', line 330
def self.department_select_options
where.not(department: nil).order('department').distinct.pluck(:department)
end
|
.employees_and_departments_hybrid_for_select ⇒ Object
243
244
245
246
247
248
249
250
251
|
# File 'app/models/employee_record.rb', line 243
def self.employees_and_departments_hybrid_for_select
collection = []
collection << ["\u221e Everyone", '*']
active_employees.includes(:party).order(:department).group_by(&:department).each do |department, employee_records|
collection << ["\u272a #{department}", "D|#{department}", { class: 'department-select-option' }]
collection += employee_records.sort_by { |er| er.party.full_name }.map { |er| [er.party.full_name, "EID|#{er.party.id}", { class: 'employee-select-option' }] }
end
collection
end
|
.employees_grouped_by_department ⇒ Object
231
232
233
234
235
236
237
238
239
240
241
|
# File 'app/models/employee_record.rb', line 231
def self.employees_grouped_by_department
options = active_employees.includes(:party).order(:department).group_by(&:department)
options.each do |department, employee_records|
options[department] = (begin
employee_records.map { |s| [s.party.full_name, s.party.id] }
rescue StandardError
nil
end) || []
end
options
end
|
.job_title_select_options ⇒ Object
326
327
328
|
# File 'app/models/employee_record.rb', line 326
def self.job_title_select_options
where.not(job_title: nil).order('job_title').distinct.pluck(:job_title)
end
|
.managed_by ⇒ ActiveRecord::Relation<EmployeeRecord>
A relation of EmployeeRecords that are managed by. Active Record Scope
172
|
# File 'app/models/employee_record.rb', line 172
scope :managed_by, ->(manager_party_id) { joins(:party).where(party_id: Employee.descendants_ids(manager_party_id)) }
|
.managers ⇒ ActiveRecord::Relation<EmployeeRecord>
A relation of EmployeeRecords that are managers. Active Record Scope
168
|
# File 'app/models/employee_record.rb', line 168
scope :managers, -> { where(MANAGER_SQL) }
|
.managers_select_options ⇒ Object
322
323
324
|
# File 'app/models/employee_record.rb', line 322
def self.managers_select_options
managers.joins(:party).order('parties.full_name').pluck('parties.full_name', :id) end
|
.mba_inventory_for_select ⇒ Object
314
315
316
|
# File 'app/models/employee_record.rb', line 314
def self.mba_inventory_for_select
['Receiving Gifts', 'Quality Time', 'Words of Affirmation', 'Acts of Service', 'Physical Touch']
end
|
218
219
220
221
222
223
224
225
226
227
228
229
|
# File 'app/models/employee_record.rb', line 218
def self.
res = %w[activities articles catalogs communications customers customers_training quotes orders engineering ap ar ledger employee_training items logistics marketing reports tech phone it].sort
res.insert(0, 'home') hsh = res.index_with { |m| m.humanize.titleize }
hsh['ap'] = 'A/P'
hsh['ar'] = 'A/R'
hsh['it'] = 'Information Technology'
hsh['image_profiles'] = 'Image Profile Manager'
hsh.invert
end
|
.primary_sales_rep_for_select ⇒ Object
257
258
259
260
261
|
# File 'app/models/employee_record.rb', line 257
def self.primary_sales_rep_for_select
EmployeeRecord.joins(:party)
.includes(:party)
.merge(Employee.primary_sales_reps.active_employees).map { |er| [er.employee_name, er.id] }
end
|
.sales_reps ⇒ ActiveRecord::Relation<EmployeeRecord>
A relation of EmployeeRecords that are sales reps. Active Record Scope
169
|
# File 'app/models/employee_record.rb', line 169
scope :sales_reps, -> { where(SALES_REP_SQL) }
|
.select_options(scope = nil) ⇒ Object
.with_author_page ⇒ ActiveRecord::Relation<EmployeeRecord>
A relation of EmployeeRecords that are with author page. Active Record Scope
192
|
# File 'app/models/employee_record.rb', line 192
scope :with_author_page, -> { where(author_page: true) }
|
.without_an_open_review ⇒ ActiveRecord::Relation<EmployeeRecord>
A relation of EmployeeRecords that are without an open review. Active Record Scope
171
|
# File 'app/models/employee_record.rb', line 171
scope :without_an_open_review, -> { active_employees.where("not exists(select 1 from employee_reviews er where er.employee_record_id = employee_records.id and er.state in ('pending'))") }
|
Instance Method Details
#active? ⇒ Object
176
|
# File 'app/models/employee_record.rb', line 176
delegate :full_name, :inactive?, :active?, to: :party
|
#anniversary_date ⇒ Object
303
304
305
306
307
|
# File 'app/models/employee_record.rb', line 303
def anniversary_date
return unless hire_date
hire_date.strftime("%B #{hire_date.day.ordinalize}")
end
|
#appraisals ⇒ ActiveRecord::Relation<Appraisal>
154
|
# File 'app/models/employee_record.rb', line 154
has_many :appraisals
|
#author_slug_source ⇒ Object
194
195
196
|
# File 'app/models/employee_record.rb', line 194
def author_slug_source
party&.full_name
end
|
142
|
# File 'app/models/employee_record.rb', line 142
belongs_to :backup_rep, class_name: 'Employee', optional: true
|
#clifton_strengths ⇒ ActiveRecord::Relation<CliftonStrength>
150
|
# File 'app/models/employee_record.rb', line 150
has_many :clifton_strengths, -> { order('strength_themes.priority') }, through: :strength_themes
|
143
|
# File 'app/models/employee_record.rb', line 143
belongs_to :commission_structure, optional: true
|
#days_until_next_anniversary ⇒ Object
297
298
299
300
301
|
# File 'app/models/employee_record.rb', line 297
def days_until_next_anniversary
return unless next_work_anniversary
(next_work_anniversary - Date.current).to_i
end
|
#effective_scheduler_link ⇒ Object
275
276
277
278
279
280
281
282
283
|
# File 'app/models/employee_record.rb', line 275
def effective_scheduler_link
case scheduler_link_type
when 'heatwave'
slug = party&.scheduler_profile&.slug
slug.present? ? "#{WEB_URL}/en-US/meet/#{slug}" : nil
when 'external'
calendly_link
end
end
|
#employee ⇒ Object
202
203
204
|
# File 'app/models/employee_record.rb', line 202
def employee
party
end
|
#employee_goals ⇒ ActiveRecord::Relation<EmployeeGoal>
153
|
# File 'app/models/employee_record.rb', line 153
has_many :employee_goals, through: :employee_reviews
|
#employee_name ⇒ Object
206
207
208
|
# File 'app/models/employee_record.rb', line 206
def employee_name
party&.full_name
end
|
#employee_records_printers ⇒ ActiveRecord::Relation<EmployeeRecordsPrinter>
156
|
# File 'app/models/employee_record.rb', line 156
has_many :employee_records_printers
|
#employee_reviewed ⇒ ActiveRecord::Relation<EmployeeReview>
152
|
# File 'app/models/employee_record.rb', line 152
has_many :employee_reviewed, class_name: 'EmployeeReview', foreign_key: 'reviewer_id', inverse_of: :reviewer
|
#employee_reviews ⇒ ActiveRecord::Relation<EmployeeReview>
151
|
# File 'app/models/employee_record.rb', line 151
has_many :employee_reviews, inverse_of: :employee_record
|
#full_name ⇒ Object
Alias for Party#full_name
176
|
# File 'app/models/employee_record.rb', line 176
delegate :full_name, :inactive?, :active?, to: :party
|
#inactive? ⇒ Object
Alias for Party#inactive?
176
|
# File 'app/models/employee_record.rb', line 176
delegate :full_name, :inactive?, :active?, to: :party
|
#is_manager? ⇒ Boolean
263
264
265
|
# File 'app/models/employee_record.rb', line 263
def is_manager?
self.class.managers.where(id:).present?
end
|
#managers_select_options ⇒ Object
318
319
320
|
# File 'app/models/employee_record.rb', line 318
def managers_select_options
self.class.managers_select_options.reject { |v| v[1] == id }
end
|
#manages ⇒ Object
267
268
269
|
# File 'app/models/employee_record.rb', line 267
def manages
self.class.active_employees.managed_by(party_id)
end
|
#manages_employee_record_ids ⇒ Object
271
272
273
|
# File 'app/models/employee_record.rb', line 271
def manages_employee_record_ids
manages.pluck(:id)
end
|
#mba_inventory_1 ⇒ Object
334
335
336
|
# File 'app/models/employee_record.rb', line 334
def mba_inventory_1
mba_inventory&.dig(0)
end
|
#mba_inventory_1=(val) ⇒ Object
338
339
340
341
|
# File 'app/models/employee_record.rb', line 338
def mba_inventory_1=(val)
self.mba_inventory ||= Array.new(3)
self.mba_inventory[0] = val
end
|
#mba_inventory_2 ⇒ Object
343
344
345
|
# File 'app/models/employee_record.rb', line 343
def mba_inventory_2
mba_inventory&.dig(1)
end
|
#mba_inventory_2=(val) ⇒ Object
347
348
349
350
|
# File 'app/models/employee_record.rb', line 347
def mba_inventory_2=(val)
self.mba_inventory ||= Array.new(3)
self.mba_inventory[1] = val
end
|
#mba_inventory_3 ⇒ Object
352
353
354
|
# File 'app/models/employee_record.rb', line 352
def mba_inventory_3
mba_inventory&.dig(2)
end
|
#mba_inventory_3=(val) ⇒ Object
356
357
358
359
|
# File 'app/models/employee_record.rb', line 356
def mba_inventory_3=(val)
self.mba_inventory ||= Array.new(3)
self.mba_inventory[2] = val
end
|
attr_accessible :title, :body
141
|
# File 'app/models/employee_record.rb', line 141
belongs_to :party, optional: true, touch: true
|
#praises ⇒ ActiveRecord::Relation<Praise>
155
|
# File 'app/models/employee_record.rb', line 155
has_many :praises, through: :appraisals
|
#printers ⇒ ActiveRecord::Relation<Printer>
157
|
# File 'app/models/employee_record.rb', line 157
has_many :printers, through: :employee_records_printers
|
#profile_picture ⇒ Image
144
|
# File 'app/models/employee_record.rb', line 144
belongs_to :profile_picture, class_name: 'Image', optional: true
|
210
211
212
213
214
215
216
|
# File 'app/models/employee_record.rb', line 210
def
res = self.class..invert
if .present?
res = res.select { |k, _v| k.in?( || []) }
end res
end
|
#set_first_anniversary ⇒ Object
372
373
374
375
376
377
378
379
380
381
382
|
# File 'app/models/employee_record.rb', line 372
def set_first_anniversary
unless hire_date.present?
return
end return unless hire_date_changed? || next_work_anniversary.nil? || next_work_anniversary < Date.current
na = hire_date.dup.change(year: Date.current.year)
na += 1.year if na < Date.current
self.next_work_anniversary = na
end
|
#set_first_birthday ⇒ Object
361
362
363
364
365
366
367
368
369
370
|
# File 'app/models/employee_record.rb', line 361
def set_first_birthday
if next_birthday.present? && next_birthday > Date.current
return
end return unless employee.dob.present?
nb = employee.dob.dup.change(year: Date.current.year)
nb += 1.year if nb < Date.current
self.next_birthday = nb
end
|
#should_generate_new_friendly_id? ⇒ Boolean
198
199
200
|
# File 'app/models/employee_record.rb', line 198
def should_generate_new_friendly_id?
slug.blank? || will_save_change_to_party_id?
end
|
#signature_picture ⇒ Image
145
|
# File 'app/models/employee_record.rb', line 145
belongs_to :signature_picture, class_name: 'Image', optional: true
|
#signature_picture_small ⇒ Object
285
286
287
288
289
|
# File 'app/models/employee_record.rb', line 285
def signature_picture_small
return nil if signature_picture.nil?
signature_picture.image_url(width: 80)
end
|
#strength_themes ⇒ ActiveRecord::Relation<StrengthTheme>
149
|
# File 'app/models/employee_record.rb', line 149
has_many :strength_themes, -> { order(:priority) }
|
#sync_profile_picture_to_party ⇒ Object
Sync profile_picture_id to Party.profile_image_id
This keeps the legacy employee_record.profile_picture_id in sync with the
consolidated Party.profile_image_id column
387
388
389
390
391
|
# File 'app/models/employee_record.rb', line 387
def sync_profile_picture_to_party
return unless profile_picture_id_changed? && party.present?
party.update_column(:profile_image_id, profile_picture_id)
end
|
#visa_duration_months ⇒ Object
393
394
395
396
397
398
399
|
# File 'app/models/employee_record.rb', line 393
def visa_duration_months
return 0 if visa_start_date.blank? || visa_end_date.blank?
months = (visa_end_date.year * 12 + visa_end_date.month) - (visa_start_date.year * 12 + visa_start_date.month)
months -= 1 if visa_end_date.day < visa_start_date.day
[months, 0].max
end
|
#years_at_work ⇒ Object
291
292
293
294
295
|
# File 'app/models/employee_record.rb', line 291
def years_at_work
return unless hire_date
((Date.current - hire_date) / 365).floor
end
|