├── app ├── helpers │ └── version_burndown_charts_helper.rb ├── views │ └── version_burndown_charts │ │ └── index.html.erb └── controllers │ └── version_burndown_charts_controller.rb ├── .DS_Store ├── config ├── .DS_Store └── locales │ ├── ja.yml │ ├── no.yml │ ├── es.yml │ └── en.yml ├── assets └── stylesheets │ └── version_burndown_charts.css ├── test ├── test_helper.rb └── functional │ └── version_burndown_controller_test.rb ├── init.rb └── README.rdoc /app/helpers/version_burndown_charts_helper.rb: -------------------------------------------------------------------------------- 1 | module VersionBurndownChartsHelper 2 | end 3 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daipresents/redmine_version_burndown_charts/HEAD/.DS_Store -------------------------------------------------------------------------------- /config/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daipresents/redmine_version_burndown_charts/HEAD/config/.DS_Store -------------------------------------------------------------------------------- /assets/stylesheets/version_burndown_charts.css: -------------------------------------------------------------------------------- 1 | .selected { 2 | font-weight: bold; 3 | font-style: italic; 4 | } 5 | 6 | dd{ 7 | margin-left:1em; 8 | } -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # Load the normal Rails helper 2 | require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper') 3 | 4 | # Ensure that we are using the temporary fixture path 5 | Engines::Testing.set_fixture_path 6 | -------------------------------------------------------------------------------- /test/functional/version_burndown_controller_test.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../test_helper' 2 | 3 | class VersionBurndownControllerTest < ActionController::TestCase 4 | # Replace this with your real tests. 5 | def test_truth 6 | assert true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /init.rb: -------------------------------------------------------------------------------- 1 | require 'redmine' 2 | 3 | Redmine::Plugin.register :redmine_version_burndown do 4 | name 'Redmine Version Burndown Charts plugin' 5 | author 'Dai Fujihara' 6 | description 'Version Burndown Charts Plugin is graphical chart plugin for Scrum.' 7 | author_url 'http://daipresents.com/weblog/fujihalab/' 8 | url 'http://daipresents.com/weblog/fujihalab/archives/2010/02/redmine-version-burndown-charts-plugin-release.php ' 9 | 10 | requires_redmine :version_or_higher => '0.9.0' 11 | version '0.0.5' 12 | 13 | project_module :version_burndown_charts do 14 | permission :version_burndown_charts_view, :version_burndown_charts => :index 15 | end 16 | 17 | menu :project_menu, :version_burndown_charts, { :controller => 'version_burndown_charts', :action => 'index' }, 18 | :caption => :version_burndown_charts, :after => :activity, :param => :project_id 19 | end 20 | -------------------------------------------------------------------------------- /config/locales/ja.yml: -------------------------------------------------------------------------------- 1 | ja: 2 | version_burndown_charts: "バーンダウンチャート" 3 | version_burndown_charts_view: "バーンダウンチャートの表示" 4 | 5 | version_burndown_charts_xlegend: "Date" 6 | version_burndown_charts_ylegend: "Hour" 7 | version_burndown_charts_perfect_line: "理想ライン" 8 | version_burndown_charts_upper_line: "上限ライン" 9 | version_burndown_charts_lower_line: "下限ライン" 10 | version_burndown_charts_estimated_line: "予想ライン" 11 | version_burndown_charts_peformance_line: "実績ライン" 12 | version_burndown_charts_spent_line: "詳細実績ライン" 13 | 14 | version_burndown_charts_versions: "バージョン" 15 | version_burndown_charts_versions_name: "バージョン名" 16 | version_burndown_charts_versions_open: "進行中" 17 | version_burndown_charts_versions_locked: "ロック中" 18 | version_burndown_charts_versions_closed: "完了" 19 | version_burndown_charts_version_info: "バージョン情報" 20 | 21 | version_burndown_charts_estimated_hours: "予想:{{estimated_hours}}h" 22 | version_burndown_charts_spent_hours: "経過時間:{{spent_hours}}h" 23 | 24 | version_burndown_charts_issues_count: "チケット数:{{issues_count}}" 25 | version_burndown_charts_open_issues_count: "未完了:{{open_issues_count}}" 26 | version_burndown_charts_closed_issues_count: "完了:{{closed_issues_count}}" 27 | 28 | version_burndown_charts_start_date: "開始日:{{start_date}}" 29 | version_burndown_charts_due_date: "期日:{{due_date}}" 30 | version_burndown_charts_sprint_range: "スプリント期間:{{sprint_range}}日" 31 | 32 | version_burndown_charts_project_nod_found: "プロジェクトが存在しません。プロジェクトID:{{project_id}}" 33 | version_burndown_charts_version_not_found: "プロジェクトにバージョンが存在しません。" 34 | version_burndown_charts_no_version_with_due_date: "期限が設定されたバージョンが存在しません。" 35 | version_burndown_charts_version_due_date_not_found: "バージョンに期日が設定されていません。バージョン名:{{version_name}}" 36 | version_burndown_charts_version_start_date_invalid: "バージョンの期日よりあとに開始日が設定されています。バージョン名:{{version_name}}" 37 | version_burndown_charts_issues_not_found: "バージョンにチケットが存在しないか、開始日・予定工数がチケットに設定されていません。バージョン名:{{version_name}}" 38 | version_burndown_charts_issues_start_date_or_estimated_date_not_found: "バージョン内のチケットに開始日、または予定工数が設定されていません。バージョン名:{{version_name}}" 39 | -------------------------------------------------------------------------------- /config/locales/no.yml: -------------------------------------------------------------------------------- 1 | "no": 2 | version_burndown_charts: "Version Burndown Charts" 3 | version_burndown_charts_view: "Vis Version Burndown Charts" 4 | 5 | version_burndown_charts_xlegend: "Dato" 6 | version_burndown_charts_ylegend: "Time" 7 | version_burndown_charts_perfect_line: "Perfekt linje" 8 | version_burndown_charts_estimated_line: "Estimert linje" 9 | version_burndown_charts_peformance_line: "Ytelseslinje" 10 | 11 | version_burndown_charts_versions: "Versjon" 12 | version_burndown_charts_versions_name: "Versjonsnavn" 13 | version_burndown_charts_versions_open: "Apen" 14 | version_burndown_charts_versions_locked: "Last" 15 | version_burndown_charts_versions_closed: "Lukket" 16 | version_burndown_charts_version_info: "Versjonsinformasjon" 17 | version_burndown_charts_estimated_hours: "Estimert tid:{{estimated_hours}}h" 18 | version_burndown_charts_spent_hours: "Tid brukt:{{spent_hours}}t" 19 | version_burndown_charts_spent_hours: "Timer brukt:{{spent_hours}}" 20 | 21 | version_burndown_charts_issues_count: "Alle saker:{{issues_count}}" 22 | version_burndown_charts_open_issues_count: "Apne saker:{{open_issues_count}}" 23 | version_burndown_charts_closed_issues_count: "Lukka saker:{{closed_issues_count}}" 24 | 25 | version_burndown_charts_start_date: "Start:{{start_date}}" 26 | version_burndown_charts_due_date: "Frist:{{due_date}}" 27 | version_burndown_charts_sprint_range: "Lengde pa sprint:{{sprint_range}}dager" 28 | 29 | version_burndown_charts_project_nod_found: "Fant ikke prosjekt. prosjekt-id:{{project_id}}" 30 | version_burndown_charts_version_not_found: "Fant ikke versjonen i prosjektet." 31 | version_burndown_charts_no_version_with_due_date: "No version with due date." 32 | version_burndown_charts_version_due_date_not_found: "Det er ikke satt frist for versjonen. versjonsnavn:{{version_name}}" 33 | version_burndown_charts_version_start_date_invalid: "Startdato er satt senere enn fristen. versjonsnavn:{{version_name}}" 34 | version_burndown_charts_issues_not_found: "Fant ikke saken i versjonen, eller det er ikke satt startdato eller estimert timetall for saken. versjonsnavn:{{version_name}}" 35 | version_burndown_charts_issues_start_date_or_estimated_date_not_found: "Det er ikke satt startdato eller estimert timetall for saken i versjonen. versjonsnavn:{{version_name}}" 36 | -------------------------------------------------------------------------------- /config/locales/es.yml: -------------------------------------------------------------------------------- 1 | es: 2 | version_burndown_charts: "Burndown" 3 | version_burndown_charts_view: "Ver gráfica de 'Burndown'" 4 | 5 | version_burndown_charts_xlegend: "Fecha" 6 | version_burndown_charts_ylegend: "Horas" 7 | version_burndown_charts_perfect_line: "Línea ideal" 8 | version_burndown_charts_upper_line: "Línea superior" 9 | version_burndown_charts_lower_line: "Línea inferior" 10 | version_burndown_charts_estimated_line: "Estimación" 11 | version_burndown_charts_peformance_line: "Restante" 12 | 13 | version_burndown_charts_versions: "Versión" 14 | version_burndown_charts_versions_name: "Versión" 15 | version_burndown_charts_versions_open: "Abiertas" 16 | version_burndown_charts_versions_locked: "Bloqueadas" 17 | version_burndown_charts_versions_closed: "Cerradas" 18 | version_burndown_charts_version_info: "Información" 19 | version_burndown_charts_estimated_hours: "Tiempo estimado: {{estimated_hours}} h" 20 | version_burndown_charts_spent_hours: "Tiempo invertido: {{spent_hours}} h" 21 | 22 | version_burndown_charts_issues_count: "Peticiones: {{issues_count}}" 23 | version_burndown_charts_open_issues_count: "Abiertas: {{open_issues_count}}" 24 | version_burndown_charts_closed_issues_count: "Cerradas: {{closed_issues_count}}" 25 | 26 | version_burndown_charts_start_date: "Fecha de inicio: {{start_date}}" 27 | version_burndown_charts_due_date: "Fecha de fin: {{due_date}}" 28 | version_burndown_charts_sprint_range: "Duración: {{sprint_range}} días" 29 | 30 | version_burndown_charts_project_nod_found: "Proyecto no encontrado. project id:{{project_id}}" 31 | version_burndown_charts_version_not_found: "Versión no encontrada en el proyecto." 32 | version_burndown_charts_no_version_with_due_date: "No hay versiones con fecha asignada." 33 | version_burndown_charts_version_due_date_not_found: "La versión no tiene fecha asignada. version name:{{version_name}}" 34 | version_burndown_charts_version_start_date_invalid: "La fecha de inicio de la versión es posterior a la de fin. version name:{{version_name}}" 35 | version_burndown_charts_issues_not_found: "No se encontraron peticiones en la versión. version name:{{version_name}}" 36 | version_burndown_charts_issues_start_date_or_estimated_date_not_found: "Las peticiones de la versión no tienen horas estimadas o fecha de inicio. version name:{{version_name}}" 37 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = redmine_version_burndown 2 | ja: 3 | * このプラグインは、バージョンに存在するチケットの予定工数と作業実績からバーンダウンチャートを作成します。 4 | 5 | en: 6 | * Version Burndown Charts Plugin create burndown chart graph for scrum from ticket's estimated hours and %Done in target version. 7 | 8 | == Details 9 | ja: 10 | * バーンダウンチャートの開始日は、バージョン内にあるチケットの中で、最も早い開始日となります。 11 | * 実績の線は、チケットの完了日時(ジャーナルファイル)と、そのチケットの予定工数と進捗を使って計算しています。 12 | 13 | en: 14 | * The start date of the burndown chart is assumed to be earliest start date in the ticket in the version. 15 | * The line of performanse is calculated by the completion date of the ticket (by journal file) and the ticket's estimated hours and %Done. 16 | 17 | == Plugin Installation 18 | * Download open_flash_chart 2.1.1. 19 | * Unpack and move into vendor/plugins. 20 | * Rename the plugin directory to open_flash_chart. 21 | If you want to get from Github, please use following command. 22 | cd ${RAILS_ROOT} 23 | ./script/plugin install git://github.com/pullmonkey/open_flash_chart.git 24 | * Copy files from open_flash_chart/assets/* to RAILS_ROOT/public 25 | * Download Version Burndown Charts. 26 | * Unpack and move into RAILS_ROOT/vendor/plugins. 27 | * Rename the plugin directory to redmine_version_burndown_charts 28 | * If you want to get from GIthub, please use following command. 29 | cd ${RAILS_ROOT} 30 | git clone git://github.com/daipresents/redmine_version_burndown_charts.git vendor/plugins/redmine_version_burndown_chart 31 | * Restart Redmine. 32 | * Login and configure the plugin (Administration > Roles and permissions > Permissions report) 33 | * Configure the project (Project > Settings > Modules). 34 | * Create version and set due date. 35 | * Create ticket and set start date, estimated hours. 36 | * Logged ticket status... 37 | * Click to version burndown charts menu. 38 | 39 | == Note 40 | === 0.1.0 41 | * I tested this plugin Redmine 1.1.2 + MySQL5.1. 42 | * Adjust Perfect Line straight. 43 | * Added Upper and Lower line. 44 | * Modified caluculation logic that only use child issue's value. 45 | * Modified meaning of done. This plugin use "% Done" value. 46 | 47 | 0.1.0 feature made by asura(https://github.com/asura). Thank you! 48 | 49 | === 0.0.6 50 | * I tested this plugin Redmine 1.0.5 + MySQL5.1. 51 | * Added feature: Perfect Line 52 | 53 | === 0.0.5 54 | * I tested this plugin Redmine 0.9.2 + MySQL5.1. 55 | 56 | == License 57 | This plugin is licensed under GNU General Public License version 3. 58 | 59 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | version_burndown_charts: "Version Burndown Charts" 3 | version_burndown_charts_view: "View Version Burndown Charts" 4 | 5 | version_burndown_charts_xlegend: "Date" 6 | version_burndown_charts_ylegend: "Hour" 7 | version_burndown_charts_perfect_line: "Perfect Line" 8 | version_burndown_charts_upper_line: "Upper Line" 9 | version_burndown_charts_lower_line: "Lower Line" 10 | version_burndown_charts_estimated_line: "Estimated Line" 11 | version_burndown_charts_peformance_line: "Peformance Line" 12 | 13 | version_burndown_charts_versions: "Version" 14 | version_burndown_charts_versions_name: "Version Name" 15 | version_burndown_charts_versions_open: "Open" 16 | version_burndown_charts_versions_locked: "Locked" 17 | version_burndown_charts_versions_closed: "Closed" 18 | version_burndown_charts_version_info: "Version Information" 19 | version_burndown_charts_estimated_hours: "Estimated time:{{estimated_hours}}h" 20 | version_burndown_charts_spent_hours: "Spent time:{{spent_hours}}h" 21 | version_burndown_charts_spent_hours: "Spent hours:{{spent_hours}}h" 22 | 23 | version_burndown_charts_issues_count: "All Issues:{{issues_count}}" 24 | version_burndown_charts_open_issues_count: "Open Issues:{{open_issues_count}}" 25 | version_burndown_charts_closed_issues_count: "Closed Issues:{{closed_issues_count}}" 26 | 27 | version_burndown_charts_start_date: "Start Date:{{start_date}}" 28 | version_burndown_charts_due_date: "Due Date:{{due_date}}" 29 | version_burndown_charts_sprint_range: "Sprint Span:{{sprint_range}}days" 30 | 31 | version_burndown_charts_project_nod_found: "Project not found. project id:{{project_id}}" 32 | version_burndown_charts_version_not_found: "Version not found in project." 33 | version_burndown_charts_no_version_with_due_date: "No version with due date." 34 | version_burndown_charts_version_due_date_not_found: "Version due date is not set to the version. version name:{{version_name}}" 35 | version_burndown_charts_version_start_date_invalid: "Version start date is late than version due date. version name:{{version_name}}" 36 | version_burndown_charts_issues_not_found: "Ticket not found in version, or start date or estimated hours is not set to the ticket. version name:{{version_name}}" 37 | version_burndown_charts_issues_start_date_or_estimated_date_not_found: "The start date or estimated hours is not set to the ticket in the version. version name:{{version_name}}" 38 | -------------------------------------------------------------------------------- /app/views/version_burndown_charts/index.html.erb: -------------------------------------------------------------------------------- 1 | <% html_title "#{@version.name} - " + l(:version_burndown_charts) -%> 2 | <% content_for :header_tags do %> 3 | <%= javascript_include_tag '/plugin_assets/open_flash_chart/javascripts/swfobject.js' %> 4 | <%= stylesheet_link_tag 'version_burndown_charts', :plugin => 'redmine_version_burndown_charts' %> 5 | <% end %> 6 | 7 | <% unless flash[:error] -%> 8 | <%= @graph %> 9 | <% end -%> 10 | 11 | <% content_for :sidebar do -%> 12 |

<%= l(:version_burndown_charts_version_info) %>

13 |
<%=l(:version_burndown_charts_versions_name)%>:<%=link_to(@version.name, :controller => 'versions', :action => 'show', :id => @version.id) %>
14 |
<%=l(:version_burndown_charts_estimated_hours, :estimated_hours => @estimated_hours)%>
15 |
<%=l(:version_burndown_charts_spent_hours, :spent_hours => @version.spent_hours)%>
16 |
<%=l(:version_burndown_charts_issues_count, :issues_count => @version.issues_count)%>
17 |
<%=l(:version_burndown_charts_open_issues_count, :open_issues_count => @version.open_issues_count)%>(<%=@open_pourcent%>%)
18 |
<%=l(:version_burndown_charts_closed_issues_count, :closed_issues_count => @version.closed_issues_count)%>(<%=@closed_pourcent%>%)
19 |
<%=l(:version_burndown_charts_start_date, :start_date => @start_date)%>
20 |
<%=l(:version_burndown_charts_due_date, :due_date => @version.due_date)%>
21 |
<%=l(:version_burndown_charts_sprint_range, :sprint_range => @sprint_range)%>
22 | 23 |

<%= l(:version_burndown_charts_versions_open) %>

24 |
25 | <% @open_versions.each do |version| -%> 26 | > 27 | <%= version.effective_date %> 28 | 29 |
30 | <%= link_to(version.name, :controller => 'version_burndown_charts', :action => 'index', :project_id => @project.id, :version_id => version.id.to_s) %> 31 |
32 | <% end -%> 33 |
34 | 35 |

<%= l(:version_burndown_charts_versions_locked) %>

36 |
37 | <% @locked_versions.each do |version| -%> 38 | > 39 | <%= version.effective_date %> 40 | 41 |
42 | <%= link_to(version.name, :controller => 'version_burndown_charts', :action => 'index', :project_id => @project.id, :version_id => version.id.to_s) %> 43 |
44 | <% end -%> 45 |
46 | 47 |

<%= l(:version_burndown_charts_versions_closed) %>

48 |
49 | <% @closed_versions.each do |version| -%> 50 | > 51 | <%= version.effective_date %> 52 | 53 |
54 | <%= link_to(version.name, :controller => 'version_burndown_charts', :action => 'index', :project_id => @project.id, :version_id => version.id.to_s) %> 55 |
56 | <% end -%> 57 |
58 | <% end -%> 59 | -------------------------------------------------------------------------------- /app/controllers/version_burndown_charts_controller.rb: -------------------------------------------------------------------------------- 1 | class VersionBurndownChartsController < ApplicationController 2 | unloadable 3 | menu_item :version_burndown_charts 4 | before_filter :find_project, :find_versions, :find_version_issues, :find_burndown_dates, :find_version_info, :find_issues_closed_status 5 | 6 | def index 7 | relative_url_path = 8 | ActionController::Base.respond_to?(:relative_url_root) ? ActionController::Base.relative_url_root : ActionController::AbstractRequest.relative_url_root 9 | 10 | @graph = 11 | open_flash_chart_object( 880, 450, 12 | url_for( :action => 'get_graph_data', :project_id => @project.id, :version_id => @version.id ), 13 | true, "#{relative_url_path}/" ) 14 | end 15 | 16 | def get_graph_data 17 | 18 | estimated_data_array = [] 19 | performance_data_array = [] 20 | perfect_data_array = [] 21 | upper_data_array = [] 22 | lower_data_array = [] 23 | x_labels_data = [] 24 | 25 | index_date = @start_date - 1 26 | index_estimated_hours = @estimated_hours 27 | index_performance_hours = @estimated_hours 28 | count = 1 29 | 30 | while index_date <= (@version.due_date + 1) 31 | logger.debug("index_date #{index_date}") 32 | 33 | if index_date < @start_date 34 | # ready 35 | estimated_data_array << index_estimated_hours 36 | performance_data_array << index_performance_hours 37 | index_date += 1 38 | count += 1 39 | next 40 | elsif index_date == @start_date || index_date == @version.due_date 41 | x_labels_data << index_date.strftime("%m/%d") 42 | elsif @sprint_range > 20 && count % (@sprint_range / 3).round != 0 43 | x_labels_data << "" 44 | else 45 | x_labels_data << index_date.strftime("%m/%d") 46 | end 47 | 48 | estimated_data_array << round(index_estimated_hours -= calc_estimated_hours_by_date(index_date)) 49 | index_performance_hours = calc_performance_hours_by_date(index_date) 50 | performance_data_array << round(@estimated_hours - index_performance_hours) 51 | perfect_data_array << 0 52 | upper_data_array << 0 53 | lower_data_array << 0 54 | 55 | logger.debug("#{index_date} index_estimated_hours #{round(index_estimated_hours)}") 56 | logger.debug("#{index_date} index_performance_hours #{round(index_performance_hours)}") 57 | 58 | index_date += 1 59 | count += 1 60 | end 61 | 62 | perfect_data_array.fill {|i| round(@estimated_hours - (@estimated_hours / @sprint_range * i)) } 63 | upper_data_array.fill {|i| round((@estimated_hours - (@estimated_hours / @sprint_range * i)) * 1.2) } 64 | lower_data_array.fill {|i| round((@estimated_hours - (@estimated_hours / @sprint_range * i)) * 0.8) } 65 | create_graph(x_labels_data, estimated_data_array, performance_data_array, perfect_data_array, upper_data_array, lower_data_array) 66 | end 67 | 68 | def create_graph(x_labels_data, estimated_data_array, performance_data_array, perfect_data_array, upper_data_array, lower_data_array) 69 | chart =OpenFlashChart.new 70 | chart.set_title(Title.new("#{@version.name} #{l(:version_burndown_charts)}")) 71 | chart.set_bg_colour('#ffffff'); 72 | 73 | x_legend = XLegend.new("#{l(:version_burndown_charts_xlegend)}") 74 | x_legend.set_style('{font-size: 20px; color: #000000}') 75 | chart.set_x_legend(x_legend) 76 | 77 | y_legend = YLegend.new("#{l(:version_burndown_charts_ylegend)}") 78 | y_legend.set_style('{font-size: 20px; color: #000000}') 79 | chart.set_y_legend(y_legend) 80 | 81 | x = XAxis.new 82 | x.set_range(0, @sprint_range + 1, 1) 83 | x.set_labels(x_labels_data) 84 | chart.x_axis = x 85 | 86 | y = YAxis.new 87 | y.set_range(0, round(@estimated_hours * 1.2 + 1), (@estimated_hours / 6).round) 88 | chart.y_axis = y 89 | 90 | add_line(chart, "#{l(:version_burndown_charts_upper_line)}", 1, '#dfdf3f', 4, upper_data_array) 91 | add_line(chart, "#{l(:version_burndown_charts_lower_line)}", 1, '#3f3fdf', 4, lower_data_array) 92 | add_line(chart, "#{l(:version_burndown_charts_perfect_line)}", 3, '#bbbbbb', 6, perfect_data_array) 93 | add_line(chart, "#{l(:version_burndown_charts_estimated_line)}", 2, '#00a497', 4, estimated_data_array) 94 | add_line(chart, "#{l(:version_burndown_charts_peformance_line)}", 3, '#bf0000', 6, performance_data_array) 95 | 96 | render :text => chart.to_s 97 | end 98 | 99 | def add_line(chart, text, width, colour, dot_size, values) 100 | my_line = Line.new 101 | my_line.text = text 102 | my_line.width = width 103 | my_line.colour = colour 104 | my_line.dot_size = dot_size 105 | my_line.values = values 106 | chart.add_element(my_line) 107 | end 108 | 109 | def is_leaf(issue) 110 | if !(defined?(issue.rgt) and defined?(issue.lft)) then 111 | return true 112 | end 113 | if issue.rgt - issue.lft == 1 then 114 | return true 115 | else 116 | return false 117 | end 118 | end 119 | 120 | def calc_estimated_hours_by_date(target_date) 121 | target_issues = @version_issues.select { |issue| issue.due_date == target_date} 122 | target_hours = 0 123 | target_issues.each do |issue| 124 | next unless is_leaf(issue) 125 | target_hours += round(issue.estimated_hours) 126 | end 127 | logger.debug("#{target_date} estimated hours = #{target_hours}") 128 | return target_hours 129 | end 130 | 131 | def calc_performance_hours_by_date(target_date) 132 | target_hours = 0 133 | @version_issues.each do |issue| 134 | next unless is_leaf(issue) 135 | target_hours += calc_issue_performance_hours_by_date(target_date, issue) 136 | end 137 | logger.debug("issues estimated hours #{target_hours} #{target_date}") 138 | return target_hours 139 | end 140 | 141 | def calc_issue_performance_hours_by_date(target_date, issue) 142 | journals = issue.journals.select {|journal| (journal.created_on.to_date <= target_date)} 143 | if journals.empty? 144 | return 0 145 | end 146 | 147 | journal_details = 148 | journals.map(&:details).flatten.select {|detail| 'status_id' == detail.prop_key} 149 | 150 | journal_details.each do |journal_detail| 151 | logger.debug("journal_detail id #{journal_detail.id}") 152 | @closed_statuses.each do |closed_status| 153 | logger.debug("closed_status id #{closed_status.id}") 154 | if journal_detail.value.to_i == closed_status.id 155 | logger.debug("#{target_date} id #{issue.id}, issue.estimated_hours #{issue.estimated_hours}") 156 | return round(issue.estimated_hours) 157 | end 158 | end 159 | end 160 | 161 | journal_details_done_ratio = 162 | journals.map(&:details).flatten.select {|detail| 'done_ratio' == detail.prop_key} 163 | if journal_details_done_ratio.empty? 164 | return 0 165 | end 166 | 167 | target_hours = 0 168 | journal_details_done_ratio.each do |journal_detail| 169 | logger.debug("#{target_date} id #{issue.id}, journal_detail id #{journal_detail.id}, done_ratio #{journal_detail.old_value} -> #{journal_detail.value}") 170 | target_hours += round(issue.estimated_hours * (journal_detail.value.to_i - journal_detail.old_value.to_i) / 100) 171 | end 172 | 173 | logger.debug("#{target_date} id #{issue.id}, whole #{issue.estimated_hours}, done #{target_hours}") 174 | return target_hours 175 | end 176 | 177 | def round(value) 178 | unless value 179 | return 0 180 | else 181 | return (value.to_f * 1000.0).round / 1000.0 182 | end 183 | end 184 | 185 | def find_project 186 | 187 | logger.debug("params[:project_id].class #{params[:project_id].class}") 188 | 189 | if params[:project_id].blank? 190 | flash[:error] = l(:version_burndown_charts_project_nod_found, :project_id => 'parameter not found.') 191 | render_404 192 | return 193 | end 194 | 195 | begin 196 | @project = Project.find(params[:project_id]) 197 | rescue ActiveRecord::RecordNotFound 198 | flash[:error] = l(:version_burndown_charts_project_nod_found, :project_id => params[:project_id]) 199 | render_404 200 | return 201 | end 202 | end 203 | 204 | def find_versions 205 | versions = @project.versions.select(&:effective_date).sort_by(&:effective_date) 206 | @open_versions = versions.select{|version| version.status == 'open'} 207 | @locked_versions = versions.select{|version| version.status == 'locked'} 208 | @closed_versions = versions.select{|version| version.status == 'closed'} 209 | if params[:version_id] 210 | @version = Version.find(params[:version_id]) 211 | else 212 | # First display case. 213 | @version = @open_versions.first || versions.last 214 | end 215 | 216 | logger.debug("@version.class #{@version.class}") 217 | logger.debug("@version.nil? #{@version.nil?}") 218 | 219 | if @version.blank? 220 | flash[:error] = l(:version_burndown_charts_no_version_with_due_date) 221 | render_404 222 | return 223 | end 224 | 225 | unless @version.due_date 226 | flash[:error] = l(:version_burndown_charts_version_due_date_not_found, :version_name => @version.name) 227 | render :action => "index" and return false 228 | end 229 | end 230 | 231 | def find_version_issues 232 | @version_issues = Issue.find_by_sql([ 233 | "select * from issues 234 | where fixed_version_id = :version_id and start_date is not NULL and 235 | estimated_hours is not NULL order by start_date asc", 236 | {:version_id => @version.id}]) 237 | if @version_issues.empty? 238 | flash[:error] = l(:version_burndown_charts_issues_not_found, :version_name => @version.name) 239 | render :action => "index" and return false 240 | end 241 | end 242 | 243 | def find_burndown_dates 244 | @start_date = @version_issues[0].start_date 245 | if @version.due_date <= @start_date 246 | flash[:error] = l(:version_burndown_charts_version_start_date_invalid, :version_name => @version.name) 247 | render :action => "index" and return false 248 | end 249 | 250 | @sprint_range = @version.due_date - @start_date + 1 251 | 252 | logger.debug("@start_date #{@start_date}") 253 | logger.debug("@version.due_date #{@version.due_date}") 254 | logger.debug("@sprint_range = #{@sprint_range}") 255 | end 256 | 257 | def find_version_info 258 | @closed_pourcent = (@version.closed_pourcent * 100).round / 100 259 | @open_pourcent = 100 - @closed_pourcent 260 | unless @version.estimated_hours 261 | flash[:error] = l(:version_burndown_charts_issues_start_date_or_estimated_date_not_found, :version_name => @version.name) 262 | render :action => "index" and return false 263 | end 264 | @estimated_hours = round(@version.estimated_hours) 265 | logger.debug("@estimated_hours #{@estimated_hours}") 266 | end 267 | 268 | def find_issues_closed_status 269 | @closed_statuses = IssueStatus.find_all_by_is_closed(true) 270 | logger.debug("@closed_statuses #{@closed_statuses}") 271 | end 272 | end 273 | --------------------------------------------------------------------------------