Files
dunlop-core/app/services/dunlop/overdue_handling.rb
T
2018-01-20 13:02:44 -03:00

125 lines
3.9 KiB
Ruby

module Dunlop::OverdueHandling
@registry = {}
@final_states = %w[overdue completed rejected]
def self.registry
@registry
end
def self.final_states
@final_states
end
def self.final_states=(states)
@final_states = states
end
def self.define(&block)
@registry = {} # empty the registry
definition_proxy = DefinitionProxy.new
definition_proxy.instance_eval(&block)
end
def self.handle_overdue!
registry.each do |workflow_step_name, config|
base_scope = WorkflowInstance.all #where.not(state: final_states)
base_scope = base_scope.where(sti_type: config.scenarios.map{|s| "WorkflowInstance::#{s.to_s.classify}"}) if config.scenarios.any?
base_scope = base_scope.joins(workflow_step_name).where.not("#{workflow_step_name.to_s.pluralize}.state" => final_states) #.includes(workflow_step_name)
if config.from.is_nested?
base_scope = base_scope.joins(config.from.key) if config.from.key != workflow_step_name
end
base_scope = base_scope.where("#{config.date_target_class.table_name}.#{config.date_target_column} <= ?", Date.current - config.time)
base_scope.find_each do |workflow_instance|
next unless workflow_step = workflow_instance.public_send(workflow_step_name)
workflow_step.is_overdue!
end
end
end
class DefinitionProxy
def when_workflow_step(workflow_step, options = {}, &block)
raise "Workflow step #{workflow_step} does not exist" unless WorkflowInstance.possible_workflow_step_names.include?(workflow_step)
workflow_step_proxy = WorkflowStepProxy.new(workflow_step, options)
workflow_step_proxy.instance_eval(&block) if block
workflow_step_proxy.register_callbacks!
Dunlop::OverdueHandling.registry[workflow_step] = workflow_step_proxy
end
def the_final_states_are(states)
Dunlop::OverdueHandling.final_states = states
end
end
class WorkflowStepProxy
attr_reader :workflow_step, :options, :overdue_target_class
def initialize(workflow_step, options)
@workflow_step, @options = workflow_step, options
@overdue_target_class = workflow_step.to_s.classify.constantize
end
def date_target_class
@date_target_class ||= from.is_nested? ? from.key.to_s.classify.constantize : WorkflowInstance
end
def date_target_column
@date_target_column ||= from.field
end
def scenarios
options[:scenarios] || []
end
def from
WorkflowStepBaseDate.new(workflow_step, options[:from])
end
def time
options[:is]
end
#TODO: find a simple way to do this!!!
def register_callbacks!
date_target_classes = [date_target_class] #TODO: only implement on specific scenarios if given as argument
date_column = date_target_column
workflow_step_name = workflow_step # make local scope for after_save definition
overdue_time = time
date_target_classes.each do |target_class|
target_class.after_save do |record|
if saved_changes[date_column]
target_record = record.workflow_instance.public_send(workflow_step_name)
if date = record.public_send(date_column)
if date <= Date.current - overdue_time
target_record.is_overdue! if target_record.pending? or target_record.processing?
else
target_record.process! if target_record.overdue?
end
else
target_record.process! if target_record.overdue?
end
end
end
end
end
end
class WorkflowStepBaseDate
attr_reader :workflow_step, :config
def initialize(workflow_step, config)
@workflow_step, @config = workflow_step, config
end
def is_nested?
config.is_a?(Hash)
end
def key
is_nested? ? config.keys.first : config
end
def field
is_nested? ? config.values.first : config
end
end
end