• R/O
  • SSH
  • HTTPS

shibuya-trac: Commit


Commit MetaInfo

Revision778 (tree)
Time2011-04-01 18:13:13
Authorokamototk

Log Message

support show parent ticket at worktime view.

Change Summary

Incremental Difference

--- plugins/tracsteinschartplugin/trunk/tracsteinschart/worktime/web_ui.py (revision 777)
+++ plugins/tracsteinschartplugin/trunk/tracsteinschart/worktime/web_ui.py (revision 778)
@@ -4,6 +4,7 @@
44 from datetime import datetime
55 from pkg_resources import resource_filename
66 from trac.log import logger_factory
7+from trac.config import BoolOption
78 from trac.core import *
89 from trac.util import Markup
910 from trac.util.datefmt import utc, to_utimestamp
@@ -19,6 +20,8 @@
1920
2021 class WorktimeRecorder(Component):
2122 implements(INavigationContributor, IRequestHandler, ITemplateProvider)
23+
24+ show_parent_ticket = BoolOption('steinschart', 'show_parent_ticket', 'false', """Show parent ticket (needs subtickets plugin).(default: false)""")
2225
2326 def __init__(self):
2427 locale_dir = resource_filename('tracsteinschart', 'locale')
@@ -81,7 +84,7 @@
8184 add_warning(req,"チケット#%sの残り作業時間%sが実数ではありません。" % (id ,p[property]))
8285 except ValueError:
8386 pass
84- self.log.info(params)
87+ self.log.debug(params)
8588 if len(errors)==0:
8689 self.update_tickets(req,cursor,db,params)
8790 user = req.authname
@@ -88,20 +91,34 @@
8891 def addMessage(s):
8992 messages.extend([s]);
9093
91- tickets = self.get_tickets(req, cursor)
92- # replace error fields
93- self.log.info(errors)
94- self.log.info(tickets)
95- for e in errors:
96- id = int(e['id'])
97- for ticket in tickets:
98- if ticket['id']==id:
99- ticket[e['name']]=e['value']
94+ show_parent_ticket = self.config.getbool('steinschart','show_parent_ticket')
95+ if show_parent_ticket:
96+ tickets = self.get_nested_tickets(req, cursor)
97+# for e in errors:
98+# id = int(e['id'])
99+# for ptickets in tickets.values():
100+# for ntickets in ptickets.values():
101+# for ticket in ntickets:
102+# if ticket['id']==id:
103+# ticket[e['name']]=e['value']
104+
105+
106+ else:
107+ tickets = self.get_tickets(req, cursor)
108+# for e in errors:
109+# id = int(e['id'])
110+# for ticket in tickets:
111+# if ticket['id']==id:
112+# ticket[e['name']]=e['value']
113+
100114
101115 add_script(req, 'steinschart/js/worktime.js')
102116 add_stylesheet(req, 'common/css/report.css')
103- return 'worktime.html', {'tickets':tickets, 'req':req, 'today': datetime.today()}, None
104-
117+ if show_parent_ticket:
118+ return 'worktime_nestedticket.html', {'tickets':tickets, 'req':req, 'today': datetime.today()}, None
119+ else:
120+ return 'worktime.html', {'tickets':tickets, 'req':req, 'today': datetime.today()}, None
121+
105122 def update_tickets(self, req, cursor, db, params):
106123 change_time = datetime.now(utc)
107124 for ticket_id in params:
@@ -127,7 +144,7 @@
127144 (ticket_id, to_utimestamp(change_time), req.authname, hours))
128145 if abs(current_estimatedhours - estimatedhours) >= 0.01:
129146 changed = True
130- self.log.info("change estimatedhours: %s -> %s" %
147+ self.log.debug("change estimatedhours: %s -> %s" %
131148 (current_estimatedhours, estimatedhours))
132149 ticket["estimatedhours"] = str(estimatedhours)
133150
@@ -148,6 +165,75 @@
148165 ticket.save_changes(author=req.authname, when=change_time)
149166 db.commit()
150167
168+ def get_nested_tickets(self, req, cursor):
169+ sql = """SELECT t.milestone ,sub.parent ,parent.summary ,t.id ,t.type ,t.owner, t.summary ,t.priority ,cth.value ,cbil.value , cest.value FROM ticket t
170+ JOIN ticket_custom cth ON t.id=cth.ticket
171+ JOIN ticket_custom cbil ON t.id=cbil.ticket
172+ JOIN ticket_custom cest ON t.id=cest.ticket
173+ LEFT JOIN subtickets sub ON t.id=sub.child
174+ LEFT JOIN ticket parent ON parent.id=sub.parent
175+ WHERE t.status <> 'closed' AND t.owner='%s' AND
176+ cth.name='totalhours' AND cbil.name='billable' AND cest.name='estimatedhours'
177+ ORDER BY t.milestone, sub.parent""" % req.authname
178+ cursor.execute(sql)
179+ tickets = []
180+ ptickets = {}
181+ current_milestone=''
182+ current_psummary=''
183+ current_pid=0
184+ mtickets = {}
185+ for milestone, pid, psummary, id, type, owner, summary, priority, totalhours, billable, estimatedhours in cursor:
186+ # 初回のループの場合、初期化
187+ if current_pid == 0:
188+ current_milestone = milestone
189+ current_pid = pid
190+ current_psummary = psummary
191+ if not pid:
192+ current_psummary = u'その他(親チケットなし)'
193+
194+ billable = 'true' if billable=='1' else 'false'
195+ totalhours = totalhours if totalhours!='' else '0'
196+ estimatedhours = estimatedhours if totalhours!='' else '0'
197+ t = {'pid':pid, 'psummary':psummary, 'id':id ,'type':type, 'owner': owner, 'summary':summary, 'priority': priority , 'milestone':milestone, 'totalhours': totalhours, 'billable': billable, 'estimatedhours': estimatedhours}
198+ if milestone == current_milestone:
199+ if pid!= current_pid:
200+ ptickets[(current_pid, current_psummary)]=tickets;
201+ tickets = []
202+ tickets.append(t)
203+ current_pid = pid
204+ current_psummary = psummary
205+ if not pid:
206+ current_psummary = u'その他(親チケットなし)'
207+ else:
208+ ptickets[(current_pid, current_psummary)]=tickets;
209+ mtickets[current_milestone] = ptickets
210+ ptickets = {}
211+ tickets = []
212+ current_milestone = milestone
213+ current_pid = pid
214+ current_psummary = psummary
215+ if not pid:
216+ current_psummary = u'その他(親チケットなし)'
217+ tickets.append(t)
218+
219+ ptickets[(current_pid, current_psummary)]=tickets;
220+ mtickets[current_milestone] = ptickets
221+ t = datetime.today()
222+ t = datetime(t.year,t.month,t.day)
223+ start = int(time.mktime(t.timetuple())*1e6)
224+ end = int(time.mktime(t.timetuple())*1e6+24*60*60*1e6)
225+ for ptickets in mtickets.values():
226+ for tickets in ptickets.values():
227+ for ticket in tickets:
228+ sql = "SELECT * from ticket_change WHERE ticket='%s' AND field='totalhours' AND time > %s AND time < %s" % (ticket['id'], start, end)
229+ self.log.debug(sql)
230+ cursor.execute(sql)
231+ row = cursor.fetchone()
232+ if row:
233+ ticket['reported'] = True
234+ else:
235+ ticket['reported'] = False
236+ return mtickets
151237
152238 def get_tickets(self, req, cursor):
153239 sql = """SELECT t.id ,t.type ,t.owner, t.summary ,t.priority ,t.milestone ,cth.value ,cbil.value , cest.value FROM ticket t
@@ -172,7 +258,7 @@
172258
173259 for ticket in tickets:
174260 sql = "SELECT * from ticket_change WHERE ticket='%s' AND field='totalhours' AND time > %s AND time < %s" % (ticket['id'], start, end)
175- self.log.info(sql)
261+ self.log.debug(sql)
176262 cursor.execute(sql)
177263 row = cursor.fetchone()
178264 if row:
--- plugins/tracsteinschartplugin/trunk/README-ja.txt (revision 777)
+++ plugins/tracsteinschartplugin/trunk/README-ja.txt (revision 778)
@@ -1,43 +1,57 @@
1-= シュタインズチャートプラグイン =
2-このプラグインは、Tracにスクラムのバーンダウンチャート機能を追加します。シュタインズチャートという名前に特に意味はありません。
1+= 繧キ繝・繧ソ繧、繝ウ繧コ繝√Ε繝シ繝医?繝ゥ繧ー繧、繝ウ =
2+縺薙?繝励Λ繧ー繧、繝ウ縺ッ縲ゝrac縺ォ繧ケ繧ッ繝ゥ繝?縺ョ繝舌?繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝域ゥ溯?繧定ソス蜉?縺励∪縺吶?ゅす繝・繧ソ繧、繝ウ繧コ繝√Ε繝シ繝医→縺?≧蜷榊燕縺ォ迚ケ縺ォ諢丞袖縺ッ縺ゅj縺セ縺帙s縲
33
4-プロジェクト全体のバーンダウンチャートと、チーム個別のバーンダウンチャートを表示することができます。
5-複数のチームで開発している場合は、全てのチームのバーンダウンチャートを重ねて表示することもできます;
4+繝励Ο繧ク繧ァ繧ッ繝亥?菴薙?繝舌?繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝医→縲√メ繝シ繝?蛟句挨縺ョ繝舌?繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝医r陦ィ遉コ縺吶k縺薙→縺後〒縺阪∪縺吶?
5+隍?焚縺ョ繝√?繝?縺ァ髢狗匱縺励※縺?k蝣エ蜷医?縲∝?縺ヲ縺ョ繝√?繝?縺ョ繝舌?繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝医r驥阪?縺ヲ陦ィ遉コ縺吶k縺薙→繧ゅ〒縺阪∪縺呻シ
66
7-日本の企業向けにカスタマイズしており、作業時間を入力していくことにより、同時にチームメンバーの稼動時間も管理できるようにしています。うるさいマネージャ対策として、稼動時間の表示は無効にすることもできます。
7+譌・譛ャ縺ョ莨∵・ュ蜷代¢縺ォ繧ォ繧ケ繧ソ繝槭う繧コ縺励※縺翫j縲∽ス懈・ュ譎る俣繧貞?蜉帙@縺ヲ縺?¥縺薙→縺ォ繧医j縲∝酔譎ゅ↓繝√?繝?繝。繝ウ繝舌?縺ョ遞シ蜍墓凾髢薙b邂。逅?〒縺阪k繧医≧縺ォ縺励※縺?∪縺吶?ゅ≧繧九&縺??繝阪?繧ク繝」蟇セ遲悶→縺励※縲∫ィシ蜍墓凾髢薙?陦ィ遉コ縺ッ辟。蜉ケ縺ォ縺吶k縺薙→繧ゅ〒縺阪∪縺吶?
88
9-== 特徴 ==
10-=== バーンダウンチャートの表示 ===
11-実績のバーンダウンを表示することができます。また、休日を考慮した目標残作業時間も表示します。
9+== 迚ケ蠕エ ==
10+=== 繝舌?繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝医?陦ィ遉コ ===
11+螳溽クセ縺ョ繝舌?繝ウ繝?繧ヲ繝ウ繧定。ィ遉コ縺吶k縺薙→縺後〒縺阪∪縺吶?ゅ∪縺溘?∽シ第律繧定???縺励◆逶ョ讓呎ョ倶ス懈・ュ譎る俣繧り。ィ遉コ縺励∪縺吶?
1212
13-=== 複数チームに対応 ===
14-コンポーネントにチームを割り当てることで、複数のチームの管理を行うことができます。もちろん、1つのチームでもご利用頂けます。複数のチームのバーンダウンを重ね合わせて全体の進捗を管理する機能も持っています。
13+=== 隍?焚繝√?繝?縺ォ蟇セ蠢 ===
14+繧ウ繝ウ繝昴?繝阪Φ繝医↓繝√?繝?繧貞牡繧雁ス薙※繧九%縺ィ縺ァ縲∬、?焚縺ョ繝√?繝?縺ョ邂。逅?r陦後≧縺薙→縺後〒縺阪∪縺吶?ゅb縺。繧阪s縲?縺、縺ョ繝√?繝?縺ァ繧ゅ#蛻ゥ逕ィ鬆ゅ¢縺セ縺吶?り、?焚縺ョ繝√?繝?縺ョ繝舌?繝ウ繝?繧ヲ繝ウ繧帝?縺ュ蜷医o縺帙※蜈ィ菴薙?騾イ謐励r邂。逅?☆繧区ゥ溯?繧よ戟縺」縺ヲ縺?∪縺吶?
1515
16-=== プロジェクトマネージャ用の分析機能 ===
17-本来スクラムプロセスでは、プロジェクトマネージャは存在しません。しかしながら、多くの日本企業には部長、課長という役職が存在し、残念ながら彼らはスクラムマスターやチームメンバーになり得まず、スクラムから外れた存在になってしまいます。タイムライン分析機能や、稼動時間の集計機能など、彼ら向けの機能を提供することにより日本の現場により導入し易くなります。
16+=== 繝励Ο繧ク繧ァ繧ッ繝医?繝阪?繧ク繝」逕ィ縺ョ蛻?梵讖溯? ===
17+譛ャ譚・繧ケ繧ッ繝ゥ繝?繝励Ο繧サ繧ケ縺ァ縺ッ縲√?繝ュ繧ク繧ァ繧ッ繝医?繝阪?繧ク繝」縺ッ蟄伜惠縺励∪縺帙s縲ゅ@縺九@縺ェ縺後i縲∝、壹¥縺ョ譌・譛ャ莨∵・ュ縺ォ縺ッ驛ィ髟キ縲∬ェイ髟キ縺ィ縺?≧蠖ケ閨キ縺悟ュ伜惠縺励?∵ョ句ソオ縺ェ縺後i蠖シ繧峨?繧ケ繧ッ繝ゥ繝?繝槭せ繧ソ繝シ繧?メ繝シ繝?繝。繝ウ繝舌?縺ォ縺ェ繧雁セ励∪縺壹?√せ繧ッ繝ゥ繝?縺九i螟悶l縺溷ュ伜惠縺ォ縺ェ縺」縺ヲ縺励∪縺?∪縺吶?ゅち繧、繝?繝ゥ繧、繝ウ蛻?梵讖溯?繧??∫ィシ蜍墓凾髢薙?髮?ィ域ゥ溯?縺ェ縺ゥ縲∝スシ繧牙髄縺代?讖溯?繧呈署萓帙☆繧九%縺ィ縺ォ繧医j譌・譛ャ縺ョ迴セ蝣エ縺ォ繧医j蟆主?縺玲?縺上↑繧翫∪縺吶?
1818
19-== バーンダウンチャートの実績からタイムラインを参照可能 ==
20-ある日のバーンダウンが急激に上昇した場合、プロジェクトで何らかの問題が発生したことが予想されます。Steins;Chartでは、バーンダウンチャート上にプロットされた点をクリックすることにより、その日のタイムラインを表示することができ、問題を確認することができます。
19+== 繝舌?繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝医?螳溽クセ縺九i繧ソ繧、繝?繝ゥ繧、繝ウ繧貞盾辣ァ蜿ッ閭ス ==
20+縺ゅk譌・縺ョ繝舌?繝ウ繝?繧ヲ繝ウ縺梧?・豼?縺ォ荳頑?縺励◆蝣エ蜷医?√?繝ュ繧ク繧ァ繧ッ繝医〒菴輔i縺九?蝠城。後′逋コ逕溘@縺溘%縺ィ縺御コ域Φ縺輔l縺セ縺吶?4teins;Chart縺ァ縺ッ縲√ヰ繝シ繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝井ク翫↓繝励Ο繝?ヨ縺輔l縺溽せ繧偵け繝ェ繝?け縺吶k縺薙→縺ォ繧医j縲√◎縺ョ譌・縺ョ繧ソ繧、繝?繝ゥ繧、繝ウ繧定。ィ遉コ縺吶k縺薙→縺後〒縺阪?∝撫鬘後r遒コ隱阪☆繧九%縺ィ縺後〒縺阪∪縺吶?
2121
22-== 稼働時間の集計が可能 ==
23-チームメンバがタスクの稼動時間を入力していくことにより、チームメンバの稼動時間を集計することができます。また、稼動時間の入力に負荷を掛けないように、1画面でその日の稼動時間を入力できる一括入力ビューを提供しています。
22+== 遞シ蜒肴凾髢薙?髮?ィ医′蜿ッ閭ス ==
23+繝√?繝?繝。繝ウ繝舌′繧ソ繧ケ繧ッ縺ョ遞シ蜍墓凾髢薙r蜈・蜉帙@縺ヲ縺?¥縺薙→縺ォ繧医j縲√メ繝シ繝?繝。繝ウ繝舌?遞シ蜍墓凾髢薙r髮?ィ医☆繧九%縺ィ縺後〒縺阪∪縺吶?ゅ∪縺溘?∫ィシ蜍墓凾髢薙?蜈・蜉帙↓雋?闕キ繧呈寺縺代↑縺?h縺?↓縲?逕サ髱「縺ァ縺昴?譌・縺ョ遞シ蜍墓凾髢薙r蜈・蜉帙〒縺阪k荳?諡ャ蜈・蜉帙ン繝・繝シ繧呈署萓帙@縺ヲ縺?∪縺吶?
2424
25-== ScrumBurndownプラグイン互換 ==
26-既にTracでスクラムのバーンダウンチャートを利用するためのプラグインとしてScrumBurndownPluginが提供されています。Steins;Chartプラグインは既にScrumBurndownPluginを利用している場合、置き換えて利用することができます(Steins;Chartプラグインを利用する場合、ScrumBurndownPluginは必ず無効にしてください)
25+== ScrumBurndown繝励Λ繧ー繧、繝ウ莠呈鋤 ==
26+譌「縺ォTrac縺ァ繧ケ繧ッ繝ゥ繝?縺ョ繝舌?繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝医r蛻ゥ逕ィ縺吶k縺溘a縺ョ繝励Λ繧ー繧、繝ウ縺ィ縺励※ScrumBurndownPlugin縺梧署萓帙&繧後※縺?∪縺吶?4teins;Chart繝励Λ繧ー繧、繝ウ縺ッ譌「縺ォScrumBurndownPlugin繧貞茜逕ィ縺励※縺?k蝣エ蜷医?∫スョ縺肴鋤縺医※蛻ゥ逕ィ縺吶k縺薙→縺後〒縺阪∪縺?Steins;Chart繝励Λ繧ー繧、繝ウ繧貞茜逕ィ縺吶k蝣エ蜷医?ヾcrumBurndownPlugin縺ッ蠢?★辟。蜉ケ縺ォ縺励※縺上□縺輔>)
2727
28-== 前提条件 ==
29-timingandestimateプラグインを利用することを前提としています。
30-また、subticketsプラグインを利用するとプロダクトバックログとスプリントバックログの紐付けができて便利です。必須ではありませんが、subticketsプラグインの利用を推奨します。
28+== 蜑肴署譚。莉カ ==
29+timingandestimate繝励Λ繧ー繧、繝ウ繧貞茜逕ィ縺吶k縺薙→繧貞燕謠舌→縺励※縺?∪縺吶?
30+縺セ縺溘?《ubtickets繝励Λ繧ー繧、繝ウ繧貞茜逕ィ縺吶k縺ィ繝励Ο繝?繧ッ繝医ヰ繝?け繝ュ繧ー縺ィ繧ケ繝励Μ繝ウ繝医ヰ繝?け繝ュ繧ー縺ョ邏蝉サ倥¢縺後〒縺阪※萓ソ蛻ゥ縺ァ縺吶?ょソ??医〒縺ッ縺ゅj縺セ縺帙s縺後?《ubtickets繝励Λ繧ー繧、繝ウ縺ョ蛻ゥ逕ィ繧呈耳螂ィ縺励∪縺吶?
3131
32-バーンダウンの表示は、billable(集計に含める?)フィールドにチェックが入っているチケットが対象です。必ずチェックを入れてください。
32+繝舌?繝ウ繝?繧ヲ繝ウ縺ョ陦ィ遉コ縺ッ縲|illable(髮?ィ医↓蜷ォ繧√k?)繝輔ぅ繝シ繝ォ繝峨↓繝√ぉ繝?け縺悟?縺」縺ヲ縺?k繝√こ繝?ヨ縺悟ッセ雎。縺ァ縺吶?ょソ?★繝√ぉ繝?け繧貞?繧後※縺上□縺輔>縲
3333
34-== インストール ==
34+== 繧、繝ウ繧ケ繝医?繝ォ ==
3535 {{{
3636 > svn co http://****/
3737 > python setup.py install
3838 }}}
3939
40+== 險ュ螳 ==
41+=== 隕ェ繝√こ繝?ヨ縺ョ陦ィ遉コ ==
42+繧キ繝・繧ソ繧、繝ウ繧コ繝サ繝√Ε繝シ繝医?縲∽ス懈・ュ蜈・蜉帛?蜉帷判髱「縺ョ繝√こ繝?ヨ陦ィ遉コ縺ァ隕ェ繝√こ繝?ヨ繧定。ィ遉コ縺吶k縺薙→縺後〒縺阪∪縺吶?ゅ%縺ョ讖溯?縺ッ繧ケ繧ッ繝ゥ繝?縺ァ繧ケ繝医?繝ェ縺ィ繧ソ繧ケ繧ッ繧呈律繧ゆサ倥¢縺ヲ陦ィ遉コ縺励◆縺?→縺堺セソ蛻ゥ縺ァ縺吶?
43+隕ェ繧ソ繧ケ繧ッ繧定。ィ遉コ縺吶k縺ォ縺ッ縲》rac.ini繝輔ぃ繧、繝ォ縺ァ谺。縺ョ繧医≧縺ォ險ュ螳壹@縺ヲ縺上□縺輔>縲
4044
45+[steinschart]
46+show_parent_ticket=true
4147
4248
49+=== 菴懈・ュ譎る俣縺ョ陦ィ遉コ ===
50+繧キ繝・繧ソ繧、繝ウ繧コ繝√Ε繝シ繝医〒縺ッ縲√ヰ繝シ繝ウ繝?繧ヲ繝ウ繝√Ε繝シ繝医?逕サ髱「縺ァ蜷?メ繝シ繝?繝。繝ウ繝舌?菴懈・ュ譎る俣繧定。ィ遉コ縺吶k縺薙→縺後〒縺阪∪縺吶?
51+荳?闊ャ逧?↓繧「繧ク繝」繧、繝ォ髢狗匱縺ァ縺ッ蜷?メ繝シ繝?繝。繝ウ繝舌?菴懈・ュ譎る俣繧帝寔險医☆繧九%縺ィ縺ッ螂ス縺セ繧後∪縺帙s縺後?√◎縺ョ繧医≧縺ェ繝九?繧コ繧ゅ≠繧九→閠?∴縲√%縺ョ讖溯?繧呈戟縺」縺ヲ縺?∪縺吶?ゅョ繝輔か繝ォ繝医〒縺ッ辟。蜉ケ縺ォ縺ェ縺」縺ヲ縺?∪縺吶′縲∵ャ。縺ョ繧医≧縺ォtrac.ini縺ォ險ュ螳壹☆繧九%縺ィ縺ォ繧医j譛牙柑縺ォ縺吶k縺薙→縺後〒縺阪∪縺吶?
4352
53+[steinschart]
54+draw_worktime=true
55+
56+
57+
Show on old repository browser