[NEW] Project Cumulative Flow and Task History for Kanban
bzr revid: fp@tinyerp.com-20111203140427-jf57fyvvo60g31dl
This commit is contained in:
parent
21b068b38d
commit
c1810c3483
|
@ -55,7 +55,8 @@ Dashboard for project members that includes:
|
|||
"res_partner_view.xml",
|
||||
"report/project_report_view.xml",
|
||||
"board_project_view.xml",
|
||||
'board_project_manager_view.xml'
|
||||
'board_project_manager_view.xml',
|
||||
'report/project_cumulative.xml'
|
||||
],
|
||||
'demo_xml': [
|
||||
'project_demo.xml',
|
||||
|
|
|
@ -974,6 +974,24 @@ class task(osv.osv):
|
|||
def prev_type(self, cr, uid, ids, *args):
|
||||
return self._change_type(cr, uid, ids, False, *args)
|
||||
|
||||
def _store_history(self, cr, uid, ids, context=None):
|
||||
for task in self.browse(cr, uid, ids, context=context):
|
||||
self.pool.get('project.task.history').create(cr, uid, {
|
||||
'task_id': task.id,
|
||||
'remaining_hours': task.remaining_hours,
|
||||
'kanban_state': task.kanban_state,
|
||||
'type_id': task.type_id.id,
|
||||
'state': task.state,
|
||||
'user_id': task.user_id.id
|
||||
|
||||
}, context=context)
|
||||
return True
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
result = super(task, self).create(cr, uid, vals, context=context)
|
||||
self._store_history(cr, uid, [result], context=context)
|
||||
return result
|
||||
|
||||
# Overridden to reset the kanban_state to normal whenever
|
||||
# the stage (type_id) of the task changes.
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
|
@ -985,8 +1003,12 @@ class task(osv.osv):
|
|||
for t in self.browse(cr, uid, ids, context=context):
|
||||
write_vals = vals_reset_kstate if t.type_id != new_stage else vals
|
||||
super(task,self).write(cr, uid, [t.id], write_vals, context=context)
|
||||
return True
|
||||
return super(task,self).write(cr, uid, ids, vals, context=context)
|
||||
result = True
|
||||
else:
|
||||
result = super(task,self).write(cr, uid, ids, vals, context=context)
|
||||
if ('type_id' in vals) or ('remaining_hours' in vals) or ('user_id' in vals) or ('state' in vals) or ('kanban_state' in vals):
|
||||
self._store_history(cr, uid, ids, context=context)
|
||||
return result
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
if context == None:
|
||||
|
@ -1084,4 +1106,91 @@ class account_analytic_account(osv.osv):
|
|||
|
||||
account_analytic_account()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
#
|
||||
# Tasks History, used for cumulative flow charts (Lean/Agile)
|
||||
#
|
||||
|
||||
class project_task_history(osv.osv):
|
||||
_name = 'project.task.history'
|
||||
_description = 'History of Tasks'
|
||||
_rec_name = 'task_id'
|
||||
_log_access = False
|
||||
def _get_date(self, cr, uid, ids, name, arg, context=None):
|
||||
result = {}
|
||||
for history in self.browse(cr, uid, ids, context=context):
|
||||
if history.state in ('done','cancelled'):
|
||||
result[history.id] = history.date
|
||||
continue
|
||||
cr.execute('''select
|
||||
date
|
||||
from
|
||||
project_task_history
|
||||
where
|
||||
task_id=%s and
|
||||
id>%s
|
||||
order by id limit 1''', (history.task_id.id, history.id))
|
||||
res = cr.fetchone()
|
||||
result[history.id] = res and res[0] or False
|
||||
return result
|
||||
|
||||
def _get_related_date(self, cr, uid, ids, context=None):
|
||||
result = []
|
||||
for history in self.browse(cr, uid, ids, context=context):
|
||||
cr.execute('''select
|
||||
id
|
||||
from
|
||||
project_task_history
|
||||
where
|
||||
task_id=%s and
|
||||
id<%s
|
||||
order by id desc limit 1''', (history.task_id.id, history.id))
|
||||
res = cr.fetchone()
|
||||
if res:
|
||||
result.append(res[0])
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'task_id': fields.many2one('project.task', 'Task', ondelete='cascade', required=True, select=True),
|
||||
'type_id': fields.many2one('project.task.type', 'Stage'),
|
||||
'state': fields.selection([('draft', 'New'),('open', 'In Progress'),('pending', 'Pending'), ('done', 'Done'), ('cancelled', 'Cancelled')], 'State'),
|
||||
'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready To Pull')], 'Kanban State', required=False),
|
||||
'date': fields.date('Date', select=True),
|
||||
'end_date': fields.function(_get_date, string='End Date', type="date", store={
|
||||
'project.task.history': (_get_related_date, None, 20)
|
||||
}),
|
||||
'remaining_hours': fields.float('Remaining Hours', digits=(16,2)),
|
||||
'user_id': fields.many2one('res.users', 'Responsible'),
|
||||
}
|
||||
_defaults = {
|
||||
'date': lambda s,c,u,ctx: time.strftime('%Y-%m-%d')
|
||||
}
|
||||
project_task_history()
|
||||
|
||||
class project_task_history_cumulative(osv.osv):
|
||||
_name = 'project.task.history.cumulative'
|
||||
_table = 'project_task_history_cumulative'
|
||||
_inherit = 'project.task.history'
|
||||
_auto = False
|
||||
_columns = {
|
||||
'end_date': fields.date('End Date'),
|
||||
'project_id': fields.related('task_id', 'project_id', string='Project', type='many2one', relation='project.project')
|
||||
}
|
||||
def init(self, cr):
|
||||
cr.execute(""" CREATE OR REPLACE VIEW project_task_history_cumulative AS (
|
||||
SELECT
|
||||
history.date::varchar||'-'||history.history_id::varchar as id,
|
||||
history.date as end_date,
|
||||
*
|
||||
FROM (
|
||||
SELECT
|
||||
id as history_id,
|
||||
date+generate_series(0, CAST((coalesce(end_date,DATE 'tomorrow')::date - date)AS integer)-1) as date,
|
||||
task_id, type_id, user_id, kanban_state, state,
|
||||
remaining_hours
|
||||
FROM
|
||||
project_task_history
|
||||
) as history
|
||||
)
|
||||
""")
|
||||
project_task_history_cumulative()
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_task_history_tree" model="ir.ui.view">
|
||||
<field name="name">project.task.history.cumulative.tree</field>
|
||||
<field name="model">project.task.history.cumulative</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Tasks's Cumulative Flow">
|
||||
<field name="date"/>
|
||||
<field name="project_id"/>
|
||||
<field name="task_id"/>
|
||||
<field name="type_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="remaining_hours"/>
|
||||
<field name="kanban_state"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_task_history_graph" model="ir.ui.view">
|
||||
<field name="name">project.task.history.cumulative.graph</field>
|
||||
<field name="model">project.task.history.cumulative</field>
|
||||
<field name="type">graph</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Project Tasks" type="bar">
|
||||
<field name="date"/>
|
||||
<field name="remaining_hours" operator="+"/>
|
||||
<field name="type_id" group="True"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_task_history_search" model="ir.ui.view">
|
||||
<field name="name">project.task.history.cumulative.search</field>
|
||||
<field name="model">project.task.history.cumulative</field>
|
||||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Task's Cumulative Flow">
|
||||
<group>
|
||||
<filter name="open" string="In Progress" domain="[('state','in',('open','draft'))]" help="In Progress Tasks" icon="terp-camera_test"/>
|
||||
<filter string="Pending" domain="[('state','=','pending')]" context="{'show_delegated':False}" help="Pending Tasks" icon="terp-gtk-media-pause"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter name="kanban_blocked" string="Blocked" domain="[('kanban_state','=','blocked')]" icon="terp-gtk-media-pause"/>
|
||||
<filter name="kanban_ready" string="Ready" domain="[('kanban_state','=','done')]" icon="terp-camera_test"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter string="Month" icon="terp-go-month" name="this_month"
|
||||
domain="[('date','<=',(datetime.date.today()+relativedelta(day=31)).strftime('%%Y-%%m-%%d')),('date','>=',(datetime.date.today()-relativedelta(day=1)).strftime('%%Y-%%m-%%d'))]"/>
|
||||
<filter icon="terp-go-month" string="Month-1" name="month1"
|
||||
domain="[('date','<=', (datetime.date.today() - relativedelta(day=31, months=1)).strftime('%%Y-%%m-%%d')),('date','>=',(datetime.date.today() - relativedelta(day=1,months=1)).strftime('%%Y-%%m-%%d'))]"/>
|
||||
<filter icon="terp-go-month" string="Month-2" name="month2"
|
||||
domain="[('date','<=', (datetime.date.today() - relativedelta(day=31, months=2)).strftime('%%Y-%%m-%%d')),('date','>=',(datetime.date.today() - relativedelta(day=1,months=2)).strftime('%%Y-%%m-%%d'))]"/>
|
||||
<separator orientation="vertical"/>
|
||||
<field name="project_id">
|
||||
<filter domain="[('project_id.user_id','=',uid)]" help="My Projects" icon="terp-personal"/>
|
||||
</field>
|
||||
<field name="user_id">
|
||||
<filter domain="[('user_id','=',uid)]" help="My Tasks" icon="terp-personal" />
|
||||
<filter domain="[('user_id','=',False)]" help="Unassigned Tasks" icon="terp-personal-" />
|
||||
</field>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_view_task_history_cumulative" model="ir.actions.act_window">
|
||||
<field name="name">Cumulative Flow</field>
|
||||
<field name="res_model">project.task.history.cumulative</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">graph,tree</field>
|
||||
<field eval="False" name="filter"/>
|
||||
<field name="context">{"search_default_open":1, "search_default_this_month": 1}</field>
|
||||
</record>
|
||||
<menuitem action="action_view_task_history_cumulative"
|
||||
id="menu_action_view_task_history_cumulative"
|
||||
parent="project_report_task" />
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -5,6 +5,8 @@
|
|||
<menuitem id="base.menu_project_report" name="Reporting"
|
||||
groups="project.group_project_manager"
|
||||
parent="base.menu_main_pm" sequence="50"/>
|
||||
<menuitem id="project_report_task" name="Tasks"
|
||||
parent="base.menu_project_report"/>
|
||||
|
||||
<record id="view_task_project_user_tree" model="ir.ui.view">
|
||||
<field name="name">report.project.task.user.tree</field>
|
||||
|
@ -152,7 +154,7 @@
|
|||
<field name="help">This report allows you to analyse the performance of your projects and users. You can analyse the quantities of tasks, the hours spent compared to the planned hours, the average number of days to open or close a task, etc.</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_project_task_user_tree" id="menu_project_task_user_tree" parent="base.menu_project_report"/>
|
||||
<menuitem action="action_project_task_user_tree" id="menu_project_task_user_tree" parent="project_report_task"/>
|
||||
|
||||
<!-- Views and action for project dashboard -->
|
||||
<record id="view_project_vs_remaining_hours_tree" model="ir.ui.view">
|
||||
|
|
|
@ -22,3 +22,5 @@
|
|||
"access_project_task_sale_user","project.task salesman","model_project_task","base.group_sale_salesman",1,0,0,0
|
||||
"access_project_project_sale_user","project.project salesman","model_project_project","base.group_sale_salesman",1,0,0,0
|
||||
"access_account_analytic_line_project","account.analytic.line project","analytic.model_account_analytic_line","project.group_project_manager",1,1,1,1
|
||||
"access_project_task_history","project.task.history project","project.model_project_task_history","project.group_project_user",1,1,1,0
|
||||
"access_project_task_history_cumulative","project.task.history project","project.model_project_task_history_cumulative","project.group_project_manager",1,0,0,0
|
||||
|
|
|
Loading…
Reference in New Issue