Class: Customer::SalesRepChanger

Inherits:
Object
  • Object
show all
Defined in:
app/services/customer/sales_rep_changer.rb

Overview

This class is responsible for handling everything related to a customer's
sales rep change

Defined Under Namespace

Classes: InvalidCustomerState, UnrecognizedRepAttribute

Constant Summary collapse

REP_FIELDS =
%i[primary_sales_rep_id secondary_sales_rep_id local_sales_rep_id service_rep_id]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(customer, options = {}) ⇒ SalesRepChanger

Returns a new instance of SalesRepChanger.



13
14
15
16
17
18
# File 'app/services/customer/sales_rep_changer.rb', line 13

def initialize(customer, options = {})
  @customer = customer
  @options = options || {}
  @skip_activity_creation = options[:skip_activity_creation]
  @logger = @options[:logger] || Rails.logger
end

Instance Attribute Details

#fresh_primary_repObject (readonly)

Returns the value of attribute fresh_primary_rep.



8
9
10
# File 'app/services/customer/sales_rep_changer.rb', line 8

def fresh_primary_rep
  @fresh_primary_rep
end

#loggerObject

Returns the value of attribute logger.



7
8
9
# File 'app/services/customer/sales_rep_changer.rb', line 7

def logger
  @logger
end

#primary_rep_assignedObject (readonly)

Returns the value of attribute primary_rep_assigned.



8
9
10
# File 'app/services/customer/sales_rep_changer.rb', line 8

def primary_rep_assigned
  @primary_rep_assigned
end

#primary_rep_changedObject (readonly)

Returns the value of attribute primary_rep_changed.



8
9
10
# File 'app/services/customer/sales_rep_changer.rb', line 8

def primary_rep_changed
  @primary_rep_changed
end

#primary_rep_replacedObject (readonly)

Returns the value of attribute primary_rep_replaced.



8
9
10
# File 'app/services/customer/sales_rep_changer.rb', line 8

def primary_rep_replaced
  @primary_rep_replaced
end

#rep_changesObject (readonly)

Returns the value of attribute rep_changes.



8
9
10
# File 'app/services/customer/sales_rep_changer.rb', line 8

def rep_changes
  @rep_changes
end

#skip_activity_creationObject (readonly)

Returns the value of attribute skip_activity_creation.



8
9
10
# File 'app/services/customer/sales_rep_changer.rb', line 8

def skip_activity_creation
  @skip_activity_creation
end

Instance Method Details

#analyze_changesObject



42
43
44
45
46
47
48
# File 'app/services/customer/sales_rep_changer.rb', line 42

def analyze_changes
  @primary_rep_replaced = @customer.primary_sales_rep_id_was && @customer.primary_sales_rep_id_changed?
  @fresh_primary_rep = @customer.primary_sales_rep_id_was.nil? && @customer.primary_sales_rep_id
  @primary_rep_changed = @customer.primary_sales_rep_id_changed?
  @primary_rep_assigned = @customer.primary_sales_rep_id.present?
  @rep_changes = determine_rep_changes
end

#assign_lead_activitiesObject

Assign lead activities



114
115
116
117
118
119
120
121
122
123
# File 'app/services/customer/sales_rep_changer.rb', line 114

def assign_lead_activities
  return :skip_activity_creation_set if @skip_activity_creation
  return :no_primary_assigned unless @primary_rep_assigned

  if primary_rep_replaced
    @customer.create_intro_activity # New account manager activity
  else
    NewLead::LeadActivityAssigner.new.process(@customer)
  end
end

#assign_reps(rep_attributes = {}) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'app/services/customer/sales_rep_changer.rb', line 20

def assign_reps(rep_attributes = {})
  return unless rep_attributes.present?

  invalid_attributes = rep_attributes.reject { |k| REP_FIELDS.include? k.to_sym }
  raise(UnrecognizedRepAttribute, "Attribute not recognized #{invalid_attributes.keys.join(',')}, can only be #{REP_FIELDS.join(', ')}", caller) if invalid_attributes.present?

  @customer.attributes = rep_attributes
  analyze_changes
  reset_sales_watch
  begin
    return false unless @customer.save
  rescue ActiveRecord::RecordNotUnique => e
    raise unless e.message.include?('activities_parties')

    @customer.reload
    @customer.attributes = rep_attributes
    return false unless @customer.save
  end

  handle_rep_changes
end

#determine_rep_changesObject



50
51
52
53
54
55
56
# File 'app/services/customer/sales_rep_changer.rb', line 50

def determine_rep_changes
  changes = {}
  REP_FIELDS.each do |rf|
    changes[rf] = @customer.send("#{rf}_change") if @customer.send("#{rf}_changed?")
  end
  changes
end

#handle_rep_changesObject



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'app/services/customer/sales_rep_changer.rb', line 62

def handle_rep_changes
  return true unless rep_changed?

  changes_for_log = @rep_changes.transform_values do |value|
    if value.is_a?(Array)
      value.map { |v| v.respond_to?(:id) ? v.id : v }
    else
      value.respond_to?(:id) ? value.id : value
    end
  end

  logger.debug('Rep change detected', customer_id: @customer.id, changes: changes_for_log)
  reset_sales_watch
  reset_open_opportunities
  reset_activity_assignments
  assign_lead_activities
  true
end

#rep_changed?Boolean

Returns:

  • (Boolean)


58
59
60
# File 'app/services/customer/sales_rep_changer.rb', line 58

def rep_changed?
  @rep_changes.any?
end

#reset_activity_assignmentsObject

Re run all open activities through the queue assignment system



98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'app/services/customer/sales_rep_changer.rb', line 98

def reset_activity_assignments
  @customer.all_activities.open_activities.each do |activity|
    logger.info "Evaluating activity #{activity}"
    # If activity is allocated on a week end of 'after hours', go to the next business day.  5pm is our end of day cutoff
    due_datetime = activity.target_datetime
    due_datetime = WorkingHours.advance_to_closing_time(Time.current.next_business_day) if activity.overdue? || activity.target_datetime_outside_business_hours?
    # We pick the best resource for the activity, we are going to ignore in this context
    # the possible activity overload check by passing ignore_target_date
    # For instance if a rep already has his/her max of activities for that day, we ignore and we assign the 'ideal' rep
    activity.auto_assign(due_datetime, nil, ignore_target_date: true)
    logger.info " -- assigned to #{activity.assigned_resource.try(:name)}"
    activity.save
  end
end

#reset_open_opportunitiesObject

Any open opportunity will get their reps reset to the new primary, secondary and local



90
91
92
93
94
95
# File 'app/services/customer/sales_rep_changer.rb', line 90

def reset_open_opportunities
  @customer.opportunities.not_won_or_lost.each do |opportunity|
    opportunity.synchronize_reps
    opportunity.save!
  end
end

#reset_sales_watchObject

REset the sales watch if rep is nillified



82
83
84
85
86
87
# File 'app/services/customer/sales_rep_changer.rb', line 82

def reset_sales_watch
  return :reset_not_needed if @primary_rep_assigned

  logger.info 'Rep changed to nil, resetting watch'
  @customer.watch = Customer.watches[:not_watched_auto]
end