app/controllers/projects_controller.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/>.
#
#############################################################################
class ProjectsController < ApplicationController
include WbsActivityElementsHelper
include ModuleProjectsHelper
include ProjectsHelper
include PemoduleEstimationMethods
load_resource
helper_method :sort_direction, :is_collapsible?, :set_attribute_unit
helper_method :enable_update_in_local? #For the wbs-activity-element
helper_method :show_status_change_comments
before_filter :load_data, :only => [:update, :edit, :new, :create, :show]
before_filter :get_record_statuses
# This function is only use to show the WBS-Activity tree view
# in the link_activity_element function in wbs_activity_elements_helper
def enable_update_in_local?
#No authorize required since this method is protected and won't be call from route
if is_master_instance?
true
else
if params[:action] == 'new'
true
elsif params[:action] == 'edit'
@wbs_activity_element = WbsActivityElement.find(params[:id])
if @wbs_activity_element.is_defined? || @wbs_activity_element.defined?
false
else
true
end
end
end
end
#protected
private
def load_data
#No authorize required since this method protected and is used to load data and shared by the other one.
if params[:id]
@project = Project.find(params[:id])
else
@project = Project.new :state => 'preliminary'
end
@pemodules ||= Pemodule.defined
@project_modules = @project.pemodules
@module_positions = ModuleProject.where(:project_id => @project.id).order(:position_y).all.map(&:position_y).uniq.max || 1
@module_positions_x = @project.module_projects.order(:position_x).all.map(&:position_x).max
if current_user.super_admin == true
@organizations = Organization.all
else
@organizations = current_user.organizations
end
@project_modules = @project.pemodules
@project_security_levels = ProjectSecurityLevel.all
@module_project = ModuleProject.find_by_project_id(@project.id)
end
public
def dashboard
authorize! :show_project, @project
# return if user doesn't have the rigth to consult the estimation
if !can_show_estimation?(@project)
redirect_to(organization_estimations_path(@current_organization), flash: { warning: I18n.t(:warning_no_show_permission_on_project_status)}) and return
end
if @current_organization.is_image_organization == true
redirect_to(root_url, flash: { error: "Vous ne pouvez pas accéder à une organization image"}) and return
end
set_page_title "Estimation - #{@current_organization}"
@user = current_user
@pemodules ||= Pemodule.all
@module_project = current_module_project
@show_hidden = 'true'
@organization_default_iew = View.where("name = ? AND organization_id = ?", "Default view", @project.organization_id).first_or_create(name: "Default view", organization_id: @project.organization_id, :description => "Default view for widgets. If no view is selected for module project, this view will be automatically selected.")
status_comment_link = ""
if can_alter_estimation?(@project) && ( can?(:alter_estimation_status, @project) || can?(:alter_project_status_comment, @project))
status_comment_link = "#{main_app.add_comment_on_status_change_path(:project_id => @project.id)}"
end
set_breadcrumbs "Organizations" => "/organizationals_params", @current_organization.to_s => organization_estimations_path(@current_organization), "#{@project}" => "#{main_app.edit_project_path(@project)}", "<span class='badge' style='background-color: #{@project.status_background_color}'> #{@project.status_name}" => status_comment_link
@project_organization = @project.organization
@module_projects = @project.module_projects
#Get the initialization module_project
@initialization_module_project ||= ModuleProject.where('pemodule_id = ? AND project_id = ?', @initialization_module.id, @project.id).first unless @initialization_module.nil?
@module_positions = ModuleProject.where(:project_id => @project.id).order(:position_y).all.map(&:position_y).uniq.max || 1
@module_positions_x = @project.module_projects.order(:position_x).all.map(&:position_x).max
if @module_project.pemodule.alias == "expert_judgement"
if current_module_project.expert_judgement_instance.nil?
@expert_judgement_instance = ExpertJudgement::Instance.first
else
@expert_judgement_instance = current_module_project.expert_judgement_instance
end
array_attributes = Array.new
if @expert_judgement_instance.enabled_size?
array_attributes << "retained_size"
end
if @expert_judgement_instance.enabled_effort?
array_attributes << "effort"
end
if @expert_judgement_instance.enabled_cost?
array_attributes << "cost"
end
@expert_judgement_attributes = PeAttribute.where(alias: array_attributes)
array_attributes.each do |a|
ie = ExpertJudgement::InstanceEstimate.where( pe_attribute_id: PeAttribute.find_by_alias(a).id,
expert_judgement_instance_id: @expert_judgement_instance.id.to_i,
module_project_id: current_module_project.id,
pbs_project_element_id: current_component.id).first_or_create!
end
elsif @module_project.pemodule.alias == "ge"
#if current_module_project.ge_model.nil?
# @ge_model = Ge::GeModel.first
#else
@ge_model = current_module_project.ge_model
#end
elsif @module_project.pemodule.alias == "guw"
#if current_module_project.guw_model.nil?
# @guw_model = Guw::GuwModel.first
#else
@guw_model = current_module_project.guw_model
#end
@unit_of_work_groups = Guw::GuwUnitOfWorkGroup.where(pbs_project_element_id: current_component.id, module_project_id: current_module_project.id).all
elsif @module_project.pemodule.alias == "uow"
@pbs = current_component
@uow_inputs = UowInput.where(module_project_id: @module_project, pbs_project_element_id: @pbs.id).order("display_order ASC").all
if @uow_inputs.empty?
@input = UowInput.new(module_project_id: @module_project.id, pbs_project_element_id: @pbs.id, display_order: 0)
@input.save(validate: false)
@uow_inputs = UowInput.where(module_project_id: @module_project, pbs_project_element_id: @pbs.id).order("display_order ASC").all
end
@organization_technologies = @project.organization.organization_technologies.map{|i| [i.name, i.id]}
@unit_of_works = @project.organization.unit_of_works.map{|i| [i.name, i.id]}
current_component_technology = current_component.organization_technology
@complexities = current_component_technology.nil? ? [] : current_component_technology.organization_uow_complexities.map{|i| [i.name, i.id]}
@module_project.pemodule.attribute_modules.each do |am|
if am.pe_attribute.alias == "retained_size"
@size = EstimationValue.where(:module_project_id => @module_project.id,
:pe_attribute_id => am.pe_attribute.id,
:in_out => "input" ).first
@gross_size = EstimationValue.where(:module_project_id => @module_project.id, :pe_attribute_id => am.pe_attribute.id).first
end
end
elsif @module_project.pemodule.alias == "cocomo_advanced"
@aprod = Array.new
aliass = %w(rely data cplx ruse docu)
aliass.each do |a|
@aprod << Factor.where(alias: a, factor_type: "advanced").first
end
@aplat = Array.new
aliass = %w(time stor pvol)
aliass.each do |a|
@aplat << Factor.where(alias: a, factor_type: "advanced").first
end
@apers = Array.new
aliass = %w(acap aexp ltex pcap pexp pcon)
aliass.each do |a|
@apers << Factor.where(alias: a, factor_type: "advanced").first
end
@aproj = Array.new
aliass = %w(tool site sced)
aliass.each do |a|
@aproj << Factor.where(alias: a, factor_type: "advanced").first
end
else
@sf = []
@em = []
aliass = %w(pers rcpx ruse pdif prex fcil sced)
aliass.each do |a|
@em << Factor.where(alias: a).first
end
aliass = %w(prec flex resl team pmat)
aliass.each do |a|
@sf << Factor.where(alias: a).first
end
end
end
def index
#No authorize required since everyone can access the list (permission will be managed project per project)
set_page_title 'Estimations'
# The current user can only see projects of its organizations
@projects = current_user.organizations.map{|i| i.projects }.flatten.reject { |j| !j.is_childless? } #Then only projects on which the current is authorise to see will be displayed
end
#Allow to user to change the estimation data when creating from template
def change_new_estimation_data
@project_template = Project.find(params[:template_id])
@new_project = Project.new
@project_areas = @current_organization.project_areas
@platform_categories = @current_organization.platform_categories
@acquisition_categories = @current_organization.acquisition_categories
@project_categories = @current_organization.project_categories
end
def new
# To create an estimation model, use should have a :manage_estimation_models authorization
@is_model = params[:is_model]
if @is_model
authorize! :manage_estimation_models, Project
set_breadcrumbs "#{I18n.t(:estimation_models)}" => organization_setting_path(@current_organization, anchor: "tabs-estimation-models")
set_page_title 'New estimation model'
else
authorize! :create_project_from_scratch, Project
set_breadcrumbs "Estimations" => organization_estimations_path(@current_organization)
set_page_title 'New estimation'
end
@organization = Organization.find(params[:organization_id])
@project_areas = @organization.project_areas
@platform_categories = @organization.platform_categories
@acquisition_categories = @organization.acquisition_categories
@project_categories = @organization.project_categories
end
#Create a new project
def create
@is_model = params[:project][:is_model]
if @is_model == "true"
authorize! :manage_estimation_models, Project
else
authorize! :create_project_from_scratch, Project
end
set_page_title 'Create estimation'
@product_name = params[:project][:product_name]
@project_title = params[:project][:title]
@project = Project.new(params[:project])
@project.creator_id = current_user.id
@project.status_comment = "#{I18n.l(Time.now)} : #{I18n.t(:estimation_created_by, username: current_user.name)} \r\n"
@organization = Organization.find(params[:project][:organization_id])
@project_areas = @organization.project_areas
@platform_categories = @organization.platform_categories
@acquisition_categories = @organization.platform_categories
@project_categories = @organization.project_categories
#Give full control to project creator
full_control_security_level = ProjectSecurityLevel.where(name: 'FullControl', organization_id: @organization.id).first_or_create(name: 'FullControl', organization_id: @organization.id, description: "Authorization to Read + Comment + Modify + Define + can change users's permissions on the project")
manage_project_permission = Permission.where(alias: "manage", object_associated: "Project", record_status_id: @defined_record_status).first_or_create(alias: "manage", object_associated: "Project", record_status_id: @defined_record_status, name: "Manage Projet", uuid: UUIDTools::UUID.random_create.to_s)
# Add the "manage project" authorization to the "FullControl" security level
if manage_project_permission
if !manage_project_permission.in?(full_control_security_level.permission_ids)
full_control_security_level.update_attribute('permission_ids', manage_project_permission.id)
end
end
current_user_ps = @project.project_securities.build
current_user_ps.user = current_user
current_user_ps.project_security_level = full_control_security_level
@project.is_locked = false
if @project.start_date.nil? or @project.start_date.blank?
@project.start_date = Time.now.to_date
end
Project.transaction do
begin
@project.add_to_transaction
if @project.save
#New default Pe-Wbs-Project
pe_wbs_project_product = @project.pe_wbs_projects.build(:name => "#{@project.title}", :wbs_type => 'Product')
pe_wbs_project_product.add_to_transaction
pe_wbs_project_product.save!
##New root Pbs-Project-Element
pbs_project_element = pe_wbs_project_product.pbs_project_elements.build(:name => "#{@product_name.blank? ? @project_title : @product_name}",
:is_root => true, :start_date => Time.now, :position => 0,
:work_element_type_id => default_work_element_type.id,
:organization_technology_id => @organization.organization_technologies.first_or_create(name: "Java", alias: "Java", organization_id: @organization.id, productivity_ratio: 1, state: "draft").id)
pbs_project_element.add_to_transaction
pbs_project_element.save!
pe_wbs_project_product.save!
#Get the initialization module from ApplicationController
#When creating project, we need to create module_projects for created initialization
unless @initialization_module.nil?
# Create the project's Initialization module
cap_module_project = ModuleProject.new(:project_id => @project.id, :pemodule_id => @initialization_module.id, :position_x => 0, :position_y => 0, show_results_view: true)
# Create the Initialization module view
cap_module_project.build_view(name: "#{cap_module_project.to_s} - Module project View", organization_id: @project.organization_id)
if cap_module_project.save!
#Create the corresponding EstimationValues
unless @project.organization.nil? || @project.organization.attribute_organizations.nil?
@project.organization.attribute_organizations.each do |am|
['input', 'output'].each do |in_out|
mpa = EstimationValue.create(:pe_attribute_id => am.pe_attribute.id,
:module_project_id => cap_module_project.id,
:in_out => in_out,
:is_mandatory => am.is_mandatory,
:description => am.pe_attribute.description,
:display_order => nil,
:string_data_low => {:pe_attribute_name => am.pe_attribute.name, :default_low => ''},
:string_data_most_likely => {:pe_attribute_name => am.pe_attribute.name, :default_most_likely => ''},
:string_data_high => {:pe_attribute_name => am.pe_attribute.name, :default_high => ''})
end
end
end
end
end
redirect_to redirect_apply(edit_project_path(@project)), notice: "#{I18n.t(:notice_project_successful_created)}"
else
flash[:error] = "#{I18n.t(:error_project_creation_failed)} #{@project.errors.full_messages.to_sentence}"
render action: :new
end
#raise ActiveRecord::Rollback
rescue ActiveRecord::UnknownAttributeError, ActiveRecord::StatementInvalid, ActiveRecord::RecordInvalid => error
flash[:error] = "#{I18n.t (:error_project_creation_failed)} #{@project.errors.full_messages.to_sentence}"
redirect_to (@project.is_model ? organization_setting_path(@organization, anchor: "tabs-estimation-models") : organization_estimations_path(@organization))
end
end
end
#Edit a selected project
def edit
set_page_title 'Edit estimation'
@project = Project.find(params[:id])
@organization = @project.organization
@project_areas = @organization.project_areas
@platform_categories = @organization.platform_categories
@acquisition_categories = @organization.acquisition_categories
@project_categories = @organization.project_categories
#set_breadcrumbs "Estimations" => projects_path, @project => edit_project_path(@project)
if @project.is_model
set_breadcrumbs "#{I18n.t(:estimation_models)}" => organization_setting_path(@organization, anchor: "tabs-estimation-models"), "#{@project} <span class='badge' style='background-color: #{@project.status_background_color}'>#{@project.status_name}</span>" => edit_project_path(@project)
if cannot?(:manage_estimation_models, Project) # No write access to project
if can_show_estimation?(@project)
redirect_to(:action => 'show') and return
else
redirect_to(organization_setting_path(@organization), flash: { warning: I18n.t(:warning_no_show_permission_on_project_status)}) and return
end
end
else
set_breadcrumbs "Estimations" => organization_estimations_path(@organization), "#{@project} <span class='badge' style='background-color: #{@project.status_background_color}'>#{@project.status_name}</span>" => edit_project_path(@project)
if cannot?(:edit_project, @project) # No write access to project
redirect_to(:action => 'show') and return
end
# We need to verify user's groups rights on estimation according to the current estimation status
if !can_modify_estimation?(@project)
if can_show_estimation?(@project)
redirect_to(:action => 'show')
else
redirect_to(organization_estimations_path(@organization), flash: { warning: I18n.t(:warning_no_show_permission_on_project_status)}) and return
end
end
end
@initialization_module_project = @initialization_module.nil? ? nil : @project.module_projects.find_by_pemodule_id(@initialization_module.id)
@pe_wbs_project_product = @project.pe_wbs_projects.products_wbs.first
#@pe_wbs_project_activity = @project.pe_wbs_projects.activities_wbs.first
# Get the max X and Y positions of modules
@module_positions = ModuleProject.where(:project_id => @project.id).order(:position_y).all.map(&:position_y).uniq.max || 1
@module_positions_x = @project.module_projects.order(:position_x).all.map(&:position_x).max
@guw_module = Pemodule.where(alias: "guw").first
@ge_module = Pemodule.where(alias: "ge").first
@ej_module = Pemodule.where(alias: "expert_judgement").first
@ebd_module = Pemodule.where(alias: "effort_breakdown").first
@guw_modules = @project.organization.guw_models.map{|i| [i, "#{i.id},#{@guw_module.id}"] }
@ge_models = @project.organization.ge_models.map{|i| [i, "#{i.id},#{@ge_module.id}"] }
@ej_modules = @project.organization.expert_judgement_instances.map{|i| [i, "#{i.id},#{@ej_module.id}"] }
@wbs_instances = @project.organization.wbs_activities.map{|i| [i, "#{i.id},#{@ebd_module.id}"] }
@modules_selected = (Pemodule.defined.all - [@guw_module, @ge_module, @ej_module, @ebd_module]).map{|i| [i.title,i.id]}
project_root = @project.root
project_tree = project_root.subtree
arranged_projects = project_tree.arrange
array_json_tree = Project.json_tree(arranged_projects)
@projects_json_tree = Hash[*array_json_tree.flatten]
@projects_json_tree = @projects_json_tree.to_json
end
def update
set_page_title 'Edit estimation'
@project = Project.find(params[:id])
@organization = @project.organization
@project_areas = @organization.project_areas
@platform_categories = @organization.platform_categories
@acquisition_categories = @organization.platform_categories
@project_categories = @organization.project_categories
if @project.is_model
set_breadcrumbs "#{I18n.t(:estimation_models)}" => organization_setting_path(@organization, anchor: "tabs-estimation-models"), "#{@project} <span class='badge' style='background-color: #{@project.status_background_color}'>#{@project.status_name}</span>" => edit_project_path(@project)
if cannot?(:manage_estimation_models, Project) # No write access to project
if can_show_estimation?(@project)
redirect_to(:action => 'show') and return
else
redirect_to(organization_setting_path(@organization), flash: { warning: I18n.t(:warning_no_modify_permission_on_project_status)}) and return
end
end
else
set_breadcrumbs "Estimations" => organization_estimations_path(@organization), "#{@project} <span class='badge' style='background-color: #{@project.status_background_color}'>#{@project.status_name}</span>" => edit_project_path(@project)
# We need to verify user's groups rights on estimation according to the current estimation status
if !can_modify_estimation?(@project) && !can_alter_estimation?(@project)
flash[:warning] = I18n.t(:warning_no_modify_permission_on_project_status)
if can_show_estimation?(@project)
redirect_to(:action => 'show') and return
else
redirect_to(organization_estimations_path(@organization)) and return
end
end
end
if (@project.is_model && can?(:manage_estimation_models, Project)) || (!@project.is_model && (can?(:edit_project, @project) || can_alter_estimation?(@project))) # Have the write access to project
@product_name = params[:project][:product_name]
project_root = @project.root_component
project_root_name = "#{@product_name.blank? ? @project.title : @product_name}"
project_root.update_attribute(:name, project_root_name)
@pe_wbs_project_product = @project.pe_wbs_projects.products_wbs.first
@wbs_activity_elements = []
@initialization_module_project = @initialization_module.nil? ? nil : @project.module_projects.find_by_pemodule_id(@initialization_module.id)
# we can update user securities levels on edit or on show with some restrictions
#if params['is_project_show_view'].nil? || (params['is_project_show_view'] =="true" && !params['user_security_levels'].nil?)
# @project.organization.users.uniq.each do |u|
# ps = ProjectSecurity.find_by_user_id_and_project_id(u.id, @project.id)
# if ps
# ps.project_security_level_id = params["user_securities_#{u.id}"]
# ps.save
# elsif !params["user_securities_#{u.id}"].blank?
# new_ps = @project.project_securities.build #ProjectSecurity.new
# new_ps.user_id = u.id
# new_ps.project_security_level_id = params["user_securities_#{u.id}"]
# end
# end
#end
# we can update group securities levels on edit or on show with some restrictions
if params['is_project_show_view'].nil? || (params['is_project_show_view'] == "true" && !params['group_security_levels'].nil?)
is_model_permission = nil
# if this is a model permission, is_model_permission should be true
if !params[:model_group_security_levels].nil?
is_model_permission = true
end
@project.project_securities.delete_all
unless params["group_securities"].nil?
params["group_securities"].each do |psl|
params["group_securities"][psl.first].each do |group|
ProjectSecurity.create(group_id: group.first.to_i,
project_id: @project.id,
project_security_level_id: psl.first,
is_model_permission: true)
end
end
end
unless params["group_securities_from_model"].nil?
params["group_securities_from_model"].each do |psl|
params["group_securities_from_model"][psl.first].each do |group|
ProjectSecurity.create(group_id: group.first.to_i,
project_id: @project.id,
project_security_level_id: psl.first,
is_model_permission: false)
end
end
end
unless params["user_securities_from_model"].nil?
params["user_securities_from_model"].each do |psl|
params["user_securities_from_model"][psl.first].each do |group|
ProjectSecurity.create(user_id: group.first.to_i,
project_id: @project.id,
project_security_level_id: psl.first,
is_model_permission: false)
end
end
end
end
# Get the max X and Y positions of modules
@module_positions = ModuleProject.where(:project_id => @project.id).order(:position_y).all.map(&:position_y).uniq.max || 1
@module_positions_x = @project.module_projects.order(:position_x).all.map(&:position_x).max
#Get the project Organization before update
project_organization = @project.organization
# Before saving project, update the project comment when the status has changed
if params[:project][:estimation_status_id]
new_status_id = params[:project][:estimation_status_id].to_i
if @project.estimation_status_id != new_status_id
new_comments = auto_update_status_comment(params[:id], new_status_id)
new_comments << "#{@project.status_comment} \r\n"
@project.status_comment = new_comments
end
end
if @project.update_attributes(params[:project])
begin
#start_date = Date.strptime(params[:project][:start_date], I18n.t('%m/%d/%Y'))
start_date = Date.strptime(params[:project][:start_date], I18n.t('date.formats.default'))
@project.start_date = start_date
rescue
@project.start_date = Time.now.to_date
end
# Initialization Module
unless @initialization_module.nil?
# Get the project initialization module_project or create if it doesn't exist
cap_module_project = @project.module_projects.find_by_pemodule_id(@initialization_module.id)
if cap_module_project.nil?
cap_module_project = @project.module_projects.create(:pemodule_id => @initialization_module.id, :position_x => 0, :position_y => 0)
end
# Create the project initialization module estimation_values if project organization has changed and not nil
if project_organization.nil? && !@project.organization.nil?
#Create the corresponding EstimationValues
unless @project.organization.attribute_organizations.nil?
@project.organization.attribute_organizations.each do |am|
['input', 'output'].each do |in_out|
mpa = EstimationValue.create(:pe_attribute_id => am.pe_attribute.id, :module_project_id => cap_module_project.id, :in_out => in_out,
:is_mandatory => am.is_mandatory, :description => am.pe_attribute.description, :display_order => nil,
:string_data_low => {:pe_attribute_name => am.pe_attribute.name, :default_low => ''},
:string_data_most_likely => {:pe_attribute_name => am.pe_attribute.name, :default_most_likely => ''},
:string_data_high => {:pe_attribute_name => am.pe_attribute.name, :default_high => ''})
end
end
end
# When project organization exists
elsif !project_organization.nil?
# project's organization is deleted and none one is selected
if @project.organization.nil?
cap_module_project.estimation_values.delete_all
end
# Project's organization has changed
if !@project.organization.nil? && project_organization != @project.organization
# Delete all last estimation values for this organization on this project
cap_module_project.estimation_values.delete_all
# Create estimation_values for the new selected organization
@project.organization.attribute_organizations.each do |am|
['input', 'output'].each do |in_out|
mpa = EstimationValue.create(:pe_attribute_id => am.pe_attribute.id,
:module_project_id => cap_module_project.id,
:in_out => in_out, :is_mandatory => am.is_mandatory,
:description => am.pe_attribute.description, :display_order => nil,
:string_data_low => {:pe_attribute_name => am.pe_attribute.name, :default_low => ''},
:string_data_most_likely => {:pe_attribute_name => am.pe_attribute.name, :default_most_likely => ''},
:string_data_high => {:pe_attribute_name => am.pe_attribute.name, :default_high => ''})
end
end
end
end
end
@project.save
flash[:notice] = I18n.t(:notice_project_successful_updated)
if @project.is_model
redirect_to redirect_apply(edit_project_path(@project, :anchor => session[:anchor]), nil, organization_setting_path(@project.organization, anchor: "tabs-estimation-models")) and return
else
redirect_to redirect_apply(edit_project_path(@project, :anchor => session[:anchor]), nil, organization_estimations_path(@project.organization)) and return
end
else
render :action => 'edit'
end
end
end
def show
@project = Project.find(params[:id])
@organization = @project.organization
set_breadcrumbs "Estimations" => organization_estimations_path(@organization), "#{@project} <span class='badge' style='background-color: #{@project.status_background_color}'>#{@project.status_name}</span>" => edit_project_path(@project)
@project_areas = @organization.project_areas
@platform_categories = @organization.platform_categories
@acquisition_categories = @organization.acquisition_categories
@project_categories = @organization.project_categories
authorize! :show_project, @project
set_page_title 'Show estimation'
# We need to verify user's groups rights on estimation according to the current estimation status
if !can_show_estimation?(@project)
redirect_to(organization_estimations_path(@organization), flash: { warning: I18n.t(:warning_no_show_permission_on_project_status)})
end
@pe_wbs_project_product = @project.pe_wbs_projects.products_wbs.first
#@pe_wbs_project_activity = @project.pe_wbs_projects.activities_wbs.first
@initialization_module_project = @initialization_module.nil? ? nil : @project.module_projects.find_by_pemodule_id(@initialization_module.id)
# Get the max X and Y positions of modules
@module_positions = ModuleProject.where(:project_id => @project.id).order(:position_y).all.map(&:position_y).uniq.max || 1
@module_positions_x = @project.module_projects.order(:position_x).all.map(&:position_x).max
@guw_module = Pemodule.where(alias: "guw").first
@ge_module = Pemodule.where(alias: "ge").first
@ej_module = Pemodule.where(alias: "expert_judgement").first
@ebd_module = Pemodule.where(alias: "effort_breakdown").first
@guw_modules = @project.organization.guw_models.map{|i| [i, "#{i.id},#{@guw_module.id}"] }
@ge_models = @project.organization.ge_models.map{|i| [i, "#{i.id},#{@ge_module.id}"] }
@ej_modules = @project.organization.expert_judgement_instances.map{|i| [i, "#{i.id},#{@ej_module.id}"] }
@wbs_instances = @project.organization.wbs_activities.map{|i| [i, "#{i.id},#{@ebd_module.id}"] }
@modules_selected = (Pemodule.defined.all - [@guw_module, @ge_module, @ej_module, @ebd_module]).map{|i| [i.title,i.id]}
project_root = @project.root
project_tree = project_root.subtree
arranged_projects = project_tree.arrange
array_json_tree = Project.json_tree(arranged_projects)
@projects_json_tree = Hash[*array_json_tree.flatten]
@projects_json_tree = @projects_json_tree.to_json
end
def destroy
@project = Project.find(params[:id])
authorize! :delete_project, @project
is_model = @project.is_model
case params[:commit]
when I18n.t('delete')
if params[:yes_confirmation] == 'selected'
if ((can? :delete_project, @project) || (can? :manage, @project)) && @project.is_childless?
@project.destroy
###current_user.delete_recent_project(@project.id)
session[:project_id] = current_user.projects.first
flash[:notice] = I18n.t(:notice_project_successful_deleted, :value => 'Project')
if !params[:from_tree_history_view].blank? && params['current_showed_project_id'] != params[:id]
redirect_to edit_project_path(:id => params['current_showed_project_id'], :anchor => 'tabs-history')
else
redirect_to (is_model ? organization_setting_path(@current_organization, anchor: "tabs-estimation-models") : organization_estimations_path(@current_organization))
end
else
flash[:warning] = I18n.t(:error_access_denied)
redirect_to (params[:from_tree_history_view].nil? ? organization_estimations_path(@organization) : edit_project_path(:id => params['current_showed_project_id'], :anchor => 'tabs-history'))
end
else
flash[:warning] = I18n.t('warning_need_check_box_confirmation')
render :template => 'projects/confirm_deletion'
end
when I18n.t('cancel')
redirect_to (is_model ? organization_setting_path(@current_organization, anchor: "tabs-estimation-models") : organization_estimations_path(@current_organization))
else
render :template => 'projects/confirm_deletion'
end
end
#Update the project's organization estimation statuses
def update_organization_estimation_statuses
@estimation_statuses = []
unless params[:project_organization_id].nil? || params[:project_organization_id].blank?
@organization = Organization.find(params[:project_organization_id])
if params[:project_id].present?
@project = Project.find(params[:project_id])
# Editing project that does not have estimation status
if @project.estimation_status.nil? || !@organization.estimation_statuses.include?(@project.estimation_status)
# Note: When estimation's organization changed, the status id won't be valid for the new selected organization
initial_status = @organization.estimation_statuses.order(:status_number).first_or_create(organization_id: @project.organization_id, status_number: 0, status_alias: 'preliminary', name: 'Préliminaire', status_color: 'F5FFFD')
@estimation_statuses = [[initial_status.name, initial_status.id]]
else
estimation_statuses = @project.estimation_status.to_transition_statuses.map{ |i| [i.name, i.id]}
estimation_statuses << [@project.estimation_status.name, @project.estimation_status.id]
@estimation_statuses = estimation_statuses.uniq
end
else
initial_status = @organization.estimation_statuses.order(:status_number)
@estimation_statuses = [[initial_status.first.name, initial_status.first.id]]
end
end
@estimation_statuses
end
def confirm_deletion
@project = Project.find(params[:project_id])
authorize! :delete_project, @project
@from_tree_history_view = params[:from_tree_history_view]
@current_showed_project_id = params['current_showed_project_id']
#if @project.has_children? || @project.rejected? || @project.released? || @project.checkpoint?
if @project.has_children?
if @from_tree_history_view
redirect_to edit_project_path(:id => params['current_showed_project_id'], :anchor => 'tabs-history'), :flash => {:warning => I18n.t(:warning_project_cannot_be_deleted)}
else
flash[:warning] = I18n.t(:warning_project_cannot_be_deleted)
redirect_to (@project.is_model ? organization_setting_path(@current_organization, anchor: "tabs-estimation-models") : organization_estimations_path(@current_organization))
end
end
end
def select_categories
#No authorize required
if params[:project_area_selected].is_numeric?
@project_area = ProjectArea.find(params[:project_area_selected])
else
@project_area = ProjectArea.find_by_name(params[:project_area_selected])
end
@project_areas = ProjectArea.all
@platform_categories = PlatformCategory.all
@acquisition_categories = AcquisitionCategory.all
@project_categories = ProjectCategory.all
end
#Load specific security depending of user selected (last tabs on project editing page)
def load_security_for_selected_user
#No authorize required
set_page_title 'Project securities'
@user = User.find(params[:user_id])
@project = Project.find(params[:project_id])
@prj_scrt = ProjectSecurity.find_by_user_id_and_project_id(@user.id, @project.id)
if @prj_scrt.nil?
@prj_scrt = ProjectSecurity.create(:user_id => @user.id, :project_id => @project.id)
end
respond_to do |format|
format.js { render :partial => 'projects/run_estimation' }
end
end
#Load specific security depending of user selected (last tabs on project editing page)
def load_security_for_selected_group
#No authorize required
set_page_title 'Project securities'
@group = Group.find(params[:group_id])
@project = Project.find(params[:project_id])
@prj_scrt = ProjectSecurity.find_by_group_id_and_project_id(@group.id, @project.id)
if @prj_scrt.nil?
@prj_scrt = ProjectSecurity.create(:group_id => @user.id, :project_id => @project.id)
end
respond_to do |format|
format.js { render :partial => 'projects/run_estimation' }
end
end
#Updates the security according to the previous users
def update_project_security_level
#TODO check if No authorize is required
set_page_title 'Project securities'
@user = User.find(params[:user_id].to_i)
@prj_scrt = ProjectSecurity.find_by_user_id_and_project_id(@user.id, @project.id)
@prj_scrt.update_attribute('project_security_level_id', params[:project_security_level])
respond_to do |format|
format.js { render :partial => 'projects/run_estimation' }
end
end
#Updates the security according to the previous users
def update_project_security_level_group
#TODO check if No authorize is required
set_page_title 'Project securities'
@group = Group.find(params[:group_id].to_i)
@prj_scrt = ProjectSecurity.find_by_group_id_and_project_id(@group.id, @project.id)
@prj_scrt.update_attribute('project_security_level_id', params[:project_security_level])
respond_to do |format|
format.js { render :partial => 'projects/run_estimation' }
end
end
#Allow o add or append a pemodule to a estimation process
def append_pemodule
@project = Project.find(params[:project_id])
@pemodule = Pemodule.find(params[:module_selected].split(',').last.to_i)
authorize! :alter_estimation_plan, @project
@initialization_module_project = @initialization_module.nil? ? nil : @project.module_projects.find_by_pemodule_id(@initialization_module.id)
if params[:pbs_project_element_id] && params[:pbs_project_element_id] != ''
@pbs_project_element = PbsProjectElement.find(params[:pbs_project_element_id])
else
@pbs_project_element = @project.root_component
end
unless @pemodule.nil? || @project.nil?
@array_modules = Pemodule.defined
@pemodules ||= Pemodule.defined
#Max pos or 1
@module_positions = ModuleProject.where(:project_id => @project.id).order(:position_y).all.map(&:position_y).uniq.max || 1
@module_positions_x = ModuleProject.where(:project_id => @project.id).all.map(&:position_x).uniq.max
#When adding a module in the "timeline", it creates an entry in the table ModuleProject for the current project, at position 2 (the one being reserved for the input module).
my_module_project = ModuleProject.new(:project_id => @project.id, :pemodule_id => @pemodule.id, :position_y => 1, :position_x => @module_positions_x.to_i + 1)
#Select the default view for module_project
#default_view_for_widgets = View.where("name = ? AND organization_id = ?", "Default view", @project.organization_id).first_or_create(name: "Default view", organization_id: @project.organization_id, :description => "Default view for widgets. If no view is selected for module project, this view will be automatically selected.")
default_view_for_widgets = View.where("organization_id = ? AND pemodule_id = ? AND is_default_view = ?", @project.organization_id, @pemodule.id, true).first_or_create(organization_id: @project.organization_id, pemodule_id: @pemodule.id, is_default_view: true, :name => "Default view for the #{@pemodule}.")
my_module_project.view_id = default_view_for_widgets.id
my_module_project.save
#si le module est un module generic on l'associe le module project
if @pemodule.alias == "guw"
my_module_project.guw_model_id = params[:module_selected].split(',').first
elsif @pemodule.alias == "ge"
my_module_project.ge_model_id = params[:module_selected].split(',').first
elsif @pemodule.alias == "effort_breakdown"
wbs_id = params[:module_selected].split(',').first.to_i
my_module_project.wbs_activity_id = wbs_id
wai = WbsActivityInput.new(module_project_id: my_module_project.id,
wbs_activity_id: wbs_id,
wbs_activity_ratio_id: my_module_project.wbs_activity.wbs_activity_ratios.first )
wai.save
elsif @pemodule.alias == "expert_judgement"
eji_id = params[:module_selected].split(',').first
my_module_project.expert_judgement_instance_id = eji_id.to_i
end
my_module_project.save
@module_positions = ModuleProject.where(:project_id => @project.id).order(:position_y).all.map(&:position_y).uniq.max || 1
@module_positions_x = ModuleProject.where(:project_id => @project.id).all.map(&:position_x).uniq.max
#For each attribute of this new ModuleProject, it copy in the table ModuleAttributeProject, the attributes of modules.
my_module_project.pemodule.attribute_modules.each do |am|
if am.in_out == 'both'
['input', 'output'].each do |in_out|
mpa = EstimationValue.create(:pe_attribute_id => am.pe_attribute.id,
:module_project_id => my_module_project.id,
:in_out => in_out,
:is_mandatory => am.is_mandatory,
:description => am.description,
:display_order => am.display_order,
:string_data_low => {:pe_attribute_name => am.pe_attribute.name, :default_low => am.default_low},
:string_data_most_likely => {:pe_attribute_name => am.pe_attribute.name, :default_most_likely => am.default_most_likely},
:string_data_high => {:pe_attribute_name => am.pe_attribute.name, :default_high => am.default_high},
:custom_attribute => am.custom_attribute,
:project_value => am.project_value)
end
else
mpa = EstimationValue.create(:pe_attribute_id => am.pe_attribute.id,
:module_project_id => my_module_project.id,
:in_out => am.in_out,
:is_mandatory => am.is_mandatory,
:display_order => am.display_order,
:description => am.description,
:string_data_low => {:pe_attribute_name => am.pe_attribute.name, :default_low => am.default_low},
:string_data_most_likely => {:pe_attribute_name => am.pe_attribute.name, :default_most_likely => am.default_most_likely},
:string_data_high => {:pe_attribute_name => am.pe_attribute.name, :default_high => am.default_high},
:custom_attribute => am.custom_attribute,
:project_value => am.project_value)
end
end
#Link initialization module to other modules
unless @initialization_module.nil?
my_module_project.update_attribute('associated_module_project_ids', @initialization_module_project.id) unless @initialization_module_project.nil?
end
end
end
# Select component on project/estimation dashboard
def select_pbs_project_elements
#No authorize required
@project = Project.find(params[:project_id])
@module_projects = @project.module_projects
@initialization_module_project = @initialization_module.nil? ? nil : @module_projects.find_by_pemodule_id(@initialization_module.id)
if params[:pbs_project_element_id] && params[:pbs_project_element_id] != ''
@pbs_project_element = PbsProjectElement.find(params[:pbs_project_element_id])
else
@pbs_project_element = @project.root_component
end
@module_positions = ModuleProject.where(:project_id => @project.id).order(:position_y).all.map(&:position_y).uniq.max || 1
@module_positions_x = ModuleProject.where(:project_id => @project.id).all.map(&:position_x).uniq.max
end
def read_tree_nodes(current_node)
#No authorize required
ordered_list_of_nodes = Array.new
next_nodes = current_node.next.sort { |node1, node2| (node1.position_y <=> node2.position_y) && (node1.position_x <=> node2.position_x) }.uniq
ordered_list_of_nodes = ordered_list_of_nodes + next_nodes
ordered_list_of_nodes.uniq
next_nodes.each do |n|
read_tree_nodes(n)
end
end
def execute_estimation
#pour chaque module
#recupérer les attribut d'entrée
#appeller set_attribut
#end
#end
#current_module_project.nexts.each do |mp|
# mp.pemodule.pe_attributes.each do |attr|
#
# mp_klass = "#{mp.pemodule.alias.camelcase.constantize}::#{mp.pemodule.alias.camelcase.constantize}".gsub(' ', '').constantize
#
# if ""
#
# end
# case mp.pemodule.alias
# when "guw"
# obj = mp_klass.send(:new, @project, current_module_project)
# obj.send("get_#{attr.alias}")
# when "ge"
# obj = mp_klass.send(:new, @project, current_module_project)
# obj.send("get_#{attr.alias}")
#
# p "GE : #{attr.alias}"
# p obj.send("get_#{attr.alias}")
# when "effort_breakdown"
# obj = mp_klass.send(:new, current_component, mp, nil, WbsActivityRatio.first)
# obj.send("get_#{attr.alias}")
#
# p "EB : #{attr.alias}"
# p obj.send("get_#{attr.alias}")
# when "expert_judgement"
# obj = mp_klass.send(:new)
# else
# obj = mp_klass.send(:new)
# end
#ev = EstimationValue.where(module_project_id: mp.id,
# pe_attribute_id: attr.id,
# in_out: "input").first.string_data_low[current_component.id]
#p mp.input_attributes.map(&:name)
#p mp.output_attributes.map(&:name)
#p "==="
# end
#end
#redirect_to dashboard_path(@project)
end
#Run estimation process
def run_estimation(start_module_project = nil, pbs_project_element_id = nil, rest_of_module_projects = nil, set_attributes = nil)
#@project = current_project
authorize! :execute_estimation_plan, @project
@my_results = Hash.new
@last_estimation_results = Hash.new
set_attributes_name_list = {'low' => [], 'high' => [], 'most_likely' => []}
if start_module_project.nil?
pbs_project_element = current_component
pbs_project_element_id = pbs_project_element.id
start_module_project = current_module_project
rest_of_module_projects = crawl_module_project(current_module_project, pbs_project_element)
set_attributes = {'low' => {}, 'most_likely' => {}, 'high' => {}}
['low', 'most_likely', 'high'].each do |level|
params[level].each do |key, hash|
set_attributes[level][key] = hash[current_module_project.id.to_s]
end
end
end
# if the EffortBreakdown module is called, we need to have at least one Wbs-activity/Ratio defined in the PBS or in project level
#if start_module_project.pemodule.alias == Projestimate::Application::EFFORT_BREAKDOWN
# pe_wbs_activity = start_module_project.project.pe_wbs_projects.activities_wbs.first
# project_wbs_project_elt_root = pe_wbs_activity.wbs_project_elements.elements_root.first
# wbs_project_elt_with_ratio = project_wbs_project_elt_root.children.where('is_added_wbs_root = ?', true).first
# #If the PBS has ratio this will be used, otherwise the general Ratio (in project's side) will be used
# if current_component.wbs_activity_ratio.nil? && wbs_project_elt_with_ratio.nil?
# flash[:notice] = "Wbs-Activity est non existant, veuillez choisir un Wbs-activity au projet"
# #return redirect_to(:back, :alert =>"Wbs-Activity est non existant, veuillez choisir un Wbs-activity au projet" )
# redirect_to(root_path(flash: { error: "Wbs-Activity est non existant, veuillez choisir un Wbs-activity au projet"})) and return
# end
#end
# Execution of the first/current module-project
['low', 'most_likely', 'high'].each do |level|
@my_results[level.to_sym] = run_estimation_plan(set_attributes[level], pbs_project_element_id, level, @project, start_module_project)
end
# Save output values: only for current pbs_project_element and for current module-project
# Component parent estimation results is computed again in a asynchronous jobs processing in the "save_estimation_results" method
save_estimation_results(start_module_project, set_attributes, @my_results)
# Need to execute other module_projects if all required input attributes are present
# Get all required attributes for each module (where)
# Get all module_projects from the current_module_project : crawl_module_project(start_module_project)
#until rest_of_module_projects.empty?
# module_project = rest_of_module_projects.shift
#
# @module_project_results = Hash.new
# required_input_attributes = Array.new
# input_attribute_modules = module_project.estimation_values.where('in_out IN (?) AND is_mandatory = ?', %w(input both), true)
# input_attribute_modules.each do |attr_module|
# required_input_attributes << attr_module.pe_attribute.alias
# end
#
# # Verification will be done only if there are some required attribute for the module
# #unless required_input_attributes.empty?
# # Re-initialize the current module_project
# # @my_results is like that {:low => {:complexity_467 => 'organic', :sloc_467 => 10}, :most_likely => {:complexity_467 => 'organic', :sloc_467 => 10}, :hight => {:complexity_467 => 'organic', :sloc_467 => 10}}
# get_all_required_attributes = []
#
# ['low', 'most_likely', 'high'].each do |level|
# level_result = @my_results[level.to_sym]
#
# level_result.each do |key, value|
# attribute_alias = key.to_s.split("_#{start_module_project.id}").first
#
# # For modules with activities
# if start_module_project.pemodule.yes_for_output_with_ratio? || start_module_project.pemodule.yes_for_output_without_ratio? || start_module_project.pemodule.yes_for_input_output_with_ratio? || start_module_project.pemodule.yes_for_input_output_without_ratio?
# value = value.inject({}) { |wbs_value, (k, v)| wbs_value[k.to_s] = v; wbs_value }
# end
#
# set_attributes[level][attribute_alias] = value
# end
#
# # Update the set_attributes_name_list with the last one,
# # Attribute is only added to the set_attributes_name_list if it's present
# set_attributes[level].keys.each { |key| set_attributes_name_list[level] << key }
#
# # Need to verify that all required attributes for this module are present
# # If all required attributes are present
# get_all_required_attributes << ((required_input_attributes & set_attributes_name_list[level]) == required_input_attributes)
# end
#
# at_least_one_all_required_attr = nil
# get_all_required_attributes.each do |elt|
# at_least_one_all_required_attr = elt
# break if at_least_one_all_required_attr == true
# end
#
# #Run the estimation until there is one module_project that doesn't has all required attributes
# catch (:done) do
# throw :done if !at_least_one_all_required_attr
# # Run estimation plan for the current module_project
# run_estimation(module_project, pbs_project_element_id, rest_of_module_projects, set_attributes)
# end
#end
# Get the estimation results by profile for the EffortBreakdown module and save data
#if start_module_project.pemodule.alias == Projestimate::Application::EFFORT_BREAKDOWN
# ###results_with_activities_by_profile
# @current_component = pbs_project_element
# @project_organization = @project.organization
# @project_organization_profiles = @project_organization.organization_profiles
# @module_project = start_module_project
#
# # If Another default ratio was defined in PBS, it will override the one defined in module-project
# if !@current_component.wbs_activity_ratio.nil?
# @ratio_reference = @current_component.wbs_activity_ratio
# else
# # By default, use the project default Ratio as Reference, unless PSB got its own Ratio,
# @ratio_reference = wbs_project_elt_with_ratio.wbs_activity_ratio
# end
#
# @attribute = PeAttribute.find_by_alias_and_record_status_id("effort", @defined_record_status)
# @estimation_values = @module_project.estimation_values.where('pe_attribute_id = ? AND in_out = ?', @attribute.id, "output").first
# @estimation_probable_results = @estimation_values.send('string_data_probable')
# @estimation_pbs_probable_results = @estimation_probable_results[@current_component.id]
#end
redirect_to dashboard_path(@project)
end
# Function that save current module_project estimation result in DB
#Save output values: only for current pbs_project_element
def save_estimation_results(start_module_project, input_attributes, output_data)
#@project = current_project
authorize! :execute_estimation_plan, @project
@pbs_project_element = current_component
# get the estimation_value for the current_pbs_project_element
current_pbs_estimations = start_module_project.estimation_values
current_pbs_estimations.each do |est_val|
est_val_attribute_alias = est_val.pe_attribute.alias
est_val_attribute_type = est_val.pe_attribute.attribute_type
if est_val.in_out == 'output'
out_result = Hash.new
@my_results.each do |res|
['low', 'most_likely', 'high'].each do |level|
# We don't have to replace the value, but we need to update them
level_estimation_value = Hash.new
level_estimation_value = est_val.send("string_data_#{level}")
level_estimation_value_without_consistency = @my_results[level.to_sym]["#{est_val_attribute_alias}_#{start_module_project.id.to_s}".to_sym]
# In case when module use the wbs_project_element, the is_consistent need to be set
if start_module_project.pemodule.yes_for_output_with_ratio? || start_module_project.pemodule.yes_for_output_without_ratio? || start_module_project.pemodule.yes_for_input_output_with_ratio? || start_module_project.pemodule.yes_for_input_output_without_ratio?
psb_level_estimation = level_estimation_value[@pbs_project_element.id]
level_estimation_value[@pbs_project_element.id] = set_element_value_with_activities(level_estimation_value_without_consistency, start_module_project)
else
level_estimation_value[@pbs_project_element.id] = level_estimation_value_without_consistency
end
out_result["string_data_#{level}"] = level_estimation_value
end
# compute the probable value for each node
probable_estimation_value = Hash.new
probable_estimation_value = est_val.send('string_data_probable')
if est_val_attribute_type == 'numeric'
probable_estimation_value[@pbs_project_element.id] = probable_value(@my_results, est_val)
######### if module_project use Ratio for output (like the Effort breakdown estimation module) ###############
# Get the effort per Activity by profile
#if start_module_project.pemodule.yes_for_output_with_ratio? || start_module_project.pemodule.yes_for_input_output_with_ratio?
#copy paste
#end
# We remove the code
else
probable_estimation_value[@pbs_project_element.id] = @my_results[:most_likely]["#{est_val_attribute_alias}_#{est_val.module_project_id.to_s}".to_sym]
end
# Update the pbs probable value
out_result['string_data_probable'] = probable_estimation_value
end
#Update current pbs estimation values
est_val.update_attributes(out_result)
elsif est_val.in_out == 'input'
in_result = Hash.new
['low', 'most_likely', 'high'].each do |level|
level_estimation_value = Hash.new
level_estimation_value = est_val.send("string_data_#{level}")
begin
pbs_level_form_input = input_attributes[level][est_val_attribute_alias]
rescue
pbs_level_form_input = input_attributes[est_val_attribute_alias.to_sym]
end
wbs_root = start_module_project.project.pe_wbs_projects.activities_wbs.first.wbs_project_elements.where('is_root = ?', true).first
if start_module_project.pemodule.yes_for_input? || start_module_project.pemodule.yes_for_input_output_with_ratio? || start_module_project.pemodule.yes_for_input_output_without_ratio?
unless start_module_project.pemodule.alias == 'effort_balancing'
level_estimation_value[@pbs_project_element.id] = compute_tree_node_estimation_value(wbs_root, pbs_level_form_input)
end
else
level_estimation_value[@pbs_project_element.id] = pbs_level_form_input
end
in_result["string_data_#{level}"] = level_estimation_value
end
#calulate the Probable value for the input data
input_probable_estimation_value = Hash.new
input_probable_estimation_value = est_val.send('string_data_probable')
minimum = in_result["string_data_low"][@pbs_project_element.id].to_f
most_likely = in_result["string_data_most_likely"][@pbs_project_element.id].to_f
maximum = in_result["string_data_high"][@pbs_project_element.id].to_f
# The module is not using Ratio and Activities
if !start_module_project.pemodule.yes_for_input? && !start_module_project.pemodule.yes_for_input_output_with_ratio?
if est_val_attribute_type == 'numeric'
input_probable_estimation_value[@pbs_project_element.id] = compute_probable_value(minimum, most_likely, maximum, est_val)[:value] #probable_value(in_result, est_val)
else
input_probable_estimation_value[@pbs_project_element.id] = in_result["string_data_most_likely"][@pbs_project_element.id]
end
#update the iput result with probable value
in_result["string_data_probable"] = input_probable_estimation_value
end
#Update the Input data estimation values
est_val.update_attributes(in_result)
end
# Save estimation for the current component parent
if est_val.save
EstimationsWorker.perform_async(@pbs_project_element.id, est_val.id)
###perform_test(@pbs_project_element.id, est_val.id)
end
end
end
private
# Breadth-First Traversal of a Tree
# This function list the next module_projects according to the given (starting_node) module_project
# compatibility between the module_projects with the current_component is verified
# Then return the module_projects like Tree Breadth
def crawl_module_project(starting_node, pbs_project_element)
#No authorize required since this method is private and won't be call from any route
list = []
items=[starting_node]
until items.empty?
# Returns the first element of items and removes it (shifting all other elements down by one).
item = items.shift
# Get all next module_projects that are linked to the current item
list << item unless list.include?(item)
kids = item.next.select { |i| i.pbs_project_elements.map(&:id).include?(pbs_project_element.id) }
kids = kids.sort { |mp1, mp2| (mp1.position_y <=> mp2.position_y) && (mp1.position_x <=> mp2.position_x) } #Get next module_project
kids.each { |kid| items << kid }
end
list - [starting_node]
end
# Compute the input element value
## values_to_set : Hash
def compute_tree_node_estimation_value(tree_root, values_to_set)
#No authorize required since this method is private and won't be call from any route
WbsActivityElement.rebuild_depth_cache!
new_effort_person_hour = Hash.new
tree_root.children.each do |node|
# Sort node subtree by ancestry_depth
sorted_node_elements = node.subtree.order('ancestry_depth desc')
sorted_node_elements.each do |wbs_project_element|
if wbs_project_element.is_childless?
new_effort_person_hour[wbs_project_element.id] = values_to_set[wbs_project_element.id.to_s]
else
new_effort_person_hour[wbs_project_element.id] = compact_array_and_compute_node_value(wbs_project_element, new_effort_person_hour)
end
end
end
new_effort_person_hour[tree_root.id] = compact_array_and_compute_node_value(tree_root, new_effort_person_hour) ###root_element_effort_person_hour
new_effort_person_hour
end
#This method set result in DB with the :value key for node estimation value
def set_element_value_with_activities(estimation_result, module_project)
authorize! :execute_estimation_plan, @project
result_with_consistency = Hash.new
consistency = true
if !estimation_result.nil? && !estimation_result.eql?('-')
estimation_result.each do |wbs_project_elt_id, est_value|
if module_project.pemodule.alias == 'wbs_activity_completion'
wbs_project_elt = WbsActivityElement.find(wbs_project_elt_id)
if wbs_project_elt.has_new_complement_child?
consistency = set_wbs_completion_node_consistency(estimation_result, wbs_project_elt)
end
result_with_consistency[wbs_project_elt_id] = {:value => est_value, :is_consistent => consistency}
elsif module_project.pemodule.alias == 'effort_balancing'
result_with_consistency[wbs_project_elt_id] = {:value => est_value}
else
result_with_consistency[wbs_project_elt_id] = {:value => est_value}
end
end
else
result_with_consistency = nil
end
result_with_consistency
end
# After estimation, need to know if node value are consistent or not for WBS-Completion modules
def set_wbs_completion_node_consistency(estimation_result, wbs_project_element)
#@project = current_project
authorize! :alter_project_pbs_products, @project
consistency = true
estimation_result_without_null_value = []
wbs_project_element.child_ids.each do |child_id|
value = estimation_result[child_id]
if value.is_a?(Float) or value.is_a?(Integer)
estimation_result_without_null_value << value
end
end
if estimation_result[wbs_project_element.id].to_f != estimation_result_without_null_value.sum.to_f
consistency = false
end
consistency
end
public
# This estimation plan method is called for each component
def run_estimation_plan(input_data, pbs_project_element_id, level, project, current_mp_to_execute)
@project = project #current_project
authorize! :execute_estimation_plan, @project
@result_hash = Hash.new
inputs = Hash.new
# Add the current project id in input data parameters
input_data['current_project_id'.to_sym] = @project.id
#Need to add input for pbs_project_element and module_project
input_data['pbs_project_element_id'.to_sym] = pbs_project_element_id
input_data['module_project_id'.to_sym] = current_mp_to_execute.id
# For Balancing-Module : Estimation will be calculated only for the current selected balancing attribute
if current_mp_to_execute.pemodule.alias.to_s == Projestimate::Application::BALANCING_MODULE
balancing_attr_est_values = current_mp_to_execute.estimation_values.where('in_out = ? AND pe_attribute_id = ?', "output", current_balancing_attribute).last
current_module = "#{current_mp_to_execute.pemodule.alias.camelcase.constantize}::#{current_mp_to_execute.pemodule.alias.camelcase.constantize}".gsub(' ', '').constantize
input_data['pe_attribute_alias'.to_sym] = balancing_attr_est_values.pe_attribute.alias
# Normally, the input data is commonly from the Expert Judgment Module on PBS (when running estimation on its product)
cm = current_module.send(:new, input_data)
@result_hash["#{balancing_attr_est_values.pe_attribute.alias}_#{current_mp_to_execute.id}".to_sym] = cm.send("get_#{balancing_attr_est_values.pe_attribute.alias}", project.id, current_mp_to_execute.id, pbs_project_element_id, level)
# For others modules
else
#current_mp_to_execute.estimation_values.sort! { |a, b| a.in_out <=> b.in_out }.each do |est_val|
current_mp_to_execute.estimation_values.each do |est_val|
current_module = "#{current_mp_to_execute.pemodule.alias.camelcase.constantize}::#{current_mp_to_execute.pemodule.alias.camelcase.constantize}".gsub(' ', '').constantize
input_data['pe_attribute_alias'.to_sym] = est_val.pe_attribute.alias
# Normally, the input data is commonly from the Expert Judgment Module on PBS (when running estimation on its product)
cm = current_module.send(:new, input_data)
if est_val.in_out == 'output' or est_val.in_out=='both'
@result_hash["#{est_val.pe_attribute.alias}_#{current_mp_to_execute.id}".to_sym] = cm.send("get_#{est_val.pe_attribute.alias}", project.id, current_mp_to_execute.id, pbs_project_element_id, level)
end
end
end
@result_hash
end
#Update new project/estimation views and widgets
def update_views_and_widgets(new_prj, old_mp, new_mp)
#For initialization module level
if old_mp.pemodule.alias == Projestimate::Application::INITIALIZATION
#Copy the views and widgets for the new project
new_view = View.create(organization_id: new_prj.organization_id, name: "#{new_prj.to_s} : view for #{new_mp.to_s}", description: "Please rename the view's name and description if needed.")
#We have to copy all the selected view's widgets in a new view for the current module_project
if old_mp.view
old_mp_view_widgets = old_mp.view.views_widgets.all
old_mp_view_widgets.each do |old_view_widget|
new_view_widget_mp = ModuleProject.find_by_project_id_and_copy_id(new_prj.id, old_view_widget.module_project_id)
new_view_widget_mp_id = new_view_widget_mp.nil? ? nil : new_view_widget_mp.id
widget_est_val = old_view_widget.estimation_value
unless widget_est_val.nil?
in_out = widget_est_val.in_out
widget_pe_attribute_id = widget_est_val.pe_attribute_id
unless new_view_widget_mp.nil?
new_estimation_value = new_view_widget_mp.estimation_values.where('pe_attribute_id = ? AND in_out=?', widget_pe_attribute_id, in_out).last
estimation_value_id = new_estimation_value.nil? ? nil : new_estimation_value.id
new_view_widget = ViewsWidget.create(view_id: new_view.id, module_project_id: new_view_widget_mp_id, estimation_value_id: estimation_value_id, name: old_view_widget.name, show_name: old_view_widget.show_name,
icon_class: old_view_widget.icon_class, color: old_view_widget.color, show_min_max: old_view_widget.show_min_max, widget_type: old_view_widget.widget_type,
width: old_view_widget.width, height: old_view_widget.height, position: old_view_widget.position, position_x: old_view_widget.position_x, position_y: old_view_widget.position_y)
pf = ProjectField.where(project_id: new_prj.id, views_widget_id: old_view_widget.id).first
unless pf.nil?
pf.views_widget_id = new_view_widget.id
pf.save
end
end
end
end
end
#update the new module_project view
new_mp.update_attribute(:view_id, new_view.id)
end
end
#Duplicate an estimation/project
def duplicate
# To duplicate a project user need to have the "show_project" and "create_project_from_scratch" authorizations
if params[:action_name] == "duplication"
authorize! :create_project_from_scratch, Project
# To Create a project from a template user need to have "create_project_from_template" authorization
#elsif params[:action_name] == "create_project_from_template"
elsif !params[:create_project_from_template].nil?
authorize! :create_project_from_template, Project
end
@organization = Organization.find(params[:organization_id])
old_prj = Project.find(params[:project_id])
new_prj = old_prj.amoeba_dup #amoeba gem is configured in Project class model
new_prj.status_comment = "#{I18n.l(Time.now)} : #{I18n.t(:estimation_created_from_estimation_by, estimation_name: old_prj, username: current_user.name)} \r\n"
new_prj.ancestry = nil
if params[:action_name] == "duplication_model"
new_prj.is_model = true
else
new_prj.is_model = false
end
#if creation from template
if !params[:create_project_from_template].nil?
new_prj.original_model_id = old_prj.id
#Update some params with the form input data
new_prj.status_comment = "#{I18n.l(Time.now)} : #{I18n.t(:estimation_created_from_model_by, model_name: old_prj, username: current_user.name)} \r\n"
new_prj.title = params['project']['title']
new_prj.version = params['project']['version']
new_prj.description = params['project']['description']
start_date = (params['project']['start_date'].nil? || params['project']['start_date'].blank?) ? Time.now.to_date : params['project']['start_date']
new_prj.start_date = start_date
new_prj.creator_id = current_user.id
#Only the securities for the generated project will be taken in account
new_prj.project_securities = new_prj.project_securities.reject{|i| i.is_model_permission == true }
end
if new_prj.save
old_prj.save #Original project copy number will be incremented to 1
#Update the project securities for the current user who create the estimation from model
#if params[:action_name] == "create_project_from_template"
if !params[:create_project_from_template].nil?
creator_securities = old_prj.creator.project_securities_for_select(new_prj.id)
unless creator_securities.nil?
creator_securities.update_attribute(:user_id, current_user.id)
end
end
#Managing the component tree : PBS
pe_wbs_product = new_prj.pe_wbs_projects.products_wbs.first
# For PBS
new_prj_components = pe_wbs_product.pbs_project_elements
new_prj_components.each do |new_c|
if new_c.is_root == true
if !params[:create_project_from_template].nil?
new_c.name = params['project']['product_name']
new_c.save
end
end
new_ancestor_ids_list = []
new_c.ancestor_ids.each do |ancestor_id|
ancestor_id = PbsProjectElement.find_by_pe_wbs_project_id_and_copy_id(new_c.pe_wbs_project_id, ancestor_id).id
new_ancestor_ids_list.push(ancestor_id)
end
new_c.ancestry = new_ancestor_ids_list.join('/')
new_c.save
end
# For ModuleProject associations
old_prj.module_projects.group(:id).each do |old_mp|
new_mp = ModuleProject.find_by_project_id_and_copy_id(new_prj.id, old_mp.id)
# ModuleProject Associations for the new project
old_mp.associated_module_projects.each do |associated_mp|
new_associated_mp = ModuleProject.where('project_id = ? AND copy_id = ?', new_prj.id, associated_mp.id).first
new_mp.associated_module_projects << new_associated_mp
end
# if the module_project is nil
if new_mp.view.nil?
default_view = @organization.views.where('pemodule_id = ? AND is_default_view = ?', new_mp.pemodule_id, true).first
if default_view.nil?
default_view = View.create(name: "#{new_mp} view", description: "", pemodule_id: new_mp.pemodule_id, organization_id: @organization.id)
end
new_mp.update_attribute(:view_id, default_view.id)
end
#Update the new project/estimation views and widgets
update_views_and_widgets(new_prj, old_mp, new_mp)
#Update the Unit of works's groups
new_mp.guw_unit_of_work_groups.each do |guw_group|
new_pbs_project_element = new_prj_components.find_by_copy_id(guw_group.pbs_project_element_id)
new_pbs_project_element_id = new_pbs_project_element.nil? ? nil : new_pbs_project_element.id
guw_group.update_attribute(:pbs_project_element_id, new_pbs_project_element_id)
# Update the group unit of works and attributes
guw_group.guw_unit_of_works.each do |guw_uow|
new_uow_mp = ModuleProject.find_by_project_id_and_copy_id(new_prj.id, guw_uow.module_project_id)
new_uow_mp_id = new_uow_mp.nil? ? nil : new_uow_mp.id
new_pbs = new_prj_components.find_by_copy_id(guw_uow.pbs_project_element_id)
new_pbs_id = new_pbs.nil? ? nil : new_pbs.id
guw_uow.update_attributes(module_project_id: new_uow_mp_id, pbs_project_element_id: new_pbs_id)
end
end
new_mp.uow_inputs.each do |uo|
new_pbs_project_element = new_prj_components.find_by_copy_id(uo.pbs_project_element_id)
new_pbs_project_element_id = new_pbs_project_element.nil? ? nil : new_pbs_project_element.id
uo.update_attribute(:pbs_project_element_id, new_pbs_project_element_id)
end
["input", "output"].each do |io|
new_mp.pemodule.pe_attributes.each do |attr|
old_prj.pbs_project_elements.each do |old_component|
new_prj_components.each do |new_component|
ev = new_mp.estimation_values.where(pe_attribute_id: attr.id, in_out: io).first
unless ev.nil?
ev.string_data_low[new_component.id.to_i] = ev.string_data_low.delete old_component.id
ev.string_data_most_likely[new_component.id.to_i] = ev.string_data_most_likely.delete old_component.id
ev.string_data_high[new_component.id.to_i] = ev.string_data_high.delete old_component.id
ev.string_data_probable[new_component.id.to_i] = ev.string_data_probable.delete old_component.id
ev.save
end
end
end
end
end
end
flash[:success] = I18n.t(:notice_project_successful_duplicated)
redirect_to edit_project_path(new_prj) and return
else
flash[:error] = I18n.t(:error_project_failed_duplicate)
#if params[:action_name] == "create_project_from_template"
if !params[:create_project_from_template].nil?
redirect_to projects_from_path(organization_id: @organization.id) and return
else
redirect_to organization_estimations_path(@current_organization)
end
end
end
def commit
project = Project.find(params[:project_id])
authorize! :commit_project, project
if !can_modify_estimation?(project)
redirect_to(organization_estimations_path(@current_organization), flash: {warning: I18n.t(:warning_no_show_permission_on_project_status)}) and return
end
#change project's status
project.commit_status
if params[:from_tree_history_view]
redirect_to edit_project_path(:id => params['current_showed_project_id'], :anchor => 'tabs-history')
else
redirect_to organization_estimations_path(@current_organization)
end
end
#Find which projects/estimations are created from this model
def find_use_estimation_model
@project = Project.find(params[:project_id])
authorize! :show_project, @project
@related_projects = Project.where(original_model_id: @project.id).all
end
#Find where is used the project
def find_use_project
@project = Project.find(params[:project_id])
authorize! :show_project, @project
@related_projects = Array.new
@related_projects_inverse = Array.new
unless @project.nil?
related_pe_wbs_project = @project.pe_wbs_projects.products_wbs
related_pbs_projects = PbsProjectElement.where(:pe_wbs_project_id => related_pe_wbs_project)
unless related_pe_wbs_project.empty?
related_pbs_projects.each do |pbs|
unless pbs.project_link.nil? or pbs.project_link.blank?
p = Project.find_by_id(pbs.project_link)
@related_projects << p
end
end
end
end
related_pbs_project_elements = PbsProjectElement.where('project_link IN (?)', [params[:project_id]]).all
related_pbs_project_elements.each do |i|
@related_projects_inverse << i.pe_wbs_project.project
end
@related_users = @project.organization.users
@related_groups = @project.organization.groups
end
def projects_global_params
set_page_title 'Project global parameters'
end
def sort_direction
%w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc'
end
def default_work_element_type
wet = @current_organization.work_element_types.first_or_create(name: "Default", alias: "default")
end
#Add/Import a WBS-Activity template from Library to Project
def add_wbs_activity_to_project
@project = Project.find(params[:project_id])
@pe_wbs_project_activity = @project.pe_wbs_projects.activities_wbs.first
@wbs_project_elements_root = @project.wbs_project_element_root
selected_wbs_activity_elt = WbsActivityElement.find(params[:wbs_activity_element])
# Delete all other wbs_project_elements when the wbs_project_element is valide
#wbs_project_elements_to_delete = @project.wbs_project_elements.where('id != ?', @wbs_project_elements_root.id)
#@project.wbs_project_elements.where('is_root != ?', true).destroy_all
@project.wbs_project_elements.where(:is_root => [nil, false]).destroy_all
wbs_project_element = WbsProjectElement.new(:pe_wbs_project_id => @pe_wbs_project_activity.id, :wbs_activity_element_id => selected_wbs_activity_elt.id,
:wbs_activity_id => selected_wbs_activity_elt.wbs_activity_id, :name => selected_wbs_activity_elt.name,
:description => selected_wbs_activity_elt.description, :ancestry => @wbs_project_elements_root.id,
:author_id => current_user.id, :copy_number => 0,
:wbs_activity_ratio_id => params[:project_default_wbs_activity_ratio], # Update Project default Wbs-Activity-Ratio
:is_added_wbs_root => true)
selected_wbs_activity_children = selected_wbs_activity_elt.children
respond_to do |format|
#wbs_project_element.transaction do
if wbs_project_element.save
selected_wbs_activity_children.each do |child|
create_wbs_activity_from_child(child, @pe_wbs_project_activity, @wbs_project_elements_root)
end
#add some additional information for leaf element customization
added_wbs_project_elements = WbsProjectElement.find_all_by_wbs_activity_id_and_pe_wbs_project_id(wbs_project_element.wbs_activity_id, @pe_wbs_project_activity.id)
added_wbs_project_elements.each do |project_elt|
if project_elt.has_children?
project_elt.can_get_new_child = false
else
project_elt.can_get_new_child = true
end
project_elt.save
end
@project.included_wbs_activities.push(wbs_project_element.wbs_activity_id)
if @project.save
flash[:notice] = I18n.t(:notice_wbs_activity_successful_added)
else
flash[:error] = "#{@project.errors.full_messages.to_sentence}"
end
else
flash[:error] = "#{wbs_project_element.errors.full_messages.to_sentence}"
end
#end
format.html { redirect_to edit_project_path(@project, :anchor => 'tabs-3') }
format.js { redirect_to edit_project_path(@project, :anchor => 'tabs-3') }
end
end
private
def get_new_ancestors(node, pe_wbs_activity, wbs_elt_root)
#No authorize required since this method is private and won't be call from any route
node_ancestors = node.ancestry.split('/')
new_ancestors = []
new_ancestors << wbs_elt_root.id
node_ancestors.each do |ancestor|
corresponding_wbs_project = WbsProjectElement.where('wbs_activity_element_id = ? and pe_wbs_project_id = ?', ancestor, pe_wbs_activity.id).first
new_ancestors << corresponding_wbs_project.id
end
new_ancestors.join('/')
end
def create_wbs_activity_from_child(node, pe_wbs_activity, wbs_elt_root)
project = pe_wbs_activity.project
authorize! :alter_wbsactivities, @project
wbs_project_element = WbsProjectElement.new(:pe_wbs_project_id => pe_wbs_activity.id, :wbs_activity_element_id => node.id, :wbs_activity_id => node.wbs_activity_id, :name => node.name,
:description => node.description, :ancestry => get_new_ancestors(node, pe_wbs_activity, wbs_elt_root), :author_id => current_user.id, :copy_number => 0)
wbs_project_element.transaction do
wbs_project_element.save
if node.has_children?
node_children = node.children
node_children.each do |node_child|
ActiveRecord::Base.transaction do
create_wbs_activity_from_child(node_child, pe_wbs_activity, wbs_elt_root)
end
end
end
end
end
public
def refresh_wbs_project_elements
@project = Project.find(params[:project_id])
authorize! :edit_project, @project
@pe_wbs_project_activity = @project.pe_wbs_projects.activities_wbs.first
@show_hidden = params[:show_hidden]
@is_project_show_view = params[:is_project_show_view]
end
#On edit page, select ratios according to the selected wbs_activity
def refresh_wbs_activity_ratios
if params[:wbs_activity_element_id].empty? || params[:wbs_activity_element_id].nil?
@wbs_activity_ratios = []
else
selected_wbs_activity_elt = WbsActivityElement.find(params[:wbs_activity_element_id])
@wbs_activity = selected_wbs_activity_elt.wbs_activity
@wbs_activity_ratios = @wbs_activity.wbs_activity_ratios
end
end
# On the project edit view, we are going to show to user the current selected WBS-Activity elements
# without adding it to the project until it saves it with the "Add" button
def render_selected_wbs_activity_elements
@project = Project.find(params[:project_id])
authorize! :edit_project, @project
@pe_wbs_project_activity = @project.pe_wbs_projects.activities_wbs.first
@show_hidden = params[:show_hidden]
@is_project_show_view = params[:is_project_show_view]
@wbs_activity_element = WbsActivityElement.find(params[:wbs_activity_elt_id])
@wbs_activity = @wbs_activity_element.wbs_activity
@wbs_activity_elements_list = @wbs_activity.wbs_activity_elements
@wbs_activity_elements = WbsActivityElement.sort_by_ancestry(@wbs_activity_elements_list)
@wbs_activity_ratios = @wbs_activity.wbs_activity_ratios
@wbs_activity_organization = @wbs_activity.organization
@wbs_organization_profiles = @wbs_activity_organization.nil? ? [] : @wbs_activity_organization.organization_profiles
@wbs_activity_ratio_elements = []
@total = 0
if params[:Ratio]
@wbs_activity_elements.each do |wbs|
@wbs_activity_ratio_elements += wbs.wbs_activity_ratio_elements.where(:wbs_activity_ratio_id => params[:Ratio])
@total = @wbs_activity_ratio_elements.reject{|i| i.ratio_value.nil? or i.ratio_value.blank? }.compact.sum(&:ratio_value)
end
else
unless @wbs_activity.wbs_activity_ratios.empty?
@wbs_activity_elements.each do |wbs|
@wbs_activity_ratio_elements += wbs.wbs_activity_ratio_elements.where(:wbs_activity_ratio_id => @wbs_activity.wbs_activity_ratios.first.id)
end
@total = @wbs_activity_ratio_elements.reject{|i| i.ratio_value.nil? or i.ratio_value.blank? }.compact.sum(&:ratio_value)
end
end
end
def locked_plan
@project = Project.find(params[:project_id])
authorize! :alter_estimation_plan, @project
@project.locked? ? @project.is_locked = false : @project.is_locked = true
@project.save
redirect_to edit_project_path(@project, :anchor => 'tabs-4')
end
def projects_from
authorize! :create_project_from_template, Project
@organization = Organization.find(params[:organization_id])
@estimation_models = @organization.projects.where(:is_model => true)
end
#Set the checkout version
def set_checkout_version
@project = Project.find(params[:project_id])
end
#Checkout the project : create a new version of the project
def checkout
old_prj = Project.find(params[:project_id])
authorize! :commit_project, old_prj
#if !can_modify_estimation?(project)
if !(can_alter_estimation?(old_prj) && can?(:commit_project, old_prj))
redirect_to(organization_estimations_path(@current_organization), flash: {warning: I18n.t(:warning_checkout_unauthorized_action)}) and return
end
# If project is not childless, a new branch need to be created
# And user need have the "allow_to_create_branch" permission to create new branch
if old_prj.has_children? && (cannot? :allow_to_create_branch, old_prj)
redirect_to organization_estimations_path(@current_organization), :flash => {:warning => I18n.t('warning_not_allow_to_create_new_branch_of_project')} and return
end
begin
old_prj_copy_number = old_prj.copy_number
old_prj_pe_wbs_product_name = old_prj.pe_wbs_projects.products_wbs.first.name
#old_prj_pe_wbs_activity_name = old_prj.pe_wbs_projects.activities_wbs.first.name
new_prj = old_prj.amoeba_dup #amoeba gem is configured in Project class model
old_prj.copy_number = old_prj_copy_number
new_prj.title = old_prj.title
new_prj.alias = old_prj.alias
new_prj.description = params[:description]
new_prj.parent_id = old_prj.id
new_prj.version = params[:new_version] #set_project_version(old_prj)
if params[:new_version].nil? || params[:new_version].empty?
new_prj.version = set_project_version(old_prj)
end
new_prj.status_comment = "#{I18n.l(Time.now)} : #{I18n.t(:change_estimation_version_from_to, from_version: old_prj.version, to_version: new_prj.version, current_user_name: current_user.name)}. \r\n"
if new_prj.save
old_prj.save #Original project copy number will be incremented to 1
#Managing the component tree : PBS
pe_wbs_product = new_prj.pe_wbs_projects.products_wbs.first
#pe_wbs_activity = new_prj.pe_wbs_projects.activities_wbs.first
pe_wbs_product.name = old_prj_pe_wbs_product_name
#pe_wbs_activity.name = old_prj_pe_wbs_activity_name
pe_wbs_product.save
#pe_wbs_activity.save
# For PBS
new_prj_components = pe_wbs_product.pbs_project_elements
new_prj_components.each do |new_c|
unless new_c.is_root?
new_ancestor_ids_list = []
new_c.ancestor_ids.each do |ancestor_id|
ancestor_id = PbsProjectElement.find_by_pe_wbs_project_id_and_copy_id(new_c.pe_wbs_project_id, ancestor_id).id
new_ancestor_ids_list.push(ancestor_id)
end
new_c.ancestry = new_ancestor_ids_list.join('/')
# For PBS-Project-Element Links with modules
#old_pbs = PbsProjectElement.find(new_c.copy_id)
#new_c.module_projects = old_pbs.module_projects
new_c.save
end
end
# For ModuleProject associations
old_prj.module_projects.group(:id).each do |old_mp|
new_mp = ModuleProject.find_by_project_id_and_copy_id(new_prj.id, old_mp.id)
# ModuleProject Associations for the new project
old_mp.associated_module_projects.each do |associated_mp|
new_associated_mp = ModuleProject.where('project_id = ? AND copy_id = ?', new_prj.id, associated_mp.id).first
new_mp.associated_module_projects << new_associated_mp
end
#For initialization module level
update_views_and_widgets(new_prj, old_mp, new_mp)
#Update the Unit of works's groups
new_mp.guw_unit_of_work_groups.each do |guw_group|
new_pbs_project_element = new_prj_components.find_by_copy_id(guw_group.pbs_project_element_id)
new_pbs_project_element_id = new_pbs_project_element.nil? ? nil : new_pbs_project_element.id
guw_group.update_attribute(:pbs_project_element_id, new_pbs_project_element_id)
# Update the group unit of works and attributes
guw_group.guw_unit_of_works.each do |guw_uow|
new_uow_mp = ModuleProject.find_by_project_id_and_copy_id(new_prj.id, guw_uow.module_project_id)
new_uow_mp_id = new_uow_mp.nil? ? nil : new_uow_mp.id
new_pbs = new_prj_components.find_by_copy_id(guw_uow.pbs_project_element_id)
new_pbs_id = new_pbs.nil? ? nil : new_pbs.id
guw_uow.update_attributes(module_project_id: new_uow_mp_id, pbs_project_element_id: new_pbs_id)
end
end
new_mp.uow_inputs.each do |uo|
new_pbs_project_element = new_prj_components.find_by_copy_id(uo.pbs_project_element_id)
new_pbs_project_element_id = new_pbs_project_element.nil? ? nil : new_pbs_project_element.id
uo.update_attribute(:pbs_project_element_id, new_pbs_project_element_id)
end
["input", "output"].each do |io|
new_mp.pemodule.pe_attributes.each do |attr|
old_prj.pbs_project_elements.each do |old_component|
new_prj_components.each do |new_component|
ev = new_mp.estimation_values.where(pe_attribute_id: attr.id, in_out: io).first
unless ev.nil?
ev.string_data_low[new_component.id.to_i] = ev.string_data_low.delete old_component.id
ev.string_data_most_likely[new_component.id.to_i] = ev.string_data_most_likely.delete old_component.id
ev.string_data_high[new_component.id.to_i] = ev.string_data_high.delete old_component.id
ev.string_data_probable[new_component.id.to_i] = ev.string_data_probable.delete old_component.id
ev.save
end
end
end
end
end
end
flash[:success] = I18n.t(:notice_project_successful_checkout)
redirect_to (edit_project_path(new_prj, :anchor => "tabs-history")), :notice => I18n.t(:notice_project_successful_checkout) and return
#raise "#{RuntimeError}"
else
flash[:error] = I18n.t(:error_project_checkout_failed)
redirect_to organization_estimations_path(@current_organization), :flash => {:error => I18n.t(:error_project_checkout_failed)} and return
end
rescue
flash[:error] = I18n.t(:error_project_checkout_failed)
redirect_to organization_estimations_path(@current_organization), :flash => {:error => I18n.t(:error_project_checkout_failed)} and return
##redirect_to(edit_project_path(old_prj, :anchor => 'tabs-history'), :flash => {:error => I18n.t(:error_project_checkout_failed)} ) and return
end
#else
#redirect_to "#{session[:return_to]}", :flash => {:warning => I18n.t('warning_project_cannot_be_checkout')}
#end # END commit permission
end
private
# Set the new checked-outed project version
def set_project_version(project_to_checkout)
#No authorize is required as method is private and could not be accessed by any route
new_version = ''
parent_version = project_to_checkout.version
# The new version number is calculated according to the parent project position (if parent project has children or not)
if project_to_checkout.is_childless?
# get the version last numerical value
version_ended = parent_version.split(/(\d\d*)$/).last
#Test if ended version value is a Integer
if version_ended.valid_integer?
new_version_ended = "#{ version_ended.to_i + 1 }"
new_version = parent_version.gsub(/(\d\d*)$/, new_version_ended)
else
new_version = "#{ version_ended }.1"
end
else
#That means project has successor(s)/children, and a new branch need to be created
branch_version = 1
branch_name = ''
parent_version_ended_end = 0
if parent_version.include?('-')
split_parent_version = parent_version.split('-')
branch_name = split_parent_version.first
parent_version_ended = split_parent_version.last
split_parent_version_ended = parent_version_ended.split('.')
parent_version_ended_begin = split_parent_version_ended.first
parent_version_ended_end = split_parent_version_ended.last
branch_version = parent_version_ended_begin.to_i + 1
#new_version = parent_version.gsub(/(-.*)/, "-#{branch_version}")
new_version = "#{branch_name}-#{branch_version}.#{parent_version_ended_end}"
else
branch_name = parent_version
new_version = "#{branch_name}-#{branch_version}.0"
end
# If new_version is not available, then check for new available version
until is_project_version_available?(project_to_checkout.title, project_to_checkout.alias, new_version)
branch_version = branch_version+1
new_version = "#{branch_name}-#{branch_version}.#{parent_version_ended_end}"
end
end
new_version
end
#Function that check the couples (title,version) and (alias, version) availability
def is_project_version_available?(parent_title, parent_alias, new_version)
begin
#No authorize required
project = Project.where('(title=? AND version=?) OR (alias=? AND version=?)', parent_title, new_version, parent_alias, new_version).first
if project
false
else
true
end
rescue
false
end
end
public
#Filter the projects list according to version
def add_filter_on_project_version
#No authorize required
selected_filter_version = params[:filter_selected]
#"Display leaves projects only",1], ["Display all versions",2], ["Display root version only",3], ["Most recent version",4]
# The current user can only see projects of its organizations
@organization_user_projects = []
current_user.organizations.each do |organization|
@organization_user_projects << organization.projects.all
end
# Differents parameters according to the page on witch the filter is set ("filter_projects_version", "filter_organization_projects_version", "filter_user_projects_version","filter_group_projects_version")
case params[:project_list_name]
when "filter_projects_version"
# Then only projects on which the current is authorise to see will be displayed
@projects = @organization_user_projects.flatten ###& current_user.projects
when "filter_organization_projects_version"
# The current organizations's projects
organization_id = params['organization_id']
if organization_id.present? && organization_id != 'undefined'
@organization = Organization.find(organization_id.to_i)
@projects = @organization.projects.all
end
else
@projects = @organization_user_projects.flatten ###& current_user.projects
end
unless selected_filter_version.empty?
case selected_filter_version
when '1' #Display leaves projects only
@projects = @projects.reject { |i| !i.is_childless? }
when '2' #Display all versions
@projects = @projects
when '3' #Display root version only
@projects = @projects.reject { |i| !i.is_root? }
when '4' #Most recent version
#@projects = @projects.reorder('updated_at DESC').uniq_by(&:title)
@projects = @projects.sort{ |x,y| y.updated_at <=> x.updated_at }.uniq(&:title)
else
@projects = @projects #Project.all
end
end
@projects = @projects.reject{|i| i.is_model == true}
end
#Function that manage link_to from project history graphical view
def show_project_history
#No authorize required as authorizations are manage in each called function...
@counter = params['counter']
checked_node_ids = params['checked_node_ids']
action_id = params['action_id']
@string_url = ""
if @counter.to_i > 0
begin
project_id = checked_node_ids.first
organization = Project.find(project_id).organization
case action_id
when "edit_node_path"
@string_url = edit_project_path(:id => project_id)
when "delete_node_path"
@string_url = confirm_deletion_path(:project_id => project_id, :from_tree_history_view => true, :current_showed_project_id => params['current_showed_project_id'])
when "activate_node_path"
@string_url = dashboard_path(:project_id => project_id)
when "find_use_projects" #when "find_use_node_path"
@string_url = find_use_project_path(:project_id => project_id)
when "promote_node_path"
@string_url = commit_path(:project_id => project_id, :from_tree_history_view => true, :current_showed_project_id => params['current_showed_project_id'])
when "duplicate_node_path"
@string_url = "/projects/#{project_id}/duplicate?organization_id=#{organization.id}"
when "checkout_node_path"
@string_url = checkout_path(:project_id => project_id)
#when "collapse_node_path"
#@string_url = collapse_project_version_path(:project_ids => params[:project_ids], :from_tree_history_view => true, :current_showed_project_id => params['current_showed_project_id'])
when "set_checkout_version_path"
@string_url = set_checkout_version_path(:project_id => project_id)
else
@string_url = session[:return_to]
end
rescue
@string_url = session[:return_to]
end
end
end
#Function for collapsing project version
def collapse_project_version
projects = Project.find_all_by_id(params[:project_ids])
flash_error = ""
Project.transaction do
projects.each do |project|
begin
authorize! :delete_project, project
if is_collapsible?(project.reload)
project_parent = project.parent
project_child = project.children.first
#delete link between project to delete and its parent and child
new_ancestry = project_child.ancestor_ids.delete_if { |x| x == project.id }.join("/")
#project_child.update_attribute project.class.ancestry_column, new_ancestry || nil
project_child.update_attribute(:parent, project_parent)
project_child.save
project.destroy
###current_user.delete_recent_project(project.id)
session[:current_project_id] = current_user.projects.first
session[:project_id] = current_user.projects.first
else
flash_error += "\n\n" + I18n.t('project_is_not_collapsible', :project_title_version => "#{project.title}-#{project.version}")
next
end
rescue CanCan::AccessDenied
flash_error += "\n\n" + I18n.t('project_is_not_collapsible', :project_title_version => "#{project.title}-#{project.version}") + "," + I18n.t(:error_access_denied)
next
end
end
end
unless flash_error.blank?
flash[:error] = flash_error + I18n.t('collapsible_project_only')
end
if params['current_showed_project_id'].nil? || (params['current_showed_project_id'] && params['current_showed_project_id'].in?(params[:project_ids]) )
redirect_to organization_estimations_path(@current_organization), :notice => I18n.t('notice_successful_collapse_project_version')
else
redirect_to edit_project_path(:id => params['current_showed_project_id'], :anchor => 'tabs-history'), :notice => I18n.t('notice_successful_collapse_project_version')
end
end
#Function that check if project is collapsible
def is_collapsible?(project)
#No authorize is required
begin
if project.checkpoint?
if !project.is_root? && project.child_ids.length==1
true
else
false
end
else
false
end
rescue
false
end
end
def show_module_configuration
end
# Display the estimation results with activities by profile
def results_with_activities_by_profile
authorize! :execute_estimation_plan, @project
@current_component = current_component
@project_organization = @project.organization
@project_organization_profiles = @project_organization.organization_profiles
@module_project = current_module_project
# Project pe_wbs_activity
pe_wbs_activity = @project.pe_wbs_projects.activities_wbs.first
# Get the wbs_project_element which contain the wbs_activity_ratio
project_wbs_project_elt_root = pe_wbs_activity.wbs_project_elements.elements_root.first
#wbs_project_elt_with_ratio = WbsProjectElement.where("pe_wbs_project_id = ? and wbs_activity_id = ? and is_added_wbs_root = ?", pe_wbs_activity.id, @pbs_project_element.wbs_activity_id, true).first
# If we manage more than one wbs_activity per project, this will be depend on the wbs_project_element ancestry(witch has the wbs_activity_ratio)
wbs_project_elt_with_ratio = project_wbs_project_elt_root.children.where('is_added_wbs_root = ?', true).first
# By default, use the project default Ratio as Reference, unless PSB got its own Ratio,
@ratio_reference = wbs_project_elt_with_ratio.wbs_activity_ratio
# If Another default ratio was defined in PBS, it will override the one defined in module-project
if !@current_component.wbs_activity_ratio.nil?
@ratio_reference = @current_component.wbs_activity_ratio
end
@attribute = PeAttribute.find_by_alias_and_record_status_id("effort", @defined_record_status)
@estimation_values = @module_project.estimation_values.where('pe_attribute_id = ? AND in_out = ?', @attribute.id, "output").first
@estimation_probable_results = @estimation_values.send('string_data_probable')
@estimation_pbs_probable_results = @estimation_probable_results[@current_component.id]
end
# Function that show the estimation graph
#def show_estimation_graph
# @timeline = []
# @project = current_project
# @current_module_project = current_module_project
# @component = current_component
#
# #unless @current_module_project.pemodule.alias == Projestimate::Application::EFFORT_BREAKDOWN
# delay = PeAttribute.where(alias: "delay").first
# end_date = PeAttribute.where(alias: "end_date").first
# staffing = PeAttribute.where(alias: "staffing").first
# effort = PeAttribute.where(alias: "effort").first
#
# products = @project.root_component.subtree.sort_by(&:position)
# products.each_with_index do |element, i|
# begin
# dev = EstimationValue.where(pe_attribute_id: delay.id, module_project_id: @current_module_project.id).first.string_data_probable[element.id]
# if !dev.nil?
# d = dev.to_f
# if d.nil?
# dh = 1.hours
# else
# dh = d.hours
# end
#
# ed = EstimationValue.where(pe_attribute_id: end_date.id, module_project_id: @current_module_project.id).first.string_data_probable[element.id]
#
# @component.end_date = ed
# @component.save
#
# unless dh.nan?
# @timeline << [element.name,
# element.start_date.nil? ? @project.start_date : element.start_date,
# element.start_date.nil? ? @project.start_date + dh : element.start_date + dh]
# else
# @timeline << [element.name, element.start_date.nil? ? @project.start_date : element.start_date, element.start_date.nil? ? @project.start_date : element.start_date]
# end
# end
# rescue
#
# end
# end
#
# #begin
# # @timeline[0][2] = @timeline.map(&:last).max
# #rescue
# #end
#
# unless @current_module_project.pemodule.alias == Projestimate::Application::EFFORT_BREAKDOWN
# k = EstimationValue.where(pe_attribute_id: effort.id, module_project_id: @current_module_project.id).first.string_data_probable[current_component.id].to_i
# a = 2
# m = EstimationValue.where(module_project_id: current_module_project.id, pe_attribute_id: delay.id).first.string_data_probable[current_component.id].to_f / current_project.organization.number_hours_per_month
# if !k.nil?
# @schedule_hash = {}
# ((0..m).to_a).each do |i|
# #@schedule_hash[i.to_s] = 3*i**0.33
# t = i/12.to_f
# @schedule_hash[i.to_s] = 2*k*a*t*Math.exp(-(a)*t*t)
# end
# end
#
# k = EstimationValue.where(pe_attribute_id: effort.id, module_project_id: @current_module_project.id).first.string_data_probable[current_component.id].to_i
# p k
# p effort
# p @current_module_project.id
# p current_component.id
#
# begin
# @schedule_hash2 = {}
# ((0..k).to_a).each do |i|
# @schedule_hash2[i.to_s] = 3*i**0.33
# end
# rescue
# @schedule_hash2 = {}
# ((0..100).to_a).each do |i|
# @schedule_hash2[i.to_s] = 3*i**0.33
# end
# end
# end
#
#
# #Barchart
# @efforts = Hash.new
# results = EstimationValue.where(module_project_id: @current_module_project.id, in_out: "output").all
# results.each do |result|
# level_values = []
# ["low", "most_likely", "high"].each do |level|
# level_values << [level, result.send("string_data_#{level}")[current_component.id]]
# end
# @efforts[result.pe_attribute.name] = level_values
# end
#
#
# @project_organization = @project.organization
# @project_module_projects = @project.module_projects
# # the current activated component (PBS)
# @current_component = current_component
#
# #get the current activated module project
# @current_mp_attributes = []
# @input_dataset = {}
# @all_cocomo_advanced_factors_names = []
# @complexities_name = []
# @organization_uow_complexities = []
# @cocomo_advanced_input_dataset = {}
# # Dataset of the effort-breakdown stacked bar chart
# @effort_breakdown_stacked_bar_dataset = {}
# # the Cocomo_advanced = Cocomo_Intermediate factors
# @cocomo_advanced_factor_corresponding = []
# # The CocomoII = Cocomo_Expert factors
# @cocomo2_factors_corresponding = []
# # Contains all attribute name according to their aliases
# @all_attributes_names = {"effort_person_hour" => I18n.t(:effort_person_hour), "effort" => I18n.t(:effort), "effort_person_week" => I18n.t(:effort_person_week), "cost" => I18n.t(:cost),
# "delay" => I18n.t(:delay), "end_date" => I18n.t(:end_date), "staffing" => I18n.t(:staffing), "staffing_complexity" => I18n.t(:staffing_complexity), "duration" => I18n.t(:duration),
# "effective_technology" => I18n.t(:effective_technology), "schedule" => I18n.t(:schedule), "defects"=>I18n.t(:defects), "note" => I18n.t(:note), "methodology" => I18n.t(:methodology),
# "real_time_constraint" => I18n.t(:real_time_constraint), "platform_maturity" => I18n.t(:platform_maturity), "list_sandbox" => I18n.t(:list_sandbox), "date_sandbox"=>I18n.t(:date_sandbox),
# "description_sandbox"=>I18n.t(:description_sandbox), "float_sandbox" =>I18n.t(:float_sandbox), "integer_sandbox"=> I18n.t(:integer_sandbox), "complexity"=>I18n.t(:complexity),
# "sloc"=>I18n.t(:sloc), "sloc"=>I18n.t(:sloc), "size"=>I18n.t(:size)}
#
# # Attributes Unit : Table of Attributes units according to their aliases
# @attribute_yAxisUnit_array = {
# 'cost' => (@project_organization.currency.nil? ? "Unit" : @project_organization.currency.name.capitalize),
# 'effort' => I18n.t(:unit_effort), 'effort_person_hour' => I18n.t(:unit_effort_person_hour),
# 'delay' => I18n.t(:unit_delay), 'end_date' => I18n.t(:unit_end_date), 'staffing' => I18n.t(:unit_staffing),
# 'sloc' => I18n.t(:unit_sloc), 'sloc' => I18n.t(:unit_sloc)
# }
#
# #========================================== CocomoIntermediate (CocomoAdvanced) AND CocomoII (CocomoExpert) modules data =============================================
#
# #if @current_module_project.pemodule.alias == Projestimate::Application::COCOMO_ADVANCED
# if @current_module_project.pemodule.alias.in? Projestimate::Application::MODULES_WITH_FACTORS
# # get the factors for the CocomoAdvanced and CocomoII estimation modules: the data are stored in the "input_cocomos" table that make links between the factors and the CocomoAdvanced module
# @complexities_name = @current_module_project.organization_uow_complexities.map(&:name).uniq
# @cocomo_advanced_factors = @current_module_project.factors #Factor.where('factor_type = ?', "advanced") #
# @all_cocomo_advanced_factors_names = @cocomo_advanced_factors.map(&:name)
# current_module_project_name = @current_module_project.pemodule.alias
#
# coefficients_hash = {"Extra Low" => 1, "Very Low" => 2, "Low" => 3, "Normal" => 4, "High" => 5, "Very High" => 6, "Extra High" => 7}
# # Median value correspond to the "Default" value defined by the Organization
# @cocomo_advanced_input_dataset["default"] = Array.new
# @cocomo_advanced_input_dataset["#{current_module_project_name}"] = Array.new
#
# factor_data = {}
# @complexities_name.each do |complexity_name|
# factor_data["#{complexity_name}"] = Array.new
# end
#
# project_organization =
# # dataset for the Radar chart about Factors
# @current_module_project.input_cocomos.where('pbs_project_element_id = ?', @current_component.id).each do |input_cocomo|
# @cocomo_advanced_factor_corresponding << input_cocomo.factor.name
# @cocomo_advanced_input_dataset["#{current_module_project_name}"] << coefficients_hash[input_cocomo.organization_uow_complexity.name]
#
# ###@cocomo_advanced_input_dataset["median"] << coefficients_hash["Normal"]
# # The Median value will be the value defined in the project's organization default factors values
# #org_factor_with_default_cplex = input_cocomo.factor.organization_uow_complexities.where('organization_id=? AND is_default = ?', @project_organization.id, true)
# org_factor_uow_with_default_cplex = input_cocomo.factor.organization_uow_complexities.where('organization_id=? AND is_default = ?', @project_organization.id, true).first
# if org_factor_uow_with_default_cplex.nil?
# # Median value will be set to 0
# @cocomo_advanced_input_dataset["default"] << 0
# else
# @cocomo_advanced_input_dataset["default"] << coefficients_hash[org_factor_uow_with_default_cplex.name]
# end
# end
#
# attr_staffing = PeAttribute.where('alias=? AND record_status_id=? ', "staffing", @defined_status).first
# staffing = @current_module_project.estimation_values.where(pe_attribute_id: attr_staffing.id).first.string_data_probable[current_component.id]
# @staffing_profile_data = []
# begin
# @staffing_profile_data << staffing.to_i
# rescue
# @staffing_profile_data << nil.to_i
# end
#
# #Rayleigh
# @staffing_profile_data = []
# @staffing_labels = []
#
# #begin
# attr_effort = PeAttribute.find_by_alias('effort')
# attr_delay = PeAttribute.find_by_alias('delay')
#
# delay = EstimationValue.where(module_project_id: current_module_project.id, pe_attribute_id: attr_delay.id).last.string_data_probable[current_component.id]
# effort = EstimationValue.where(module_project_id: current_module_project.id, pe_attribute_id: attr_effort.id).last.string_data_probable[current_component.id]
#
# m = delay.to_f / current_project.organization.number_hours_per_month
# k = effort
# a = 2 #pente
#
# m.floor.times do |i|
# t = i/12.to_f
# @staffing_labels << i
# @staffing_profile_data << 2*k*a*t*Math.exp(-(a)*t*t)
# end
# #rescue
# #end
#
# puts "ALL FACTOR_DATA LAST = #{@cocomo_advanced_input_dataset}"
# end
#
# #======================================== CURRENT MODULE OUTPUTS DATA ==============================================
# @current_mp_outputs_dataset = {}
# @current_mp_effort_per_activity = Hash.new
# # get all current module_project attributes for outputs data
# end_date_attribute = PeAttribute.find_by_alias_and_record_status_id("end_date", @defined_status.id)
# #@current_mp_outputs_attr_modules = @current_module_project.pemodule.attribute_modules.where('in_out IN (?)', %w(output both))
# @current_mp_outputs_attr_modules = @current_module_project.pemodule.attribute_modules.where('in_out IN (?) AND pe_attribute_id != ?', %w(output both), end_date_attribute)
# # Outputs attributes array
# @current_mp_outputs_attributes = []
#
# # For the Balancing module, only selected balancing attribute results will be displayed in chart
# if @current_module_project.pemodule.alias == Projestimate::Application::BALANCING_MODULE
# @current_mp_outputs_attributes << current_balancing_attribute
# else
# @current_mp_outputs_attr_modules.each do |attr_module|
# @current_mp_outputs_attributes << attr_module.pe_attribute
# end
# end
#
# # get all project's wbs-project_elements
# @project_wbs_project_elts = @project.wbs_project_elements
# @project_wbs_project_elts.each do |wbs_project_elt|
# @effort_breakdown_stacked_bar_dataset["#{wbs_project_elt.name.parameterize.underscore}"] = Array.new
# end
#
# # get all Attributes aliases
# @current_mp_outputs_attributes_aliases = @current_mp_outputs_attributes.map(&:alias)
# puts "@current_mp_outputs_attributes_aliases = #{@current_mp_outputs_attributes_aliases}"
#
# # generate output attributes values
# @current_mp_outputs_attributes.each do |output_attr|
# attr_data = [] # [low_value, most_likely_value, high_value]
# attr_estimation_value = @current_module_project.estimation_values.where('pe_attribute_id = ? AND in_out = ?', output_attr.id, "output").last
# if !attr_estimation_value.nil?
# # attr_data = [attr_estimation_value.string_data_low[@current_component.id], attr_estimation_value.string_data_most_likely[@current_component.id], attr_estimation_value.string_data_high[@current_component.id], attr_estimation_value.string_data_probable[@current_component.id]]
# ["low", "most_likely", "high", "probable"].each do |level|
# level_value = attr_estimation_value.send("string_data_#{level}")
# if @current_module_project.pemodule.with_activities.in?(%w(yes_for_output_with_ratio yes_for_input_output_without_ratio yes_for_input_output_without_ratio yes_for_input_output_without_ratio))
# # module with activities
# @current_mp_effort_per_activity = { "low" => {}, "most_likely" => {}, "high" => {}, "probable" => {} }
# if level_value.nil?
# pbs_level_value=nil.to_i
# @project_wbs_project_elts.each do |elt|
# @effort_breakdown_stacked_bar_dataset["#{elt.name.parameterize.underscore}"] << 0
# end
# else
# # Data structure : test = {"5" => {"36" => {:value => 10} , "37"=> {:value => 20} }, "6" => {"36" => {:value => 5}, "37"=> {:value => 15} } }
# pbs_level_with_activities = level_value[@current_component.id]
# sum_of_value = 0.0
# if !pbs_level_with_activities.nil?
# pbs_level_with_activities.each do |wbs_activity_elt_id, hash_value|
# sum_of_value = sum_of_value + hash_value[:value]
# wbs_project_elt = WbsProjectElement.find(wbs_activity_elt_id)
# unless wbs_project_elt.is_root || wbs_project_elt.has_children?
# @current_mp_effort_per_activity[level]["#{wbs_project_elt.name.parameterize.underscore}"] = hash_value[:value]
# @effort_breakdown_stacked_bar_dataset["#{wbs_project_elt.name.parameterize.underscore}"] << hash_value[:value]
# end
# end
# end
# pbs_level_value = sum_of_value
# end
# else
# # Attribute for Date and Datetime need to be customized for the chart
# #if output_attr.attr_type == "date"
# #level_value.nil? ? (pbs_level_value=nil.to_i) : (pbs_level_value=level_value[@current_component.id].to_i)
# #else
# level_value.nil? ? (pbs_level_value=nil.to_i) : (pbs_level_value=level_value[@current_component.id].to_f)
# #end
# end
# attr_data << pbs_level_value
# end
# end
# #update the attribute array in dataset
# @current_mp_outputs_dataset["#{output_attr.alias}"] = attr_data
# end
# puts "OUTOUT_DATASET = #{@current_mp_outputs_dataset}"
# puts "STACKED_BAR = #{@effort_breakdown_stacked_bar_dataset}"
#
# #======================================== END CURRENT MODULE OUTPUTS DATA ==============================================
#
# # get all current module_project attribute value
# @current_module_project.pemodule.pe_attributes.each do |attr|
# attr_data = Array.new
# attr_estimation_value = @current_module_project.estimation_values.where('pe_attribute_id = ? AND in_out = ?', attr.id, "input").last
# unless attr_estimation_value.nil?
# # on estimation, we have four (4) levels : (string_data_low, string_data_most_likely, string_data_high, string_data_probable)
# ["low", "most_likely", "high"].each do |level|
# #@current_mp_attributes << attr_estimation_value.pe_attribute
# string_data_level = attr_estimation_value.send("string_data_#{level}")
# if string_data_level.nil?
# attr_data << ""
# else
# attr_data << string_data_level[@current_component.id]
# end
# #@input_dataset["#{attr.alias}"] = attr_data
# @input_dataset["#{attr_estimation_value.pe_attribute.alias}"] = attr_data
# end
# end
# end
# puts "INPUT DATA = #{@input_dataset}"
#
#
# #============================================= All project data (modules, attributes, ...) ==========================================
# #================================ Initialization module data for all estimations chart (per attribute) ================================
#
# # When user selects the Initialization module from the Dashbord, chart will be displayed for all estimations
#
# # get the all project modules for the charts labels
# @project_modules = []
# @corresponding_attributes_aliases_for_init = %w(effort effort_person_hour effort_person_week cost delay staffing sloc)
# # contains all the modules attributes labels
# @init_attributes_labels = []
# @attributes = []
# @project_module_projects.each do |mp|
# @project_modules << mp.pemodule
# @attributes << mp.pemodule.pe_attributes.where('alias IN (?)', @corresponding_attributes_aliases_for_init)
# #@attributes_labels = @attributes_labels + mp.pemodule.pe_attributes.all.map(&:alias)
# end
# @attributes = @attributes.flatten.sort.uniq
# @init_attributes_labels = @attributes.map(&:alias).flatten.sort.uniq
# @init_project_modules = @project_modules.map(&:title)
#
# # get the project PBS root
# psb_root = @project.pbs_project_elements.first.root
#
# # generate the dataset for charts
# @init_module_dataset = {}
# # Dataset is get by attribute
# # one dataset data correspond of all modules values for this attribute
# @attributes.each do |attr|
# attr_data = Array.new
# @project_module_projects.each do |mp|
# attr_estimation_value = mp.estimation_values.where('pe_attribute_id = ? AND in_out = ?', attr.id, 'output').last
# pbs_level_value = nil.to_i
# ###==================
# if !attr_estimation_value.nil?
# #attr_data << attr_estimation_value.string_data_low[psb_root.id]
# #attr_data << attr_estimation_value.string_data_probable[@current_component.id]
# level_value = attr_estimation_value.send("string_data_probable")
# if mp.pemodule.with_activities.in?(%w(yes_for_output_with_ratio yes_for_input_output_without_ratio yes_for_input_output_without_ratio yes_for_input_output_without_ratio))
# # module with activities
# mp_value_per_activity = { "low" => {}, "most_likely" => {}, "high" => {}, "probable" => {} }
# if !level_value.nil?
# # Data structure : test = {"5" => {"36" => {:value => 10} , "37"=> {:value => 20} }, "6" => {"36" => {:value => 5}, "37"=> {:value => 15} } }
# pbs_level_with_activities = level_value[@current_component.id]
# sum_of_value = 0.0
# if !pbs_level_with_activities.nil?
# pbs_level_with_activities.each do |wbs_activity_elt_id, hash_value|
# sum_of_value = sum_of_value + hash_value[:value]
# end
# end
# pbs_level_value = sum_of_value
# end
# else
# level_value.nil? ? (pbs_level_value=nil.to_i) : (pbs_level_value=level_value[@current_component.id].to_f)
# end
# end
# attr_data << pbs_level_value
#
# #========================
# end
# @init_module_dataset[:"#{attr.alias}"] = attr_data
# end
# puts "DATASET = #{@init_module_dataset}"
#end
# update and show comments regarding the estimation status changes
def add_comment_on_status_change
@project = Project.find(params[:project_id])
@text_comments = ""
if !@project.status_comment.nil?
@text_comments = @project.status_comment
end
end
# update comments on estimation status changes
def update_comments_status_change
@project = Project.find(params[:project_id])
new_comments = ""
auto_updated_comments = ""
# Add and update comments on estimation status change
if params["project"]["new_status_comment"] and !params["project"]["new_status_comment"].empty?
new_comments << show_status_change_comments(params["project"]["new_status_comment"])
end
# Before saving project, update the project comment when the status has changed
if params[:project][:estimation_status_id]
new_status_id = params[:project][:estimation_status_id].to_i
if @project.estimation_status_id != new_status_id
auto_updated_comments << auto_update_status_comment(params[:project_id], new_status_id)
new_comments = auto_updated_comments + new_comments
#update estimation status
@project.estimation_status_id = params["project"]["estimation_status_id"]
end
end
#add the last comments to the new comments
new_comments << "#{@project.status_comment} \r\n"
#update project's comments
@project.status_comment = new_comments
if @project.save
flash[:notice] = I18n.t(:notice_comment_status_successfully_updated)
else
flash[:error] = I18n.t('errors.messages.not_saved')
end
redirect_to :back
end
# Display comments about estimation status changes
def show_status_change_comments(new_comments, current_note_length = 0)
user_infos = ""
#current_comments = @project.status_comment.nil? ? "" : @project.status_comment
#appended_text = new_comments.sub(current_comments, '')
user_infos << "#{I18n.l(Time.now)} : #{I18n.t(:notes_updated_by)} #{current_user.name}\r\n"
user_infos << "#{new_comments} \r\n"
user_infos << "___________________________________________________________________________\r\n"
#user_infos << "#{current_comments} \r\n"
end
# Automatically update the project's comment when estimation_status has changed
def auto_update_status_comment(project_id, new_status_id)
project = Project.find(project_id)
if project
# Get the project status before updating the value
last_estimation_status_name = project.estimation_status_id.nil? ? "" : project.estimation_status.name
# Get changes on the project estimation_status_id after the update (to be compra with the last one)
new_estimation_status_name = new_status_id.nil? ? "" : EstimationStatus.find(new_status_id).name
#current_comments = project.status_comment.to_s
new_comments = "#{I18n.l(Time.now)} : #{I18n.t(:change_estimation_status_from_to, from_status: last_estimation_status_name, to_status: new_estimation_status_name, current_user_name: current_user.name)}. \r\n"
new_comments << "___________________________________________________________________________\r\n"
#new_comments << current_comments
end
end
end