Class: SupportCase

Inherits:
ApplicationRecord show all
Includes:
Models::Auditable, Models::LiquidMethods
Defined in:
app/models/support_case.rb

Overview

== Schema Information

Table name: support_cases
Database name: primary

id :integer not null, primary key
case_number :string not null
case_type :string(255)
closed_at :datetime
closed_reason :string
customer_24h_notification :datetime
description :text
first_review_request_processed :boolean default(FALSE)
first_review_request_processed_date :datetime
mileage :integer
notified_at :datetime
opened_at :datetime
original_case_number :string
preferred_service_timeframe :string
priority :string(255)
reopened_reason :string
review_snoozed_until :datetime
reviewable :boolean default(FALSE)
reviewed :boolean default(FALSE)
service :string
service_date :date
service_duration :integer
service_room_qty :integer
service_time :time
state :string(255)
travel_time :integer
unassigned_notification_sent :boolean default(FALSE), not null
created_at :datetime not null
updated_at :datetime not null
assigned_to_id :integer
creator_id :integer
parent_id :integer
service_address_id :integer
updater_id :integer

Indexes

by_ct_atid (case_type,assigned_to_id)
idx_parent_id (parent_id)
idx_serv_date_case_type_serv_time (service_date,case_type,service_time)
idx_service_address_id (service_address_id)
idx_support_cases_state (state) WHERE (assigned_to_id IS NULL)
index_support_cases_on_case_number (case_number) UNIQUE
index_support_cases_on_state_and_id (state,id)

Foreign Keys

fk_rails_... (parent_id => support_cases.id)
fk_rails_... (service_address_id => addresses.id)

Defined Under Namespace

Classes: Create

Constant Summary collapse

FIELD_TECHNICIAN_CELL =

Field technician cell.

'12245511225'
REFERENCE_NUMBER_PATTERN =

Regex pattern matching reference number.

/^.TK\d+/i
CLOSED_REASONS =

Closed reasons.

[
  'Answered question',
  'Problem fixed',
  'Stat defaults changed',
  'Damage Repaired Warranty',
  'Damage Repaired Non-Warranty',
  'Heating Product Replaced Warranty',
  'Heating Product Replaced Non-Warranty',
  'Customer Waiting for Other Parties',
  'Customer Decided to Abandon the System',
  "Customer Doesn't Respond",
  'Duplicate'
].freeze
SERVICE_CLOSED_REASONS =

Service closed reasons.

[
  'Service has been completed',
  'Service has been completed - warranty claim - free service',
  'Service has not been completed - no show / no refund',
  'Service has not been completed - cancelled within the 24h grace period',
  'Service has not been completed - not able to perform due to comply with T&C',
  'Duplicate',
  "Customer Doesn't Respond"
].freeze
PRIORITIES_HASH =

Priorities hash.

{
  Low: { label: 'Low (within 1 business day)', follow_up_delay: 7 },
  Medium: { label: 'Medium (within 2 hours)', follow_up_delay: 3 },
  High: { label: 'High (within 20 minutes)', follow_up_delay: 1 }
}.freeze
LOCKED_STATES =

Recognised locked states.

%i[open closed waiting_on_customer waiting_to_confirm_appointment pending_service_payment site_visit_scheduled
third_party_site_visit_scheduled waiting_on_accountant waiting_on_warmlyyours sent_to_collections].freeze

Constants included from Models::Auditable

Models::Auditable::ALWAYS_IGNORED

Constants included from Models::Schedulable

Models::Schedulable::SIMPLE_FORM_OPTIONS

Instance Attribute Summary collapse

Belongs to collapse

Methods included from Models::Auditable

#creator, #updater

Has and belongs to many collapse

Has many collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::Auditable

#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Models::Schedulable

config

Methods included from Models::AfterCommittable

#after_commit

Methods included from Models::EventPublishable

#publish_event

Instance Attribute Details

#case_typeObject (readonly)



134
# File 'app/models/support_case.rb', line 134

validates :description, :case_type, :priority, presence: true

#descriptionObject (readonly)



134
# File 'app/models/support_case.rb', line 134

validates :description, :case_type, :priority, presence: true

#order_idObject

Returns the value of attribute order_id.



142
143
144
# File 'app/models/support_case.rb', line 142

def order_id
  @order_id
end

#priorityObject (readonly)



134
# File 'app/models/support_case.rb', line 134

validates :description, :case_type, :priority, presence: true

#service_creation_optionObject

Returns the value of attribute service_creation_option.



142
143
144
# File 'app/models/support_case.rb', line 142

def service_creation_option
  @service_creation_option
end

Class Method Details

.case_type_for_search_selectObject

Search keeps SmartService so historical service cases stay findable.



284
285
286
# File 'app/models/support_case.rb', line 284

def self.case_type_for_search_select
  ['Tech', 'Accounting', 'Ecommerce', 'Customer Service', 'SmartService'].map { |ct| [ct, ct] }
end

.case_type_for_selectObject

SmartService is deliberately absent — those cases are created by the
checkout/service flows, not hand-picked on the new-ticket screen.



279
280
281
# File 'app/models/support_case.rb', line 279

def self.case_type_for_select
  ['Tech', 'Accounting', 'Ecommerce', 'Customer Service'].map { |ct| [ct, ct] }
end

.case_typesObject



242
243
244
# File 'app/models/support_case.rb', line 242

def self.case_types
  ['Tech', 'Accounting', 'Ecommerce', 'Customer Service']
end

.closed_casesActiveRecord::Relation<SupportCase>

A relation of SupportCases that are closed cases. Active Record Scope

Returns:

See Also:



147
# File 'app/models/support_case.rb', line 147

scope :closed_cases, -> { where(state: %w[closed]) }

.lockedActiveRecord::Relation<SupportCase>

A relation of SupportCases that are locked. Active Record Scope

Returns:

See Also:



151
# File 'app/models/support_case.rb', line 151

scope :locked, -> { where(state: LOCKED_STATES) }

.lookupActiveRecord::Relation<SupportCase>

A relation of SupportCases that are lookup. Active Record Scope

Returns:

See Also:



144
# File 'app/models/support_case.rb', line 144

scope :lookup, ->(q) { where(SupportCase[:case_number].matches("#{q}%")) }

.not_closed_casesActiveRecord::Relation<SupportCase>

A relation of SupportCases that are not closed cases. Active Record Scope

Returns:

See Also:



153
# File 'app/models/support_case.rb', line 153

scope :not_closed_cases, -> { where.not(state: :closed) }

.open_casesActiveRecord::Relation<SupportCase>

A relation of SupportCases that are open cases. Active Record Scope

Returns:

See Also:



146
# File 'app/models/support_case.rb', line 146

scope :open_cases, -> { where(state: %w[new open]) }

.pending_service_paymentActiveRecord::Relation<SupportCase>

A relation of SupportCases that are pending service payment. Active Record Scope

Returns:

See Also:



152
# File 'app/models/support_case.rb', line 152

scope :pending_service_payment, -> { where(state: %w[pending_service_payment]) }

.priorities_for_selectObject



292
293
294
# File 'app/models/support_case.rb', line 292

def self.priorities_for_select
  PRIORITIES_HASH.map { |ph_k, ph_sh| [ph_sh[:label], ph_k.to_s] }
end

.service_creation_optionsObject



597
598
599
600
# File 'app/models/support_case.rb', line 597

def self.service_creation_options
  [['Create a new support case', 'new_support_case'], ['Use existing support sase', 'existing_support_case'],
   ["Don't create a support case", 'skip_support_case']]
end

.servicesActiveRecord::Relation<SupportCase>

A relation of SupportCases that are services. Active Record Scope

Returns:

See Also:



145
# File 'app/models/support_case.rb', line 145

scope :services, -> { where(case_type: %w[SmartService SmartInstall SmartSupport SmartFix]) }

.states_for_selectObject



288
289
290
# File 'app/models/support_case.rb', line 288

def self.states_for_select
  state_machines[:state].states.map { |s| [s.human_name, s.value] }
end

.waiting_casesActiveRecord::Relation<SupportCase>

A relation of SupportCases that are waiting cases. Active Record Scope

Returns:

See Also:



148
149
150
# File 'app/models/support_case.rb', line 148

scope :waiting_cases, -> {
  where(state: %w[waiting_on_customer pending_service_payment waiting_to_confirm_appointment site_visit_scheduled waiting_on_equipment site_visit_scheduled third_party_site_visit_scheduled waiting_on_accountant waiting_on_warmlyyours])
}

Instance Method Details

#activitiesActiveRecord::Relation<Activity>

Returns:

See Also:



112
# File 'app/models/support_case.rb', line 112

has_many :activities, as: :resource, dependent: :destroy

#advance_follow_up_activityObject

When another activity occurs, we need to advance the tickout activity



483
484
485
486
487
488
489
490
491
492
# File 'app/models/support_case.rb', line 483

def advance_follow_up_activity
  return unless (tickout = activities.open_activities.find_by(activity_type_id: ActivityTypeConstants::TICKOUT))

  tickout.target_datetime = follow_up_delay.working.days.from_now
  tickout.assigned_resource = assigned_to
  tickout.lock_target_datetime = true
  tickout.party ||= support_case_participants.first&.party
  tickout.save
  tickout
end

#all_credit_memosObject



308
309
310
311
# File 'app/models/support_case.rb', line 308

def all_credit_memos
  all_credit_memo_ids = ([] + order_credit_memo_ids + credit_memo_ids).compact.uniq
  CreditMemo.where(id: all_credit_memo_ids)
end

#all_participantsObject



503
504
505
# File 'app/models/support_case.rb', line 503

def all_participants
  support_case_participants.with_party.map { |scp| scp.party.full_name }.join(', ')
end

#all_rmasObject



313
314
315
316
# File 'app/models/support_case.rb', line 313

def all_rmas
  all_rma_ids = ([] + rma_ids + order_rma_ids).compact.uniq
  Rma.where(id: all_rma_ids)
end

#assigned_toEmployee

Returns:

See Also:



104
# File 'app/models/support_case.rb', line 104

belongs_to :assigned_to, class_name: 'Employee', optional: true

#assigned_to_nameObject



218
219
220
# File 'app/models/support_case.rb', line 218

def assigned_to_name
  assigned_to.nil? ? 'Unassigned' : assigned_to.full_name
end

#assignment_email_urlObject



352
353
354
# File 'app/models/support_case.rb', line 352

def assignment_email_url
  SUPPORT_CASE_CRM_BASE_URL + id.to_s
end

#build_activityObject



300
301
302
# File 'app/models/support_case.rb', line 300

def build_activity
  activities.build resource: self, party: support_case_participants.with_party.first&.party
end

#build_new_participant(np) ⇒ Object

Build an unsaved participant with a new Contact party when the caller
isn't in the system yet (e.g. phone popup for an unknown number). The
SupportCaseParticipant#set_party callback turns the virtual
party_name / contact_name into a real Customer / Contact on save.



401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
# File 'app/models/support_case.rb', line 401

def build_new_participant(np)
  new_party = Contact.new
  new_party.contact_points.build(category: ContactPoint::EMAIL)
  new_party.contact_points.build(category: ContactPoint::CELL)
  new_party.contact_points.build(category: ContactPoint::PHONE, detail: np[:phone].presence)
  new_party.contact_points.build(category: ContactPoint::FAX)

  support_case_participants.build(
    party: new_party,
    party_name: np[:party_name].presence,
    contact_name: np[:contact_name].presence,
    role: np[:role].presence || 'homeowner',
    preferred_language: np[:preferred_language].presence
  )
end

#build_participants_and_rooms(params) ⇒ Object



356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'app/models/support_case.rb', line 356

def build_participants_and_rooms(params)
  if params[:new_participant].present?
    build_new_participant(params[:new_participant])
    return
  end

  if params[:participant_id]
    party = Party.find(params[:participant_id])
  elsif params[:room_configuration_id]
    rc = RoomConfiguration.find(params[:room_configuration_id])
    party = rc.customer
    self.room_configuration_ids = [params[:room_configuration_id]]
  elsif params[:order_id]
    ord = Order.find(params[:order_id])
    party = ord.customer
    contact = ord.contact
    self.room_configuration_ids = ord.room_configuration_ids if ord.room_configuration_ids.any?
    self.order_ids = [ord.id]
    # In this case we'll have the contact and the customer as participants.
    if contact.present?
      support_case_participants.build(party: contact,
                                      email: contact.contact_points.emails.first,
                                      phone: contact.contact_points.voice_callable.first,
                                      role: 'homeowner',
                                      preferred_language: contact.preferred_language)
    end
  elsif params[:quote_id]
    quo = Quote.find(params[:quote_id])
    party = quo.customer
    self.room_configuration_ids += quo.room_configuration_ids
    self.quote_ids = [quo.id]
  end
  return if party.blank?

  support_case_participants.build(party: party,
                                  email: party.contact_points.emails.first,
                                  phone: party.contact_points.voice_callable.first,
                                  role: 'homeowner',
                                  preferred_language: party.preferred_language)
end

#close_tickoutObject



494
495
496
497
498
499
500
501
# File 'app/models/support_case.rb', line 494

def close_tickout
  activities.open_activities.where(activity_type_id: ActivityTypeConstants::TICKOUT).find_each do |a|
    a.halt_chain = true
    a.completion_datetime = Time.current
    a.activity_result_type_id = ActivityResultTypeConstants::CANCEL
    a.save
  end
end

#communication_template_system_codeObject



537
538
539
540
541
542
543
544
545
546
# File 'app/models/support_case.rb', line 537

def communication_template_system_code
  case case_type
  when 'Accounting'
    'ACCT_TCKT_UPDATE'
  when 'Ecommerce'
    'ECOM_TCKT_UPDATE'
  else
    'SUPPORTCASE_UPDATE'
  end
end

#communicationsActiveRecord::Relation<Communication>

Returns:

See Also:



113
# File 'app/models/support_case.rb', line 113

has_many :communications, as: :resource, dependent: :nullify

#company_review_urlObject

Reviews.io dynamic link for company review using the case number as order_id



603
604
605
# File 'app/models/support_case.rb', line 603

def company_review_url
  Api::ReviewsIo::DynamicLinkBuilder.for_support_case(self)
end

#convert_to_stkObject



621
622
623
624
625
626
627
628
629
630
631
632
633
# File 'app/models/support_case.rb', line 621

def convert_to_stk
  res = false
  if case_number.include?('TTK')
    self.original_case_number = case_number
    case_number.sub!('TTK', 'STK')
    self.case_type = 'SmartService'
    self.state = 'pending_service_payment'
    self.assigned_to_id = Employee::SCOTT
    res = save
    converted_from_ttk_to_stk_activity
  end
  res
end

#converted_from_ttk_to_stk_activityObject



635
636
637
638
# File 'app/models/support_case.rb', line 635

def converted_from_ttk_to_stk_activity
  Activity.create(resource: self,
                  notes: 'Support Case converted from TTK to STK.')
end

#create_follow_up_activityObject



471
472
473
474
475
476
477
478
479
480
# File 'app/models/support_case.rb', line 471

def create_follow_up_activity
  # unless you've already got one
  Activity.create(lock_target_datetime: true,
                  activity_type_id: ActivityTypeConstants::TICKOUT,
                  target_datetime: follow_up_delay.working.days.from_now,
                  assigned_resource: assigned_to,
                  party: support_case_participants.first&.party,
                  resource: self,
                  notes: "Follow up on Support Case #{case_number}.")
end

#create_initial_service_activityObject



417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
# File 'app/models/support_case.rb', line 417

def create_initial_service_activity
  order = orders.contains_service_items.first # The first order is the one who initiated the service case
  return if order.blank?

  if order.is_smartfit_service?
    first_activity = ActivityTypeConstants::SERVICECONFIRM
  elsif order.is_smartinstall_service?
    first_activity = ActivityTypeConstants::SSI_PREPLAN_MEET
  elsif order.is_smartfix_service?
    first_activity = ActivityTypeConstants::SSFIX_SERVICE_CONFIRM
  elsif order.is_smartguide_service?
    first_activity = if order.line_items.joins(:item).merge(Item.where(sku: 'SGS_ONSITE_FIXRATE')).any?
                       ActivityTypeConstants::SGS_ONSITE_PREPLAN_MEET
                     else
                       ActivityTypeConstants::SGS_REMOTE_PREPLAN_MEET
                     end
  end

  Activity.create(lock_target_datetime: false,
                  activity_type_id: first_activity,
                  target_datetime: 1.working.days.from_now,
                  assigned_resource: Employee.find_by(id: 82), # Assigned by default to Scott
                  party: order.customer,
                  resource: self,
                  notes: 'Call Customer to confirm date and time of the service.')

  SupportMailer.smart_service_requested_notification(self).deliver_later
end

#create_new_tickout(note) ⇒ Object



640
641
642
643
644
645
646
647
648
# File 'app/models/support_case.rb', line 640

def create_new_tickout(note)
  Activity.create(lock_target_datetime: true,
                  activity_type_id: ActivityTypeConstants::TICKOUT,
                  target_datetime: 0.working.days.from_now,
                  assigned_resource: assigned_to,
                  party: support_case_participants.with_party.first&.party,
                  resource: self,
                  notes: "Case reopened. Reason: #{note}")
end

#credit_memosActiveRecord::Relation<CreditMemo>

Returns:

See Also:



117
# File 'app/models/support_case.rb', line 117

has_many :credit_memos

#customerObject



246
247
248
# File 'app/models/support_case.rb', line 246

def customer
  support_case_participants.with_party.find { |sc| sc.party&.customer }&.party&.customer
end

#customer_addressObject



262
263
264
265
266
267
# File 'app/models/support_case.rb', line 262

def customer_address
  address = service_address
  return unless address

  ApplicationController.helpers.format_for_display address, { address_type: false, include_recipient: false }
end

#customer_emailObject



269
270
271
# File 'app/models/support_case.rb', line 269

def customer_email
  customer.try(:email) || 'unspecified'
end

#customer_full_nameObject



254
255
256
# File 'app/models/support_case.rb', line 254

def customer_full_name
  customer.try(:full_name) || 'unspecified'
end

#customer_phoneObject



258
259
260
# File 'app/models/support_case.rb', line 258

def customer_phone
  customer.try(:phone) || 'unspecified'
end

#customer_reference_numberObject



250
251
252
# File 'app/models/support_case.rb', line 250

def customer_reference_number
  customer.try(:reference_number) || 'unspecified'
end

#editing_locked?Boolean

Returns:

  • (Boolean)


556
557
558
# File 'app/models/support_case.rb', line 556

def editing_locked?
  LOCKED_STATES.include?(state.to_sym)
end

#events_for_selectObject



296
297
298
# File 'app/models/support_case.rb', line 296

def events_for_select
  state_events.select { |evt| send(:"can_#{evt}?") }.sort.map { |evt| [evt.to_s.titleize, evt] }
end

#field_technician_cellObject

In the future with more than one tech we can change this method



214
215
216
# File 'app/models/support_case.rb', line 214

def field_technician_cell
  FIELD_TECHNICIAN_CELL
end

#formatted_service_timeObject



465
466
467
468
469
# File 'app/models/support_case.rb', line 465

def formatted_service_time
  service_time.strftime('%l:%M %p')
rescue StandardError
  nil
end

#generate_service_calendar_eventObject



446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
# File 'app/models/support_case.rb', line 446

def generate_service_calendar_event
  return nil if service_date.nil? || service_time.nil?

  event_start = DateTime.new service_date.year, service_date.month, service_date.day, service_time.hour, service_time.min, service_time.sec
  event_end = DateTime.new service_date.year, service_date.month, service_date.day, service_time.hour + 3, service_time.min, service_time.sec

  # create PTO block in JL calendar
  Employee.find(Employee::SCOTT).employee_events.new(status: 'working_on_service', date: event_start.to_date, from_hour: event_start.to_time,
                                                     to_hour: event_end.to_time, authorized: true).save

  IcsEventBuilder.new(
    tzid: 'America/Chicago',
    starts_at: event_start,
    ends_at: event_end,
    summary: "WarmlyYours Onsite Service #{case_number}",
    description: 'If you want to change or cancel this appointment, please contact WarmlyYours at 800-875-5285.'
  ).calendar
end

#is_accounting?Boolean

Returns:

  • (Boolean)


230
231
232
# File 'app/models/support_case.rb', line 230

def is_accounting?
  case_type == 'Accounting'
end

#is_customer_service?Boolean

Returns:

  • (Boolean)


238
239
240
# File 'app/models/support_case.rb', line 238

def is_customer_service?
  case_type == 'Customer Service'
end

#is_ecommerce?Boolean

Returns:

  • (Boolean)


234
235
236
# File 'app/models/support_case.rb', line 234

def is_ecommerce?
  case_type == 'Ecommerce'
end

#is_service?Boolean

Returns:

  • (Boolean)


226
227
228
# File 'app/models/support_case.rb', line 226

def is_service?
  case_type == 'SmartService'
end

#is_tech?Boolean

Returns:

  • (Boolean)


222
223
224
# File 'app/models/support_case.rb', line 222

def is_tech?
  case_type == 'Tech'
end

Use for activity callback



336
337
338
# File 'app/models/support_case.rb', line 336

def link_party_ids
  support_case_participants.with_party.pluck(:party_id)
end

#linked_casesActiveRecord::Relation<SupportCase>

Returns:

See Also:



119
# File 'app/models/support_case.rb', line 119

has_many :linked_cases, class_name: 'SupportCase', foreign_key: 'parent_id'

#nameObject



340
341
342
# File 'app/models/support_case.rb', line 340

def name
  "Ticket #{case_number}"
end

#order_credit_memosActiveRecord::Relation<CreditMemo>

Returns:

See Also:



118
# File 'app/models/support_case.rb', line 118

has_many :order_credit_memos, class_name: 'CreditMemo', through: :orders, source: :credit_memos

#order_rmasActiveRecord::Relation<Rma>

Returns:

  • (ActiveRecord::Relation<Rma>)

See Also:



116
# File 'app/models/support_case.rb', line 116

has_many :order_rmas, class_name: 'Rma', through: :orders, source: :rmas

#ordersActiveRecord::Relation<Order>

Returns:

  • (ActiveRecord::Relation<Order>)

See Also:



108
# File 'app/models/support_case.rb', line 108

has_and_belongs_to_many :orders, validate: false

#participants_options_for_selectObject



515
516
517
# File 'app/models/support_case.rb', line 515

def participants_options_for_select
  support_case_participants.with_party.map { |scp| [scp.party.full_name, scp.party_id] }
end

#primary_partyObject



304
305
306
# File 'app/models/support_case.rb', line 304

def primary_party
  support_case_participants.with_party.first&.party
end

#project_nameObject



548
549
550
# File 'app/models/support_case.rb', line 548

def project_name
  orders.first&.opportunity&.name || room_configurations.first&.opportunity&.name
end

#quotesActiveRecord::Relation<Quote>

Returns:

  • (ActiveRecord::Relation<Quote>)

See Also:



109
# File 'app/models/support_case.rb', line 109

has_and_belongs_to_many :quotes, validate: false

#reviews_io_reviewsObject

Find Reviews.io reviews linked to this support case (by case_number as order_id)



608
609
610
611
612
# File 'app/models/support_case.rb', line 608

def reviews_io_reviews
  identifiers = [case_number]
  identifiers << customer&.reference_number if customer.present?
  ReviewsIo.active.store_reviews.where(order_id: identifiers.compact).recent
end

#rmasActiveRecord::Relation<Rma>

Returns:

  • (ActiveRecord::Relation<Rma>)

See Also:



115
# File 'app/models/support_case.rb', line 115

has_many :rmas

#room_configurationsActiveRecord::Relation<RoomConfiguration>

Returns:

See Also:



107
# File 'app/models/support_case.rb', line 107

has_and_belongs_to_many :room_configurations, validate: false

#selection_nameObject



348
349
350
# File 'app/models/support_case.rb', line 348

def selection_name
  "#{case_number} - #{case_type} - #{human_state_name}"
end

#send_24h_customer_notificationObject



566
567
568
569
570
571
# File 'app/models/support_case.rb', line 566

def send_24h_customer_notification
  smartservice_reminder(ActivityTypeConstants::ONSITESERVICE, 'SMARTFIT_APPOINTMENT_REMINDER')
  smartservice_reminder(ActivityTypeConstants::SSI_INSTALL, 'SMARTINSTALL_APPOINTMENT_REMINDER')
  smartservice_reminder(ActivityTypeConstants::SGS_ONSITESUPPORT, 'SMARTSUPPORT_APPOINTMENT_REMINDER')
  smartservice_reminder(ActivityTypeConstants::SGS_REMOTESUPPORT, 'SMARTSUPPORT_APPOINTMENT_REMINDER')
end

#send_unassigned_emailObject



519
520
521
522
# File 'app/models/support_case.rb', line 519

def send_unassigned_email
  CommunicationBuilder.new(resource: self, template_system_code: unassigned_ticket_system_code).create
  update(unassigned_notification_sent: true)
end

#service_addressAddress

Returns:

See Also:



105
# File 'app/models/support_case.rb', line 105

belongs_to :service_address, class_name: 'Address', optional: true

#service_priceObject



552
553
554
# File 'app/models/support_case.rb', line 552

def service_price
  orders.first.total
end

#service_total_priceObject



273
274
275
# File 'app/models/support_case.rb', line 273

def service_total_price
  ActionController::Base.helpers.number_to_currency(service_price)
end

#smart_service_scheduleObject



560
561
562
563
564
# File 'app/models/support_case.rb', line 560

def smart_service_schedule
  return nil unless service_date.present? && preferred_service_timeframe.present?

  "#{service_date.strftime('%b %d, %Y')} - #{preferred_service_timeframe.titleize} frame"
end

#smartservice_reminder(activity_type, email_template) ⇒ Object



573
574
575
576
577
578
579
580
581
582
583
584
585
# File 'app/models/support_case.rb', line 573

def smartservice_reminder(activity_type, email_template)
  return unless (ss_activity = activities.where(activity_type_id: activity_type).last)

  sender_party = ss_activity.sender_party

  CommunicationBuilder.new(resource: self,
                           sender_party: sender_party,
                           recipient_party: ss_activity.customer,
                           current_user: sender_party,
                           use_best_email: true,
                           template: EmailTemplate.find_by(system_code: email_template)).create
  update(customer_24h_notification: Time.current)
end

#sms_enabled_numbersObject



507
508
509
# File 'app/models/support_case.rb', line 507

def sms_enabled_numbers
  ContactPoint.joins(party: :support_case_participants).merge(support_case_participants).sms_numbers.order(:detail).map(&:formatted_for_sms).uniq
end

#sms_messagesObject



511
512
513
# File 'app/models/support_case.rb', line 511

def sms_messages
  SmsMessage.for_numbers(sms_enabled_numbers)
end

#suggested_participantsObject



318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'app/models/support_case.rb', line 318

def suggested_participants
  parties = []
  room_configurations.each do |rc|
    parties << rc.customer
    parties.concat(rc.customer.contacts)
  end
  support_case_participants.with_party.each do |scp|
    unless scp.party.nil?
      parties << scp.party
      parties.concat(scp.party.contacts)
    end
  end
  # Reject parties already in
  parties = parties.reject { |p| p.inactive || support_case_participants.with_party.any? { |scp| scp.party_id == p.id } }
  parties.compact.uniq
end

#support_case_participantsActiveRecord::Relation<SupportCaseParticipant>

Returns:

See Also:



111
# File 'app/models/support_case.rb', line 111

has_many :support_case_participants, inverse_of: :support_case

#technical_article_evidence_linksActiveRecord::Relation<ContentLink>

Returns:

See Also:



120
121
122
123
124
# File 'app/models/support_case.rb', line 120

has_many :technical_article_evidence_links, -> { where(link_type: 'case_evidence') },
class_name: 'ContentLink',
foreign_key: :target_support_case_id,
inverse_of: :target_support_case,
dependent: :destroy

#technical_articlesActiveRecord::Relation<TechnicalArticle>

Returns:

  • (ActiveRecord::Relation<TechnicalArticle>)

See Also:



125
# File 'app/models/support_case.rb', line 125

has_many :technical_articles, through: :technical_article_evidence_links, source: :source_article

#to_sObject



344
345
346
# File 'app/models/support_case.rb', line 344

def to_s
  "Support Case # #{case_number}"
end

#tracking_email_addressObject



614
615
616
617
618
619
# File 'app/models/support_case.rb', line 614

def tracking_email_address
  domain = Rails.application.config.x.email_domain
  prefix = 'support'
  encrypted_id = Encryption.encrypt_string(id.to_s)
  "#{prefix}+id#{encrypted_id}@#{domain}"
end

#unassigned_ticket_system_codeObject



524
525
526
527
528
529
530
531
532
533
534
535
# File 'app/models/support_case.rb', line 524

def unassigned_ticket_system_code
  case case_type
  when 'Accounting'
    'ACCT_TCKT_UNASSIGNED'
  when 'Ecommerce'
    'ECOM_TCKT_UNASSIGNED'
  when 'Customer Service'
    'CS_TCKT_UNASSIGNED'
  else
    'SUPPORTCASE_UNASSGND'
  end
end

#uploadsActiveRecord::Relation<Upload>

Returns:

  • (ActiveRecord::Relation<Upload>)

See Also:



114
# File 'app/models/support_case.rb', line 114

has_many :uploads, as: :resource, dependent: :destroy

#versions_for_audit_trail(_params = {}) ⇒ Object



587
588
589
590
591
592
593
594
595
# File 'app/models/support_case.rb', line 587

def versions_for_audit_trail(_params = {})
  RecordVersion.where(<<~SQL.squish, id: id, party_id_json: { party_id: id }.to_json)
    (item_type = 'SupportCase' AND item_id = :id)
    OR (
      item_type = 'SupportCaseParticipant'
      AND reference_data @> :party_id_json
    )
  SQL
end