app/helpers/projects_helper.rb
#encoding: utf-8
#############################################################################
#
# Estimancy, Open Source project estimation web application
# Copyright (c) 2014 Estimancy (http://www.estimancy.com)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# ======================================================================
#
# ProjEstimate, Open Source project estimation web application
# Copyright (c) 2013 Spirula (http://www.spirula.fr)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#############################################################################
module ProjectsHelper
# This helper method will display Estimation Result according the estimation purpose (PBS and/or Activities)
def display_results
res = String.new
unless @project.nil?
#pbs_project_element = @pbs_project_element || @project.root_component
pbs_project_element = @pbs_project_element || current_component
#get the current module_project
module_project_to_display = current_module_project
if module_project_to_display.pemodule.yes_for_output_with_ratio? || module_project_to_display.pemodule.yes_for_output_without_ratio? || module_project_to_display.pemodule.yes_for_input_output_with_ratio? || module_project_to_display.pemodule.yes_for_input_output_without_ratio?
if module_project_to_display.pemodule.alias == 'effort_balancing'
res << display_effort_balancing_output(module_project_to_display)
else
res << display_results_with_activities(module_project_to_display)
end
else
if module_project_to_display.pemodule.alias == Projestimate::Application::BALANCING_MODULE
res << display_balancing_output(module_project_to_display)
else
res << display_results_without_activities(module_project_to_display)
end
end
res
end
res
end
# Display the units of attributes
def get_attribute_unit(pe_attribute)
case pe_attribute.alias
when "effort"
I18n.t(:unit_effort_person_hour)
when "staffing"
I18n.t(:unit_staffing)
when "end_date"
"jj/mm/aaaa"
when "delay"
I18n.t(:delay)
when "cost"
#@project.organization.currency.nil? ? nil.to_s : "#{@project.organization.currency.name.underscore.pluralize}"
@project.organization.currency.nil? ? nil.to_s : "#{@project.organization.currency.sign}"
else
""
end
end
#Conversion en fonction des seuils et de la précision de l'utilisateur #> 12.12300 (si precision = 5)
def convert(v, organization)
unless v.class == Hash
value = v.to_f
if value < organization.limit1.to_i
convert_with_precision(value / organization.limit1_coef.to_f, user_number_precision)
elsif value < organization.limit2.to_i
convert_with_precision(value / organization.limit2_coef.to_f, user_number_precision)
elsif value < organization.limit3.to_i
convert_with_precision(value / organization.limit3_coef.to_f, user_number_precision)
elsif value < organization.limit4.to_i
convert_with_precision(value / organization.limit4_coef.to_f, user_number_precision)
else
convert_with_precision(value / organization.limit4_coef.to_f, user_number_precision)
end
else
0
end
end
#Conversion en fonction des seuils et de la précision en params #> 12.123 (si precision = 5) ou 12.12 si (si precision = 2)
def convert_with_specific_precision(v, organization, precision)
unless v.class == Hash
value = v.to_f
if value < organization.limit1.to_i
(value / organization.limit1_coef.to_f).round(precision)
elsif value < organization.limit2.to_i
(value / organization.limit2_coef.to_f).round(precision)
elsif value < organization.limit3.to_i
(value / organization.limit3_coef.to_f).round(precision)
elsif value < organization.limit4.to_i
(value / organization.limit4_coef.to_f).round(precision)
else
(value / organization.limit4_coef.to_f).round(precision)
end
else
0
end
end
#Conversion en fonction des seuils uniquement #> 12.123 (si precision = 5) ou 12.12 si (si precision = 2)
def convert_without_precision(v, organization)
unless v.class == Hash
value = v.to_f
if value < organization.limit1.to_i
value / organization.limit1_coef.to_f
elsif value < organization.limit2.to_i
value / organization.limit2_coef.to_f
elsif value < organization.limit3.to_i
value / organization.limit3_coef.to_f
elsif value < organization.limit4.to_i
value / organization.limit4_coef.to_f
else
value / organization.limit4_coef.to_f
end
else
0
end
end
#Conversion en fonction de la précision en params uniquement #> 12.12300 (si precision = 5) ou 12.12 si (si precision = 2)
def convert_with_precision(value, precision)
"%.#{precision}f" % value
end
def convert_label(v, organization)
unless v.class == Hash
value = v.to_f
if value < organization.limit1.to_i
organization.limit1_unit
elsif value < organization.limit2.to_i
organization.limit2_unit
elsif value < organization.limit3.to_i
organization.limit3_unit
elsif value < organization.limit4.to_i
organization.limit4_unit
else
organization.limit4_unit
end
else
0
end
end
# Methdods that display estimation results
def display_results_without_activities(module_project)
res = String.new
pbs_project_element = @pbs_project_element || current_component
pemodule = Pemodule.find(module_project.pemodule.id)
res << "<table class='table table-condensed table-bordered'>
<tr>
<th></th>"
['low', 'most_likely', 'high', 'probable'].each do |level|
res << "<th>#{level.humanize}</th>"
end
res << '</tr>'
module_project.estimation_values.where('in_out = ?', 'output').order('display_order ASC').each do |est_val|
est_val_pe_attribute = est_val.pe_attribute
res << "<tr><td><span class='attribute_tooltip tree_element_in_out' title='#{est_val_pe_attribute.description} #{display_rule(est_val)}'>#{est_val_pe_attribute.name} (#{get_attribute_unit(est_val_pe_attribute)})</span></td>"
['low', 'most_likely', 'high', 'probable'].each do |level|
res << '<td>'
level_estimation_values = Hash.new
level_estimation_values = est_val.send("string_data_#{level}")
total = []
if level_estimation_values.nil? || level_estimation_values[pbs_project_element.id].nil? || level_estimation_values[pbs_project_element.id].blank?
res << '-'
else
res << "#{display_value(level_estimation_values[pbs_project_element.id], est_val)}"
end
res << '</td>'
end
res << '</tr>'
end
res << '</table>'
res
end
#The view to display result with ACTIVITIES
def display_results_with_activities(module_project)
res = String.new
pbs_project_element = @pbs_project_element || current_component
pe_wbs_activity = module_project.project.pe_wbs_projects.activities_wbs.first
project_wbs_project_elt_root = pe_wbs_activity.wbs_project_elements.elements_root.first
pemodule = Pemodule.find(module_project.pemodule.id)
res << " <table class='table table-condensed table-bordered'>
<tr>
<th></th>"
# Get the module_project probable estimation values for showing element consistency
probable_est_value_for_consistency = nil
pbs_level_data_for_consistency = Hash.new
module_project.estimation_values.order('display_order ASC').each do |est_val|
if (est_val.in_out == 'output' or est_val.in_out=='both') and est_val.module_project.id == module_project.id
probable_est_value_for_consistency = est_val.send("string_data_probable")
res << "<th colspan='4'><span class='attribute_tooltip' title='#{est_val.pe_attribute.description} #{display_rule(est_val)}'> #{est_val.pe_attribute.name} (#{get_attribute_unit(est_val.pe_attribute)})</span></th>"
# For is_consistent purpose
['low', 'most_likely', 'high', 'probable'].each do |level|
unless level.eql?("probable")
pbs_data_level = est_val.send("string_data_#{level}")
pbs_data_level.nil? ? pbs_level_data_for_consistency[level] = nil : pbs_level_data_for_consistency[level] = pbs_data_level[pbs_project_element.id]
end
end
end
end
res << '</tr>'
# We are showing for each PBS and/or ACTIVITY the (low, most_likely, high) values
res << '<tr>
<th></th>'
['low', 'most_likely', 'high', 'probable'].each do |level|
res << "<th>#{level.humanize}</th>"
end
res << '</tr>'
module_project.project.pe_wbs_projects.activities_wbs.first.wbs_project_elements.each do |wbs_project_elt|
pbs_probable_for_consistency = probable_est_value_for_consistency.nil? ? nil : probable_est_value_for_consistency[pbs_project_element.id]
wbs_project_elt_consistency = (pbs_probable_for_consistency.nil? || pbs_probable_for_consistency[wbs_project_elt.id].nil?) ? false : pbs_probable_for_consistency[wbs_project_elt.id][:is_consistent]
show_consistency_class = nil
unless wbs_project_elt_consistency || module_project.pemodule.alias == "effort_breakdown"
show_consistency_class = "<span class='icon-warning-sign not_consistent attribute_tooltip' title='<strong>#{I18n.t(:warning_caution)}</strong> </br> #{I18n.t(:warning_wbs_not_complete, :value => wbs_project_elt.name)}'></span>"
end
#For wbs-activity-completion node consistency
completion_consistency = ""
title = ""
if module_project.pemodule.alias == "wbs_activity_completion"
current_wbs_consistency = true
pbs_level_data_for_consistency.each do |level, level_value|
#if !pbs_level_data_for_consistency.nil?
if !level_value.nil? && !level_value.empty?
wbs_level_data = level_value[wbs_project_elt.id]
wbs_level_data.nil? ? current_wbs_consistency_level = nil : current_wbs_consistency_level = wbs_level_data[:is_consistent]
current_wbs_consistency = current_wbs_consistency && current_wbs_consistency_level
if !!current_wbs_consistency == false
if show_consistency_class.nil?
completion_consistency = "icon-warning-sign not_consistent attribute_tooltip"
title = I18n.t(:warning_caution) + " : " + I18n.t(:warning_wbs_not_consistent)
else
show_consistency_class = "<span class='icon-warning-sign not_consistent attribute_tooltip' title=' <strong>#{I18n.t(:warning_caution)}</strong> </br> * #{I18n.t(:warning_wbs_not_complete, :value => wbs_project_elt.name)} </br> * #{I18n.t(:warning_wbs_not_consistent)}'></span>"
end
break
end
end
end
end
res << "<tr> <td> <span class='tree_element_in_out #{completion_consistency}' title='#{title}' style='margin-left:#{wbs_project_elt.depth}em;'> #{show_consistency_class} #{wbs_project_elt.name} </span> </td>"
['low', 'most_likely', 'high', 'probable'].each do |level|
res << '<td>'
module_project.estimation_values.where('in_out = ?', 'output').each do |est_val|
if (est_val.in_out == 'output' or est_val.in_out=='both') and est_val.module_project.id == module_project.id
level_estimation_values = Hash.new
level_estimation_values = est_val.send("string_data_#{level}")
if level_estimation_values.nil? || level_estimation_values[pbs_project_element.id].nil? || level_estimation_values[pbs_project_element.id][wbs_project_elt.id].nil? || level_estimation_values[pbs_project_element.id][wbs_project_elt.id][:value].nil?
res << ' - '
else
res << "#{display_value(level_estimation_values[pbs_project_element.id][wbs_project_elt.id][:value], est_val)}"
end
end
end
res << '</td>'
end
res << '</tr>'
end
#Show the global result of the PBS
res << '<tr>
<td><strong> </strong></td>'
['low', 'most_likely', 'high', 'probable'].each do |level|
res << '<td></td>'
end
res << '</tr>'
# Show the probable values
res << "<tr><td colspan='4'><strong> #{current_component.name} (Probable Value) </strong> </td>"
module_project.estimation_values.each do |est_val|
if (est_val.in_out == 'output' or est_val.in_out=='both') and est_val.module_project_id == module_project.id
res << "<td>"
level_probable_value = est_val.send('string_data_probable')
if level_probable_value.nil? || level_probable_value[pbs_project_element.id].nil? || level_probable_value[pbs_project_element.id][project_wbs_project_elt_root.id].nil? || level_probable_value[pbs_project_element.id][project_wbs_project_elt_root.id][:value].nil?
res << '-'
else
res << "<div align='center'><strong>#{display_value(level_probable_value[pbs_project_element.id][project_wbs_project_elt_root.id][:value], est_val)}</strong></div>"
end
res << '</td>'
end
end
res << '</tr>'
res << '</table>'
res
end
# The Balancing module output
def display_balancing_output(module_project)
#pbs_project_element = @pbs_project_element || @project.root_component
pbs_project_element = current_component
res = String.new
if module_project.compatible_with(current_component.work_element_type.alias) || current_component
pemodule = Pemodule.find(module_project.pemodule.id)
res << "<table class='table table-condensed table-bordered'>"
# Get the current balancing attribute
@current_balancing_attribute = current_balancing_attribute
mp_attr_est_values = module_project.estimation_values.where('in_out = ? AND pe_attribute_id = ?', "output", @current_balancing_attribute)
est_val = nil
res << '<tr>
<th></th>'
if !mp_attr_est_values.nil? && !mp_attr_est_values.empty?
est_val = mp_attr_est_values.last
res << "<th><span class='attribute_tooltip' title='#{est_val.pe_attribute.description} #{display_rule(est_val)}' rel='tooltip'>#{est_val.pe_attribute.name} (#{get_attribute_unit(est_val.pe_attribute)})</span></th>"
else
res << "<th><span class='red_color'> #{I18n.t(:text_please_select_balancing_attribute)} </span></td>"
end
res << '</tr>'
# Attribute Balancing résult
res << "<tr>"
res << "<td> #{current_component.name} </td>"
res << "<td>"
if est_val.nil?
res << "-"
else
level_estimation_values = Hash.new
level_estimation_values = est_val.send("string_data_probable")
if !level_estimation_values[pbs_project_element.id].nil? && !level_estimation_values[pbs_project_element.id].blank?
res << "#{ display_value(level_estimation_values[pbs_project_element.id], est_val) }"
else
res << "-"
end
end
res << "</td>"
res << "</tr>"
res << '</table>'
end
end
def display_effort_balancing_output(module_project)
pbs_project_element = @pbs_project_element || current_component
res = String.new
if module_project.compatible_with(current_component.work_element_type.alias) || current_component
pemodule = Pemodule.find(module_project.pemodule.id)
res << "<table class='table table-condensed table-bordered'>"
res << '<tr>
<th></th>'
module_project.estimation_values.each do |est_val|
if (est_val.in_out == 'output' or est_val.in_out=='both') and est_val.module_project.id == module_project.id
res << "<th><span class='attribute_tooltip' title='#{est_val.pe_attribute.description} #{display_rule(est_val)}' rel='tooltip'>#{est_val.pe_attribute.name} (#{get_attribute_unit(est_val.pe_attribute)})</span></th>"
end
end
res << '</tr>'
module_project.project.pe_wbs_projects.activities_wbs.first.wbs_project_elements.each do |wbs_project_elt|
res << "<tr>
<td>
<span class='tree_element_in_out' style='margin-left:#{wbs_project_elt.depth}em;'>#{wbs_project_elt.name}</span></td>"
res << '</td>'
module_project.estimation_values.select { |i| i.in_out == 'output' or i.in_out=='both' }.each do |est_val|
level_estimation_values = Hash.new
level_estimation_values = est_val.send("string_data_probable")
res << '<td>'
if level_estimation_values and level_estimation_values[pbs_project_element.id]
if level_estimation_values[pbs_project_element.id] and level_estimation_values[pbs_project_element.id][wbs_project_elt.id].blank?
res << "#{level_estimation_values[pbs_project_element.id][wbs_project_elt.id]}"
else
if est_val.pe_attribute.attribute_type == "numeric"
res << "#{level_estimation_values[pbs_project_element.id][wbs_project_elt.id][:value]}"
else
res << "#{level_estimation_values[pbs_project_element.id][wbs_project_elt.id]}"
end
end
else
res << "-"
end
res << '</td>'
end
res << '</tr>'
end
res << '</table>'
end
end
# Display link to add notes to attribute
def add_attribute_notes_link(estimation_value, pbs_id)
res = ""
add_notes_title = I18n.t(:label_add_notes)
icon_class = ""
unless estimation_value.notes.nil?
add_notes_title_est_val = estimation_value.notes
if !estimation_value.notes["#{pbs_id}"].nil? && !estimation_value.notes["#{pbs_id}"].empty?
add_notes_title = estimation_value.notes["#{pbs_id}"]
icon_class = "icon-green"
end
end
res << link_to('', main_app.add_note_to_attribute_path(:estimation_value_id => estimation_value.id, :pbs_project_elt_id => pbs_id), :class => "icon-edit #{icon_class}", :title => "#{add_notes_title}" , :remote => true)
end
# Display Estimations output results according to the module behavior
def display_input
res = String.new
unless @project.nil?
pbs_project_element = current_component
@project = current_module_project.project
current_module_project_pemodule = current_module_project.pemodule
##if module_project.pemodule.with_activities
if current_module_project_pemodule.yes_for_input? || current_module_project_pemodule.yes_for_input_output_without_ratio? || current_module_project_pemodule.yes_for_input_output_with_ratio?
# For WBS-ACTIVITY-COMPLETION MODULE
if current_module_project_pemodule.alias == "wbs_activity_completion"
@defined_status = RecordStatus.find_by_name("Defined")
last_estimation_result = nil
effort_breakdown_module = Pemodule.where("alias = ? AND record_status_id = ?", "effort_breakdown", @defined_status.id).first
unless effort_breakdown_module.nil?
#refer_module_potential_ids = module_project.associated_module_projects ###+ module_project.inverse_associated_module_projects
#unless refer_module.empty?
refer_module_potential_ids = current_module_project.associated_module_projects
refer_attribute = PeAttribute.where("alias = ? AND record_status_id = ?", "effort", @defined_status.id).first
refer_modules_project = ModuleProject.joins(:project, :pbs_project_elements).where("pemodule_id = ? AND project_id =? AND pbs_project_elements.id = ?", effort_breakdown_module.id, @project.id, pbs_project_element.id)
refer_module_project = refer_modules_project.where(["module_project_id IN (?)", refer_module_potential_ids]).last
unless refer_module_project.nil?
# Get the estimation_value corresponding to the linked Effort_breakdown module (if there is one)
last_estimation_results = EstimationValue.where('in_out = ? AND pe_attribute_id = ? AND module_project_id = ?', 'output', refer_attribute.id, refer_module_project.id).first
if last_estimation_results.nil?
last_estimation_result = Hash.new
else
last_estimation_result = last_estimation_results
pe_wbs_project_activity = @project.pe_wbs_projects.activities_wbs.first
project_wbs_root = pe_wbs_project_activity.wbs_project_elements.where("is_added_wbs_root = ?", true).first
# Get all complement children
complement_children_ids = project_wbs_root.get_all_complement_children
# This will be completed only if WBS has one or more not coming from library
unless complement_children_ids.empty?
current_mp_est_value = current_module_project.estimation_values.where("pe_attribute_id = ? AND in_out = ?", refer_attribute.id, "output").last
##new_created_estimation_value = EstimationValue.new
new_created_estimation_value = last_estimation_results
['low', 'most_likely', 'high'].each do |level|
new_created_estimation_value_level = new_created_estimation_value.send("string_data_#{level}")
level_current_mp_est_val = current_mp_est_value.send("string_data_#{level}")
if !level_current_mp_est_val.nil? || !level_current_mp_est_val.empty?
pbs_level_value = level_current_mp_est_val[pbs_project_element.id]
unless pbs_level_value.nil?
complement_children_ids.each do |complement_child_id|
#new_created_estimation_value_level[pbs_project_element.id] << complement_child_id
if !pbs_level_value[complement_child_id].nil? && !level_current_mp_est_val[pbs_project_element.id][complement_child_id].nil?
new_created_estimation_value_level[pbs_project_element.id][complement_child_id] = {:value => level_current_mp_est_val[pbs_project_element.id][complement_child_id][:value]}
end
end
new_created_estimation_value.send("string_data_#{level}=".to_sym, new_created_estimation_value_level)
end
end
end
last_estimation_result = new_created_estimation_value
end
end
end
end
res << display_inputs_with_activities(current_module_project, last_estimation_result)
# For Effort balancing module
elsif current_module_project_pemodule.alias == 'effort_balancing'
res << display_effort_balancing_input(current_module_project, last_estimation_result)
# For others module with Activities
else
res << display_inputs_with_activities(current_module_project)
end
# For effort balancing module without activities (only for component)
elsif current_module_project_pemodule.alias == Projestimate::Application::BALANCING_MODULE
res << display_balancing_input(current_module_project, last_estimation_result)
# For others modules that don't use WSB-Activities values in input
elsif current_module_project_pemodule.no? || current_module_project_pemodule.yes_for_output_with_ratio? || current_module_project_pemodule.yes_for_output_without_ratio?
res << display_inputs_without_activities(current_module_project)
end
end
res
end
# Display the Effort Balancing Input without activity
def display_balancing_input(module_project, last_estimation_result)
pbs_project_element = current_component
#Get the current balancing attribute
@current_balancing_attribute = current_balancing_attribute
res = String.new
if module_project.compatible_with(current_component.work_element_type.alias) || current_component
pemodule = Pemodule.find(module_project.pemodule.id)
# render view according to the selected attribute
res << "<div class='attribute_balancing_input' style='margin-bottom:15px;'>"
res << "</div>"
res << "<table class='table table-condensed table-bordered'>"
if @current_balancing_attribute.nil?
res << "<tr><th colspan='#{module_project.previous.size+2}'> <span class='red_color'> #{ I18n.t(:text_please_select_balancing_attribute) } </span> </th></tr>"
else
res << "<tr><th colspan='#{module_project.previous.size+2}'> #{ @current_balancing_attribute.name } </th></tr>"
end
res << '<tr>'
# Get the balancing attribute
# Only the module_project that have the @current_balancing_attribute attribute as OUTPUT attribute are compatibles
compatible_previous_mp = []
module_project.previous.each_with_index do |est_mp, i|
compatible_attribute_module = est_mp.pemodule.attribute_modules.where('pe_attribute_id = ?', @current_balancing_attribute)
if !compatible_attribute_module.nil?
if !compatible_attribute_module.last.nil? && compatible_attribute_module.last.in_out.in?(%w(output both))
compatible_previous_mp << compatible_attribute_module.last
end
end
res << "<th>#{est_mp.pemodule.title}</th>"
end
res << "<th>#{I18n.t(:text_balancing_value)}</td>"
res << "<th>Notes</th>"
res << '</tr>'
res << "<tr>"
module_project.previous.each do |mp|
res << "<td>"
level = "probable"
# Get estimation_value of previous mp for same attribute
mp_attr_est_values = mp.estimation_values.where('in_out = ? AND pe_attribute_id = ?', "output", @current_balancing_attribute)
if mp_attr_est_values == nil || mp_attr_est_values.length==0
res << "-"
else
corresponding_est_val = mp_attr_est_values.last
# Get probable value : value of output attributes of previous pemodule_projects
level_estimation_values = Hash.new
level_estimation_values = corresponding_est_val.send("string_data_probable")
if level_estimation_values[pbs_project_element.id]
begin
res << text_field_tag("", display_value(level_estimation_values[pbs_project_element.id], corresponding_est_val),
:readonly => true, :class => "input-small #{level} #{corresponding_est_val.id}",
"data-est_val_id" => corresponding_est_val.id)
rescue
res << "-"
end
else
res << '-'
end
end
res << "</td>"
end
# Text_field the balancing value
balancing_attr_est_values = module_project.estimation_values.where('in_out = ? AND pe_attribute_id = ?', "input", @current_balancing_attribute)
res << '<td>'
balancing_attr_est_val = EstimationValue.new
if !balancing_attr_est_values.nil? && balancing_attr_est_values.length !=0
balancing_attr_est_val = balancing_attr_est_values.last
level_estimation_values = Hash.new
level_estimation_values = balancing_attr_est_val.send("string_data_low") #balancing_attr_est_val.send("string_data_most_likely")
if level_estimation_values[pbs_project_element.id].nil? or level_estimation_values[pbs_project_element.id].blank?
#res << "#{text_field_tag "['low'][#{balancing_attr_est_val.pe_attribute.alias.to_sym}][#{module_project.id.to_s}]",
# nil,
# :class => "input-small #{balancing_attr_est_val.id}",
# "data-est_val_id" => balancing_attr_est_val.id}"
res << pemodule_input("low", balancing_attr_est_val, module_project, level_estimation_values, pbs_project_element, attribute_type="", read_only_value=false)
else
#res << "#{text_field_tag "[#{balancing_attr_est_val.pe_attribute.alias.to_sym}][#{module_project.id.to_s}]",
# #level_estimation_values[pbs_project_element.id],
# display_value(level_estimation_values[pbs_project_element.id], balancing_attr_est_val),
# :class => "input-small #{balancing_attr_est_val.id}",
# "data-est_val_id" => balancing_attr_est_val.id}"
res << pemodule_input("low", balancing_attr_est_val, module_project, level_estimation_values, pbs_project_element, attribute_type="", read_only_value=false)
end
# As the estimation result is calculated today, we need to have
["high", "most_likely"].each do |level|
res << "#{hidden_field_tag "[#{level}][#{balancing_attr_est_val.pe_attribute.alias.to_sym}][#{module_project.id.to_s}]",
nil,
:class => "input_high_most_likely",
"data-est_val_id" => balancing_attr_est_val.id}"
end
else
res << "-"
# Need to create estimation_value record for the balancing attribute if it doesn't exist
end
res << '</td>'
# Notes to justify value
res << '<td>'
res << add_attribute_notes_link(balancing_attr_est_val, pbs_project_element.id)
res << '</td>'
res << "</tr>"
res << '</table>'
end
end
#Display the Effort Balancing Input
def display_effort_balancing_input(module_project, last_estimation_result)
pbs_project_element = current_component
res = String.new
if module_project.compatible_with(current_component.work_element_type.alias) || current_component
pemodule = Pemodule.find(module_project.pemodule.id)
res << "<table class='table table-condensed table-bordered'>"
res << '<tr>
<th></th>'
module_project.previous.each_with_index do |est_mp, i|
res << "<th>#{display_path([], module_project, i).reverse.join('<br>')}</th>"
end
module_project.estimation_values.each do |est_val|
if (est_val.in_out == 'input' or est_val.in_out=='both') and est_val.module_project.id == module_project.id
res << "<th>"
res << "<span class='attribute_tooltip' title='#{est_val.pe_attribute.description} #{display_rule(est_val)}' rel='tooltip'>#{est_val.pe_attribute.name}</span>"
res << "<span class='note_input_with_activities'>"
res << add_attribute_notes_link(est_val, pbs_project_element.id)
res << '</span>'
res << '</th>'
end
end
res << '</tr>'
module_project.project.pe_wbs_projects.activities_wbs.first.wbs_project_elements.each do |wbs_project_elt|
res << "<tr>
<td>
<span class='tree_element_in_out' style='margin-left:#{wbs_project_elt.depth}em;'>#{wbs_project_elt.name}</span></td>"
res << '</td>'
module_project.previous.each do |mp|
level = "probable"
#value of output attributes of previous pemodule_projects
mp.estimation_values.select { |i| i.in_out == 'output' }.each do |est_val|
level_estimation_values = Hash.new
level_estimation_values = est_val.send("string_data_probable")
res << '<td>'
if level_estimation_values[pbs_project_element.id]
begin
res << text_field_tag("", level_estimation_values[pbs_project_element.id][wbs_project_elt.id][:value],
:readonly => true, :class => "input-small #{level} #{est_val.id}",
"data-est_val_id" => est_val.id)
rescue
res << text_field_tag("", level_estimation_values[pbs_project_element.id],
:readonly => true, :class => "input-small #{level} #{est_val.id}",
"data-est_val_id" => est_val.id)
end
else
res << '-'
end
res << '</td>'
end
end
module_project.estimation_values.select { |i| i.in_out == 'output' }.each do |est_val|
res << '<td>'
level_estimation_values = Hash.new
level_estimation_values = est_val.send("string_data_most_likely")
if level_estimation_values[pbs_project_element.id].nil? or level_estimation_values[pbs_project_element.id][wbs_project_elt.id].blank?
res << "#{text_field_tag "[#{est_val.pe_attribute.alias.to_sym}][#{module_project.id.to_s}][#{wbs_project_elt.id.to_s}]",
nil,
:class => "input-small #{est_val.id}",
"data-est_val_id" => est_val.id}"
else
res << "#{text_field_tag "[#{est_val.pe_attribute.alias.to_sym}][#{module_project.id.to_s}][#{wbs_project_elt.id.to_s}]",
level_estimation_values[pbs_project_element.id][wbs_project_elt.id][:value],
:class => "input-small #{est_val.id}",
"data-est_val_id" => est_val.id}"
end
res << '</td>'
end
res << '</tr>'
end
res << '</table>'
end
end
#Display the Effort Balancing Output
def display_inputs_with_activities(module_project, last_estimation_result=nil)
pbs_project_element = current_component
res = String.new
if module_project.compatible_with(current_component.work_element_type.alias)# || current_component
pemodule = Pemodule.find(module_project.pemodule.id)
res << "<table class='table table-condensed table-bordered'>"
res << '<tr>
<th></th>'
module_project.estimation_values.order('display_order ASC').each do |est_val|
est_val_pe_attribute = est_val.pe_attribute
est_val_in_out = est_val.in_out
if (est_val_in_out == 'output' or est_val_in_out=='both') and est_val.module_project.id == module_project.id
res << "<th colspan=4><span class='attribute_tooltip' title='#{est_val_pe_attribute.description} #{display_rule(est_val)}' rel='tooltip'>#{est_val_pe_attribute.name}</span>"
res << "<span class='note_input_with_activities'>"
res << add_attribute_notes_link(est_val, pbs_project_element.id)
res << '</span>'
res << '</th>'
end
end
res << '</tr>'
res << '<tr><th></th>'
['low', '', 'most_likely', 'high'].each do |level|
res << "<th>#{level.humanize}</th>"
end
res << '</tr>'
module_project.project.pe_wbs_projects.activities_wbs.first.wbs_project_elements.each do |wbs_project_elt|
pe_attribute_alias = nil
level_parameter = ''
readonly_option = false
res << "<tr><td><span class='tree_element_in_out' style='margin-left:#{wbs_project_elt.depth}em;'>#{wbs_project_elt.name}</span></td>" ###res << "<tr><td>#{wbs_project_elt.name}</td>"
['low', 'most_likely', 'high'].each do |level|
res << '<td>'
module_project.estimation_values.where('in_out = ?', 'input').each do |est_val|
est_val_pe_attribute = est_val.pe_attribute
est_val_in_out = est_val.in_out
if (est_val_in_out == 'input' and est_val.module_project.id == module_project.id)
level_estimation_values = nil
level_estimation_values = est_val.send("string_data_#{level}")
# customize the single attribute entry
# this class will only be applied on the low level, as most_likely and high values are read_only
attribute_type = ""
read_only_attribute_level = false
if est_val.pe_attribute.single_entry_attribute
if level == "low"
attribute_type = "single_entry_attribute"
else # for otheres level(most-likely, high)
read_only_attribute_level = true
end
end
# For Wbs_Activity Complemention module, input data are from last executed module
if module_project.pemodule.alias == 'wbs_activity_completion'
pbs_last_result = nil
unless last_estimation_result.nil? || last_estimation_result.empty?
level_last_result = last_estimation_result.send("string_data_#{level}")
pbs_last_result = level_last_result[pbs_project_element.id]
end
if pbs_last_result.nil?
res << "#{text_field_tag "[#{level}][#{est_val_pe_attribute.alias.to_sym}][#{module_project.id.to_s}][#{wbs_project_elt.id.to_s}]",
nil,
:class => "input-small #{level} #{est_val.id} #{wbs_project_elt.id} #{attribute_type}",
"data-est_val_id" => est_val.id, "data-wbs_project_elt_id" => wbs_project_elt.id, :readonly => read_only_attribute_level}"
elsif wbs_project_elt.wbs_activity_element.nil?
if wbs_project_elt.is_root? || wbs_project_elt.has_children?
res << "#{text_field_tag "[#{level}][#{est_val_pe_attribute.alias.to_sym}][#{module_project.id.to_s}][#{wbs_project_elt.id.to_s}]",
pbs_last_result[wbs_project_elt.id][:value],
:readonly => true,
:class => "input-small #{level} #{est_val.id} #{wbs_project_elt.id} #{attribute_type}",
"data-est_val_id" => est_val.id, "data-wbs_project_elt_id" => wbs_project_elt.id}"
readonly_option = true
else
# If element is not from library
res << "#{text_field_tag "[#{level}][#{est_val_pe_attribute.alias.to_sym}][#{module_project.id.to_s}][#{wbs_project_elt.id.to_s}]",
pbs_last_result[wbs_project_elt.id].nil? ? nil : pbs_last_result[wbs_project_elt.id][:value],
:class => "input-small #{level} #{est_val.id} #{wbs_project_elt.id} #{attribute_type}",
"data-est_val_id" => est_val.id, "data-wbs_project_elt_id" => wbs_project_elt.id}"
end
else
res << "#{text_field_tag "[#{level}][#{est_val_pe_attribute.alias.to_sym}][#{module_project.id.to_s}][#{wbs_project_elt.id.to_s}]",
pbs_last_result[wbs_project_elt.id][:value],
:readonly => true, :class => "input-small #{level} #{est_val.id} #{wbs_project_elt.id} #{attribute_type}",
"data-est_val_id" => est_val.id, "data-wbs_project_elt_id" => wbs_project_elt.id}"
readonly_option = true
end
else
readonly_option = wbs_project_elt.has_children? ? true : false
nullity_condition = (level_estimation_values.nil? or level_estimation_values[pbs_project_element.id].nil? or level_estimation_values[pbs_project_element.id][wbs_project_elt.id].nil?)
if wbs_project_elt.is_root? || wbs_project_elt.has_children?
res << "#{ text_field_tag "[#{level}][#{est_val_pe_attribute.alias.to_sym}][#{module_project.id.to_s}][#{wbs_project_elt.id.to_s}]",
nullity_condition ? nil : level_estimation_values[pbs_project_element.id][wbs_project_elt.id],
:readonly => readonly_option || read_only_attribute_level,
:class => "input-small #{level} #{est_val.id} #{wbs_project_elt.id} #{attribute_type}",
"data-est_val_id" => est_val.id, "data-wbs_project_elt_id" => wbs_project_elt.id }"
else
res << "#{ text_field_tag "[#{level}][#{est_val_pe_attribute.alias.to_sym}][#{module_project.id.to_s}][#{wbs_project_elt.id.to_s}]",
nullity_condition ? level_estimation_values["default_#{level}".to_sym] : level_estimation_values[pbs_project_element.id][wbs_project_elt.id],
:readonly => readonly_option || read_only_attribute_level,
:class => "input-small #{level} #{est_val.id} #{wbs_project_elt.id} #{attribute_type}",
"data-est_val_id" => est_val.id, "data-wbs_project_elt_id" => wbs_project_elt.id }"
end
end
end
pe_attribute_alias = est_val_pe_attribute.alias
end
res << '</td>'
if level == 'low'
#Available to copy value
input_id = "_#{pe_attribute_alias}_#{module_project.id}_#{wbs_project_elt.id}"
res << '<td>'
unless readonly_option
res << "<span id='#{input_id}' class='copyLib icon icon-chevron-right' data-effort_input_id='#{input_id}' title='Copy value in other fields' onblur='this.style.cursor='default''></span>"
end
res << '</td>'
end
end
res << '</tr>'
end
res << '</table>'
end
res
end
# Display th inputs parameters view
def display_inputs_without_activities(module_project)
pbs_project_element = current_component
res = String.new
if module_project.compatible_with(current_component.work_element_type.alias) || current_component
pemodule = Pemodule.find(module_project.pemodule.id)
res << "<table class='table table-condensed table-bordered'>
<tr>
<th></th>"
['low', '', 'most_likely', 'high', ''].each do |level|
res << "<th>#{level.humanize}</th>"
end
res << '</tr>'
module_project.estimation_values.order('display_order ASC').each do |est_val|
est_val_pe_attribute = est_val.pe_attribute
est_val_in_out = est_val.in_out
if (est_val_in_out == 'input' or est_val_in_out == 'both') and (est_val.module_project.id == module_project.id) and est_val_pe_attribute
res << '<tr>'
res << "<td><span class='attribute_tooltip tree_element_in_out' title='#{est_val_pe_attribute.description} #{display_rule(est_val)}'>#{est_val_pe_attribute.name}</span></td>"
level_estimation_values = Hash.new
['low', 'most_likely', 'high'].each do |level|
attribute_type = ""
read_only_attribute = false
disable_attribute_level = false
# customize the single attribute entry
# this class will only be applied on the low level, as most_likely and high values are read_only
if est_val.pe_attribute.single_entry_attribute
if level == "low"
attribute_type = "single_entry_attribute"
else
read_only_attribute = true
disable_attribute_level = true
end
end
level_estimation_values = est_val.send("string_data_#{level}")
res << "<td>#{pemodule_input(level, est_val, module_project, level_estimation_values, pbs_project_element, attribute_type, read_only_attribute)}</td>"
if level == 'low'
input_id = "_#{est_val_pe_attribute.alias}_#{module_project.id}"
res << "<td>"
res << "<span id='#{input_id}' class='copyLib icon icon-chevron-right' data-effort_input_id='#{input_id}' title='Copy value in other fields' onblur='this.style.cursor='default''></span>"
res << '</td>'
end
end
# Add link to add attribute Note to justify each estimation attribute
res << '<td>'
res << add_attribute_notes_link(est_val, pbs_project_element.id)
res << '</td>'
res << '</td>'
end
res << '</tr>'
end
res << '</table>'
end
res
end
def pemodule_input(level, est_val, module_project, level_estimation_values, pbs_project_element, attribute_type="", read_only_value=false)
est_val_pe_attribute = est_val.pe_attribute
if est_val_pe_attribute.attr_type == 'integer' or est_val_pe_attribute.attr_type == 'float'
display_text_field_tag(level, est_val, module_project, level_estimation_values, pbs_project_element, attribute_type, read_only_value)
elsif est_val_pe_attribute.attr_type == 'list'
select_tag "[#{level}][#{est_val_pe_attribute.alias.to_sym}][#{module_project.id}]",
options_for_select(
est_val_pe_attribute.options[2].split(';'),
:selected => (level_estimation_values[pbs_project_element.id].nil? ? level_estimation_values["default_#{level}".to_sym] : level_estimation_values[pbs_project_element.id])),
:class => "input-small #{level} #{est_val.id} #{attribute_type}",
:prompt => "Unset",
"data-est_val_id" => est_val.id,
"data-module_project_id" => module_project.id,
:readonly => read_only_value#, :disabled => read_only_value
elsif est_val_pe_attribute.attr_type == 'date'
text_field_tag "[#{level}][#{est_val_pe_attribute.alias.to_sym}][#{module_project.id}]",
level_estimation_values[pbs_project_element.id].nil? ? display_date(level_estimation_values["default_#{level}".to_sym]) : display_date(level_estimation_values[pbs_project_element.id]),
:class => "input-small #{level} #{est_val.id} date-picker #{attribute_type}",
"data-est_val_id" => est_val.id,
"data-module_project_id" => module_project.id,
:readonly => read_only_value
else #type = text
text_field_tag "[#{level}][#{est_val_pe_attribute.alias.to_sym}][#{module_project.id}]",
(level_estimation_values[pbs_project_element.id].nil?) ? level_estimation_values["default_#{level}".to_sym] : level_estimation_values[pbs_project_element.id],
:class => "input-small #{level} #{est_val.id} #{attribute_type}",
"data-est_val_id" => est_val.id,
"data-module_project_id" => module_project.id,
:readonly => read_only_value
end
end
def display_value(value, est_val, mp_id)
module_project = ModuleProject.find(mp_id)
est_val_pe_attribute = est_val.pe_attribute
precision = est_val_pe_attribute.precision.nil? ? user_number_precision : est_val_pe_attribute.precision
if est_val_pe_attribute.alias == "retained_size" || est_val_pe_attribute.alias == "theorical_size"
"#{convert_with_precision(value.to_f, precision)} #{module_project.size}"
elsif est_val_pe_attribute.alias == "effort"
"#{convert_with_precision(convert(value, @project.organization), precision)} #{convert_label(value, @project.organization)}"
elsif est_val_pe_attribute.alias == "cost"
unless value.class == Hash
"#{convert_with_precision(value, 2)} #{get_attribute_unit(est_val_pe_attribute)}"
end
else
case est_val_pe_attribute
when 'date'
display_date(value)
when 'float'
"#{ convert_with_precision(convert(value, @project.organization), precision) } #{convert_label(value, @project.organization)}"
when 'integer'
"#{convert(value, @project.organization).round(precision)} #{convert_label(value, @project.organization)}"
else
value
end
end
end
#Display a date depending user time zone
def display_date(date)
begin
I18n.l(date.to_date)
rescue
date
end
end
#Display text field tag depending of estimation plan.
#Some pemodules can take previous and computed values
# attribute_type parameter will be aqual to "single_attribute_entry" if single_attribute_entry
def display_text_field_tag(level, est_val, module_project, level_estimation_values, pbs_project_element, attribute_type="", read_only_value=false)
est_val_pe_attribute = est_val.pe_attribute
organization = module_project.project.organization
precision = est_val_pe_attribute.precision.nil? ? user_number_precision : est_val_pe_attribute.precision
res = []
read_only_value = false
if module_project.previous.empty? || !est_val["string_data_#{level}"][pbs_project_element.id].nil?
text_field_tag "[#{level}][#{est_val_pe_attribute.alias.to_sym}][#{module_project.id}]",
convert(level_estimation_values[pbs_project_element.id].nil? ? level_estimation_values["default_#{level}".to_sym] : level_estimation_values[pbs_project_element.id], organization),
:class => "input-small #{level} #{est_val.id} #{attribute_type}",
"data-est_val_id" => est_val.id,
"data-module_project_id" => module_project.id,
:readonly => read_only_value
else
comm_attr = ModuleProject::common_attributes(module_project.previous.first, module_project)
if comm_attr.empty?
text_field_tag "[#{level}][#{est_val_pe_attribute.alias.to_sym}][#{module_project.id}]",
convert((level_estimation_values[pbs_project_element.id].nil? ? level_estimation_values["default_#{level}".to_sym] : level_estimation_values[pbs_project_element.id]), organization).to_f.round(precision),
:class => "input-small #{level} #{est_val.id} #{attribute_type}",
"data-est_val_id" => est_val.id,
"data-module_project_id" => module_project.id,
:readonly => read_only_value
else
estimation_value = EstimationValue.where(:pe_attribute_id => comm_attr.first.id,
:module_project_id => module_project.previous.first.id,
:in_out => "output").first
new_level_estimation_values = estimation_value.send("string_data_#{level}")
text_field_tag "[#{level}][#{est_val_pe_attribute.alias.to_sym}][#{module_project.id}]",
convert(new_level_estimation_values[pbs_project_element.id], organization).to_f.round(precision),
:class => "input-small #{level} #{est_val.id} #{attribute_type}",
"data-est_val_id" => est_val.id,
"data-module_project_id" => module_project.id,
:readonly => read_only_value
end
end
end
#Display rule and options of an attribute in a bootstrap tooltip
def display_rule(est_val)
"<br> #{I18n.t(:tooltip_attribute_rules)}: <strong>#{est_val.pe_attribute.options.join(' ')} </strong> <br> #{est_val.is_mandatory ? I18n.t(:mandatory) : I18n.t(:no_mandatory) }"
end
#Display Security_Level Description in a bootstrap tooltip
def display_security_level_description(security_level)
"#{security_level.description}"
end
def display_path(res, mp, i)
if mp.previous[i].nil?
res << ([mp] + mp.previous).flatten.reverse.join('<br>')
else
display_path(res, mp.previous[i], i)
end
res
end
def send_notice(project)
#if project.state == "in_progress"
# I18n.t(:warning_project_state_to_checkpoint, :value_b => 'RELEASED')
#elsif project.state == "in_review"
# I18n.t(:warning_project_state_to_released, :value_b => 'RELEASED')
#end
end
#Helper method that build project history graph
def build_project_history_graph
#Project.arrange_as_array.each{|n| "#{'-' * n.depth} #{n.version}" }
Project.arrange_as_json.each do |n|
project = Project.find(n[:id])
"#{'-' * project.depth} #{n[:title]}"
end
end
def build_project_history_graph_as_array
#Project.arrange_as_array.each{|n| "#{'-' * n.depth} #{n.version}" }
Project.arrange_as_array.each do |n|
"#{'-' * n.depth} #{n.title}"
end
end
def build_project_history_graph_json
proj = Project.find(304)
end
def helper_show_project_history
@projects.each do |prj|
"#{'-' * prj[0].depth} #{prj[0].title}(#{prj[0].version})"
end
end
def show_project_history_graph(project)
require 'gratr/import'
require 'gratr/dot'
#ObjectSpace.each_object(Module) do |m|
# m.ancestors.each {|a| module_graph.add_edge!(m,a) if m != a}
#end
project = Project.find(301)
project_root = project.root
project_tree = project_root.subtree
module_graph = Digraph.new
project_tree.each do |proj|
#proj.parent.each {|parent| module_graph.add_edge!(parent.version, proj.version) if proj != parent} unless proj.is_root?
module_graph.add_edge!(proj.parent.version, proj.version) unless proj.is_root?
proj.children.each {|child| module_graph.add_edge!(proj.version, child.version) if proj != child}
end
gv = module_graph.vertices.select {|v| v.to_s.match(/GRATR/)}
#module_graph.induced_subgraph(gv).write_to_graphic_file('jpg','module_graph_project')
module_graph.write_to_graphic_file('jpg','graph_project_history')
end
# Authorizations based on estimations's statuses roles
# Estimation status Role by groups
# The possible project_permission_action_alias = ("see_project", "show_project", "edit_project", "delete_project")
def can_do_action_on_estimation?(estimation, project_permission_action_alias)
can_do_something = false
# SuperAdmin user or those who has all permissions has all rights
if current_user.super_admin? || can?(:manage, :all)
can_do_something = true
else
#begin
permission_to_show_project = ProjectSecurityLevel.find_by_alias(project_permission_action_alias)
###if can?(:show_project, estimation)
#if can?(:see_project, estimation)
# if at least one of the current_user's groups is in the estimation's organization groups
groups_intersection = current_user.groups.all & estimation.organization.groups
unless groups_intersection.nil?
groups_intersection.each do |group|
if estimation.estimation_status.estimation_status_group_roles.where(group_id: group.id).map(&:project_security_level_id).include?(permission_to_show_project.id)
can_do_something = true
break if can_do_something
end
end
end
#end
#rescue
# false
#end
end
can_do_something
end
# Got the right to see the estimation from estimations list
def can_see_estimation?(estimation)
#authorization = can_do_action_on_estimation?(estimation, "see_project")# || can_do_action_on_estimation?(estimation, "show_project") || can_do_action_on_estimation?(estimation, "edit_project")
#authorization &&
can?(:see_project, estimation)
end
# Got the right to show the estimation details
def can_show_estimation?(estimation)
#authorization = can_do_action_on_estimation?(estimation, "show_project")# || can_do_action_on_estimation?(estimation, "edit_project")
#authorization &&
can?(:show_project, estimation)
end
# Got the right to edit and modify the estimation details
def can_modify_estimation?(estimation)
#authorization = can_do_action_on_estimation?(estimation, "edit_project")
#authorization &&
can?(:edit_project, estimation)
end
# Got the right to Alter and modify only some parts of the estimation details if user has the rights to edit the project in its status
def can_alter_estimation?(estimation)
can?(:show_project, estimation)# && can_do_action_on_estimation?(estimation, "edit_project")
#can?(:show_project, estimation, estimation_status_id: estimation.estimation_status_id)
end
# Got the right to delete the estimation
def can_delete_estimation?(estimation)
#authorization = can_do_action_on_estimation?(estimation, "delete_project")
#authorization &&
can?(:delete_project, estimation)
end
end