125 lines
3.9 KiB
Ruby
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
|