Class: Activity::ChainRunner

Inherits:
Object
  • Object
show all
Defined in:
app/services/activity/chain_runner.rb

Defined Under Namespace

Classes: NoActivityResultError, NoActivityTypeError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(activity, options = {}) ⇒ ChainRunner

Returns a new instance of ChainRunner.



16
17
18
19
20
21
22
23
24
25
26
# File 'app/services/activity/chain_runner.rb', line 16

def initialize(activity, options = {})
  @activity = activity
  @activity_type = activity.activity_type
  @activity_result_type = options[:new_activity_result_type] || activity.activity_result_type
  @logger = options[:logger] || Rails.logger

  raise NoActivityTypeError unless @activity_type
  raise NoActivityResultError unless @activity_result_type

  @chains_for_result = @activity_type.activity_chain_types.select { |act| act.activity_result_type_id == @activity_result_type.id }
end

Instance Attribute Details

#activityObject (readonly)

Returns the value of attribute activity.



5
6
7
# File 'app/services/activity/chain_runner.rb', line 5

def activity
  @activity
end

#activity_result_typeObject (readonly)

Returns the value of attribute activity_result_type.



5
6
7
# File 'app/services/activity/chain_runner.rb', line 5

def activity_result_type
  @activity_result_type
end

#activity_typeObject (readonly)

Returns the value of attribute activity_type.



5
6
7
# File 'app/services/activity/chain_runner.rb', line 5

def activity_type
  @activity_type
end

#chained_activitiesObject (readonly)

Returns the value of attribute chained_activities.



5
6
7
# File 'app/services/activity/chain_runner.rb', line 5

def chained_activities
  @chained_activities
end

#chains_for_resultObject (readonly)

Returns the value of attribute chains_for_result.



5
6
7
# File 'app/services/activity/chain_runner.rb', line 5

def chains_for_result
  @chains_for_result
end

#loggerObject (readonly)

Returns the value of attribute logger.



5
6
7
# File 'app/services/activity/chain_runner.rb', line 5

def logger
  @logger
end

Class Method Details

.initialize_and_execute_chains(activity, options = {}) ⇒ Object



7
8
9
10
11
12
13
14
# File 'app/services/activity/chain_runner.rb', line 7

def self.initialize_and_execute_chains(activity, options = {})
  chain_runner = new(activity, options)
  chain_runner.execute_chains
rescue NoActivityTypeError => e
  :no_activity_type
rescue NoActivityResultError => e
  :no_activity_result
end

Instance Method Details

#assign_resource_and_time(new_activity, offset_days = 0) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'app/services/activity/chain_runner.rb', line 115

def assign_resource_and_time(new_activity, offset_days = 0)
  new_activity.assigned_resource = new_activity.best_resource_employee

  if new_activity.assigned_resource.instance_of? Employee
    begin
      new_activity.target_datetime = new_activity.assigned_resource.next_working_day(Time.current, offset_days)
    rescue StandardError => e
      # Add validation error instead of using fallback date
      new_activity.errors.add(:assigned_resource, e.message)
      logger.error "Cannot assign activity to employee #{new_activity.assigned_resource.id}: #{e.message}"
      # Set a reasonable fallback for now, but the validation error will prevent saving
      new_activity.target_datetime = (Time.current + offset_days.days + 1.week).beginning_of_day
    end
  else
    new_activity.target_datetime = offset_days.days.from_now
  end
  new_activity
end

#chains_for_result_has_campaigns?Boolean

Returns:

  • (Boolean)


32
33
34
# File 'app/services/activity/chain_runner.rb', line 32

def chains_for_result_has_campaigns?
  chains_for_result.any?(&:campaign_id)
end

#chains_to_executeObject



36
37
38
39
40
41
42
43
44
# File 'app/services/activity/chain_runner.rb', line 36

def chains_to_execute
  # If our list of chains has campaigns specified, we focus results only on those with the same campaign specified
  # or nil campaign matching
  if chains_for_result_has_campaigns?
    @chains_for_result.select { |chain| chain.campaign_id == @activity.campaign_id }
  else # All results are valid which have no campaign
    @chains_for_result.select { |chain| chain.campaign_id.nil? }
  end
end

#execute_activity_chain(chain) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'app/services/activity/chain_runner.rb', line 59

def execute_activity_chain(chain)
  return unless chain.chain_activity_type

  if @activity.party.respond_to?(:assign_chained_activities?) && !@activity.party.assign_chained_activities?
    logger.warn "Could not run chained activity #{chain.chain_activity_type} triggered on activity id:#{@activity.id} because party assign_chained_activities returned false"
    return
  end
  # Chain activity
  new_activity = Activity.new activity_type: chain.chain_activity_type,
                              party: @activity.party,
                              resource: @activity.resource,
                              parent_activity_id: @activity.id,
                              campaign_id: @activity.campaign_id,
                              creator: @activity.closed_by || @activity.creator

  # If our activity chain is opportunity_promise we make some calculations
  if chain.opportunity_promise? && @activity.resource.respond_to?(:close_date)
    opp = @activity.resource
    # When is the opportunity promise date?
    target_date = opp.close_date || opp.planned_installation_date
    if target_date
      # What's the offset in days
      offset_days = (target_date.to_date - Date.current).to_i
      # Go 7 days earlier
      offset_days -= 7
      # Is it negative or zero, its probably garbage data or too close so lets' ignore it and let the
      # default offset take it over
      offset_days = nil if offset_days <= 0
    end
  end
  # The static offset is the default
  offset_days ||= chain.offset_days
  offset_days ||= 0

  assign_resource_and_time(new_activity, offset_days)

  if new_activity.save
    @chained_activities << new_activity
  else
    logger.error "Could not save chained activity #{new_activity.inspect} triggered on activity id:#{@activity.id}, errors: #{new_activity.errors_to_s}"
  end
end

#execute_chain(chain) ⇒ Object



54
55
56
57
# File 'app/services/activity/chain_runner.rb', line 54

def execute_chain(chain)
  execute_activity_chain chain
  execute_email_template chain
end

#execute_chainsObject



46
47
48
49
50
51
52
# File 'app/services/activity/chain_runner.rb', line 46

def execute_chains
  @chained_activities = []
  chains_to_execute.each do |chain|
    execute_chain(chain)
  end
  @activity.chained_activity_result = @chained_activities
end

#execute_email_template(chain) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
# File 'app/services/activity/chain_runner.rb', line 102

def execute_email_template(chain)
  return unless chain.email_template

  comm = CommunicationBuilder.new(sender_party: @activity.sender_party,
                                  resource: @activity.resource,
                                  recipient_party: @activity.party,
                                  template: chain.email_template,
                                  current_user: @activity.updater,
                                  transmit_at: chain.email_transmit_at_time,
                                  use_best_email: true).create
  Rails.logger.info "Chain Runner for chain #{chain.id} created communication #{comm.id}"
end