Redmineプラグイン開発 – 日付指定で時間コストを表示

感想おまちしてます!

  • NetBeans6.5で作ります。
  • ソースはGoogle Codeを参照のこと。
  • redmineは「c:\fujihara\Ruby\redmine-0.8.0」にあって、WEBrickを使って動かす。
スポンサーリンク

ValueObject

表示用データを格納するValueObjectをplugin_root/app/libに作成。
Main

 # To change this template, choose Tools | Templates
# and open the template in the editor.
class TimeReportMainVO
TRACKER_SUM_STRING = "合計"
def initialize
@project_name = ""
#FIXME
@trackers = Hash.new()
all_trackers = Tracker.find(:all)
all_trackers.each do |tracker|
@trackers[tracker.name] = TimeReportDetailVO.new()
end
@trackers[TRACKER_SUM_STRING] = TimeReportDetailVO.new()
end
def get_tracker(name)
return trackers[name]
end
def put_tracker(name, value)
trackers[name] = value
end
attr_accessor :project_name, :trackers
end

Main has Detailになっている。
Detail

 # To change this template, choose Tools | Templates
# and open the template in the editor.
class TimeReportDetailVO
def initialize
@estimated_hours = 0.0
@actual_performances = 0.0
@percentages = 0.0
end
attr_accessor :estimated_hours, :actual_performances, :percentages
end

Controller

ControllerではVOに計算したデータを格納する。
daizu_time_report_controller.rb

 require 'logger'
require 'time_report_detail_v_o'
require 'time_report_main_v_o'
class DaizuTimeReportController < ApplicationController
before_filter :init
TRACKER_SUM_STRING = "合計"
def index
if @project_id && @start_date && @due_date
# counting per tracker.
# counting estimated_hours and time_entries and percentages.
@results = []
if @project_id == "all"
@projects.each do |project|
calc_per_project(project)
end
all_sumvo = calc_allsum(@results)
@results.push(all_sumvo)
else
project = Project.find(:first, :conditions => ["id = ?", @project_id])
calc_per_project(project)
end
end
end
def calc_per_project(project)
# per project.
mainvo = TimeReportMainVO.new()
mainvo.project_name = project.name
issues =
Issue.find(:all,
:conditions => ["start_date >= ? and due_date <= ? and project_id = ?",
@start_date, @due_date, project.id])
mainvo = count_per_tracker(issues, mainvo)
mainvo = calc_percentages(mainvo)
@results.push(mainvo)
end
def count_per_tracker(issues, mainvo)
sumvo = mainvo.get_tracker(TRACKER_SUM_STRING)
# counting per project and per tracker.
issues.each do |issue|
tracker_name = @trakcer_names[issue.tracker_id]
detailvo = mainvo.get_tracker(tracker_name)
# counting estimated_hours.
detailvo.estimated_hours += issue.estimated_hours
sumvo.estimated_hours += issue.estimated_hours
# counting time_entries.
time_entry = TimeEntry.find(:all, :conditions => ["issue_id = ?", issue.id])
time_entry.each do |entry|
detailvo.actual_performances += entry.hours
sumvo.actual_performances += entry.hours
end
mainvo.put_tracker(tracker_name, detailvo)
end
mainvo.put_tracker(TRACKER_SUM_STRING, sumvo)
return mainvo
end
def calc_percentages(mainvo)
mainvo.trackers.each do |key, detailvo|
detailvo.percentages =
calc_percentage(detailvo.estimated_hours, detailvo.actual_performances)
mainvo.put_tracker(key, detailvo)
end
return mainvo
end
def calc_percentage(estimated_hours, actual_performances)
if estimated_hours != 0 && actual_performances != 0
percentage =
(actual_performances / estimated_hours) * 100
percentage = percentage * 100
percentage = percentage.round
percentage = percentage / 100
return percentage
else
return 0.0
end
end
def calc_allsum(results)
sumvo = TimeReportMainVO.new()
sumvo.project_name = TRACKER_SUM_STRING
results.each do |result|
result.trackers.each do |tracker_name, detailvo|
detailsumvo = sumvo.get_tracker(tracker_name)
detailsumvo.estimated_hours += detailvo.estimated_hours
detailsumvo.actual_performances += detailvo.actual_performances
sumvo.put_tracker(tracker_name, detailsumvo)
end
end
sumvo.trackers.each do |tracker_name, tracker|
detailsumvo = sumvo.get_tracker(tracker_name)
detailsumvo.percentages =
calc_percentage(detailsumvo.estimated_hours, detailsumvo.actual_performances)
end
return sumvo
end
def init
@log = Logger.new(STDOUT)
@log.level = Logger::DEBUG
@project_id = params[:project_id]
@start_date = params[:start_date]
@due_date = params[:due_date]
@projects = Project.find :all
@trackers = Tracker.find(:all)
@trackers.push(Tracker.new(:name => TRACKER_SUM_STRING))
@trakcer_names = {}
@trackers.each do |tracker|
@trakcer_names[tracker.id] = tracker.name
end
end
end

View

グラフで表示するためにHTML5.JPのライブラリを利用。
plugin_root/app/assets/javascripts/html5jpにライブラリを配置した。

 <script src="/javascripts/calendar/calendar.js" type="text/javascript"></script>
<script src="/javascripts/calendar/lang/calendar-ja.js" type="text/javascript"></script>
<script src="/javascripts/calendar/calendar-setup.js" type="text/javascript"></script>
<link href="/stylesheets/calendar.css" media="screen" rel="stylesheet" type="text/css" />
<h2><%= link_to h('大豆トップページ'), :controller => 'daizu_main', :action => 'index' %> > タイムレポート</h2>
<% form_tag({ :controller => 'daizu_time_report', :action => 'index' }, :id => 'query_form') do %>
<p><label for="project_id">プロジェクト</label>
<select name="project_id">
<option value="all">全てのプロジェクト</option>
<% @projects.each do |project| %>
<option value="<%= project.id %>"><%= project.name %></option>
<% end %>
</select>
<p><label for="issue_start_date">開始日</label>
<input id="issue_start_date" name="start_date" size="15" type="text" value="<%= params[:start_date] %>" />
<img alt="Calendar" class="calendar-trigger" id="issue_start_date_trigger" src="/images/calendar.png" />
<script type="text/javascript">
//<![CDATA[
Calendar.setup({inputField : 'issue_start_date', ifFormat : '%Y-%m-%d', button : 'issue_start_date_trigger' });
//]]>
</script></p>
<p><label for="issue_due_date">期限日</label>
<input id="issue_due_date" name="due_date" size="15" type="text" value="<%= params[:due_date] %>" />
<img alt="Calendar" class="calendar-trigger" id="issue_due_date_trigger" src="/images/calendar.png" />
<script type="text/javascript">
//<![CDATA[
Calendar.setup({inputField : 'issue_due_date', ifFormat : '%Y-%m-%d', button : 'issue_due_date_trigger' });
//]]>
</script></p>
<button type="submit">GO</button>
<% end %>
<% if @results %>
<p>[from:<%= params[:start_date] %> to:<%= params[:due_date] %>] のタイムレポート。</p>
<table class="list">
<tr>
<th></th>
<% @trackers.each do |tracker| %>
<th colspan="3" ><%= tracker.name %></th>
<% end %>
</tr>
<tr>
<th></th>
<% @trackers.each do |tracker| %>
<th>予想</th>
<th>実績</th>
<th>進捗</th>
<% end %>
</tr>
<% @results.each do |result| %>
<tr>
<th><%= result.project_name %></th>
<% @trackers.each do |tracker| %>
<td><%= result.get_tracker(tracker.name).estimated_hours %></td>
<td><%= result.get_tracker(tracker.name).actual_performances %></td>
<td>
<table class="progress" style="width: 40px;">
<tr>
<% if result.get_tracker(tracker.name).percentages == 0 %>
<td class="todo" style="width:100%;"></td>
<% elsif result.get_tracker(tracker.name).percentages == 100 %>
<td class="closed" style="width:100%;"></td>
<% elsif result.get_tracker(tracker.name).percentages > 100 %>
<td style="width:100%;background-color:red;"></td>
<% else %>
<td class="closed" style="<%= "width:" + result.get_tracker(tracker.name).percentages.to_s + "%;" %>"></td>
<td class="todo" style="<%= "width:" + (100 - result.get_tracker(tracker.name).percentages).to_s + "%;" %>"></td>
<% end %>
</tr>
</table>
<p class="pourcent"><%= result.get_tracker(tracker.name).percentages.to_s %>%</p>
</td>
<% end %>
</tr>
<% end %>
</table>
<% if params[:project_id] != "all" %>
<% @results.each do |result| %>
<h3><%= result.project_name %>の統計情報</h3>
<!--[if IE]><script src="/plugin_assets/redmine_daizu/javascripts/html5jp/excanvas/excanvas.js" type="text/javascript"></script><![endif]-->
<script src="/plugin_assets/redmine_daizu/javascripts/html5jp/graph/circle.js" type="text/javascript"></script>
<script type="text/javascript">
window.onload = function() {
var cg = new html5jp.graph.circle("yosou");
if( ! cg ) { return; }
var items = [
<% @trackers.each do |tracker| %>
<% if tracker.name != "合計" %>
<% if result.get_tracker(tracker.name).actual_performances != 0.0 %>
["<%=tracker.name%>", <%= result.get_tracker(tracker.name).actual_performances %>],
<% end %>
<% end %>
<% end %>
];
cg.draw(items);
var cg = new html5jp.graph.circle("jisseki");
if( ! cg ) { return; }
var items = [
<% @trackers.each do |tracker| %>
<% if tracker.name != "合計" %>
<% if result.get_tracker(tracker.name).estimated_hours != 0.0 %>
["<%=tracker.name%>", <%= result.get_tracker(tracker.name).estimated_hours %>],
<% end %>
<% end %>
<% end %>
];
cg.draw(items);
};
</script>
<table>
<tr>
<td>
<h4>予想</h4>
<div>
<canvas width="300" height="200" id="yosou"></canvas>
</div>
</td>
<td>
<h4>実績</h4>
<div>
<canvas width="300" height="200" id="jisseki"></canvas>
</div>
</td>
</tr>
</table>
<% end %>
<% end %>
<% end %>

できあがりのイメージ

画面で値を設定してSubumitすると・・・
pic20090214_123711

おおお!できましたね!!!