summaryrefslogtreecommitdiff
path: root/addons/project
diff options
context:
space:
mode:
Diffstat (limited to 'addons/project')
-rw-r--r--addons/project/__openerp__.py9
-rw-r--r--addons/project/board_project_view.xml5
-rw-r--r--addons/project/project.py160
-rw-r--r--addons/project/project_demo.xml13
-rw-r--r--addons/project/project_view.xml26
-rw-r--r--addons/project/report/project_cumulative.xml109
-rw-r--r--addons/project/report/project_report_view.xml29
-rw-r--r--addons/project/res_partner_view.xml3
-rw-r--r--addons/project/security/ir.model.access.csv42
-rw-r--r--addons/project/security/project_security.xml10
-rw-r--r--addons/project/static/src/img/icon.pngbin0 -> 4172 bytes
-rw-r--r--addons/project/test/project_demo.yml12
-rw-r--r--addons/project/test/project_process.yml70
-rw-r--r--addons/project/test/task_process.yml76
-rw-r--r--addons/project/test/test_project.yml296
-rw-r--r--addons/project/test/test_project_delegation.yml230
16 files changed, 476 insertions, 614 deletions
diff --git a/addons/project/__openerp__.py b/addons/project/__openerp__.py
index 9132636b56f..1b25c9d15cc 100644
--- a/addons/project/__openerp__.py
+++ b/addons/project/__openerp__.py
@@ -55,17 +55,20 @@ 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',
],
'test':[
- 'test/test_project.yml',
- 'test/test_project_delegation.yml',
+ 'test/project_demo.yml',
+ 'test/project_process.yml',
+ 'test/task_process.yml',
],
'installable': True,
'active': False,
+ 'application': True,
'certificate': '0075116868317',
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/project/board_project_view.xml b/addons/project/board_project_view.xml
index a58557c94ba..88424be85fa 100644
--- a/addons/project/board_project_view.xml
+++ b/addons/project/board_project_view.xml
@@ -81,13 +81,12 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="My Board">
- <board style="1-2">
+ <board style="2-1">
<column>
- <action name="%(my_open_tasks_action)d" string="My Open Tasks"/>
+ <action name="%(my_open_tasks_action)d" string="My Open Tasks" creatable="true"/>
<action name="%(action_view_delegate_task_tree)d" string="My Delegated Tasks"/>
</column>
<column>
- <action name="%(project.action_project_vs_planned_total_hours_graph)d" string="My Projects: Planned vs Total Hours"/>
<action name="%(project.action_project_vs_remaining_hours_graph)d" string="My Remaining Hours by Project"/>
</column>
</board>
diff --git a/addons/project/project.py b/addons/project/project.py
index abebd2d35ff..0046dea4409 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -114,6 +114,7 @@ class project(osv.osv):
if task.project_id: result[task.project_id.id] = True
return result.keys()
+ #dead code
def _get_project_work(self, cr, uid, ids, context=None):
result = {}
for work in self.pool.get('project.task.work').browse(cr, uid, ids, context=context):
@@ -360,7 +361,7 @@ def Project():
working_days = %s
resource = %s
""" % (
- project.id,
+ project.id,
project.date_start, working_days,
'|'.join(['User_'+str(x) for x in puids])
)
@@ -879,14 +880,24 @@ class task(osv.osv):
self.write(cr, uid, ids, {'state': 'draft'}, context=context)
return True
+
+ def _delegate_task_attachments(self, cr, uid, task_id, delegated_task_id, context=None):
+ attachment = self.pool.get('ir.attachment')
+ attachment_ids = attachment.search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', task_id)], context=context)
+ new_attachment_ids = []
+ for attachment_id in attachment_ids:
+ new_attachment_ids.append(attachment.copy(cr, uid, attachment_id, default={'res_id': delegated_task_id}, context=context))
+ return new_attachment_ids
+
+
def do_delegate(self, cr, uid, ids, delegate_data={}, context=None):
"""
Delegate Task to another users.
"""
assert delegate_data['user_id'], _("Delegated User should be specified")
- delegrated_tasks = {}
+ delegated_tasks = {}
for task in self.browse(cr, uid, ids, context=context):
- delegrated_task_id = self.copy(cr, uid, task.id, {
+ delegated_task_id = self.copy(cr, uid, task.id, {
'name': delegate_data['name'],
'project_id': delegate_data['project_id'] and delegate_data['project_id'][0] or False,
'user_id': delegate_data['user_id'] and delegate_data['user_id'][0] or False,
@@ -897,6 +908,7 @@ class task(osv.osv):
'child_ids': [],
'work_ids': []
}, context=context)
+ self._delegate_task_attachments(cr, uid, task.id, delegated_task_id, context=context)
newname = delegate_data['prefix'] or ''
task.write({
'remaining_hours': delegate_data['planned_hours_me'],
@@ -910,8 +922,8 @@ class task(osv.osv):
message = _("The task '%s' has been delegated to %s.") % (delegate_data['name'], delegate_data['user_id'][1])
self.log(cr, uid, task.id, message)
- delegrated_tasks[task.id] = delegrated_task_id
- return delegrated_tasks
+ delegated_tasks[task.id] = delegated_task_id
+ return delegated_tasks
def do_pending(self, cr, uid, ids, context={}):
self.write(cr, uid, ids, {'state': 'pending'}, context=context)
@@ -920,21 +932,24 @@ class task(osv.osv):
self.log(cr, uid, id, message)
return True
- def set_remaining_time_1(self, cr, uid, ids, context=None):
- self.write(cr, uid, ids, {'remaining_hours': 1.0}, context=context)
+ def set_remaining_time(self, cr, uid, ids, remaining_time=1.0, context=None):
+ for task in self.browse(cr, uid, ids, context=context):
+ if (task.state=='draft') or (task.planned_hours==0.0):
+ self.write(cr, uid, [task.id], {'planned_hours': remaining_time}, context=context)
+ self.write(cr, uid, ids, {'remaining_hours': remaining_time}, context=context)
return True
+ def set_remaining_time_1(self, cr, uid, ids, context=None):
+ return self.set_remaining_time(cr, uid, ids, 1.0, context)
+
def set_remaining_time_2(self, cr, uid, ids, context=None):
- self.write(cr, uid, ids, {'remaining_hours': 2.0}, context=context)
- return True
+ return self.set_remaining_time(cr, uid, ids, 2.0, context)
def set_remaining_time_5(self, cr, uid, ids, context=None):
- self.write(cr, uid, ids, {'remaining_hours': 5.0}, context=context)
- return True
+ return self.set_remaining_time(cr, uid, ids, 5.0, context)
def set_remaining_time_10(self, cr, uid, ids, context=None):
- self.write(cr, uid, ids, {'remaining_hours': 10.0}, context=context)
- return True
+ return self.set_remaining_time(cr, uid, ids, 10.0, context)
def set_kanban_state_blocked(self, cr, uid, ids, context=None):
self.write(cr, uid, ids, {'kanban_state': 'blocked'}, context=context)
@@ -974,6 +989,25 @@ 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,
+ 'planned_hours': task.planned_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 +1019,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:
@@ -1074,7 +1112,7 @@ class account_analytic_account(osv.osv):
if vals.get('child_ids', False) and context.get('analytic_project_copy', False):
vals['child_ids'] = []
return super(account_analytic_account, self).create(cr, uid, vals, context=context)
-
+
def unlink(self, cr, uid, ids, *args, **kwargs):
project_obj = self.pool.get('project.project')
analytic_ids = project_obj.search(cr, uid, [('analytic_account_id','in',ids)])
@@ -1084,4 +1122,92 @@ 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 Time', digits=(16,2)),
+ 'planned_hours': fields.float('Planned Time', 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, planned_hours
+ FROM
+ project_task_history
+ ) as history
+ )
+ """)
+project_task_history_cumulative()
+
diff --git a/addons/project/project_demo.xml b/addons/project/project_demo.xml
index 7592d24a145..42da9fdefff 100644
--- a/addons/project/project_demo.xml
+++ b/addons/project/project_demo.xml
@@ -77,6 +77,7 @@
<field name="project_id" ref="project.project_integrate_openerp"/>
<field name="name">Prepare Requirements Document</field>
<field name="type_id" ref="project_tt_specification"/>
+ <field name="color">3</field>
</record>
<record id="project_task_2" model="project.task">
@@ -94,6 +95,7 @@
<field name="priority">2</field>
<field name="project_id" ref="project.project_integrate_openerp"/>
<field name="name">Design Use Cases</field>
+ <field name="date_deadline" eval="time.strftime('%Y-%m-24')"/>
<field name="type_id" ref="project_tt_specification"/>
</record>
@@ -103,6 +105,9 @@
<field name="priority">2</field>
<field name="project_id" ref="project.project_integrate_openerp"/>
<field name="name">Budget Planning</field>
+ <field name="description">Use the account_budget module</field>
+ <field name="date_deadline" eval="time.strftime('%Y-%m-19')"/>
+ <field name="color">3</field>
<field name="type_id" ref="project_tt_specification"/>
</record>
@@ -112,6 +117,9 @@
<field name="priority">2</field>
<field name="project_id" ref="project.project_integrate_openerp"/>
<field name="name">Quality Planning</field>
+ <field name="kanban_state">done</field>
+ <field name="priority">0</field>
+ <field name="date_deadline" eval="time.strftime('%Y-%m-%d')"/>
<field name="type_id" ref="project_tt_specification"/>
</record>
@@ -139,6 +147,7 @@
<field name="priority">2</field>
<field name="project_id" ref="project.project_integrate_openerp"/>
<field name="name">Dataflow Design</field>
+ <field name="priority">0</field>
<field name="type_id" ref="project_tt_specification"/>
</record>
@@ -157,6 +166,7 @@
<field name="priority">2</field>
<field name="project_id" ref="project.project_integrate_openerp"/>
<field name="name">Develop Module in Sale Management</field>
+ <field name="kanban_state">blocked</field>
<field name="type_id" ref="project_tt_development"/>
</record>
@@ -220,6 +230,7 @@
<field name="priority">2</field>
<field name="project_id" ref="project.project_integrate_openerp"/>
<field name="name">Performance Tuning</field>
+ <field name="description">Test on Runbot</field>
<field name="type_id" ref="project_tt_specification"/>
</record>
<function model="project.task" name="do_open" eval="[ref('project_task_16')]"/>
@@ -329,6 +340,7 @@
<field name="priority">0</field>
<field name="project_id" ref="project_project_21"/>
<field name="name">Customer analysis + Architecture</field>
+ <field name="color">3</field>
</record>
<record id="project_task_186" model="project.task">
<field name="sequence">15</field>
@@ -338,6 +350,7 @@
<field name="user_id" eval="False"/>
<field name="project_id" ref="project_project_21"/>
<field name="name">Internal testing + Software Install</field>
+ <field name="color">4</field>
</record>
<record id="project_task_188" model="project.task">
<field name="sequence">17</field>
diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml
index 9f79b4ca95d..22fc175246e 100644
--- a/addons/project/project_view.xml
+++ b/addons/project/project_view.xml
@@ -313,7 +313,7 @@
</field>
</record>
-
+
<!-- Project Task Kanban View -->
<record model="ir.ui.view" id="view_task_kanban">
<field name="name">project.task.kanban</field>
@@ -350,8 +350,8 @@
<a t-if="record.priority.raw_value == 1" icon="star-on" type="object" name="set_normal_priority"/>
<a t-if="record.priority.raw_value != 1" icon="star-off" type="object" name="set_high_priority" style="opacity:0.6; filter:alpha(opacity=60);"/>
</td>
- <td align="left" valign="middle" class="oe_kanban_title3" tooltip="task_details">
- <b><field name="name"/></b>
+ <td align="left" valign="middle" class="oe_kanban_title" tooltip="task_details">
+ <field name="name"/>
</td>
<td valign="top" width="22">
<img t-att-src="kanban_gravatar(record.user_email.value, 22)" class="oe_kanban_gravatar" t-att-title="record.user_id.value"/>
@@ -378,6 +378,7 @@
type="object" class="oe_kanban_button"><t t-esc="time[0]"/></a
><b t-if="time[1]" class="oe_kanban_button oe_kanban_button_active"><t t-esc="Math.round(hours)"/></b
></t>
+ <a name="do_open" states="draft" string="Validate planned time and open task" type="object" class="oe_kanban_button oe_kanban_button_active">!</a>
</span>
</div>
<div class="oe_kanban_clear"/>
@@ -488,11 +489,6 @@
<filter name="open" string="In Progress" domain="[('state','=','open')]" 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="edit"
- string="Edit" context="{'set_editable':True,'seq_visible': True}"
- icon="gtk-execute"
- groups="base.group_extended"/>
- <separator orientation="vertical"/>
<filter string="Deadlines" context="{'deadline_visible': False}" domain="[('date_deadline','&lt;&gt;',False)]" help="Show only tasks having a deadline" icon="terp-gnome-cpu-frequency-applet+"/>
<separator orientation="vertical"/>
<field name="name"/>
@@ -526,13 +522,23 @@
<field name="name">Tasks</field>
<field name="res_model">project.task</field>
<field name="view_type">form</field>
- <field name="view_mode">tree,form,calendar,gantt,graph,kanban</field>
+ <field name="view_mode">kanban,tree,form,calendar,gantt,graph</field>
<field eval="False" name="filter"/>
- <field name="view_id" ref="view_task_tree2"/>
+ <field name="view_id" eval="False"/>
<field name="context">{"search_default_draft": 1, "search_default_open":1, "search_default_project_id": project_id}</field>
<field name="search_view_id" ref="view_task_search_form"/>
<field name="help">A task represents a work that has to be done. Each user works in his own list of tasks where he can record his task work in hours. He can work and close the task itself or delegate it to another user. If you delegate a task to another user, you get a new task in pending state, which will be reopened when you have to review the work achieved. If you install the project_timesheet module, task work can be invoiced based on the project configuration. With the project_mrp module, sales orders can create tasks automatically when they are confirmed.</field>
</record>
+ <record id="open_view_task_list_kanban" model="ir.actions.act_window.view">
+ <field name="sequence" eval="0"/>
+ <field name="view_mode">kanban</field>
+ <field name="act_window_id" ref="action_view_task"/>
+ </record>
+ <record id="open_view_task_list_tree" model="ir.actions.act_window.view">
+ <field name="sequence" eval="1"/>
+ <field name="view_mode">tree</field>
+ <field name="act_window_id" ref="action_view_task"/>
+ </record>
<menuitem action="action_view_task" id="menu_action_view_task" parent="project.menu_project_management" sequence="3"/>
diff --git a/addons/project/report/project_cumulative.xml b/addons/project/report/project_cumulative.xml
new file mode 100644
index 00000000000..89667992f0a
--- /dev/null
+++ b/addons/project/report/project_cumulative.xml
@@ -0,0 +1,109 @@
+<?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="planned_hours" operator="+"/>
+ <field name="type_id" group="True"/>
+ </graph>
+ </field>
+ </record>
+ <record id="view_task_history_burndown_graph" model="ir.ui.view">
+ <field name="name">project.task.history.burndown.graph</field>
+ <field name="model">project.task.history.burndown</field>
+ <field name="type">graph</field>
+ <field name="arch" type="xml">
+ <graph string="Burndown Chart of 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 Analysis">
+ <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','&lt;=',(datetime.date.today()+relativedelta(day=31)).strftime('%%Y-%%m-%%d')),('date','&gt;=',(datetime.date.today()-relativedelta(day=1)).strftime('%%Y-%%m-%%d'))]"/>
+ <filter icon="terp-go-month" string="Month-1" name="month1"
+ domain="[('date','&lt;=', (datetime.date.today() - relativedelta(day=31, months=1)).strftime('%%Y-%%m-%%d')),('date','&gt;=',(datetime.date.today() - relativedelta(day=1,months=1)).strftime('%%Y-%%m-%%d'))]"/>
+ <filter icon="terp-go-month" string="Month-2" name="month2"
+ domain="[('date','&lt;=', (datetime.date.today() - relativedelta(day=31, months=2)).strftime('%%Y-%%m-%%d')),('date','&gt;=',(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 name="view_id" ref="view_task_history_graph"/>
+ <field eval="False" name="filter"/>
+ <field name="context">{"search_default_open":1, "search_default_this_month": 1, "search_default_project_id": project_id}</field>
+ </record>
+ <menuitem action="action_view_task_history_cumulative"
+ id="menu_action_view_task_history_cumulative"
+ parent="project_report_task" />
+
+
+ <record id="action_view_task_history_burndown" model="ir.actions.act_window">
+ <field name="name">Burndown Chart</field>
+ <field name="res_model">project.task.history.cumulative</field>
+ <field name="view_type">form</field>
+ <field name="view_mode">graph,tree</field>
+ <field name="view_id" ref="view_task_history_burndown_graph"/>
+ <field eval="False" name="filter"/>
+ <field name="context">{"search_default_open":1, "search_default_this_month": 1, "search_default_project_id": project_id}</field>
+ </record>
+ <menuitem action="action_view_task_history_burndown"
+ id="menu_action_view_task_history_burndown"
+ parent="project_report_task" />
+
+
+ </data>
+</openerp>
diff --git a/addons/project/report/project_report_view.xml b/addons/project/report/project_report_view.xml
index cfa667c7590..5af8706108f 100644
--- a/addons/project/report/project_report_view.xml
+++ b/addons/project/report/project_report_view.xml
@@ -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>
@@ -148,11 +150,11 @@
<field name="view_type">form</field>
<field name="view_mode">tree,graph</field>
<field name="search_view_id" ref="view_task_project_user_search"/>
- <field name="context">{'search_default_year':1,'search_default_month':1,'search_default_project':1,'group_by_no_leaf':1,'group_by':[]}</field>
+ <field name="context">{'search_default_year':1,'search_default_project':1,'group_by_no_leaf':1,'group_by':[]}</field>
<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">
@@ -267,28 +269,5 @@
</field>
</record>
- <record id="action_project_vs_planned_total_hours_graph" model="ir.actions.act_window">
-
- <field name="name">Projects: Planned Vs Total hours</field>
- <field name="res_model">project.vs.hours</field>
- <field name="view_type">form</field>
- <field name="view_mode">graph,tree</field>
- <field name="context">{}</field>
- <field name="domain">[('user_id','=',uid),('state','=','open')]</field>
- <field name="view_id" ref="view_project_vs_planned_total_hours_graph"/>
- </record>
-
- <record id="open_view_project_vs_planned_total_hours_tree" model="ir.actions.act_window.view">
- <field eval="2" name="sequence"/>
- <field name="view_mode">tree</field>
- <field name="view_id" ref="view_project_vs_planned_total_hours_tree"/>
- <field name="act_window_id" ref="action_project_vs_planned_total_hours_graph"/>
- </record>
- <record id="open_view_project_vs_planned_total_hours_graph" model="ir.actions.act_window.view">
- <field eval="1" name="sequence"/>
- <field name="view_mode">graph</field>
- <field name="view_id" ref="view_project_vs_planned_total_hours_graph"/>
- <field name="act_window_id" ref="action_project_vs_planned_total_hours_graph"/>
- </record>
</data>
</openerp>
diff --git a/addons/project/res_partner_view.xml b/addons/project/res_partner_view.xml
index dc0226ba50e..31c88377ddb 100644
--- a/addons/project/res_partner_view.xml
+++ b/addons/project/res_partner_view.xml
@@ -25,6 +25,9 @@
<tree string="Tasks" editable="bottom">
<field name="name"/>
<field name="user_id"/>
+ <field name="date_deadline"/>
+ <button name="do_open" states="pending,draft,done,cancelled" string="Start Task" type="object" icon="gtk-media-play" help="For changing to open state" invisible="context.get('set_visible',False)"/>
+ <button name="action_close" states="draft,pending,open" string="Done" type="object" icon="terp-dialog-close" help="For changing to done state"/>
</tree>
</field>
</page>
diff --git a/addons/project/security/ir.model.access.csv b/addons/project/security/ir.model.access.csv
index 659948bc4d0..633c5164484 100644
--- a/addons/project/security/ir.model.access.csv
+++ b/addons/project/security/ir.model.access.csv
@@ -1,24 +1,18 @@
-"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
-"access_project_project_manager","project.project manager","model_project_project","project.group_project_manager",1,1,1,1
-"access_account_analytic_account_manager","account.analytic.account","analytic.model_account_analytic_account","project.group_project_manager",1,1,1,1
-"access_project_project","project.project","model_project_project","project.group_project_user",1,1,1,1
-"access_account_analytic_account","account.analytic.account","analytic.model_account_analytic_account","project.group_project_user",1,1,1,1
-"access_project_task_type_user","project.task.type user","model_project_task_type","project.group_project_user",1,1,1,1
-"access_project_task_type","project.task.type","model_project_task_type","project.group_project_manager",1,1,1,1
-"access_project_task_manager","project.task manager","model_project_task","project.group_project_manager",1,1,1,1
-"access_project_task","project.task","model_project_task","project.group_project_user",1,1,1,1
-"access_project_task_work","project.task.work","model_project_task_work","project.group_project_user",1,1,1,1
-"access_project_task_work_manager","project.task.work.manager","model_project_task_work","project.group_project_manager",1,1,1,1
-"access_report_project_task_user","report.project.task.user","model_report_project_task_user","project.group_project_manager",1,1,1,1
-"access_project_vs_hours","project.vs.hours","model_project_vs_hours","project.group_project_user",1,1,1,1
-"access_task_by_days","task.by.days","model_task_by_days","project.group_project_user",1,1,1,1
-"access_partner_task user","base.res.partner user","base.model_res_partner","project.group_project_user",1,0,0,0
-"access_partner_task manager","base.res.partner manager","base.model_res_partner","project.group_project_manager",1,0,0,0
-"access_partner_address_task user","base.res.partner.address user","base.model_res_partner_address","project.group_project_user",1,0,0,0
-"access_partner_address_task manager","base.res.partner.address manager","base.model_res_partner_address","project.group_project_manager",1,0,0,0
-"access_task_on_partner","project.task on partners","model_project_task","base.group_user",1,0,0,0
-"access_project_on_partner","project.project on partners","model_project_project","base.group_user",1,0,0,0
-"access_project_vs_hours_manager","project.vs.hours.manager","model_project_vs_hours","project.group_project_manager",1,1,1,1
-"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
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_project_project,project.project,model_project_project,project.group_project_user,1,1,1,1
+access_account_analytic_account,account.analytic.account,analytic.model_account_analytic_account,project.group_project_user,1,1,1,1
+access_project_task_type_user,project.task.type user,model_project_task_type,project.group_project_user,1,1,1,1
+access_project_task,project.task,model_project_task,project.group_project_user,1,1,1,1
+access_project_task_work,project.task.work,model_project_task_work,project.group_project_user,1,1,1,1
+access_report_project_task_user,report.project.task.user,model_report_project_task_user,project.group_project_manager,1,1,1,1
+access_project_vs_hours,project.vs.hours,model_project_vs_hours,project.group_project_user,1,1,1,1
+access_task_by_days,task.by.days,model_task_by_days,project.group_project_user,1,1,1,1
+access_partner_task user,base.res.partner user,base.model_res_partner,project.group_project_user,1,0,0,0
+access_partner_address_task user,base.res.partner.address user,base.model_res_partner_address,project.group_project_user,1,0,0,0
+access_task_on_partner,project.task on partners,model_project_task,base.group_user,1,0,0,0
+access_project_on_partner,project.project on partners,model_project_project,base.group_user,1,0,0,0
+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
diff --git a/addons/project/security/project_security.xml b/addons/project/security/project_security.xml
index 62f74f51d1b..f1e3a6e9b74 100644
--- a/addons/project/security/project_security.xml
+++ b/addons/project/security/project_security.xml
@@ -3,18 +3,16 @@
<data noupdate="1">
<record id="group_project_user" model="res.groups">
- <field name="name">Project / User</field>
+ <field name="name">User</field>
+ <field name="category_id" ref="base.module_category_project_management"/>
</record>
<record id="group_project_manager" model="res.groups">
- <field name="name">Project / Manager</field>
+ <field name="name">Manager</field>
+ <field name="category_id" ref="base.module_category_project_management"/>
<field name="implied_ids" eval="[(4, ref('group_project_user'))]"/>
</record>
- <record id="base.group_sale_salesman" model="res.groups">
- <field name="name">Sales / User</field>
- </record>
-
<record model="ir.ui.menu" id="menu_definitions">
<field name="groups_id" eval="[(6,0,[ref('group_project_manager')])]"/>
</record>
diff --git a/addons/project/static/src/img/icon.png b/addons/project/static/src/img/icon.png
new file mode 100644
index 00000000000..20ba49f07c8
--- /dev/null
+++ b/addons/project/static/src/img/icon.png
Binary files differ
diff --git a/addons/project/test/project_demo.yml b/addons/project/test/project_demo.yml
new file mode 100644
index 00000000000..3bcae52e238
--- /dev/null
+++ b/addons/project/test/project_demo.yml
@@ -0,0 +1,12 @@
+-
+ !record {model: project.project, id: project_integrate_openerp, view: False}:
+ partner_id: base.res_partner_agrolait
+-
+ !record {model: project.task, id: project_task_1, view: False}:
+ remaining_hours: 10.00
+-
+ !record {model: project.task, id: project_task_1, view: False}:
+ planned_hours: 10.00
+-
+ !record {model: project.task, id: project_task_1, view: False}:
+ project_id: project_integrate_openerp \ No newline at end of file
diff --git a/addons/project/test/project_process.yml b/addons/project/test/project_process.yml
new file mode 100644
index 00000000000..3c51c464b1f
--- /dev/null
+++ b/addons/project/test/project_process.yml
@@ -0,0 +1,70 @@
+-
+ In order to Test Process of Project Management,
+-
+ I create duplicate template.
+-
+ !python {model: project.project}: |
+ new_template = self.duplicate_template(cr, uid, [ref("project_integrate_openerp")])
+ assert new_template, "duplicate template is not created"
+ template = self.browse(cr, uid, new_template['res_id'], context=context)
+ assert template.state == 'open', "Duplicate template must be in open state."
+-
+ I convert template into real Project.
+-
+ !python {model: project.project}: |
+ self.reset_project(cr, uid, [ref("project_integrate_openerp")])
+-
+ I check project details after convert from template.
+-
+ !assert {model: project.project, id: project_integrate_openerp, severity: error, string: Project should be active}:
+ - state == "open"
+-
+ I put project in pending.
+-
+ !python {model: project.project}: |
+ self.set_pending(cr, uid, [ref("project_integrate_openerp")])
+-
+ I check state after put in pending.
+-
+ !assert {model: project.project, id: project_integrate_openerp, severity: error, string: Project should be in pending state}:
+ - state == "pending"
+-
+ I re-open the project.
+-
+ !python {model: project.project}: |
+ self.set_open(cr, uid, [ref("project_integrate_openerp")])
+-
+ I check state after reopen.
+-
+ !assert {model: project.project, id: project_integrate_openerp, severity: error, string: Project should be open.}:
+ - state == "open"
+-
+ I close the project.
+-
+ !python {model: project.project}: |
+ self.set_done(cr, uid, [ref("project_integrate_openerp")])
+-
+ I check state after closed.
+-
+ !assert {model: project.project, id: project_integrate_openerp, severity: error, string: Project should be close.}:
+ - state == "close"
+-
+ I set project into template.
+-
+ !python {model: project.project}: |
+ self.set_template(cr, uid, [ref("project_integrate_openerp")])
+-
+ I schedule tasks of project.
+-
+ !python {model: project.project}: |
+ self.schedule_tasks(cr, uid, [ref("project_integrate_openerp")], context=context)
+-
+ I copy the tasks of project.
+-
+ !python {model: project.project}: |
+ self.template_copy(cr, uid, ref("project_integrate_openerp"))
+-
+ I cancel Project.
+-
+ !python {model: project.project}: |
+ self.set_cancel(cr, uid, [ref("project_project_9")]) \ No newline at end of file
diff --git a/addons/project/test/task_process.yml b/addons/project/test/task_process.yml
new file mode 100644
index 00000000000..73250de2963
--- /dev/null
+++ b/addons/project/test/task_process.yml
@@ -0,0 +1,76 @@
+-
+ I put task in pending due to specification is not clear.
+-
+ !python {model: project.task}: |
+ self.do_pending(cr, uid, [ref("project_task_1")])
+ context.update({"active_id": ref("project_task_1")})
+-
+ I check state of task after put in pending.
+-
+ !assert {model: project.task, id: project_task_1, severity: error, string: task should be in pending state}:
+ - state == "pending"
+-
+ !record {model: project.task.delegate, id: delegate_id}:
+ user_id: res_users_analyst
+ planned_hours: 12.0
+ planned_hours_me: 2.0
+-
+ Now I delegate task to team member.
+-
+ !python {model: project.task.delegate}: |
+ self.delegate(cr, uid, [ref("delegate_id")], {"active_id": ref("project_task_1")})
+-
+ I check delegated task details.
+-
+ !python {model: project.task}: |
+ task = self.browse(cr, uid, ref("project_task_1"), context=context)
+ assert task.planned_hours == 2.0, "Planning hours is not correct after delegated."
+ assert task.state == "pending", "Task should be in Pending after delegated."
+-
+ I re-open the task.
+-
+ !python {model: project.task}: |
+ self.do_reopen(cr, uid, [ref("project_task_1")])
+-
+ I check reopened task details.
+-
+ !assert {model: project.task, id: project_task_1, severity: error, string: task should be open.}:
+ - state == "open"
+-
+ I change the stage of task to next stage.
+-
+ !python {model: project.task}: |
+ self.next_type(cr, uid, [ref("project_task_1")])
+-
+ !record {model: project.task.reevaluate, id: reevaluate_id}:
+ remaining_hours : 120
+-
+ I reevaluate task with remaining hours.
+-
+ !python {model: project.task.reevaluate}: |
+ self.compute_hours(cr, uid, [ref("reevaluate_id")], {"active_id": ref("project_task_1")})
+-
+ I check remaining hours after reevaluated task.
+-
+ !assert {model: project.task, id: project_task_1, severity: error, string: task should be reevaluated}:
+ - remaining_hours == 120.0
+-
+ I close the task.
+-
+ !python {model: project.task}: |
+ self.action_close(cr, uid, [ref("project_task_1")])
+-
+ I check state after closed.
+-
+ !assert {model: project.task, id: project_task_1, severity: error, string: task is in open state}:
+ - state == "done"
+-
+ I change the stage of task to previous stage.
+-
+ !python {model: project.task}: |
+ self.prev_type(cr, uid, [ref("project_task_1")])
+-
+ I cancel Task.
+-
+ !python {model: project.task}: |
+ self.do_cancel(cr, uid, [ref("project_task_2")]) \ No newline at end of file
diff --git a/addons/project/test/test_project.yml b/addons/project/test/test_project.yml
deleted file mode 100644
index f79c2a34224..00000000000
--- a/addons/project/test/test_project.yml
+++ /dev/null
@@ -1,296 +0,0 @@
--
- Test project template feature
--
- Create project 'OpenERP Training Programme'
--
- !record {model: project.project, id: project_project_openerptrainingprogramme0}:
- company_id: base.main_company
- name: OpenERP Training Programme
--
- Create task 'Technical Training' for this project
--
- !record {model: project.task, id: project_task_technicaltraining0}:
- date_start: !eval time.strftime('%Y-%m-%d %H:%M:%S')
- name: Technical Training
- planned_hours: 30.0
- project_id: project_project_openerptrainingprogramme0
- remaining_hours: 30.0
- state: draft
--
- Create task 'Functional Training' for this project
--
- !record {model: project.task, id: project_task_functionaltraining0}:
- date_start: !eval time.strftime('%Y-%m-%d %H:%M:%S')
- name: Functional Training
- planned_hours: 30.0
- project_id: project_project_openerptrainingprogramme0
- remaining_hours: 30.0
- state: draft
--
- Set project as project template
--
- !python {model: project.project}: |
- self.set_template(cr, uid, [ref("project_project_openerptrainingprogramme0")],
- {"lang": "en_US", "active_model": "ir.ui.menu", "active_ids": [ref("project.menu_open_view_project_all")],
- "tz": False, "active_id": ref("project.menu_open_view_project_all"), })
--
- Check if project in template state
--
- !assert {model: project.project, id: project_project_openerptrainingprogramme0, severity: error, string: Project is in template state}:
- - state == "template"
--
- Create new project based on this template
--
- !python {model: project.project}: |
- new_prj = self.duplicate_template(cr, uid, [ref("project_project_openerptrainingprogramme0")],
- {"lang": "en_US", "active_model": "ir.ui.menu", "active_ids": [ref("project.menu_open_view_project_all")],
- "tz": False, "active_id": ref("project.menu_open_view_project_all"), })
- if not new_prj:
- raise Exception( "New project based on template not created")
- new_id = new_prj['res_id']
- new_prj = self.read(cr, uid, [new_id], ['name', 'state'])[0]
- state = new_prj['state']
- name = new_prj['name']
- assert state == 'open', "Project in %s state. Project created from template project must be in open state"%state
--
- Reset project template to normal project
--
- !python {model: project.project}: |
- self.reset_project(cr, uid, [ref("project_project_openerptrainingprogramme0")], {"lang": "en_US", "active_ids":
- [ref("project.menu_open_view_project_all")], "tz": False, "active_model":
- "ir.ui.menu", "project_id": False, "active_id": ref("project.menu_open_view_project_all"),
- })
--
- Check if project in open state
--
- !assert {model: project.project, id: project_project_openerptrainingprogramme0, severity: error, string: Project is in open state}:
- - state == "open"
--
- Test for different project-states
--
- Keep project pending
--
- !python {model: project.project}: |
- self.set_pending(cr, uid, [ref("project_project_openerptrainingprogramme0")], {"lang": "en_US", "active_ids":
- [ref("project.menu_open_view_project_all")], "tz": False, "active_model":
- "ir.ui.menu", "project_id": False, "active_id": ref("project.menu_open_view_project_all"),
- })
--
- Check if project in pending state
--
- !assert {model: project.project, id: project_project_openerptrainingprogramme0, severity: error, string: Project is in pending state}:
- - state == "pending"
--
- Cancel the project
--
- !python {model: project.project}: |
- self.set_cancel(cr, uid, [ref("project_project_openerptrainingprogramme0")], {"lang": "en_US", "active_ids":
- [ref("project.menu_open_view_project_all")], "tz": False, "active_model":
- "ir.ui.menu", "project_id": False, "active_id": ref("project.menu_open_view_project_all"),
- })
--
- Check if project in cancel state
--
- !assert {model: project.project, id: project_project_openerptrainingprogramme0, severity: error, string: Project is in cancel state}:
- - state == "cancelled"
--
- Re-open the project
--
- !python {model: project.project}: |
- self.set_open(cr, uid, [ref("project_project_openerptrainingprogramme0")], {"lang": "en_US", "active_ids": [ref("project.menu_open_view_project_all")],
- "tz": False, "active_model": "ir.ui.menu", "project_id": False, "active_id":
- ref("project.menu_open_view_project_all"), })
--
- Check if project in open state
--
- !assert {model: project.project, id: project_project_openerptrainingprogramme0, severity: error, string: Project is in open state}:
- - state == "open"
--
- Test for task work allocation
--
- As i cancelled my project before, i check if the task 'Technical Training' is in cancelled state
--
- !assert {model: project.task, id: project_task_technicaltraining0, severity: error, string: Task is in cancelled state}:
- - state == "cancelled"
--
- Now in order to reactivate the task 'Technical Training', i click on the "Reactivate" button and fill the remaining hour field
--
- !record {model: project.task.reevaluate, id: project_task_technicaltraining_remainingwiz0}:
- remaining_hours: 30.0
-- |
- I click the apply button
--
- !python {model: project.task.reevaluate}: |
- self.compute_hours(cr, uid, [ref('project_task_technicaltraining_remainingwiz0')], {'active_id': ref("project_task_technicaltraining0"),'button_reactivate': True})
-- |
- Check if task 'Technical Training' in open state and for other initial values
--
- !assert {model: project.task, id: project_task_technicaltraining0, severity: error, string: Project is in open state}:
- - state == "open"
- - planned_hours == 30
- - remaining_hours == 30
- - delay_hours == 0.0
- - effective_hours == 0.0
--
- Make a work task entry 'Training on OpenERP modules, models and classes' of 10 hours
--
- !record {model: project.task, id: project_task_technicaltraining0, context:{'no_analytic_entry':True}}:
- work_ids:
- - date: !eval time.strftime('%Y-%m-%d %H:%M:%S')
- hours: 10.0
- name: Training on OpenERP modules, models and classes
- user_id: base.user_root
--
- Check for effective hours and remaining hours, effective_hours must be equal to 10
--
- !assert {model: project.task, id: project_task_technicaltraining0, severity: error, string: After work task of 10 hours effective_hours must be equal to 10}:
- - remaining_hours == 20
- - effective_hours == 10.0
--
- Make a work task entry 'Training on OpenERP xml views' of 10 hours
--
- !record {model: project.task, id: project_task_technicaltraining0, context:{'no_analytic_entry':True}}:
- work_ids:
- - date: !eval time.strftime('%Y-%m-%d %H:%M:%S')
- hours: 10.0
- name: Training on OpenERP xml views
- user_id: base.user_root
--
- Check for effective hours and remaining hours, effective_hours must be equal to 20
--
- !assert {model: project.task, id: project_task_technicaltraining0, severity: error, string: After one more work task of 10 hours effective_hours must be equal to 20}:
- - remaining_hours == 10
- - effective_hours == 20.0
--
- Make a work task entry 'Training on workflows' of 10 hours
--
- !record {model: project.task, id: project_task_technicaltraining0, context:{'no_analytic_entry':True}}:
- work_ids:
- - date: !eval time.strftime('%Y-%m-%d %H:%M:%S')
- hours: 10.0
- name: Training on workflows
- user_id: base.user_root
--
- Check for effective hours and remaining hours, effective_hours must be equal to 30
--
- !assert {model: project.task, id: project_task_technicaltraining0, severity: error, string: After one more work task of 10 hours effective_hours must be equal to 30}:
- - remaining_hours == 0
- - effective_hours == 30.0
--
- Set remaining hours of 10 hours for reevaluating the task
--
- !record {model: project.task.reevaluate, id: config_compute_remaining_0}:
- remaining_hours: 10.0
--
- Reevaluate the task
--
- !python {model: project.task.reevaluate}: |
- self.compute_hours(cr, uid, [ref("config_compute_remaining_0")], {"lang": "en_US",
- "project_id": False, "tz": False, "active_model": "project.task", "search_default_project_id":
- False, "search_default_user_id": 1, "search_default_current": 1, "active_ids":
- [ref("project_task_technicaltraining0")], "active_id": ref("project_task_technicaltraining0"), })
-
--
- Check for effective hours and remaining hours, remaining_hours must be 10 while planned_hours remains 30
--
- !assert {model: project.task, id: project_task_technicaltraining0, severity: error, string: After reevaluating the task with 10 hours remaining_hours must be 10 while planned_hours remains 30}:
- - planned_hours == 30
- - remaining_hours == 10.0
- - effective_hours == 30.0
--
- Make a work task entry 'Training on reports and wizards' of 10 hours
--
- !record {model: project.task, id: project_task_technicaltraining0, context:{'no_analytic_entry':True}}:
- work_ids:
- - date: !eval time.strftime('%Y-%m-%d %H:%M:%S')
- hours: 10.0
- name: Training on reports and wizards
- user_id: base.user_root
--
- Check for effective hours and remaining hours
--
- !assert {model: project.task, id: project_task_technicaltraining0, severity: error, string: After one more work task of 10 hours effective_hours must be equal to 40 while planned_hours remains 30}:
- - planned_hours == 30
- - remaining_hours == 0
- - effective_hours == 40.0
--
- Close the task
--
- !python {model: project.task}: |
- self.do_close(cr, uid, [ref("project_task_technicaltraining0")], {'mail_send': False})
--
- Check if task in done state
--
- !assert {model: project.task, id: project_task_technicaltraining0, severity: error, string: Task is in done state}:
- - state == "done"
-
-
--
- Test for task reactivation
--
- Reactivate task
--
- !record {model: project.task.reevaluate, id: config_compute_remaining_1}:
- remaining_hours: 10.0
--
- Reevaluate the task with 10 hours remaining
--
- !python {model: project.task.reevaluate}: |
- self.compute_hours(cr, uid, [ref("config_compute_remaining_1")], {"lang": "en_US",
- "project_id": False, "tz": False, "button_reactivate": True, "active_model":
- "project.task", "search_default_project_id": False, "search_default_user_id":
- 1, "search_default_current": 1, "active_ids": [ref("project_task_technicaltraining0")], "active_id": ref("project_task_technicaltraining0"),
- })
--
- Check for effective hours and remaining hours, remaining_hours must be 10 while planned_hours remains 30
--
- !assert {model: project.task, id: project_task_technicaltraining0, severity: error, string: After reevaluating the task with 10 hours remaining_hours must be 10 while planned_hours remains 30}:
- - planned_hours == 30
- - remaining_hours == 10.0
- - effective_hours == 40.0
--
- Make a work task entry 'Training on yml' of 5 hours
--
- !record {model: project.task, id: project_task_technicaltraining0, context:{'no_analytic_entry':True}}:
- work_ids:
- - date: !eval time.strftime('%Y-%m-%d %H:%M:%S')
- hours: 5.0
- name: Training on yml
- user_id: base.user_root
--
- Check for effective hours and remaining hours, remaining_hours must be 5, effective_hours must be 45
--
- !assert {model: project.task, id: project_task_technicaltraining0, severity: error, string: After work task of 5 hours effective_hours must be equal to 45 and remaining_hours is 5}:
- - planned_hours == 30
- - remaining_hours == 5.0
- - effective_hours == 45.0
--
- Close the task
--
- !python {model: project.task}: |
- self.do_close(cr, uid, [ref("project_task_technicaltraining0")], {'mail_send': False})
--
- Check if task in done state
--
- !assert {model: project.task, id: project_task_technicaltraining0, severity: error}:
- - state == "done"
--
- Check for effective hours and remaining hours
--
- !assert {model: project.task, id: project_task_technicaltraining0, severity: error, string: After closing the task planned_hours must remain 30 effective_hours must be 45 and remaining hours must be 0}:
- - planned_hours == 30
- - remaining_hours == 0.0
- - effective_hours == 45.0
--
- Close project 'OpenERP Training Programme'
--
- !python {model: project.project}: |
- self.set_done(cr, uid, [ref("project_project_openerptrainingprogramme0")], {"lang": "en_US", "active_ids": [ref("project.menu_open_view_project_all")],
- "tz": False, "active_model": "ir.ui.menu", "project_id": False, "active_id":
- ref("project.menu_open_view_project_all"), })
--
- Check if project in close state
--
- !assert {model: project.project, id: project_project_openerptrainingprogramme0, severity: error, string: "Project must be in closed state"}:
- - state == "close"
-
diff --git a/addons/project/test/test_project_delegation.yml b/addons/project/test/test_project_delegation.yml
deleted file mode 100644
index 02bc9afaae8..00000000000
--- a/addons/project/test/test_project_delegation.yml
+++ /dev/null
@@ -1,230 +0,0 @@
--
- This scenario tests the delegation process. Closing all the delegated tasks(task delegation at multiple levels) transits the parent task from pending to open state.
--
- Creating a project OpenERP Documentation
--
- !record {model: project.project, id: project_project_openerpdocumentation0}:
- company_id: base.main_company
- name: OpenERP Documentation
-
--
- Creating a task 'Develop book for Technical and Functional reference'
--
- !record {model: project.task, id: project_task_documentation_book}:
- name: Develop book for Technical and Functional reference
- planned_hours: 20.0
- project_id: project_project_openerpdocumentation0
- remaining_hours: 20.0
- state: draft
-
--
- Open the task
--
- !python {model: project.task}: |
- self.do_open(cr, uid, [ref("project_task_documentation_book")],
- {"lang": "en_US", "active_model": "ir.ui.menu", "active_ids": [ref("project.menu_action_view_task")],
- "tz": False, "active_id": ref("project.menu_action_view_task"), })
-
--
- Creating a task 'Publish the References'
--
- !record {model: project.task, id: project_task_publish_book}:
- name: Publish the References
- planned_hours: 10.0
- project_id: project_project_openerpdocumentation0
- remaining_hours: 10.0
- state: draft
-
--
- Open the task
--
- !python {model: project.task}: |
- self.do_open(cr, uid, [ref("project_task_publish_book")],
- {"lang": "en_US", "active_model": "ir.ui.menu", "active_ids": [ref("project.menu_action_view_task")],
- "tz": False, "active_id": ref("project.menu_action_view_task"), })
-
--
- Test the delegate wizard
--
- Creating a delegate task 'Publish the References' of 15 hours, renaming parent task to 'CHECK Publish the References' of 1 hour
--
- !record {model: project.task.delegate, id: project_task_publish_book_delegate}:
- name: Publish the References
- new_task_description: aaa
- planned_hours: 15.0
- planned_hours_me: 1.0
- prefix: 'CHECK: Publish the References'
- state: pending
- user_id: base.user_demo
-
--
- Validating the delegate task
--
- !python {model: project.task.delegate}: |
- self.delegate(cr, uid, [ref("project_task_publish_book_delegate")],
- {"lang": "en_US", "active_model": "project.task", "tz": False, "record_id":
- 4, "active_ids": [ref("project_task_publish_book")], "active_id": ref("project_task_publish_book"),
- })
-
--
- Check if parent task 'CHECK Publish the References' is in pending state
--
- !assert {model: project.task, id: project_task_publish_book, severity: error, string: "Task must be in pending state after delegation"}:
- - state == "pending"
--
- Creating a delegate task 'Prepare a book that gives functional overview of OpenERP'
--
- !record {model: project.task, id: project_task_delegate_openerp_tutorial}:
- name: Prepare a book that gives functional overview of OpenERP
- planned_hours: 30.0
- project_id: project.project_project_openerpdocumentation0
- remaining_hours: 30.0
- state: draft
-
--
- Open the task
--
- !python {model: project.task}: |
- self.do_open(cr, uid, [ref("project_task_delegate_openerp_tutorial")],
- {"lang": "en_US", "active_model": "ir.ui.menu", "active_ids": [ref("project.menu_action_view_task")],
- "tz": False, "active_id": ref("project.menu_action_view_task"), })
-
--
- Creating a delegate task 'Prepare a technical reference for creating your modules'
--
- !record {model: project.task, id: project_task_delegate_developer_book}:
- name: Prepare a technical reference for creating your modules
- planned_hours: 30.0
- project_id: project_project_openerpdocumentation0
- remaining_hours: 30.0
- state: draft
-
--
- Open the task
--
- !python {model: project.task}: |
- self.do_open(cr, uid, [ref("project_task_delegate_developer_book")],
- {"lang": "en_US", "active_model": "ir.ui.menu", "active_ids": [ref("project.menu_action_view_task")],
- "tz": False, "active_id": ref("project.menu_action_view_task"), })
-
--
- Delegate task 'Develop book for Technical and Functional reference' to these tasks and make it pending
--
- !record {model: project.task, id: project_task_documentation_book}:
- child_ids:
- - project.project_task_delegate_openerp_tutorial
- - project.project_task_delegate_developer_book
- planned_hours: 20.0
- state: pending
-
--
- Creating a delegate task 'Prepare documentation for Module Development'
--
- !record {model: project.task, id: project_task_delegate_module_develop}:
- name: Prepare documentation for Module Development
- planned_hours: 30.0
- project_id: project.project_project_openerpdocumentation0
- remaining_hours: 30.0
- state: draft
-
-
--
- Creating a delegate 'Prepare documentation for Business Process Development'
--
- !record {model: project.task, id: project_task_delegate_business_process_develop}:
- name: Prepare documentation for Business Process Development
- planned_hours: 30.0
- project_id: project_project_openerpdocumentation0
- remaining_hours: 30.0
- state: draft
-
--
- Delegate task 'Prepare a technical reference for creating your modules' to these tasks and make it pending
--
- !record {model: project.task, id: project_task_delegate_developer_book}:
- child_ids:
- - project.project_task_delegate_module_develop
- - project.project_task_delegate_business_process_develop
- planned_hours: 20.0
- state: pending
-
--
- Open the task
--
- !python {model: project.task}: |
- self.do_open(cr, uid, [ref("project_task_delegate_module_develop")],
- {"lang": "en_US", "active_model": "ir.ui.menu", "active_ids": [ref("project.menu_action_view_task")],
- "tz": False, "active_id": ref("project.menu_action_view_task"), })
-
--
- Open the task
--
- !python {model: project.task}: |
- self.do_open(cr, uid, [ref("project_task_delegate_business_process_develop")],
- {"lang": "en_US", "active_model": "ir.ui.menu", "active_ids": [ref("project.menu_action_view_task")],
- "tz": False, "active_id": ref("project.menu_action_view_task"), })
-
--
- Check if 'Prepare a technical reference for creating your modules' in pending state
--
- !assert {model: project.task, id: project_task_delegate_developer_book, severity: error, string: Task must be in pending state}:
- - state == "pending"
-
--
- Close the child task 'Prepare documentation for Module Development'
--
- !python {model: project.task}: |
- self.do_close(cr, uid, [ref("project_task_delegate_module_develop")], {"lang": "en_US",
- "active_ids": [ref("project.menu_action_view_task")], "tz": False, "active_model":
- "ir.ui.menu", "section_id": False, "search_default_project_id": False, "search_default_user_id":
- 1, "search_default_current": 1, "mail_send": False, "active_id": ref("project.menu_action_view_task"),
- })
-
--
- Close the child task 'Prepare documentation for Business Process Development'
--
- !python {model: project.task}: |
- self.do_close(cr, uid, [ref("project_task_delegate_business_process_develop")], {"lang": "en_US",
- "active_ids": [ref("project.menu_action_view_task")], "tz": False, "active_model":
- "ir.ui.menu", "section_id": False, "search_default_project_id": False, "search_default_user_id":
- 1, "search_default_current": 1, "mail_send": False, "active_id": ref("project.menu_action_view_task"),
- })
-
--
- Parent task 'Prepare a technical reference for creating your modules' task must now be in open state
--
- !assert {model: project.task, id: project_task_delegate_developer_book, severity: error, string: Task is in done state}:
- - state == "open"
-
-
--
- Check if task 'Develop book for Technical and Functional reference' in pending state
--
- !assert {model: project.task, id: project_task_documentation_book, severity: error, string: Task is in pending state}:
- - state == "pending"
-
--
- Close the child task 'Prepare a technical reference for creating your modules'
--
- !python {model: project.task}: |
- self.do_close(cr, uid, [ref("project_task_delegate_developer_book")], {"lang": "en_US",
- "active_ids": [ref("project.menu_action_view_task")], "tz": False, "active_model":
- "ir.ui.menu", "section_id": False, "search_default_project_id": False, "search_default_user_id":
- 1, "search_default_current": 1, "mail_send": False, "active_id": ref("project.menu_action_view_task"),
- })
-
--
- Close the child task 'Prepare a book that gives functional overview of OpenERP'
--
- !python {model: project.task}: |
- self.do_close(cr, uid, [ref("project_task_delegate_openerp_tutorial")], {"lang": "en_US",
- "active_ids": [ref("project.menu_action_view_task")], "tz": False, "active_model":
- "ir.ui.menu", "section_id": False, "search_default_project_id": False, "search_default_user_id":
- 1, "search_default_current": 1, "mail_send": False, "active_id": ref("project.menu_action_view_task"),
- })
-
--
- Parent task 'Develop book for Technical and Functional reference' must be now in open state
--
- !assert {model: project.task, id: project_task_documentation_book, severity: error, string: Task is in done state}:
- - state == "open"