296 lines
18 KiB
CoffeeScript
296 lines
18 KiB
CoffeeScript
#projectGetWorkflowActionDefinitionOffsets = () ->
|
|
# true
|
|
#export default projectGetWorkflowActionDefinitionOffsets
|
|
import Ember from 'ember'
|
|
|
|
RecordNode = Ember.Object.extend
|
|
resolved: false
|
|
title: Ember.computed 'record.title', 'value_shift', ->
|
|
title = @get('record.title')
|
|
title = " #{title} (#{value_shift}d)" if value_shift = @get('value_shift')
|
|
title
|
|
|
|
OffsetNode = Ember.Object.extend
|
|
record: null
|
|
total_offset: 0
|
|
value_shift: 0
|
|
resulting_absolute_value: 0
|
|
|
|
WorkflowActionDefinitionOffsetNodes = Ember.Object.extend
|
|
iteration_context_counter: 0
|
|
workflow_action_definitions: []
|
|
reference_date: null
|
|
batch_size: 0
|
|
active_project_scenario: null
|
|
|
|
forEach: ->
|
|
@get('processed_workflow_action_definitions').forEach(arguments...)
|
|
|
|
filterBy: ->
|
|
@get('processed_workflow_action_definitions').filterBy(arguments...)
|
|
|
|
get_resolved: ->
|
|
@get('processed_workflow_action_definitions').filterBy('resolved')
|
|
|
|
init: ->
|
|
@set 'scope_workflow_action_definition_ids', @get('workflow_action_definitions').mapBy('id').toArray()
|
|
@set 'processed_workflow_action_definitions', []
|
|
@set 'working_workflow_action_definitions', []
|
|
@get_workflow_action_definition_offsets()
|
|
|
|
get_workflow_action_definition_offsets: ->
|
|
base = @
|
|
active_scenario_identifier = @get('active_project_scenario.identifier')
|
|
scope_workflow_action_definition_ids = @get('scope_workflow_action_definition_ids')
|
|
first_loop_actions = []
|
|
working_workflow_action_definitions = []
|
|
@get('workflow_action_definitions').forEach (workflow_action_definition) ->
|
|
action_added = false
|
|
if workflow_action_definition.get('offset_type') is 'configured'
|
|
workflow_action_definition.get('workflow_action_offsets').forEach (workflow_action_offset) ->
|
|
return if action_added
|
|
return if active_scenario_identifier and workflow_action_offset.get('project_scenario.identifier') and workflow_action_offset.get('project_scenario.identifier') isnt active_scenario_identifier
|
|
if not workflow_action_offset.get('base_workflow_action_definition.content') # x_based
|
|
[offset_date, offset_value] = base.get_offset_for_target(workflow_action_offset, 0)
|
|
[date, value_shift] = base.get_dynamic_offset_for_target(workflow_action_offset, offset_value)
|
|
absolute_value = offset_value + value_shift
|
|
record_wrapper = RecordNode.create
|
|
record: workflow_action_definition
|
|
record_id: workflow_action_definition.get('id')
|
|
offset_wrappers: [
|
|
OffsetNode.create(total_offset: absolute_value, value_shift: value_shift)
|
|
]
|
|
absolute_value: absolute_value
|
|
value_shift: value_shift
|
|
date: date
|
|
resolve_type: 'x'
|
|
resolved: true
|
|
resolve_level: 0
|
|
first_loop_actions.push record_wrapper
|
|
action_added = true
|
|
working_workflow_action_definitions.push workflow_action_definition unless action_added
|
|
|
|
@set 'processed_workflow_action_definitions', first_loop_actions
|
|
@set 'working_workflow_action_definitions', working_workflow_action_definitions
|
|
|
|
@incrementProperty 'iteration_context_counter'
|
|
#@set 'working_workflow_action_definitions', @get('workflow_action_definitions').filterBy('offset_type', 'configured')
|
|
@run_critical_path_resolve_loop()
|
|
resolve_level = @get('iteration_context_counter')
|
|
@get('working_workflow_action_definitions').forEach (unresolved_workflow_action_definition) => # add unresolved records
|
|
offset_wrappers = []
|
|
unresolved_workflow_action_definition.get('workflow_action_offsets').forEach (action_offset) ->
|
|
return unless action_offset.get('base_workflow_action_definition.id') in scope_workflow_action_definition_ids # do not add offsets from other scenarios
|
|
offset_wrappers.push OffsetNode.create
|
|
total_offset: action_offset.get('offset_value')
|
|
record: action_offset
|
|
@get('processed_workflow_action_definitions').push RecordNode.create
|
|
record: unresolved_workflow_action_definition
|
|
record_id: unresolved_workflow_action_definition.get('id')
|
|
offset_wrappers: offset_wrappers
|
|
resolved: false
|
|
resolve_level: resolve_level
|
|
resolve_type: 'unresolved'
|
|
|
|
get_dynamic_offset_for_target: (target, absolute_value) ->
|
|
base_date = @get('reference_date').clone().add(absolute_value, 'day')
|
|
empty = [base_date, 0]
|
|
return empty unless batch_size = @get('batch_size')
|
|
return empty unless threshold = target.get('batch_element_threshold_value')
|
|
return empty unless threshold_exceedance = Math.floor(batch_size / (0.1 + parseInt(threshold))) # + 0.1 (delta) to exclude exact match of batch_size and threshold. First day is action day
|
|
|
|
period_unit = target.get('batch_element_threshold_unit')
|
|
offset_value = target.get('offset_value')
|
|
operation = if offset_value < 0 then 'subtract' else 'add'
|
|
if period_unit is 'businessday'
|
|
operation = "business#{operation.capitalize()}"
|
|
shifted_date = base_date.clone()[operation](threshold_exceedance, business_days: target.get('batch_element_threshold_business_days'))
|
|
else
|
|
shifted_date = base_date.clone()[operation](threshold_exceedance, period_unit)
|
|
value_shift = shifted_date.diff(base_date, 'day')
|
|
[shifted_date, value_shift]
|
|
|
|
get_offset_for_target: (target, absolute_value) ->
|
|
base_date = @get('reference_date').clone().add(absolute_value, 'day')
|
|
empty = [base_date, 0]
|
|
return empty unless offset_value = target.get('offset_value')
|
|
period_unit = target.get('offset_unit')
|
|
operation = if offset_value < 0 then 'subtract' else 'add'
|
|
if period_unit is 'businessday'
|
|
operation = "business#{operation.capitalize()}"
|
|
shifted_date = base_date.clone()[operation](Math.abs(offset_value), business_days: target.get('offset_business_days'))
|
|
else
|
|
shifted_date = base_date.clone()[operation](Math.abs(offset_value), period_unit)
|
|
value_shift = shifted_date.diff(base_date, 'day')
|
|
#debugger if target.get('workflow_action_definition.title') is 'Initial check done'
|
|
[shifted_date, value_shift]
|
|
|
|
run_critical_path_resolve_loop: ->
|
|
working_indices_to_be_removed = []
|
|
active_scenario_identifier = @get('active_project_scenario.identifier')
|
|
processed_workflow_action_definitions = @get('processed_workflow_action_definitions')
|
|
scope_workflow_action_definition_ids = @get('scope_workflow_action_definition_ids')
|
|
get_dynamic_offset_for_target = @get('get_dynamic_offset_for_target').bind(@)
|
|
get_offset_for_target = @get('get_offset_for_target').bind(@)
|
|
resolve_level = @get('iteration_context_counter')
|
|
@get('working_workflow_action_definitions').forEach (working_workflow_action_definition, working_index) ->
|
|
return unless working_workflow_action_definition.get('offset_type') is 'configured'
|
|
farthest_absolute_value = 0
|
|
farthest_absolute_value_value_shift = 0
|
|
farthest_result_total_offset = 0
|
|
date = null # scoping
|
|
resolved_offset_wrappers = []
|
|
all_offsets_resolved = working_workflow_action_definition.get('workflow_action_offsets').every (workflow_action_offset) ->
|
|
return true if active_scenario_identifier and workflow_action_offset.get('project_scenario.identifier') and workflow_action_offset.get('project_scenario.identifier') isnt active_scenario_identifier
|
|
unless processed_base_workflow_action_definition_wrapper = processed_workflow_action_definitions.findBy 'record_id', workflow_action_offset.get('base_workflow_action_definition.id')
|
|
if workflow_action_offset.get('base_workflow_action_definition.id') not in scope_workflow_action_definition_ids # base is not present in this scenario, do not pursue this connection
|
|
return true
|
|
return false
|
|
processed_absolute_value = processed_base_workflow_action_definition_wrapper.get('absolute_value')
|
|
[offset_date, working_offset_value] = get_offset_for_target(workflow_action_offset, processed_absolute_value)
|
|
[date, current_connection_value_shift] = get_dynamic_offset_for_target(workflow_action_offset, processed_absolute_value + working_offset_value)
|
|
current_connection_total_offset_value = current_connection_value_shift + working_offset_value
|
|
current_connection_absolute_value = processed_absolute_value + current_connection_total_offset_value
|
|
#debugger if processed_base_workflow_action_definition_wrapper.get('record.title') is 'Initial check done'
|
|
#debugger if working_workflow_action_definition.get('title') is 'Initial check done'
|
|
if Math.abs(current_connection_absolute_value) > Math.abs(farthest_absolute_value)
|
|
farthest_absolute_value = current_connection_absolute_value
|
|
farthest_absolute_value_value_shift = current_connection_value_shift
|
|
farthest_result_total_offset = current_connection_total_offset_value
|
|
resolved_offset_wrappers.push OffsetNode.create
|
|
record: workflow_action_offset
|
|
value_shift: current_connection_value_shift
|
|
total_offset: current_connection_total_offset_value
|
|
resulting_absolute_value: current_connection_absolute_value
|
|
true # indicate processed_base_workflow_action_definition_wrapper found for all_offsets_resolved value
|
|
|
|
if all_offsets_resolved and resolved_offset_wrappers.length
|
|
record_wrapper = RecordNode.create
|
|
record: working_workflow_action_definition
|
|
record_id: working_workflow_action_definition.get('id')
|
|
offset_wrappers: resolved_offset_wrappers
|
|
value_shift: farthest_absolute_value_value_shift
|
|
absolute_value: farthest_absolute_value
|
|
date: date
|
|
resolved: true
|
|
resolve_level: resolve_level
|
|
resolve_type: 'critical-path'
|
|
processed_workflow_action_definitions.push record_wrapper
|
|
working_indices_to_be_removed.push working_index
|
|
if working_indices_to_be_removed.length
|
|
@get('working_workflow_action_definitions').splice(working_indices_to_be_removed.pop(), 1) while working_indices_to_be_removed.length
|
|
@run_critical_path_resolve_loop()
|
|
else
|
|
@incrementProperty 'iteration_context_counter'
|
|
@run_unresolved_tree_resolve_loop()
|
|
|
|
run_unresolved_tree_resolve_loop: ->
|
|
working_indices_to_be_removed = []
|
|
active_scenario_identifier = @get('active_project_scenario.identifier')
|
|
processed_workflow_action_definitions = @get('processed_workflow_action_definitions')
|
|
scope_workflow_action_definition_ids = @get('scope_workflow_action_definition_ids')
|
|
get_offset_for_target = @get('get_offset_for_target').bind(@)
|
|
get_dynamic_offset_for_target = @get('get_dynamic_offset_for_target').bind(@)
|
|
resolve_level = @get('iteration_context_counter')
|
|
@get('working_workflow_action_definitions').forEach (working_workflow_action_definition, working_index) ->
|
|
return unless working_workflow_action_definition.get('offset_type') is 'configured'
|
|
farthest_absolute_value = 0
|
|
farthest_absolute_value_value_shift = 0
|
|
farthest_result_total_offset = 0
|
|
date = null # scoping
|
|
resolved_offset_wrappers = []
|
|
working_workflow_action_definition.get('workflow_action_offsets').forEach (workflow_action_offset) ->
|
|
return if active_scenario_identifier and workflow_action_offset.get('project_scenario.identifier') and workflow_action_offset.get('project_scenario.identifier') isnt active_scenario_identifier
|
|
return unless workflow_action_offset.get('base_workflow_action_definition.id') in scope_workflow_action_definition_ids
|
|
return unless processed_base_workflow_action_definition_wrapper = processed_workflow_action_definitions.findBy 'record_id', workflow_action_offset.get('base_workflow_action_definition.id')
|
|
processed_absolute_value = processed_base_workflow_action_definition_wrapper.get('absolute_value')
|
|
[offset_date, working_offset_value] = get_offset_for_target(workflow_action_offset, processed_absolute_value)
|
|
[date, current_connection_value_shift] = get_dynamic_offset_for_target(workflow_action_offset, processed_absolute_value + working_offset_value)
|
|
current_connection_total_offset_value = current_connection_value_shift + working_offset_value
|
|
current_connection_absolute_value = processed_absolute_value + current_connection_total_offset_value
|
|
#debugger if processed_base_workflow_action_definition_wrapper.get('record.title') is 'Initial check done'
|
|
#debugger if working_workflow_action_definition.get('title') is 'Initial check done'
|
|
if Math.abs(current_connection_absolute_value) > Math.abs(farthest_absolute_value)
|
|
farthest_absolute_value = current_connection_absolute_value
|
|
farthest_absolute_value_value_shift = current_connection_value_shift
|
|
farthest_result_total_offset = current_connection_total_offset_value
|
|
resolved_offset_wrappers.push OffsetNode.create
|
|
record: workflow_action_offset
|
|
value_shift: current_connection_value_shift
|
|
total_offset: current_connection_total_offset_value
|
|
resulting_absolute_value: current_connection_absolute_value
|
|
if resolved_offset_wrappers.length
|
|
record_wrapper = RecordNode.create
|
|
record: working_workflow_action_definition
|
|
record_id: working_workflow_action_definition.get('id')
|
|
offset_wrappers: resolved_offset_wrappers # .clone()?
|
|
value_shift: farthest_absolute_value_value_shift
|
|
absolute_value: farthest_absolute_value
|
|
date: date
|
|
resolved: true
|
|
resolve_level: resolve_level
|
|
resolve_type: 'with-non-rooted-offsets'
|
|
processed_workflow_action_definitions.push record_wrapper
|
|
working_indices_to_be_removed.push working_index
|
|
|
|
if working_indices_to_be_removed.length
|
|
@get('working_workflow_action_definitions').splice(working_indices_to_be_removed.pop(), 1) while working_indices_to_be_removed.length
|
|
@run_critical_path_resolve_loop()
|
|
else
|
|
@run_offset_forwarding_loop()
|
|
|
|
run_offset_forwarding_loop: ->
|
|
working_indices_to_be_removed = []
|
|
active_scenario_identifier = @get('active_project_scenario.identifier')
|
|
processed_workflow_action_definitions = @get('processed_workflow_action_definitions')
|
|
scope_workflow_action_definition_ids = @get('scope_workflow_action_definition_ids')
|
|
get_offset_for_target = @get('get_offset_for_target').bind(@)
|
|
get_dynamic_offset_for_target = @get('get_dynamic_offset_for_target').bind(@)
|
|
resolve_level = @get('iteration_context_counter')
|
|
@get('working_workflow_action_definitions').forEach (working_workflow_action_definition, working_index) ->
|
|
farthest_absolute_value = 0
|
|
farthest_absolute_value_value_shift = 0
|
|
farthest_result_total_offset = 0
|
|
date = null # scoping
|
|
resolved_offset_wrappers = []
|
|
working_workflow_action_definition.get('dependent_workflow_action_offsets').forEach (workflow_action_offset) ->
|
|
return if active_scenario_identifier and workflow_action_offset.get('project_scenario.identifier') and workflow_action_offset.get('project_scenario.identifier') isnt active_scenario_identifier
|
|
return unless workflow_action_offset.get('workflow_action_definition.id') in scope_workflow_action_definition_ids
|
|
return unless processed_base_workflow_action_definition_wrapper = processed_workflow_action_definitions.findBy 'record_id', workflow_action_offset.get('workflow_action_definition.id')
|
|
#return if workflow_action_offset.get('workflow_action_definition.offset_type') is 'none' # do not resolve on none offset typed nodes
|
|
processed_absolute_value = processed_base_workflow_action_definition_wrapper.get('absolute_value')
|
|
[offset_date, working_offset_value] = get_offset_for_target(workflow_action_offset, processed_absolute_value)
|
|
[date, current_connection_value_shift] = get_dynamic_offset_for_target(workflow_action_offset, processed_absolute_value + working_offset_value)
|
|
current_connection_total_offset_value = current_connection_value_shift + working_offset_value
|
|
#NOTE MINUS!!!!!!!!!!!!!!!!!!!!!
|
|
current_connection_absolute_value = processed_absolute_value - current_connection_total_offset_value
|
|
#debugger if processed_base_workflow_action_definition_wrapper.get('record.title') is 'Initial check done'
|
|
#debugger if working_workflow_action_definition.get('title') is 'Initial check done'
|
|
if Math.abs(current_connection_absolute_value) > Math.abs(farthest_absolute_value)
|
|
farthest_absolute_value = current_connection_absolute_value
|
|
farthest_absolute_value_value_shift = current_connection_value_shift
|
|
farthest_result_total_offset = current_connection_total_offset_value
|
|
resolved_offset_wrappers.push OffsetNode.create
|
|
record: workflow_action_offset
|
|
value_shift: current_connection_value_shift
|
|
total_offset: current_connection_total_offset_value
|
|
resulting_absolute_value: current_connection_absolute_value
|
|
if resolved_offset_wrappers.length
|
|
record_wrapper = RecordNode.create
|
|
record: working_workflow_action_definition
|
|
record_id: working_workflow_action_definition.get('id')
|
|
offset_wrappers: resolved_offset_wrappers # .clone()?
|
|
value_shift: farthest_absolute_value_value_shift
|
|
absolute_value: farthest_absolute_value
|
|
date: date
|
|
resolved: true
|
|
resolve_level: resolve_level
|
|
resolve_type: 'offset-lookup-inversion'
|
|
processed_workflow_action_definitions.push record_wrapper
|
|
working_indices_to_be_removed.push working_index
|
|
|
|
if working_indices_to_be_removed.length
|
|
@get('working_workflow_action_definitions').splice(working_indices_to_be_removed.pop(), 1) while working_indices_to_be_removed.length
|
|
@run_critical_path_resolve_loop()
|
|
export default WorkflowActionDefinitionOffsetNodes
|