[ADD]: Project Scrum.
@ -18,6 +18,16 @@
|
||||
<field name="object">project.task</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="seq_tasks" model="ir.sequence">
|
||||
<field name="name">Tasks</field>
|
||||
<field name="code">project.task</field>
|
||||
<field name="prefix">TSK</field>
|
||||
<field name="padding">3</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- sale_timesheet and project define the same field without depending on each, which causes the field to be deleted when the module that created it
|
||||
is deleted. To avoid this, we create xmlids manually for this field in both modules to prevent accidental deletion. To fix in saas-7 by moving the field definition-->
|
||||
<record id="duplicate_field_xmlid" model="ir.model.data">
|
||||
@ -127,7 +137,7 @@
|
||||
<record forcecreate="False" id="project_task_data_0" model="project.task">
|
||||
<field name="sequence">1</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_data"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">Welcome to Flectra</field>
|
||||
@ -139,7 +149,7 @@
|
||||
<record forcecreate="False" id="project_task_data_1" model="project.task">
|
||||
<field name="sequence">2</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_data"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">Try to play with the search bar. Use the filters</field>
|
||||
@ -150,7 +160,7 @@
|
||||
<record forcecreate="False" id="project_task_data_5" model="project.task">
|
||||
<field name="sequence">3</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_data"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">Try to drag a task wherever your want</field>
|
||||
@ -161,7 +171,7 @@
|
||||
<record forcecreate="False" id="project_task_data_2" model="project.task">
|
||||
<field name="sequence">4</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_data"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">Guess what happens if you set this task as favorite?</field>
|
||||
@ -171,7 +181,7 @@
|
||||
|
||||
<record forcecreate="False" id="project_task_data_4" model="project.task">
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_data"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">Use the chatter to collaborate with your members</field>
|
||||
@ -197,7 +207,7 @@
|
||||
<record forcecreate="False" id="project_task_data_6" model="project.task">
|
||||
<field name="sequence">3</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_data"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">Use tags to organize your tasks</field>
|
||||
@ -210,7 +220,7 @@
|
||||
<record forcecreate="False" id="project_task_data_12" model="project.task">
|
||||
<field name="sequence">4</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_data"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="color">3</field>
|
||||
@ -222,7 +232,7 @@
|
||||
<record forcecreate="False" id="project_task_data_13" model="project.task">
|
||||
<field name="sequence">5</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_data"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">Set this task as 'Ready for next stage' to proceed further in the process</field>
|
||||
@ -232,7 +242,7 @@
|
||||
|
||||
<record forcecreate="False" id="project_task_data_8" model="project.task">
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_data"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">Do you want to learn more? Try our implementation guide!</field>
|
||||
@ -265,7 +275,7 @@
|
||||
|
||||
<record forcecreate="False" id="project_task_data_7" model="project.task">
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_data"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">Finished with this stage? Archive it !</field>
|
||||
@ -275,7 +285,7 @@
|
||||
|
||||
<record forcecreate="False" id="project_task_data_9" model="project.task">
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_data"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">You want to add a stage? Add a new column !</field>
|
||||
@ -285,7 +295,7 @@
|
||||
|
||||
<record forcecreate="False" id="project_task_data_11" model="project.task">
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_data"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">You can set a deadline on a task</field>
|
||||
@ -295,7 +305,7 @@
|
||||
|
||||
<record forcecreate="False" id="project_task_data_14" model="project.task">
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_data"/>
|
||||
<field name="active" eval="False"/>
|
||||
<field name="name">Send a message with a picture as attachment, and see what happens!</field>
|
||||
|
@ -124,7 +124,7 @@
|
||||
<field name="planned_hours" eval="40.0"/>
|
||||
<field name="remaining_hours" eval="40.0"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_1"/>
|
||||
<field name="name">Prepare Requirements Document</field>
|
||||
<field name="stage_id" ref="project_stage_0"/>
|
||||
@ -134,7 +134,7 @@
|
||||
<field name="planned_hours" eval="32.0"/>
|
||||
<field name="remaining_hours" eval="32.0"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_1"/>
|
||||
<field name="name">Make SRS</field>
|
||||
<field name="stage_id" ref="project_stage_1"/>
|
||||
@ -143,7 +143,7 @@
|
||||
<field name="planned_hours" eval="10.0"/>
|
||||
<field name="remaining_hours" eval="10.0"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_1"/>
|
||||
<field name="name">Budget Planning</field>
|
||||
<field name="date_deadline" eval="time.strftime('%Y-%m-24')"/>
|
||||
@ -154,7 +154,7 @@
|
||||
<field name="planned_hours" eval="60.0"/>
|
||||
<field name="remaining_hours" eval="60.0"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_1"/>
|
||||
<field name="name">Develop module for Sale Management</field>
|
||||
<field name="description">Use the account_budget module</field>
|
||||
@ -168,11 +168,11 @@
|
||||
<field name="planned_hours" eval="76.0"/>
|
||||
<field name="remaining_hours" eval="76.0"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_1"/>
|
||||
<field name="name">Develop module for Warehouse</field>
|
||||
<field name="kanban_state">done</field>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="date_deadline" eval="time.strftime('%Y-%m-%d')"/>
|
||||
<field name="stage_id" ref="project_stage_1"/>
|
||||
<field name="tag_ids" eval="[(6, 0, [
|
||||
@ -182,7 +182,7 @@
|
||||
<field name="planned_hours" eval="24.0"/>
|
||||
<field name="remaining_hours" eval="24.0"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_1"/>
|
||||
<field name="name">Integrate Modules</field>
|
||||
<field name="stage_id" ref="project_stage_1"/>
|
||||
@ -191,7 +191,7 @@
|
||||
<field name="planned_hours" eval="15.0"/>
|
||||
<field name="remaining_hours" eval="5.0"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_1"/>
|
||||
<field name="name">Internal testing + Software Install</field>
|
||||
<field name="stage_id" ref="project_stage_1"/>
|
||||
@ -200,10 +200,10 @@
|
||||
<field name="planned_hours" eval="22.0"/>
|
||||
<field name="remaining_hours" eval="22.0"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_2"/>
|
||||
<field name="name">New portal system</field>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="stage_id" ref="project_stage_2"/>
|
||||
<field name="tag_ids" eval="[(6, 0, [
|
||||
ref('project.project_tags_02')])]"/>
|
||||
@ -212,7 +212,7 @@
|
||||
<field name="planned_hours" eval="18.0"/>
|
||||
<field name="remaining_hours" eval="18.0"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_2"/>
|
||||
<field name="name">Document history management</field>
|
||||
<field name="stage_id" ref="project_stage_0"/>
|
||||
@ -221,7 +221,7 @@
|
||||
<field name="planned_hours" eval="38.0"/>
|
||||
<field name="remaining_hours" eval="38.0"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_2"/>
|
||||
<field name="name">Social network integration</field>
|
||||
<field name="kanban_state">blocked</field>
|
||||
@ -231,7 +231,7 @@
|
||||
<field name="planned_hours" eval="16.0"/>
|
||||
<field name="remaining_hours" eval="16.0"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_2"/>
|
||||
<field name="name">User interface improvements</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [
|
||||
@ -244,7 +244,7 @@
|
||||
<field name="planned_hours" eval="40.0"/>
|
||||
<field name="remaining_hours" eval="40.0"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_2"/>
|
||||
<field name="name">Improve+clean code and functionality</field>
|
||||
<field name="stage_id" ref="project_stage_0"/>
|
||||
@ -255,7 +255,7 @@
|
||||
<field name="planned_hours" eval="12.0"/>
|
||||
<field name="remaining_hours" eval="12.0"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_3"/>
|
||||
<field name="name">Design Use Cases</field>
|
||||
<field name="stage_id" ref="project_stage_1"/>
|
||||
@ -265,7 +265,7 @@
|
||||
<field name="planned_hours" eval="12.0"/>
|
||||
<field name="remaining_hours" eval="12.0"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_3"/>
|
||||
<field name="name">Dataflow Design</field>
|
||||
<field name="stage_id" ref="project_stage_1"/>
|
||||
@ -274,7 +274,7 @@
|
||||
<field name="planned_hours" eval="55.0"/>
|
||||
<field name="remaining_hours" eval="55.0"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_3"/>
|
||||
<field name="name">User Interface design</field>
|
||||
<field name="stage_id" ref="project_stage_2"/>
|
||||
@ -288,7 +288,7 @@
|
||||
<field name="planned_hours" eval="80.0"/>
|
||||
<field name="remaining_hours" eval="80.0"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_3"/>
|
||||
<field name="name">Set target for all deparments</field>
|
||||
<field name="stage_id" ref="project_stage_3"/>
|
||||
@ -298,7 +298,7 @@
|
||||
<field name="planned_hours" eval="34.0"/>
|
||||
<field name="remaining_hours" eval="34.0"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_3"/>
|
||||
<field name="name">Integration of core components</field>
|
||||
<field name="stage_id" ref="project_stage_1"/>
|
||||
@ -308,7 +308,7 @@
|
||||
<field name="planned_hours" eval="16.0"/>
|
||||
<field name="remaining_hours" eval="16.0"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_3"/>
|
||||
<field name="name">Deploy and review on live system</field>
|
||||
<field name="stage_id" ref="project_stage_2"/>
|
||||
@ -350,7 +350,7 @@
|
||||
<field name="remaining_hours">12.0</field>
|
||||
<field name="stage_id" ref="project_stage_1"/>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="priority">l</field>
|
||||
<field name="project_id" ref="project.project_project_5"/>
|
||||
<field name="name">Customer analysis + Architecture</field>
|
||||
<field name="color">7</field>
|
||||
@ -371,7 +371,7 @@
|
||||
<field name="remaining_hours">8.0</field>
|
||||
<field name="stage_id" ref="project_stage_2"/>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="priority">m</field>
|
||||
<field name="project_id" ref="project.project_project_5"/>
|
||||
<field name="name">Modifications asked by the customer</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [
|
||||
|
@ -6,6 +6,7 @@ from lxml import etree
|
||||
from flectra import api, fields, models, tools, SUPERUSER_ID, _
|
||||
from flectra.exceptions import UserError, AccessError
|
||||
from flectra.tools.safe_eval import safe_eval
|
||||
from datetime import timedelta, date
|
||||
|
||||
|
||||
class ProjectTaskType(models.Model):
|
||||
@ -46,7 +47,7 @@ class ProjectTaskType(models.Model):
|
||||
class Project(models.Model):
|
||||
_name = "project.project"
|
||||
_description = "Project"
|
||||
_inherit = ['mail.alias.mixin', 'mail.thread', 'portal.mixin']
|
||||
_inherit = ['mail.alias.mixin', 'mail.thread', 'portal.mixin', 'ir.branch.company.mixin']
|
||||
_inherits = {'account.analytic.account': "analytic_account_id"}
|
||||
_order = "sequence, name, id"
|
||||
_period_number = 5
|
||||
@ -214,6 +215,9 @@ class Project(models.Model):
|
||||
date = fields.Date(string='Expiration Date', index=True, track_visibility='onchange')
|
||||
subtask_project_id = fields.Many2one('project.project', string='Sub-task Project', ondelete="restrict",
|
||||
help="Choosing a sub-tasks project will both enable sub-tasks and set their default project (possibly the project itself)")
|
||||
low = fields.Integer("No of Days for Low priority")
|
||||
medium = fields.Integer("No of Days for Medium priority")
|
||||
high = fields.Integer("No of Days for High priority")
|
||||
|
||||
_sql_constraints = [
|
||||
('project_date_greater', 'check(date >= date_start)', 'Error! project start-date must be lower than project end-date.')
|
||||
@ -361,7 +365,7 @@ class Task(models.Model):
|
||||
_name = "project.task"
|
||||
_description = "Task"
|
||||
_date_name = "date_start"
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin', 'portal.mixin']
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin', 'portal.mixin', 'ir.branch.company.mixin']
|
||||
_mail_post_access = 'read'
|
||||
_order = "priority desc, sequence, date_start, name, id"
|
||||
|
||||
@ -386,6 +390,12 @@ class Task(models.Model):
|
||||
stage_ids = stages._search(search_domain, order=order, access_rights_uid=SUPERUSER_ID)
|
||||
return stages.browse(stage_ids)
|
||||
|
||||
@api.one
|
||||
@api.depends('stage_id')
|
||||
def calculate_actual_end_date(self):
|
||||
if self.stage_id.name == 'Done':
|
||||
self.actual_end_date = date.today()
|
||||
|
||||
active = fields.Boolean(default=True)
|
||||
name = fields.Char(string='Task Title', track_visibility='always', required=True, index=True)
|
||||
description = fields.Html(string='Description')
|
||||
@ -464,6 +474,39 @@ class Task(models.Model):
|
||||
working_days_open = fields.Float(compute='_compute_elapsed', string='Working days to assign', store=True, group_operator="avg")
|
||||
working_days_close = fields.Float(compute='_compute_elapsed', string='Working days to close', store=True, group_operator="avg")
|
||||
|
||||
task_seq = fields.Char(
|
||||
string="Reference", track_visibility='onchange',
|
||||
default=lambda self: self.env['ir.sequence'].next_by_code(
|
||||
'project.task') or '/')
|
||||
priority = fields.Selection([
|
||||
('l', 'Low'), ('m', 'Medium'), ('h', 'High'), ],
|
||||
string="Priority", default='l')
|
||||
start_date = fields.Date(string="Start Date", track_visibility='onchange')
|
||||
end_date = fields.Date(string="End Date", track_visibility='onchange')
|
||||
actual_end_date = fields.Date(
|
||||
compute='calculate_actual_end_date', string="Actual End Date",
|
||||
store=True, track_visibility='onchange'
|
||||
)
|
||||
|
||||
@api.onchange('priority', 'project_id')
|
||||
def task_deadline(self):
|
||||
if self.project_id and self.priority:
|
||||
days = 0
|
||||
if self.priority == "l":
|
||||
days = int(self.project_id.low)
|
||||
elif self.priority == "m":
|
||||
days = int(self.project_id.medium)
|
||||
else:
|
||||
days = int(self.project_id.high)
|
||||
|
||||
self.update({
|
||||
'date_deadline': date.today() + timedelta(days)
|
||||
})
|
||||
else:
|
||||
self.update({
|
||||
'date_deadline': date.today()
|
||||
})
|
||||
|
||||
def _compute_attachment_ids(self):
|
||||
for task in self:
|
||||
attachment_ids = self.env['ir.attachment'].search([('res_id', '=', task.id), ('res_model', '=', 'project.task')]).ids
|
||||
|
@ -136,10 +136,17 @@
|
||||
<group>
|
||||
<field name="user_id" string="Project Manager"
|
||||
attrs="{'readonly':[('active','=',False)]}"/>
|
||||
<field name="company_id"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="subtask_project_id" groups="project.group_subtask_project"/>
|
||||
<field name="privacy_visibility" widget="radio"/>
|
||||
<field name="partner_id" string="Customer"/>
|
||||
</group>
|
||||
<group col="6">
|
||||
<field name="low"/>
|
||||
<field name="medium"/>
|
||||
<field name="high"/>
|
||||
</group>
|
||||
<group name="misc">
|
||||
<group string="Configuration" groups="base.group_no_one">
|
||||
<field name="sequence" groups="base.group_no_one"/>
|
||||
@ -427,6 +434,10 @@
|
||||
<field name="user_id"
|
||||
class="o_task_user_field"
|
||||
options='{"no_open": True}'/>
|
||||
<field name="company_id"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="actual_end_date"/>
|
||||
<field name="legend_blocked" invisible="1"/>
|
||||
<field name="legend_normal" invisible="1"/>
|
||||
<field name="legend_done" invisible="1"/>
|
||||
@ -434,6 +445,9 @@
|
||||
<group>
|
||||
<field name="date_deadline"/>
|
||||
<field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color', 'no_create_edit': True}"/>
|
||||
<field name="task_seq" readonly="1"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="priority"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
@ -906,4 +920,85 @@
|
||||
parent="menu_project_report"
|
||||
sequence="10"/>
|
||||
|
||||
<!-- Priority Tasks Kanban -->
|
||||
<record id="view_priority_task_kanban" model="ir.ui.view">
|
||||
<field name="name">project.task.kanban</field>
|
||||
<field name="model">project.task</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban class="o_kanban_small_column o_opportunity_kanban">
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div t-attf-class="oe_kanban_card oe_kanban_global_click">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<span style="font-weight:bold;">
|
||||
<field name="name"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<span>
|
||||
<field name="user_id"/>
|
||||
<br/>
|
||||
<field name="date_deadline"/>
|
||||
<br/>
|
||||
<field name="branch_id"/>
|
||||
<br/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oe_kanban_bottom_right">
|
||||
<img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)"
|
||||
t-att-title="record.user_id.value" width="25" height="25"
|
||||
class="oe_kanban_avatar pull-right"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Priority tasks Search view -->
|
||||
<record id="view_priority_tasks_search" model="ir.ui.view">
|
||||
<field name="name">project.task.search</field>
|
||||
<field name="model">project.task</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Priority Tasks">
|
||||
<field name="name"/>
|
||||
<field name="user_id"/>
|
||||
<field name="project_id"/>
|
||||
<field name="company_id"/>
|
||||
<filter string="Low" domain="[('priority', '=', 'l')]"/>
|
||||
<filter string="Medium" domain="[('priority', '=', 'm')]"/>
|
||||
<filter string="High" domain="[('priority', '=', 'h')]"/>
|
||||
<group expand="1" string="Group By">
|
||||
<filter string="Priority" name="priority" context="{'group_by': 'priority'}"/>
|
||||
<filter string="Assigned To" name='user_id' context="{'group_by': 'user_id'}"/>
|
||||
<filter string="Stage" name='stage_id' context="{'group_by': 'stage_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Priority Tasks Action -->
|
||||
<record id="action_priority_tasks" model="ir.actions.act_window">
|
||||
<field name="name">Priority Tasks</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">project.task</field>
|
||||
<field name="view_mode">kanban,form,tree</field>
|
||||
<field name="view_id" ref="view_priority_task_kanban"/>
|
||||
<field name="search_view_id" ref="view_priority_tasks_search"/>
|
||||
<field name="context">{'search_default_priority': 1}</field>
|
||||
</record>
|
||||
|
||||
<!-- Priority Tasks Menu -->
|
||||
<menuitem
|
||||
id="menu_priority_tasks"
|
||||
parent="project.menu_project_management"
|
||||
action="action_priority_tasks"
|
||||
sequence="4"
|
||||
/>
|
||||
|
||||
</flectra>
|
||||
|
4
addons/project_scrum/__init__.py
Executable file
@ -0,0 +1,4 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
||||
from . import controllers
|
45
addons/project_scrum/__manifest__.py
Executable file
@ -0,0 +1,45 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
'name': 'Project Scrum',
|
||||
'version': '1.0',
|
||||
'category': 'Project',
|
||||
'author': 'Flectra',
|
||||
'website': 'https://flectrahq.com',
|
||||
'sequence': 40,
|
||||
'summary': 'A module for Scrum implementation',
|
||||
'depends': [
|
||||
'project', 'resource'
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'security/scrum_security.xml',
|
||||
'views/other_views.xml',
|
||||
'views/project_sprint_views.xml',
|
||||
'views/project_story_views.xml',
|
||||
'views/project_team_views.xml',
|
||||
'views/release_planning_views.xml',
|
||||
'views/cron_view.xml',
|
||||
'views/assets.xml',
|
||||
'views/retrospective_method_views.xml',
|
||||
'views/retrospective_views.xml',
|
||||
'reports/project_scrum_report.xml',
|
||||
'reports/release_planning_template.xml',
|
||||
'reports/project_sprint_template.xml',
|
||||
'data/sprint_sequence.xml',
|
||||
'data/project_sprint_data.xml',
|
||||
],
|
||||
'demo': [
|
||||
'demo/project_team_demo.xml',
|
||||
'demo/project_sprint_demo.xml',
|
||||
'demo/project_story_demo.xml',
|
||||
'demo/project_release_planning_demo.xml',
|
||||
'demo/retrospective_demo.xml',
|
||||
'demo/project_task_demo.xml',
|
||||
],
|
||||
'qweb': [
|
||||
'static/src/xml/scrum_dashboard.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
}
|
3
addons/project_scrum/controllers/__init__.py
Executable file
@ -0,0 +1,3 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import backend
|
105
addons/project_scrum/controllers/backend.py
Executable file
@ -0,0 +1,105 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra import http
|
||||
from flectra.http import request
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class Sprint(http.Controller):
|
||||
|
||||
@http.route('/project_scrum/get_sprints_data', type='json', auth='user')
|
||||
def fetch_sprints_data(self):
|
||||
res = {}
|
||||
|
||||
total_sprints = request.env['project.sprint'].search_count([])
|
||||
total_tasks = request.env['project.task'].search_count([])
|
||||
total_stories = request.env['project.story'].search_count([])
|
||||
total_projects = request.env['project.project'].search_count([])
|
||||
sprint_ids = request.env['project.sprint'].search_read(
|
||||
[], ['id', 'name'])
|
||||
|
||||
res.update({
|
||||
'total_sprints': total_sprints,
|
||||
'total_tasks': total_tasks,
|
||||
'total_stories': total_stories,
|
||||
'total_projects': total_projects,
|
||||
'sprint_ids': sprint_ids,
|
||||
})
|
||||
|
||||
return res
|
||||
|
||||
@http.route('/project_scrum/get_sprint_data_for_chart', type='json',
|
||||
auth='user')
|
||||
def fetch_data_for_chart(self):
|
||||
data = []
|
||||
sprint_ids = request.env['project.sprint'].search([])
|
||||
|
||||
for sprint in sprint_ids:
|
||||
start = datetime.strptime(sprint.start_date, '%Y-%m-%d').date()
|
||||
end = datetime.strptime(sprint.end_date, '%Y-%m-%d').date()
|
||||
diff = (end - start).days
|
||||
|
||||
data.append({
|
||||
'sprint_seq': sprint.sprint_seq or '/',
|
||||
'velocity': sprint.estimated_velocity or 0,
|
||||
'no_of_days': diff,
|
||||
})
|
||||
|
||||
return data
|
||||
|
||||
@http.route('/project_scrum/get_sprint_data', type='json', auth='user')
|
||||
def fetch_sprint_data(self, sprint_id):
|
||||
data = []
|
||||
|
||||
if sprint_id:
|
||||
sprint_obj = request.env['project.sprint'].browse(
|
||||
int(sprint_id))
|
||||
sprint_velocity = sprint_obj.estimated_velocity
|
||||
task_ids = request.env['project.task'].search([
|
||||
('sprint_id', '=', int(sprint_id))
|
||||
])
|
||||
|
||||
for task in task_ids:
|
||||
per = (float(task.velocity) * 100) / float(sprint_velocity)
|
||||
data.append({
|
||||
'velocity': task.velocity,
|
||||
'task_seq': task.task_seq or '/',
|
||||
'per': round(per, 2),
|
||||
'user': task.user_id.name or '',
|
||||
'id': task.id,
|
||||
})
|
||||
return data
|
||||
|
||||
@http.route('/project_scrum/get_sprints_task_data', type='json',
|
||||
auth='user')
|
||||
def fetch_sprints_task_data(self, sprint_id):
|
||||
res = {}
|
||||
|
||||
if sprint_id:
|
||||
domain = [('sprint_id', '=', int(sprint_id))]
|
||||
|
||||
total_tasks = request.env['project.task'].search_count(domain)
|
||||
total_stories = request.env['project.story'].search_count(domain)
|
||||
|
||||
res.update({
|
||||
'total_tasks': total_tasks,
|
||||
'total_stories': total_stories,
|
||||
})
|
||||
|
||||
return res
|
||||
|
||||
@http.route('/project_scrum/get_line_chart_data', type='json',
|
||||
auth='user')
|
||||
def fetch_line_chart_data(self):
|
||||
data = []
|
||||
sprint_ids = request.env['project.sprint'].search([])
|
||||
for sprint in sprint_ids:
|
||||
per = float(
|
||||
(sprint.actual_velocity * 100) / sprint.estimated_velocity
|
||||
if sprint.estimated_velocity > 0.0 else 0.0)
|
||||
data.append({
|
||||
'sprint_seq': sprint.sprint_seq or '/',
|
||||
'per': per,
|
||||
'velocity': sprint.estimated_velocity or 0.0,
|
||||
})
|
||||
return data
|
88
addons/project_scrum/data/project_sprint_data.xml
Executable file
@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- Sprint-related subtypes for messaging / Chatter -->
|
||||
<record id="state_sprint_draft" model="mail.message.subtype">
|
||||
<field name="name">Sprint Draft</field>
|
||||
<field name="res_model">project.sprint</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="description">Sprint Draft</field>
|
||||
</record>
|
||||
|
||||
<record id="state_sprint_in_progress" model="mail.message.subtype">
|
||||
<field name="name">Sprint In Progress</field>
|
||||
<field name="res_model">project.sprint</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="description">Sprint In Progress</field>
|
||||
</record>
|
||||
|
||||
<record id="state_sprint_pending" model="mail.message.subtype">
|
||||
<field name="name">Sprint Pending</field>
|
||||
<field name="res_model">project.sprint</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="description">Sprint Pending</field>
|
||||
</record>
|
||||
|
||||
<record id="state_sprint_done" model="mail.message.subtype">
|
||||
<field name="name">Sprint Done</field>
|
||||
<field name="res_model">project.sprint</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="description">Sprint Done</field>
|
||||
</record>
|
||||
|
||||
<record id="state_sprint_cancel" model="mail.message.subtype">
|
||||
<field name="name">Sprint Cancel</field>
|
||||
<field name="res_model">project.sprint</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="description">Sprint Cancel</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Project-related subtypes for messaging / Chatter -->
|
||||
<record id="state_project_sprint_draft" model="mail.message.subtype">
|
||||
<field name="name">Sprint Draft</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="res_model">project.team</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="parent_id" eval="ref('state_sprint_draft')"/>
|
||||
<field name="relation_field">team_id</field>
|
||||
</record>
|
||||
|
||||
<record id="state_project_sprint_in_progress" model="mail.message.subtype">
|
||||
<field name="name">Sprint In Progress</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="res_model">project.team</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="parent_id" eval="ref('state_sprint_in_progress')"/>
|
||||
<field name="relation_field">team_id</field>
|
||||
</record>
|
||||
|
||||
<record id="state_project_sprint_pending" model="mail.message.subtype">
|
||||
<field name="name">Sprint Pending</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="res_model">project.team</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="parent_id" eval="ref('state_sprint_pending')"/>
|
||||
<field name="relation_field">team_id</field>
|
||||
</record>
|
||||
|
||||
<record id="state_project_sprint_done" model="mail.message.subtype">
|
||||
<field name="name">Sprint Done</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="res_model">project.team</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="parent_id" eval="ref('state_sprint_done')"/>
|
||||
<field name="relation_field">team_id</field>
|
||||
</record>
|
||||
|
||||
<record id="state_project_sprint_cancel" model="mail.message.subtype">
|
||||
<field name="name">Sprint Cancel</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="res_model">project.team</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="parent_id" eval="ref('state_sprint_cancel')"/>
|
||||
<field name="relation_field">team_id</field>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
13
addons/project_scrum/data/sprint_sequence.xml
Executable file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data>
|
||||
<!-- Sequence for Sprint -->
|
||||
<record id="seq_sprint" model="ir.sequence">
|
||||
<field name="name">Sprints</field>
|
||||
<field name="code">project.sprint</field>
|
||||
<field name="prefix">SP</field>
|
||||
<field name="padding">3</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
42
addons/project_scrum/demo/project_release_planning_demo.xml
Executable file
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flectra>
|
||||
<data noupdate="1">
|
||||
<!--
|
||||
release.planning Demo Data
|
||||
-->
|
||||
<record id="release_planning_1" model="release.planning">
|
||||
<field name="name">Release of Development</field>
|
||||
<field name="release_date" eval="DateTime.today() - relativedelta(days=5,hours=20,minutes=2,seconds=10)"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
</record>
|
||||
|
||||
<record id="release_planning_2" model="release.planning">
|
||||
<field name="name">Release of Design & Documentation</field>
|
||||
<field name="release_date" eval="DateTime.today() - relativedelta(days=3,hours=21,minutes=4,seconds=19)"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
</record>
|
||||
|
||||
<record id="release_planning_3" model="release.planning">
|
||||
<field name="name">Release Access Rights Allocation</field>
|
||||
<field name="release_date" eval="DateTime.today() + relativedelta(days=5,hours=22,minutes=5,seconds=25)"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_2"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
</record>
|
||||
|
||||
<record id="release_planning_4" model="release.planning">
|
||||
<field name="name">Release Mail Configuration & Improved Dashboard</field>
|
||||
<field name="release_date" eval="DateTime.today() - relativedelta(days=25,hours=23,minutes=6,seconds=34)"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_3"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
</record>
|
||||
|
||||
<record id="release_planning_5" model="release.planning">
|
||||
<field name="name">Scrum Updates</field>
|
||||
<field name="release_date" eval="DateTime.today() - relativedelta(days=6,hours=24,minutes=8,seconds=55)"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_3"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
235
addons/project_scrum/demo/project_sprint_demo.xml
Executable file
@ -0,0 +1,235 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flectra>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="resource.resource_calendar_std" model="resource.calendar">
|
||||
<field name="no_of_hours">8</field>
|
||||
<field name="no_of_days">5</field>
|
||||
</record>
|
||||
|
||||
<record id="resource.resource_calendar_std_35h" model="resource.calendar">
|
||||
<field name="no_of_hours">7</field>
|
||||
<field name="no_of_days">5</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
user.role Demo Data
|
||||
-->
|
||||
<record id="user_role_1" model="user.role">
|
||||
<field name="name">Manager</field>
|
||||
<field name="code">M</field>
|
||||
</record>
|
||||
|
||||
<record id="user_role_2" model="user.role">
|
||||
<field name="name">Developer</field>
|
||||
<field name="code">D</field>
|
||||
</record>
|
||||
|
||||
<record id="user_role_3" model="user.role">
|
||||
<field name="name">Tester</field>
|
||||
<field name="code">T</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
project.sprint Demo Data
|
||||
-->
|
||||
<record id="project_sprint_1" model="project.sprint">
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="name">Module Development</field>
|
||||
<field name="state">draft</field>
|
||||
<field name="team_id" ref="project_scrum.project_team_1"/>
|
||||
<field name="start_date" eval="(DateTime.today() - relativedelta(days=8))"/>
|
||||
<field name="end_date" eval="(DateTime.today() + relativedelta(days=8))"/>
|
||||
<field name="goal_of_sprint">Develop Module with Documentation</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="hour">11</field>
|
||||
<field name="time_zone">am</field>
|
||||
<field name="meeting_date" eval="(DateTime.today() - relativedelta(days=8))"/>
|
||||
<field name="productivity_hours">8.00</field>
|
||||
<field name="holiday_type">hours</field>
|
||||
<field name="holiday_count">1.00</field>
|
||||
</record>
|
||||
|
||||
<record id="project_sprint_2" model="project.sprint">
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="name">Access Rights & Testing</field>
|
||||
<field name="state">in_progress</field>
|
||||
<field name="team_id" ref="project_scrum.project_team_2"/>
|
||||
<field name="start_date" eval="(DateTime.today() + relativedelta(days=8))"/>
|
||||
<field name="end_date" eval="(DateTime.today() + relativedelta(days=22))"/>
|
||||
<field name="goal_of_sprint">Access Rights Allocation</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="hour">15</field>
|
||||
<field name="time_zone">pm</field>
|
||||
<field name="meeting_date" eval="(DateTime.today() + relativedelta(days=8))"/>
|
||||
<field name="productivity_hours">7.00</field>
|
||||
<field name="holiday_type">hours</field>
|
||||
<field name="holiday_count">1.00</field>
|
||||
</record>
|
||||
|
||||
<record id="project_sprint_3" model="project.sprint">
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="name">Implement Mailing Functionality </field>
|
||||
<field name="state">cancel</field>
|
||||
<field name="team_id" ref="project_scrum.project_team_3"/>
|
||||
<field name="start_date" eval="(DateTime.today() + relativedelta(days=22))"/>
|
||||
<field name="end_date" eval="(DateTime.today() + relativedelta(days=36))"/>
|
||||
<field name="goal_of_sprint">Mailing and Workflow</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="hour">15</field>
|
||||
<field name="time_zone">pm</field>
|
||||
<field name="meeting_date" eval="(DateTime.today() + relativedelta(days=22))"/>
|
||||
<field name="productivity_hours">7.00</field>
|
||||
<field name="holiday_type">hours</field>
|
||||
<field name="holiday_count">1.00</field>
|
||||
</record>
|
||||
|
||||
<record id="project_sprint_4" model="project.sprint">
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="name">Dashboard Improvements</field>
|
||||
<field name="state">in_progress</field>
|
||||
<field name="team_id" ref="project_scrum.project_team_3"/>
|
||||
<field name="start_date" eval="(DateTime.today() + relativedelta(days=38))"/>
|
||||
<field name="end_date" eval="(DateTime.today() + relativedelta(days=52))"/>
|
||||
<field name="goal_of_sprint">Exclusive Dashboard</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="hour">10</field>
|
||||
<field name="time_zone">am</field>
|
||||
<field name="meeting_date" eval="(DateTime.today() + relativedelta(days=38))"/>
|
||||
<field name="productivity_hours">7.00</field>
|
||||
<field name="holiday_type">hours</field>
|
||||
<field name="holiday_count">1.00</field>
|
||||
</record>
|
||||
|
||||
<record id="project_sprint_5" model="project.sprint">
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="name">Project Integration</field>
|
||||
<field name="state">pending</field>
|
||||
<field name="team_id" ref="project_scrum.project_team_1"/>
|
||||
<field name="start_date" eval="(DateTime.today() + relativedelta(days=52))"/>
|
||||
<field name="end_date" eval="(DateTime.today() + relativedelta(days=66))"/>
|
||||
<field name="goal_of_sprint">Integrating Project</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="hour">12</field>
|
||||
<field name="time_zone">pm</field>
|
||||
<field name="meeting_date" eval="(DateTime.today() + relativedelta(days=52))"/>
|
||||
<field name="productivity_hours">7.00</field>
|
||||
<field name="holiday_type">hours</field>
|
||||
<field name="holiday_count">1.00</field>
|
||||
</record>
|
||||
<!--
|
||||
sprint.planning.line Demo Data
|
||||
-->
|
||||
<record id="sprint_planning_line_1" model="sprint.planning.line">
|
||||
<field name="user_id" ref="project_scrum.user_1"/>
|
||||
<field name="role_id" ref="project_scrum.user_role_1"/>
|
||||
<field name="available_per">100</field>
|
||||
<field name="off_hours">10.00</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
</record>
|
||||
|
||||
<record id="sprint_planning_line_2" model="sprint.planning.line">
|
||||
<field name="user_id" ref="project_scrum.user_2"/>
|
||||
<field name="role_id" ref="project_scrum.user_role_2"/>
|
||||
<field name="available_per">80</field>
|
||||
<field name="off_hours">8.00</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
</record>
|
||||
|
||||
<record id="sprint_planning_line_3" model="sprint.planning.line">
|
||||
<field name="user_id" ref="project_scrum.user_3"/>
|
||||
<field name="role_id" ref="project_scrum.user_role_2"/>
|
||||
<field name="available_per">40</field>
|
||||
<field name="off_hours">4.00</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
</record>
|
||||
|
||||
<record id="sprint_planning_line_4" model="sprint.planning.line">
|
||||
<field name="user_id" ref="project_scrum.user_1"/>
|
||||
<field name="role_id" ref="project_scrum.user_role_3"/>
|
||||
<field name="available_per">95</field>
|
||||
<field name="off_hours">1.00</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_2"/>
|
||||
</record>
|
||||
|
||||
<record id="sprint_planning_line_5" model="sprint.planning.line">
|
||||
<field name="user_id" ref="project_scrum.user_2"/>
|
||||
<field name="role_id" ref="project_scrum.user_role_2"/>
|
||||
<field name="available_per">90</field>
|
||||
<field name="off_hours">1.00</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_2"/>
|
||||
</record>
|
||||
|
||||
<record id="sprint_planning_line_6" model="sprint.planning.line">
|
||||
<field name="user_id" ref="project_scrum.user_3"/>
|
||||
<field name="role_id" ref="project_scrum.user_role_2"/>
|
||||
<field name="available_per">90</field>
|
||||
<field name="off_hours">1.00</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_2"/>
|
||||
</record>
|
||||
|
||||
<record id="sprint_planning_line_7" model="sprint.planning.line">
|
||||
<field name="user_id" ref="project_scrum.user_1"/>
|
||||
<field name="role_id" ref="project_scrum.user_role_1"/>
|
||||
<field name="available_per">80</field>
|
||||
<field name="off_hours">2.00</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_3"/>
|
||||
</record>
|
||||
|
||||
<record id="sprint_planning_line_8" model="sprint.planning.line">
|
||||
<field name="user_id" ref="project_scrum.user_2"/>
|
||||
<field name="role_id" ref="project_scrum.user_role_2"/>
|
||||
<field name="available_per">80</field>
|
||||
<field name="off_hours">1.00</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_3"/>
|
||||
</record>
|
||||
|
||||
<record id="sprint_planning_line_9" model="sprint.planning.line">
|
||||
<field name="user_id" ref="project_scrum.user_3"/>
|
||||
<field name="role_id" ref="project_scrum.user_role_3"/>
|
||||
<field name="available_per">90</field>
|
||||
<field name="off_hours">1.00</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_3"/>
|
||||
</record>
|
||||
|
||||
<record id="sprint_planning_line_10" model="sprint.planning.line">
|
||||
<field name="user_id" ref="project_scrum.user_1"/>
|
||||
<field name="role_id" ref="project_scrum.user_role_1"/>
|
||||
<field name="available_per">90</field>
|
||||
<field name="off_hours">1.00</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_4"/>
|
||||
</record>
|
||||
|
||||
<record id="sprint_planning_line_11" model="sprint.planning.line">
|
||||
<field name="user_id" ref="project_scrum.user_2"/>
|
||||
<field name="role_id" ref="project_scrum.user_role_2"/>
|
||||
<field name="available_per">100</field>
|
||||
<field name="off_hours">1.00</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_4"/>
|
||||
</record>
|
||||
|
||||
<record id="sprint_planning_line_12" model="sprint.planning.line">
|
||||
<field name="user_id" ref="project_scrum.user_3"/>
|
||||
<field name="role_id" ref="project_scrum.user_role_3"/>
|
||||
<field name="available_per">80</field>
|
||||
<field name="off_hours">2.00</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_4"/>
|
||||
</record>
|
||||
|
||||
<record id="sprint_planning_line_13" model="sprint.planning.line">
|
||||
<field name="user_id" ref="project_scrum.user_1"/>
|
||||
<field name="role_id" ref="project_scrum.user_role_1"/>
|
||||
<field name="available_per">90</field>
|
||||
<field name="off_hours">2.00</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_5"/>
|
||||
</record>
|
||||
|
||||
<record id="sprint_planning_line_14" model="sprint.planning.line">
|
||||
<field name="user_id" ref="project_scrum.user_3"/>
|
||||
<field name="role_id" ref="project_scrum.user_role_3"/>
|
||||
<field name="available_per">90</field>
|
||||
<field name="off_hours">1.00</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_5"/>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
65
addons/project_scrum/demo/project_story_demo.xml
Executable file
@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flectra>
|
||||
<data noupdate="1">
|
||||
<!--
|
||||
story.priority Demo Data
|
||||
-->
|
||||
<record id="story_priority_1" model="story.priority">
|
||||
<field name="name">High</field>
|
||||
<field name="code">HIGH</field>
|
||||
</record>
|
||||
|
||||
<record id="story_priority_2" model="story.priority">
|
||||
<field name="name">Medium</field>
|
||||
<field name="code">MEDIUM</field>
|
||||
</record>
|
||||
|
||||
<record id="story_priority_3" model="story.priority">
|
||||
<field name="name">Low</field>
|
||||
<field name="code">LOW</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
story.type Demo Data
|
||||
-->
|
||||
<record id="story_type_1" model="story.type">
|
||||
<field name="name">Descriptive Story</field>
|
||||
<field name="code">Desc</field>
|
||||
</record>
|
||||
|
||||
<record id="story_type_2" model="story.type">
|
||||
<field name="name">Brief Story</field>
|
||||
<field name="code">Brief</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
project.story Demo Data
|
||||
-->
|
||||
<record id="project_story_1" model="project.story">
|
||||
<field name="name">Development</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="priority_id" ref="project_scrum.story_priority_2"/>
|
||||
<field name="story_type_id" ref="project_scrum.story_type_2"/>
|
||||
<field name="description">Begin development...</field>
|
||||
</record>
|
||||
|
||||
<record id="project_story_2" model="project.story">
|
||||
<field name="name">Designing</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="priority_id" ref="project_scrum.story_priority_2"/>
|
||||
<field name="story_type_id" ref="project_scrum.story_type_1"/>
|
||||
<field name="description">Begin Designing...</field>
|
||||
</record>
|
||||
|
||||
<record id="project_story_3" model="project.story">
|
||||
<field name="name">Testing Workflow</field>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_2"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="priority_id" ref="project_scrum.story_priority_1"/>
|
||||
<field name="story_type_id" ref="project_scrum.story_type_2"/>
|
||||
<field name="description">Workflow testing...</field>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
250
addons/project_scrum/demo/project_task_demo.xml
Executable file
@ -0,0 +1,250 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flectra>
|
||||
<data>
|
||||
<!--
|
||||
project.task Demo Data
|
||||
-->
|
||||
<record id="project_task_1" model="project.task">
|
||||
<field name="name">Creating Objects</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="priority">m</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=5)"/>
|
||||
<field name="company_id">1</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
<field name="start_date" eval="DateTime.today() - relativedelta(days=5)"/>
|
||||
<field name="end_date" eval="DateTime.today() - relativedelta(days=2)"/>
|
||||
<field name="story_id" ref="project_scrum.project_story_2"/>
|
||||
<field name="velocity">30</field>
|
||||
<field name="release_planning_id" ref="project_scrum.release_planning_1"/>
|
||||
<field name="description">Creating necessary objects...</field>
|
||||
<field name="sequence">11</field>
|
||||
<field name="partner_id">1</field>
|
||||
</record>
|
||||
|
||||
<record id="project_task_2" model="project.task">
|
||||
<field name="name">Creating Views</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="priority">h</field>
|
||||
<field name="date_deadline" eval="DateTime.today()"/>
|
||||
<field name="company_id">1</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
<field name="start_date" eval="DateTime.today() - relativedelta(days=2)"/>
|
||||
<field name="end_date" eval="DateTime.today()"/>
|
||||
<field name="story_id" ref="project_scrum.project_story_1"/>
|
||||
<field name="velocity">20</field>
|
||||
<field name="release_planning_id" ref="project_scrum.release_planning_2"/>
|
||||
<field name="description">Creating view for objects...</field>
|
||||
<field name="sequence">12</field>
|
||||
<field name="partner_id">1</field>
|
||||
<field name="stage_id" ref="project.project_stage_2"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_3" model="project.task">
|
||||
<field name="name">Access Rights</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="priority">l</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=15)"/>
|
||||
<field name="company_id">1</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_2"/>
|
||||
<field name="start_date" eval="DateTime.today() + relativedelta(days=10)"/>
|
||||
<field name="end_date" eval="DateTime.today() + relativedelta(days=13)"/>
|
||||
<field name="story_id" ref="project_scrum.project_story_3"/>
|
||||
<field name="velocity">15</field>
|
||||
<field name="release_planning_id" ref="project_scrum.release_planning_3"/>
|
||||
<field name="description">Necessary rights for different objects...</field>
|
||||
<field name="sequence">13</field>
|
||||
<field name="partner_id">1</field>
|
||||
<field name="stage_id" ref="project.project_stage_2"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_4" model="project.task">
|
||||
<field name="name">Creating Mail Templates</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="priority">m</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=27)"/>
|
||||
<field name="company_id">1</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_3"/>
|
||||
<field name="start_date" eval="DateTime.today() + relativedelta(days=25)"/>
|
||||
<field name="end_date" eval="DateTime.today() + relativedelta(days=27)"/>
|
||||
<field name="story_id" ref="project_scrum.project_story_3"/>
|
||||
<field name="velocity">15</field>
|
||||
<field name="release_planning_id" ref="project_scrum.release_planning_4"/>
|
||||
<field name="description">Create different mail templates...</field>
|
||||
<field name="sequence">13</field>
|
||||
<field name="partner_id">1</field>
|
||||
<field name="stage_id" ref="project.project_stage_2"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_6" model="project.task">
|
||||
<field name="name">Mailing Functionality</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="priority">m</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=31)"/>
|
||||
<field name="company_id">1</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_3"/>
|
||||
<field name="start_date" eval="DateTime.today() + relativedelta(days=29)"/>
|
||||
<field name="end_date" eval="DateTime.today() + relativedelta(days=31)"/>
|
||||
<field name="story_id" ref="project_scrum.project_story_3"/>
|
||||
<field name="velocity">20</field>
|
||||
<field name="release_planning_id" ref="project_scrum.release_planning_5"/>
|
||||
<field name="description">Send Mails....</field>
|
||||
<field name="sequence">13</field>
|
||||
<field name="partner_id">1</field>
|
||||
</record>
|
||||
|
||||
<record id="project_task_7" model="project.task">
|
||||
<field name="name">Rights division for different modules</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="priority">m</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=4)"/>
|
||||
<field name="company_id">1</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
<field name="start_date" eval="DateTime.today() + relativedelta(days=1)"/>
|
||||
<field name="end_date" eval="DateTime.today() + relativedelta(days=4)"/>
|
||||
<field name="story_id" ref="project_scrum.project_story_3"/>
|
||||
<field name="velocity">25</field>
|
||||
<field name="release_planning_id" ref="project_scrum.release_planning_5"/>
|
||||
<field name="description">Rights division...</field>
|
||||
<field name="sequence">13</field>
|
||||
<field name="partner_id">1</field>
|
||||
</record>
|
||||
|
||||
<record id="project_task_8" model="project.task">
|
||||
<field name="name">Rights allocation</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="priority">m</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=15)"/>
|
||||
<field name="company_id">1</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_2"/>
|
||||
<field name="start_date" eval="DateTime.today() + relativedelta(days=13)"/>
|
||||
<field name="end_date" eval="DateTime.today() + relativedelta(days=15)"/>
|
||||
<field name="story_id" ref="project_scrum.project_story_3"/>
|
||||
<field name="velocity">30</field>
|
||||
<field name="release_planning_id" ref="project_scrum.release_planning_1"/>
|
||||
<field name="description">Rights Allocation...</field>
|
||||
<field name="sequence">13</field>
|
||||
<field name="partner_id">1</field>
|
||||
</record>
|
||||
|
||||
<record id="project_task_9" model="project.task">
|
||||
<field name="name">Testing with different Users</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="priority">m</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=18)"/>
|
||||
<field name="company_id">1</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_2"/>
|
||||
<field name="start_date" eval="DateTime.today() + relativedelta(days=16)"/>
|
||||
<field name="end_date" eval="DateTime.today() + relativedelta(days=18)"/>
|
||||
<field name="story_id" ref="project_scrum.project_story_3"/>
|
||||
<field name="velocity">25</field>
|
||||
<field name="release_planning_id" ref="project_scrum.release_planning_2"/>
|
||||
<field name="description">Testing with different users to ensure users have got the necessary access...</field>
|
||||
<field name="sequence">13</field>
|
||||
<field name="partner_id">1</field>
|
||||
<field name="stage_id" ref="project.project_stage_2"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_10" model="project.task">
|
||||
<field name="name">Dashboard Design</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="priority">m</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=43)"/>
|
||||
<field name="company_id">1</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_4"/>
|
||||
<field name="start_date" eval="DateTime.today() + relativedelta(days=40)"/>
|
||||
<field name="end_date" eval="DateTime.today() + relativedelta(days=43)"/>
|
||||
<field name="story_id" ref="project_scrum.project_story_3"/>
|
||||
<field name="velocity">35</field>
|
||||
<field name="release_planning_id" ref="project_scrum.release_planning_3"/>
|
||||
<field name="description">Design for dashboard...</field>
|
||||
<field name="sequence">13</field>
|
||||
<field name="partner_id">1</field>
|
||||
</record>
|
||||
|
||||
<record id="project_task_11" model="project.task">
|
||||
<field name="name">View Rendering</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="priority">m</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=47)"/>
|
||||
<field name="company_id">1</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_4"/>
|
||||
<field name="start_date" eval="DateTime.today() + relativedelta(days=43)"/>
|
||||
<field name="end_date" eval="DateTime.today() + relativedelta(days=47)"/>
|
||||
<field name="story_id" ref="project_scrum.project_story_3"/>
|
||||
<field name="velocity">20</field>
|
||||
<field name="release_planning_id" ref="project_scrum.release_planning_4"/>
|
||||
<field name="description">Render views...</field>
|
||||
<field name="sequence">13</field>
|
||||
<field name="partner_id">1</field>
|
||||
<field name="stage_id" ref="project.project_stage_2"/>
|
||||
|
||||
</record>
|
||||
|
||||
<record id="project_task_12" model="project.task">
|
||||
<field name="name">Enhancements</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="priority">m</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=51)"/>
|
||||
<field name="company_id">1</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_4"/>
|
||||
<field name="start_date" eval="DateTime.today() + relativedelta(days=48)"/>
|
||||
<field name="end_date" eval="DateTime.today() + relativedelta(days=51)"/>
|
||||
<field name="story_id" ref="project_scrum.project_story_3"/>
|
||||
<field name="velocity">25</field>
|
||||
<field name="release_planning_id" ref="project_scrum.release_planning_5"/>
|
||||
<field name="description">Improvements for dashboard....</field>
|
||||
<field name="sequence">13</field>
|
||||
<field name="partner_id">1</field>
|
||||
<field name="stage_id" ref="project.project_stage_2"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_13" model="project.task">
|
||||
<field name="name">Objects Integration</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="priority">m</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=55)"/>
|
||||
<field name="company_id">1</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_5"/>
|
||||
<field name="start_date" eval="DateTime.today() + relativedelta(days=53)"/>
|
||||
<field name="end_date" eval="DateTime.today() + relativedelta(days=55)"/>
|
||||
<field name="story_id" ref="project_scrum.project_story_3"/>
|
||||
<field name="velocity">25</field>
|
||||
<field name="release_planning_id" ref="project_scrum.release_planning_1"/>
|
||||
<field name="description">Integrate objects....</field>
|
||||
<field name="sequence">13</field>
|
||||
<field name="partner_id">1</field>
|
||||
</record>
|
||||
|
||||
<record id="project_task_14" model="project.task">
|
||||
<field name="name">View Enhancements</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="priority">m</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=58)"/>
|
||||
<field name="company_id">1</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_5"/>
|
||||
<field name="start_date" eval="DateTime.today() + relativedelta(days=56)"/>
|
||||
<field name="end_date" eval="DateTime.today() + relativedelta(days=58)"/>
|
||||
<field name="story_id" ref="project_scrum.project_story_3"/>
|
||||
<field name="velocity">20</field>
|
||||
<field name="release_planning_id" ref="project_scrum.release_planning_2"/>
|
||||
<field name="description">View Enhancements...</field>
|
||||
<field name="sequence">13</field>
|
||||
<field name="partner_id">1</field>
|
||||
<field name="stage_id" ref="project.project_stage_2"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</flectra>
|
75
addons/project_scrum/demo/project_team_demo.xml
Executable file
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flectra>
|
||||
|
||||
<data noupdate="1">
|
||||
<!--
|
||||
res.users Demo Data
|
||||
-->
|
||||
<record id="user_1" model="res.users">
|
||||
<field name="name">Chris Gardner</field>
|
||||
<field name="login">chris@demo.com</field>
|
||||
</record>
|
||||
|
||||
<record id="user_2" model="res.users">
|
||||
<field name="name">Oskar Schindler</field>
|
||||
<field name="login">oskar@demo.com</field>
|
||||
</record>
|
||||
|
||||
<record id="user_3" model="res.users">
|
||||
<field name="name">Andy Dufresne</field>
|
||||
<field name="login">andy@demo.com</field>
|
||||
</record>
|
||||
|
||||
<!-- Project -->
|
||||
|
||||
<record id="demo_project_1" model="project.project">
|
||||
<field name="name">Project Scrum</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="privacy_visibility">employees</field>
|
||||
<field name="partner_id">1</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="resource_calendar_id">1</field>
|
||||
<field name="type_ids"
|
||||
eval="[(6, 0, [ref('project.project_stage_0'),
|
||||
ref('project.project_stage_1'),
|
||||
ref('project.project_stage_3'), ref('project.project_stage_2')])]"/>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
project.team Demo Data
|
||||
-->
|
||||
<record id="project_team_1" model="project.team">
|
||||
<field name="name">Project Module Team</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="member_ids" eval="[(6, 0, [ref('project_scrum.user_1'), ref('project_scrum.user_2')])]"/>
|
||||
<field name="master_id" ref="project_scrum.user_1"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="strength">Technical, Functional</field>
|
||||
<field name="description">Description for the Project team...</field>
|
||||
</record>
|
||||
|
||||
<record id="project_team_2" model="project.team">
|
||||
<field name="name">Sales Team</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="member_ids"
|
||||
eval="[(6, 0, [ref('project_scrum.user_1'), ref('project_scrum.user_2'), ref('project_scrum.user_3')])]"/>
|
||||
<field name="master_id" ref="project_scrum.user_2"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="strength">Functional</field>
|
||||
<field name="description">Description for the Sales team...</field>
|
||||
</record>
|
||||
|
||||
<record id="project_team_3" model="project.team">
|
||||
<field name="name">Sales and Purchase Team</field>
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="member_ids"
|
||||
eval="[(6, 0, [ref('project_scrum.user_1'), ref('project_scrum.user_2'), ref('project_scrum.user_3')])]"/>
|
||||
<field name="master_id" ref="project_scrum.user_3"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
<field name="strength">Technical, Functional</field>
|
||||
<field name="description">Description for the team...</field>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
60
addons/project_scrum/demo/retrospective_demo.xml
Executable file
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flectra>
|
||||
<data noupdate="1">
|
||||
<!--
|
||||
retrospective.method Demo Data
|
||||
-->
|
||||
<record id="retrospective_method_1" model="retrospective.method">
|
||||
<field name="name">Went Well</field>
|
||||
<field name="description">Whatever we developed or improved, it went well</field>
|
||||
</record>
|
||||
<record id="retrospective_method_2" model="retrospective.method">
|
||||
<field name="name">Needs Improvement</field>
|
||||
<field name="description">We have found some some tasks or ideas, which needs improvements</field>
|
||||
</record>
|
||||
<record id="retrospective_method_3" model="retrospective.method">
|
||||
<field name="name">Stop</field>
|
||||
<field name="description">Now Stop Working of worthless task and go through new ideas we found.</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
retrospective Demo Data
|
||||
-->
|
||||
<record id="retrospective_1" model="retrospective">
|
||||
<field name="name">Sprint Module Retrospective</field>
|
||||
<field name="retrospective_method_id" ref="project_scrum.retrospective_method_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
</record>
|
||||
|
||||
<record id="retrospective_2" model="retrospective">
|
||||
<field name="name">Scrum Documentation Retrospective</field>
|
||||
<field name="retrospective_method_id" ref="project_scrum.retrospective_method_2"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
</record>
|
||||
|
||||
<record id="retrospective_3" model="retrospective">
|
||||
<field name="name">Access Right Retrospective</field>
|
||||
<field name="retrospective_method_id" ref="project_scrum.retrospective_method_2"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_2"/>
|
||||
</record>
|
||||
|
||||
|
||||
<!--
|
||||
retrospective.lines Demo Data
|
||||
-->
|
||||
<record id="retrospective_line_1" model="retrospective.lines">
|
||||
<field name="message">Tasks have been done well.</field>
|
||||
<field name="retrospective_id" ref="project_scrum.retrospective_1"/>
|
||||
</record>
|
||||
|
||||
<record id="retrospective_line_2" model="retrospective.lines">
|
||||
<field name="message">Add new description as per new added modules.</field>
|
||||
<field name="retrospective_id" ref="project_scrum.retrospective_2"/>
|
||||
</record>
|
||||
|
||||
<record id="retrospective_line_3" model="retrospective.lines">
|
||||
<field name="message">Implement New Access Rights according to the new modules added</field>
|
||||
<field name="retrospective_id" ref="project_scrum.retrospective_3"/>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
8
addons/project_scrum/models/__init__.py
Executable file
@ -0,0 +1,8 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import project_sprint
|
||||
from . import project_story
|
||||
from . import project_team
|
||||
from . import release_planning
|
||||
from . import retrospective_method
|
||||
from . import retrospective
|
670
addons/project_scrum/models/project_sprint.py
Executable file
@ -0,0 +1,670 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra import models, fields, api, _
|
||||
from flectra.exceptions import ValidationError
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
class ProjectSprint(models.Model):
|
||||
_name = "project.sprint"
|
||||
_inherit = ['ir.branch.company.mixin', 'mail.thread']
|
||||
_description = "Sprint of the Project"
|
||||
_rec_name = 'sprint_seq'
|
||||
|
||||
sprint_seq = fields.Char(
|
||||
string="Reference", readonly=True)
|
||||
name = fields.Char("Sprint Name", required=True,
|
||||
track_visibility="onchange")
|
||||
goal_of_sprint = fields.Char("Goal of Sprint", track_visibility="onchange")
|
||||
|
||||
meeting_date = fields.Datetime("Planning Meeting Date", required=True,
|
||||
track_visibility="onchange")
|
||||
hour = fields.Float(string="Hour", track_visibility="onchange")
|
||||
time_zone = fields.Selection([
|
||||
('am', 'AM'),
|
||||
('pm', 'PM'),
|
||||
], track_visibility="onchange")
|
||||
estimated_velocity = fields.Integer(
|
||||
compute="calculate_estimated_velocity", string="Estimated Velocity",
|
||||
store=True, track_visibility="onchange")
|
||||
actual_velocity = fields.Integer(
|
||||
compute="calculate_actual_velocity", string="Actual Velocity",
|
||||
store=True, track_visibility="onchange")
|
||||
sprint_planning_line = fields.One2many(
|
||||
'sprint.planning.line', 'sprint_id', string="Sprint Planning Lines")
|
||||
project_id = fields.Many2one('project.project', string="Project",
|
||||
track_visibility="onchange")
|
||||
start_date = fields.Date(string="Start Date", track_visibility="onchange")
|
||||
end_date = fields.Date(string="End Date", track_visibility="onchange")
|
||||
working_days = fields.Integer(
|
||||
compute="calculate_business_days", string="Business Days",
|
||||
store=True, track_visibility="onchange")
|
||||
productivity_hours = fields.Float(string="Productivity Hours",
|
||||
track_visibility="onchange")
|
||||
productivity_per = fields.Float(
|
||||
compute="calculate_productivity_per", string="Productivity (%)",
|
||||
store=True, track_visibility="onchange")
|
||||
holiday_type = fields.Selection(
|
||||
[('hours', 'Hours'), ('days', 'Days')],
|
||||
string="Holiday (Hours / Days)", default='hours',
|
||||
track_visibility="onchange")
|
||||
holiday_count = fields.Float(string="Holiday Count",
|
||||
track_visibility="onchange")
|
||||
holiday_days = fields.Float(
|
||||
compute="calculate_holiday_days", string="Holiday Days", store=True,
|
||||
track_visibility="onchange")
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
('in_progress', 'In Progress'),
|
||||
('pending', 'Pending'),
|
||||
('done', 'Done'),
|
||||
('cancel', 'Cancel')], string="State", default='draft',
|
||||
track_visibility="onchange")
|
||||
team_id = fields.Many2one('project.team', string="Team",
|
||||
track_visibility="onchange", required=True)
|
||||
task_line = fields.One2many('project.task', 'sprint_id', string='Tasks')
|
||||
color = fields.Integer('Color Index')
|
||||
|
||||
@api.depends('start_date', 'end_date')
|
||||
def days_calculate(self):
|
||||
if self.start_date and self.end_date:
|
||||
diff = datetime.strptime(
|
||||
self.end_date, '%Y-%m-%d').date() - datetime.strptime(
|
||||
self.start_date, '%Y-%m-%d').date()
|
||||
self.duration = diff.days
|
||||
|
||||
duration = fields.Integer(
|
||||
"Duration (In Days)", compute='days_calculate', store=True,
|
||||
track_visibility="onchange")
|
||||
|
||||
@api.multi
|
||||
def _get_task_count(self):
|
||||
for record in self:
|
||||
record.number_of_tasks = record.env['project.task'].search_count([
|
||||
('sprint_id', '=', record.id)])
|
||||
|
||||
number_of_tasks = fields.Integer(
|
||||
string="# of tasks", compute="_get_task_count")
|
||||
|
||||
@api.multi
|
||||
def _get_story_count(self):
|
||||
for record in self:
|
||||
count = record.env['project.story'].search_count([
|
||||
('sprint_id', '=', record.id)])
|
||||
record.number_of_stories = count
|
||||
|
||||
number_of_stories = fields.Integer(
|
||||
string="# of stories", compute="_get_story_count")
|
||||
|
||||
@api.multi
|
||||
def _get_retrospective_count(self):
|
||||
for record in self:
|
||||
count = record.env['retrospective'].search_count([
|
||||
('sprint_id', '=', record.id)])
|
||||
record.number_of_retrospectives = count
|
||||
|
||||
number_of_retrospectives = fields.Integer(
|
||||
string="# of Retrospectives", compute="_get_retrospective_count")
|
||||
|
||||
@api.multi
|
||||
@api.depends('task_line', 'task_line.stage_id', 'task_line.sprint_id',
|
||||
'estimated_velocity', 'start_date', 'end_date', 'project_id',
|
||||
'team_id')
|
||||
def calculate_tasks_json(self):
|
||||
data = []
|
||||
for record in self:
|
||||
task_ids = self.env['project.task'].search([
|
||||
('sprint_id', '=', record.id)])
|
||||
velocity = record.estimated_velocity or 1.0
|
||||
for task in task_ids:
|
||||
data.append({
|
||||
'task': task.task_seq or '/',
|
||||
'velocity': task.velocity or 0,
|
||||
'per': round(((float(task.velocity) * 100) / float(
|
||||
velocity)), 2)
|
||||
})
|
||||
record.tasks_json = data
|
||||
|
||||
tasks_json = fields.Char(
|
||||
string="Tasks", compute="calculate_tasks_json", store=True)
|
||||
|
||||
@api.multi
|
||||
def get_data(self):
|
||||
task_dict_list = []
|
||||
for record in self:
|
||||
task_pool = self.env['project.task'].search([
|
||||
('sprint_id', '=', record.id)])
|
||||
for task in task_pool:
|
||||
task_dict = {
|
||||
'reference': task.task_seq,
|
||||
'name': task.name,
|
||||
'velocity': task.velocity,
|
||||
'start_date': task.start_date,
|
||||
'end_date': task.end_date,
|
||||
'actual_end_date': task.actual_end_date,
|
||||
'assigned_to': task.user_id.name,
|
||||
'state': task.stage_id.name,
|
||||
}
|
||||
task_dict_list.append(task_dict)
|
||||
return task_dict_list
|
||||
|
||||
@api.multi
|
||||
def set_state_open(self):
|
||||
self.state = 'in_progress'
|
||||
|
||||
@api.multi
|
||||
def set_state_cancel(self):
|
||||
self.state = 'cancel'
|
||||
|
||||
@api.multi
|
||||
def set_state_pending(self):
|
||||
self.state = 'pending'
|
||||
|
||||
@api.multi
|
||||
def redirect_to_view(self, model, caption):
|
||||
return {
|
||||
'name': (_(caption)),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': model,
|
||||
'domain': [('sprint_id', '=', self.id)],
|
||||
'context': {
|
||||
'default_sprint_id': self.id,
|
||||
'default_project_id': self.project_id.id
|
||||
}
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def action_view_tasks(self):
|
||||
return self.redirect_to_view("project.task", "Tasks")
|
||||
|
||||
@api.multi
|
||||
def action_view_stories(self):
|
||||
return self.redirect_to_view("project.story", "Stories")
|
||||
|
||||
@api.multi
|
||||
def action_view_release_planning(self):
|
||||
return self.redirect_to_view("release.planning", "Release Planning")
|
||||
|
||||
@api.multi
|
||||
def action_view_retrospective(self):
|
||||
return self.redirect_to_view("retrospective", "Retrospective")
|
||||
|
||||
@api.constrains('start_date', 'end_date')
|
||||
def check_dates(self):
|
||||
if self.start_date and self.end_date and (
|
||||
self.start_date > self.end_date):
|
||||
raise ValidationError(
|
||||
"Start Date can not be greater than End date, Dude!")
|
||||
|
||||
@api.onchange('holiday_type')
|
||||
def onchange_holiday_type(self):
|
||||
self.holiday_count = 0.0
|
||||
self.holiday_days = 0.0
|
||||
|
||||
@api.multi
|
||||
@api.depends('project_id', 'project_id.no_of_days', 'start_date',
|
||||
'end_date')
|
||||
def calculate_business_days(self):
|
||||
for record in self:
|
||||
if record.start_date and record.end_date:
|
||||
days_dict = {
|
||||
0: (1, 2, 3, 4, 5, 6, 7),
|
||||
1: (2, 3, 4, 5, 6, 7),
|
||||
2: (3, 4, 5, 6, 7),
|
||||
3: (4, 5, 6, 7),
|
||||
4: (5, 6, 7),
|
||||
5: (6, 7),
|
||||
6: (7,),
|
||||
7: (),
|
||||
}
|
||||
start = datetime.strptime(record.start_date, "%Y-%m-%d").date()
|
||||
end = datetime.strptime(record.end_date, "%Y-%m-%d").date()
|
||||
delta = timedelta(days=1)
|
||||
days = 0
|
||||
|
||||
if record.project_id and end > start:
|
||||
working_days = record.project_id.no_of_days
|
||||
non_working_days = days_dict[working_days]
|
||||
|
||||
while end != start:
|
||||
end -= delta
|
||||
if end.isoweekday() not in non_working_days:
|
||||
days += 1
|
||||
|
||||
record.working_days = days
|
||||
|
||||
@api.multi
|
||||
@api.depends('project_id', 'project_id.no_of_hours', 'productivity_hours')
|
||||
def calculate_productivity_per(self):
|
||||
for record in self:
|
||||
project_id = record.project_id
|
||||
no_of_hours = project_id.no_of_hours if project_id else 0
|
||||
prod_hours = record.productivity_hours
|
||||
if project_id and no_of_hours > 0 and prod_hours:
|
||||
record.productivity_per = (prod_hours / no_of_hours) * 100
|
||||
|
||||
@api.multi
|
||||
@api.depends('project_id', 'project_id.no_of_hours', 'holiday_count')
|
||||
def calculate_holiday_days(self):
|
||||
for record in self:
|
||||
if record.holiday_type == 'days' and record.project_id:
|
||||
hours = record.holiday_count * record.project_id.no_of_hours
|
||||
record.holiday_days = hours
|
||||
|
||||
@api.multi
|
||||
@api.depends('project_id', 'task_line', 'task_line.velocity')
|
||||
def calculate_estimated_velocity(self):
|
||||
for record in self:
|
||||
task_ids = record.env['project.task'].search([
|
||||
('sprint_id', '=', record.id)
|
||||
])
|
||||
total_velocity = sum([
|
||||
task.velocity for task in task_ids if task.velocity])
|
||||
record.estimated_velocity = total_velocity
|
||||
|
||||
@api.multi
|
||||
@api.depends('project_id', 'end_date', 'task_line', 'task_line.velocity',
|
||||
'task_line.stage_id')
|
||||
def calculate_actual_velocity(self):
|
||||
for record in self:
|
||||
task_ids = record.env['project.task'].search([
|
||||
('sprint_id', '=', record.id),
|
||||
('actual_end_date', '<=', record.end_date),
|
||||
])
|
||||
total_velocity = sum([
|
||||
task.velocity for task in task_ids if task.velocity])
|
||||
record.actual_velocity = total_velocity
|
||||
|
||||
@api.onchange('duration')
|
||||
def onchange_start_date(self):
|
||||
if self.start_date:
|
||||
end_date = datetime.strptime(
|
||||
self.start_date, '%Y-%m-%d') + timedelta(days=self.duration)
|
||||
self.end_date = end_date
|
||||
|
||||
@api.onchange('project_id')
|
||||
def onchange_project(self):
|
||||
if self.project_id and self.project_id.branch_id:
|
||||
self.branch_id = self.project_id.branch_id
|
||||
|
||||
@api.multi
|
||||
def check_sprint_state(self):
|
||||
next_call = datetime.today()
|
||||
for record in self.search([('state', '!=', 'done')]):
|
||||
if record.end_date:
|
||||
end_date = datetime.strptime(
|
||||
record.end_date, '%Y-%m-%d').date()
|
||||
if end_date < next_call:
|
||||
record.state = 'done'
|
||||
|
||||
@api.constrains('sprint_planning_line')
|
||||
def check_users_in_planning_line(self):
|
||||
user_list = []
|
||||
for user in self.sprint_planning_line:
|
||||
if user.user_id.id not in user_list:
|
||||
user_list.append(user.user_id.id)
|
||||
else:
|
||||
raise ValidationError(
|
||||
"You can't add the same user twice in Sprint Planning!")
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
vals['sprint_seq'] = self.env[
|
||||
'ir.sequence'].next_by_code('project.sprint')
|
||||
|
||||
res = super(ProjectSprint, self).create(vals)
|
||||
partner_list = []
|
||||
|
||||
mail_channel_id = self.env['mail.channel'].sudo().search([
|
||||
('name', '=', 'Project Sprint')
|
||||
])
|
||||
if mail_channel_id:
|
||||
mail_channel_ids = self.env['mail.followers'].sudo().search([
|
||||
('channel_id', '=', mail_channel_id.id),
|
||||
('res_model', '=', res._name),
|
||||
('res_id', '=', res.id),
|
||||
])
|
||||
if not mail_channel_ids:
|
||||
self.env['mail.followers'].sudo().create({
|
||||
'channel_id': mail_channel_id.id,
|
||||
'res_model': res._name,
|
||||
'res_id': res.id,
|
||||
})
|
||||
|
||||
if 'team_id' in vals:
|
||||
team_id = self.env['project.team'].browse(vals['team_id'])
|
||||
partner_list += [member.partner_id.id
|
||||
for member in team_id.member_ids]
|
||||
|
||||
for follower in partner_list:
|
||||
if follower:
|
||||
mail_follower_ids = self.env['mail.followers'].sudo().search([
|
||||
('res_id', '=', res.id),
|
||||
('partner_id', '=', follower),
|
||||
('res_model', '=', res._name),
|
||||
])
|
||||
if not mail_follower_ids:
|
||||
self.env['mail.followers'].sudo().create({
|
||||
'res_id': res.id,
|
||||
'res_model': res._name,
|
||||
'partner_id': follower,
|
||||
'team_id': team_id.id,
|
||||
})
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
res = super(ProjectSprint, self).write(vals)
|
||||
|
||||
if 'team_id' in vals:
|
||||
team_id = self.env['project.team'].browse(vals['team_id'])
|
||||
else:
|
||||
team_id = self.team_id
|
||||
|
||||
delete_team_id = self.env['mail.followers'].sudo().search([
|
||||
('team_id', '!=', team_id.id),
|
||||
('res_id', '=', self.id),
|
||||
])
|
||||
delete_team_id.unlink()
|
||||
|
||||
partner_list = [member.partner_id.id for member in team_id.member_ids]
|
||||
for follower in partner_list:
|
||||
if follower:
|
||||
mail_follower_ids = self.env['mail.followers'].sudo().search([
|
||||
('res_id', '=', self.id),
|
||||
('partner_id', '=', follower),
|
||||
('res_model', '=', self._name),
|
||||
])
|
||||
if not mail_follower_ids:
|
||||
self.env['mail.followers'].sudo().create({
|
||||
'res_id': self.id,
|
||||
'res_model': self._name,
|
||||
'partner_id': follower,
|
||||
'team_id': team_id.id,
|
||||
})
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def _track_subtype(self, init_values):
|
||||
self.ensure_one()
|
||||
if 'state' in init_values and self.state == 'draft':
|
||||
return 'project_scrum.state_sprint_draft'
|
||||
elif 'state' in init_values and self.state == 'in_progress':
|
||||
return 'project_scrum.state_sprint_in_progress'
|
||||
elif 'state' in init_values and self.state == 'pending':
|
||||
return 'project_scrum.state_sprint_pending'
|
||||
elif 'state' in init_values and self.state == 'done':
|
||||
return 'project_scrum.state_sprint_done'
|
||||
elif 'state' in init_values and self.state == 'cancel':
|
||||
return 'project_scrum.state_sprint_cancel'
|
||||
return super(ProjectSprint, self)._track_subtype(init_values)
|
||||
|
||||
|
||||
class Project(models.Model):
|
||||
_inherit = "project.project"
|
||||
|
||||
@api.multi
|
||||
def _sprint_count(self):
|
||||
for project in self:
|
||||
count = project.env['project.sprint'].search_count([
|
||||
('project_id', '=', project.id)
|
||||
])
|
||||
project.sprint_count = count
|
||||
|
||||
sprint_count = fields.Integer(
|
||||
compute="_sprint_count", string="No. of sprints related to")
|
||||
|
||||
@api.multi
|
||||
def show_sprints(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'name': ("Sprints"),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'project.sprint',
|
||||
'domain': [('project_id', '=', self.id)]
|
||||
}
|
||||
|
||||
no_of_hours = fields.Integer(
|
||||
related="resource_calendar_id.no_of_hours",
|
||||
string="Working Hour(s) per Day", store=True)
|
||||
no_of_days = fields.Integer(
|
||||
related="resource_calendar_id.no_of_days",
|
||||
string="Working Day(s) per Week", store=True)
|
||||
task_type_ids = fields.Many2many(
|
||||
'project.task.type', 'project_task_type_rel', 'project_id', 'type_id',
|
||||
string='Project(s)')
|
||||
|
||||
|
||||
class SprintPlanningLine(models.Model):
|
||||
_name = "sprint.planning.line"
|
||||
|
||||
@api.multi
|
||||
@api.depends('available_per', 'sprint_id.project_id',
|
||||
'sprint_id.project_id.no_of_hours',
|
||||
'sprint_id', 'sprint_id.working_days')
|
||||
def calculate_hours(self):
|
||||
for record in self:
|
||||
project_id = record.sprint_id.project_id
|
||||
no_of_hours = project_id and project_id.no_of_hours or 0.0
|
||||
calc = (
|
||||
record.available_per *
|
||||
record.sprint_id.working_days * no_of_hours) / 100
|
||||
record.productivity_hours = float(calc)
|
||||
|
||||
@api.multi
|
||||
@api.depends('sprint_id', 'available_per', 'sprint_id.working_days',
|
||||
'sprint_id.productivity_hours')
|
||||
def calculate_sprint_hours(self):
|
||||
for record in self:
|
||||
hours = (record.available_per * record.sprint_id.working_days *
|
||||
record.sprint_id.productivity_hours) / 100
|
||||
record.sprint_hours = hours
|
||||
|
||||
@api.multi
|
||||
@api.depends('sprint_id', 'sprint_id.holiday_count',
|
||||
'sprint_id.holiday_days', 'sprint_hours', 'off_hours')
|
||||
def calculate_total_hours(self):
|
||||
for record in self:
|
||||
if record.sprint_id.holiday_type == 'hours':
|
||||
hours = (
|
||||
record.sprint_hours - record.sprint_id.holiday_count -
|
||||
record.off_hours)
|
||||
else:
|
||||
hours = (
|
||||
record.sprint_hours - record.sprint_id.holiday_days -
|
||||
record.off_hours)
|
||||
record.total_hours = hours
|
||||
|
||||
sprint_id = fields.Many2one('project.sprint', string="Sprint")
|
||||
user_id = fields.Many2one('res.users', string="User")
|
||||
role_id = fields.Many2one(
|
||||
related="user_id.role_id", string="Role", store=True)
|
||||
available_per = fields.Integer(string="Available (%)")
|
||||
productivity_hours = fields.Float(
|
||||
compute="calculate_hours", string="Productivity Hour(s)", store=True)
|
||||
sprint_hours = fields.Float(
|
||||
compute="calculate_sprint_hours", string="Sprint Hour(s)", store=True)
|
||||
off_hours = fields.Float(string="Off Hour(s)")
|
||||
total_hours = fields.Float(
|
||||
compute="calculate_total_hours", string="Total Hour(s)", store=True)
|
||||
|
||||
|
||||
class UserRole(models.Model):
|
||||
_name = "user.role"
|
||||
|
||||
name = fields.Char(string="Role")
|
||||
code = fields.Char(string="Code")
|
||||
|
||||
|
||||
class ResUsers(models.Model):
|
||||
_inherit = "res.users"
|
||||
|
||||
role_id = fields.Many2one("user.role", string="User Role")
|
||||
|
||||
|
||||
class ProjectTask(models.Model):
|
||||
_inherit = "project.task"
|
||||
|
||||
sprint_id = fields.Many2one(
|
||||
'project.sprint', string="Sprint", track_visibility="onchange")
|
||||
velocity = fields.Integer(string="Velocity", track_visibility="onchange")
|
||||
story_id = fields.Many2one(
|
||||
'project.story', string="Story", track_visibility="onchange")
|
||||
release_planning_id = fields.Many2one(
|
||||
"release.planning", string="Release Planning",
|
||||
track_visibility="onchange")
|
||||
|
||||
@api.onchange('story_id')
|
||||
def onchange_story(self):
|
||||
if self.story_id:
|
||||
self.description = self.story_id.description
|
||||
|
||||
@api.constrains('start_date', 'end_date')
|
||||
def check_dates(self):
|
||||
if self.sprint_id:
|
||||
start_date = self.sprint_id.start_date
|
||||
end_date = self.sprint_id.end_date
|
||||
|
||||
if self.start_date and start_date and (
|
||||
self.start_date < start_date):
|
||||
raise ValidationError(
|
||||
"Start date is not valid according to the Sprint.")
|
||||
|
||||
if self.end_date and end_date and (self.end_date > end_date):
|
||||
raise ValidationError(
|
||||
"End date is not valid according to the Sprint.")
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
res = super(ProjectTask, self).create(vals)
|
||||
|
||||
partner_list = [
|
||||
member.partner_id.id
|
||||
for member in res.sprint_id.team_id.member_ids
|
||||
]
|
||||
|
||||
for follower in partner_list:
|
||||
if follower:
|
||||
mail_follower_ids = self.env['mail.followers'].sudo().search([
|
||||
('res_id', '=', res.id),
|
||||
('partner_id', '=', follower),
|
||||
('res_model', '=', self._name),
|
||||
])
|
||||
if not mail_follower_ids:
|
||||
self.env['mail.followers'].sudo().create({
|
||||
'res_id': res.id,
|
||||
'res_model': self._name,
|
||||
'partner_id': follower,
|
||||
'team_id': res.sprint_id.team_id.id,
|
||||
})
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
if self.task_seq == '/':
|
||||
vals['task_seq'] = self.env['ir.sequence'].next_by_code(
|
||||
'project.task')
|
||||
res = super(ProjectTask, self).write(vals)
|
||||
|
||||
data = []
|
||||
for record in self:
|
||||
task_ids = self.search([
|
||||
('sprint_id', '=', record.sprint_id.id)])
|
||||
for task in task_ids:
|
||||
data.append({
|
||||
'task': task.task_seq or '/',
|
||||
'velocity': task.velocity or 0,
|
||||
'per': round(((float(task.velocity) * 100) / float(
|
||||
record.sprint_id.estimated_velocity)), 2)
|
||||
if record.sprint_id.estimated_velocity > 0 else 0
|
||||
})
|
||||
|
||||
record.sprint_id.write({'tasks_json': data})
|
||||
|
||||
if 'sprint_id' in vals:
|
||||
sprint_id = self.env['project.sprint'].browse(vals['sprint_id'])
|
||||
team_id = sprint_id.team_id
|
||||
else:
|
||||
team_id = self.sprint_id.team_id
|
||||
|
||||
delete_team_id = self.env['mail.followers'].sudo().search([
|
||||
('team_id', '!=', team_id.id),
|
||||
('res_id', '=', self.id),
|
||||
])
|
||||
delete_team_id.unlink()
|
||||
|
||||
partner_list = [member.partner_id.id for member in team_id.member_ids]
|
||||
for follower in partner_list:
|
||||
if follower:
|
||||
mail_follower_ids = self.env['mail.followers'].sudo().search([
|
||||
('res_id', '=', self.id),
|
||||
('partner_id', '=', follower),
|
||||
('res_model', '=', self._name),
|
||||
])
|
||||
if not mail_follower_ids:
|
||||
self.env['mail.followers'].sudo().create({
|
||||
'res_id': self.id,
|
||||
'res_model': self._name,
|
||||
'partner_id': follower,
|
||||
'team_id': team_id.id,
|
||||
})
|
||||
return res
|
||||
|
||||
|
||||
class MailFollowers(models.Model):
|
||||
_inherit = "mail.followers"
|
||||
|
||||
team_id = fields.Many2one("project.team", string="Project Team")
|
||||
|
||||
|
||||
class ResourceCalendar(models.Model):
|
||||
_inherit = "resource.calendar"
|
||||
|
||||
no_of_hours = fields.Integer(string="No. of Hour(s) a Day", default=8)
|
||||
no_of_days = fields.Integer(string="No. of Day(s) a Week", default=5)
|
||||
|
||||
@api.multi
|
||||
@api.constrains('no_of_hours', 'no_of_days', 'attendance_ids')
|
||||
def _check_days_hours(self):
|
||||
week_days = {
|
||||
0: 'Monday',
|
||||
1: 'Tuesday',
|
||||
2: 'Wednesday',
|
||||
3: 'Thursday',
|
||||
4: 'Friday',
|
||||
5: 'Saturday',
|
||||
6: 'Sunday'
|
||||
}
|
||||
|
||||
for resource in self:
|
||||
res = {}
|
||||
current_hours = resource.no_of_hours
|
||||
current_days = resource.no_of_days
|
||||
|
||||
if current_days > 7 or current_days < 1:
|
||||
raise ValidationError(_(
|
||||
"No. of Days should be in between 1 - 7."))
|
||||
|
||||
for attendance in resource.attendance_ids:
|
||||
day = attendance.dayofweek
|
||||
diff = abs(attendance.hour_from - attendance.hour_to)
|
||||
if day not in res:
|
||||
res[day] = diff
|
||||
else:
|
||||
res[day] += diff
|
||||
|
||||
if current_days and len(res) > current_days:
|
||||
raise ValidationError(_(
|
||||
"You can not Add Working Hour(s) for more than %s\
|
||||
different days.") % current_days)
|
||||
|
||||
for day, hours in sorted(list(res.items())):
|
||||
if current_hours and hours > current_hours:
|
||||
raise ValidationError(_(
|
||||
"Invalid hours for %s!\n\nWorking hours per day should\
|
||||
not be greater than %s.") % (
|
||||
week_days[int(day)], current_hours))
|
161
addons/project_scrum/models/project_story.py
Executable file
@ -0,0 +1,161 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra import fields, models, api, _
|
||||
|
||||
|
||||
class ProjectStory(models.Model):
|
||||
_name = "project.story"
|
||||
_inherit = ['ir.branch.company.mixin', 'mail.thread']
|
||||
_description = "Project Story"
|
||||
|
||||
name = fields.Char("Title", required=True, track_visibility="onchange")
|
||||
priority_id = fields.Many2one('story.priority', string="Priority",
|
||||
track_visibility="onchange")
|
||||
story_type_id = fields.Many2one('story.type', string="Type",
|
||||
track_visibility="onchange")
|
||||
tags = fields.Char("Tags", track_visibility="onchange")
|
||||
description = fields.Text("Description", track_visibility="onchange")
|
||||
owner_id = fields.Many2one(
|
||||
'res.users', string="Owner", default=lambda self: self.env.user.id,
|
||||
track_visibility='onchange')
|
||||
sprint_id = fields.Many2one('project.sprint', string="Sprint",
|
||||
track_visibility="onchange")
|
||||
estimated_velocity = fields.Integer(
|
||||
compute="calculate_estimated_velocity", string="Estimated Velocity",
|
||||
store=True, track_visibility="onchange")
|
||||
actual_velocity = fields.Integer(
|
||||
compute="calculate_actual_velocity", string="Actual Velocity",
|
||||
store=True, track_visibility="onchange")
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
('in_progress', 'In Progress'),
|
||||
('cancel', 'Cancel'),
|
||||
('done', 'Done'),
|
||||
], string="states", track_visibility="onchange", default="draft")
|
||||
|
||||
@api.multi
|
||||
def set_state_active(self):
|
||||
self.state = "in_progress"
|
||||
|
||||
@api.multi
|
||||
def set_state_cancel(self):
|
||||
self.state = "cancel"
|
||||
|
||||
@api.multi
|
||||
def set_state_done(self):
|
||||
self.state = "done"
|
||||
|
||||
@api.multi
|
||||
def action_view_tasks(self):
|
||||
return {
|
||||
'name': (_('Tasks')),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'project.task',
|
||||
'domain': [('sprint_id', '=', self.sprint_id.id)],
|
||||
'context': {
|
||||
'default_sprint_id': self.sprint_id.id,
|
||||
'default_project_id': self.sprint_id.project_id.id,
|
||||
}
|
||||
}
|
||||
|
||||
@api.multi
|
||||
@api.depends('sprint_id')
|
||||
def calculate_estimated_velocity(self):
|
||||
for story in self:
|
||||
task_ids = story.env['project.task'].search([
|
||||
('sprint_id', '=', story.sprint_id.id)
|
||||
])
|
||||
total_velocity = sum([
|
||||
task.velocity for task in task_ids if task.velocity])
|
||||
story.estimated_velocity = total_velocity
|
||||
|
||||
@api.multi
|
||||
@api.depends('sprint_id', 'sprint_id.end_date')
|
||||
def calculate_actual_velocity(self):
|
||||
for story in self:
|
||||
task_ids = story.env['project.task'].search([
|
||||
('sprint_id', '=', story.sprint_id.id),
|
||||
('actual_end_date', '<=', story.sprint_id.end_date)
|
||||
])
|
||||
total_velocity = sum([
|
||||
task.velocity for task in task_ids if task.velocity])
|
||||
story.actual_velocity = total_velocity
|
||||
|
||||
@api.onchange('sprint_id')
|
||||
def onchange_project(self):
|
||||
if self.sprint_id and self.sprint_id.project_id.branch_id:
|
||||
self.branch_id = self.sprint_id.project_id.branch_id
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
res = super(ProjectStory, self).create(vals)
|
||||
|
||||
partner_list = [
|
||||
member.partner_id.id for member in res.sprint_id.team_id.member_ids
|
||||
]
|
||||
|
||||
for follower in partner_list:
|
||||
if follower:
|
||||
mail_followers_ids = self.env['mail.followers'].sudo().search([
|
||||
('res_id', '=', res.id),
|
||||
('partner_id', '=', follower),
|
||||
('res_model', '=', self._name),
|
||||
])
|
||||
|
||||
if not mail_followers_ids:
|
||||
self.env['mail.followers'].sudo().create({
|
||||
'res_id': res.id,
|
||||
'res_model': self._name,
|
||||
'partner_id': follower,
|
||||
'team_id': res.sprint_id.team_id.id,
|
||||
})
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
res = super(ProjectStory, self).write(vals)
|
||||
delete_team_id = self.env['mail.followers'].sudo().search([
|
||||
('team_id', '!=', self.sprint_id.team_id.id),
|
||||
('res_id', '=', self.id),
|
||||
])
|
||||
|
||||
delete_team_id.unlink()
|
||||
|
||||
partner_list = [
|
||||
member.partner_id.id for member in
|
||||
self.sprint_id.team_id.member_ids
|
||||
]
|
||||
|
||||
for follower in partner_list:
|
||||
if follower:
|
||||
mail_follower_ids = self.env['mail.followers'].sudo().search([
|
||||
('res_id', '=', self.id),
|
||||
('partner_id', '=', follower),
|
||||
('res_model', '=', self._name),
|
||||
])
|
||||
if not mail_follower_ids:
|
||||
self.env['mail.followers'].sudo().create({
|
||||
'res_id': self.id,
|
||||
'res_model': self._name,
|
||||
'partner_id': follower,
|
||||
'team_id': self.sprint_id.team_id.id,
|
||||
})
|
||||
return res
|
||||
|
||||
|
||||
class StoryPriority(models.Model):
|
||||
_name = "story.priority"
|
||||
_inherit = 'mail.thread'
|
||||
|
||||
name = fields.Char("Name", track_visibility="onchange")
|
||||
code = fields.Char("Code", track_visibility="onchange")
|
||||
|
||||
|
||||
class StoryType(models.Model):
|
||||
_name = "story.type"
|
||||
_inherit = 'mail.thread'
|
||||
|
||||
name = fields.Char("Name", track_visibility="onchange")
|
||||
code = fields.Char("Code", track_visibility="onchange")
|
23
addons/project_scrum/models/project_team.py
Executable file
@ -0,0 +1,23 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra import models, fields, api
|
||||
|
||||
|
||||
class ProjectTeam(models.Model):
|
||||
_name = "project.team"
|
||||
_inherit = ['ir.branch.company.mixin', 'mail.thread']
|
||||
_description = "Project Team"
|
||||
|
||||
name = fields.Char("Team Name", required=True, track_visibility="onchange")
|
||||
strength = fields.Text("Team Strength", track_visibility="onchange")
|
||||
member_ids = fields.Many2many("res.users", string="Members")
|
||||
master_id = fields.Many2one(
|
||||
"res.users", string="Scrum Master", track_visibility="onchange")
|
||||
description = fields.Html()
|
||||
project_id = fields.Many2one(
|
||||
'project.project', string="Project", track_visibility="onchange")
|
||||
|
||||
@api.onchange('project_id')
|
||||
def onchange_project(self):
|
||||
if self.project_id and self.project_id.branch_id:
|
||||
self.branch_id = self.project_id.branch_id
|
29
addons/project_scrum/models/release_planning.py
Executable file
@ -0,0 +1,29 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra import models, fields, api
|
||||
|
||||
|
||||
class ReleasePlanning(models.Model):
|
||||
_name = "release.planning"
|
||||
_inherit = ['ir.branch.company.mixin', 'mail.thread']
|
||||
|
||||
name = fields.Char(string="Planning Name", track_visibility="onchange")
|
||||
release_date = fields.Datetime(
|
||||
string="Release Date", track_visibility="onchange")
|
||||
sprint_id = fields.Many2one(
|
||||
'project.sprint', string="Sprint", track_visibility="onchange")
|
||||
priority = fields.Selection([
|
||||
('low', 'Low'),
|
||||
('medium', 'Medium'),
|
||||
('high', 'High')], string="Priority", default='low',
|
||||
track_visibility="onchange")
|
||||
velocity = fields.Integer(
|
||||
related="sprint_id.estimated_velocity", string="Sprint Velocity",
|
||||
track_visibility="onchange", store=True)
|
||||
task_id = fields.One2many(
|
||||
"project.task", "release_planning_id", string="Task", readonly=True)
|
||||
|
||||
@api.onchange('sprint_id')
|
||||
def onchange_project(self):
|
||||
if self.sprint_id and self.sprint_id.project_id.branch_id:
|
||||
self.branch_id = self.sprint_id.project_id.branch_id
|
42
addons/project_scrum/models/retrospective.py
Executable file
@ -0,0 +1,42 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra import models, fields, api
|
||||
|
||||
|
||||
class Retrospective(models.Model):
|
||||
_name = "retrospective"
|
||||
_inherit = ['ir.branch.company.mixin', 'mail.thread']
|
||||
|
||||
name = fields.Char(string="Retrospective Name", required=True,
|
||||
track_visibility='onchange')
|
||||
retrospective_method_id = fields.Many2one(
|
||||
"retrospective.method", string="Retrospective Method",
|
||||
track_visibility='onchange')
|
||||
scrum_master = fields.Many2one("res.users", string="Scrum Master",
|
||||
track_visibility='onchange')
|
||||
sprint_id = fields.Many2one(
|
||||
"project.sprint", string="Sprint", track_visibility='onchange')
|
||||
retrospective_line_ids = fields.One2many(
|
||||
"retrospective.lines", "retrospective_id",
|
||||
string="Retrospective Lines", track_visibility='onchange')
|
||||
start_date = fields.Datetime(string="Start Date")
|
||||
end_date = fields.Datetime(string="End Date")
|
||||
|
||||
@api.onchange('sprint_id')
|
||||
def on_sprint_id_change(self):
|
||||
self.scrum_master = self.sprint_id.team_id.master_id.id
|
||||
|
||||
@api.onchange('sprint_id')
|
||||
def onchange_project(self):
|
||||
if self.sprint_id and self.sprint_id.project_id.branch_id:
|
||||
self.branch_id = self.sprint_id.project_id.branch_id
|
||||
|
||||
|
||||
class RetrospectiveLines(models.Model):
|
||||
_name = "retrospective.lines"
|
||||
|
||||
user_id = fields.Many2one("res.users", string="User", readonly=True,
|
||||
required=True,
|
||||
default=lambda self: self.env.user)
|
||||
message = fields.Text(string="Message")
|
||||
retrospective_id = fields.Many2one("retrospective", string="Retrospective")
|
15
addons/project_scrum/models/retrospective_method.py
Executable file
@ -0,0 +1,15 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra import models, fields
|
||||
|
||||
|
||||
class RetrospectiveMethod(models.Model):
|
||||
_name = "retrospective.method"
|
||||
_inherit = ['ir.branch.company.mixin', 'mail.thread']
|
||||
_description = "Retrospective Implementation for Project Scrum"
|
||||
|
||||
name = fields.Char(
|
||||
string="Method Name", required=True, track_visibility='onchange')
|
||||
|
||||
description = fields.Text(
|
||||
string="Description", track_visibility='onchange')
|
21
addons/project_scrum/reports/project_scrum_report.xml
Executable file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data>
|
||||
<report
|
||||
id="release_planning_report"
|
||||
model="release.planning"
|
||||
string="Release Planning Report"
|
||||
report_type="qweb-pdf"
|
||||
name="project_scrum.release_planning_template_id"
|
||||
file="project_scrum.release_planning_template_id"
|
||||
/>
|
||||
<report
|
||||
id="project_sprint_report"
|
||||
model="project.sprint"
|
||||
string="Project Sprint Report"
|
||||
report_type="qweb-pdf"
|
||||
name="project_scrum.project_sprint_template_id"
|
||||
file="project_scrum.project_sprint_template_id"
|
||||
/>
|
||||
</data>
|
||||
</flectra>
|
134
addons/project_scrum/reports/project_sprint_template.xml
Executable file
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data>
|
||||
<template id="project_sprint_template_id">
|
||||
<t t-call="web.html_container">
|
||||
<t t-call="web.external_layout">
|
||||
<div class="page" t-foreach="docs" t-as="object" style="page-break-after: always;">
|
||||
<div class="oe_structure"/>
|
||||
<div class="row">
|
||||
<div class="col-xs-6 mt16">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Project Name</th>
|
||||
<td>
|
||||
<span t-field="object.project_id"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Sprint Name</th>
|
||||
<td>
|
||||
<span t-field="object.name"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Team Name</th>
|
||||
<td>
|
||||
<span t-field="object.team_id"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Scrum Master</th>
|
||||
<td>
|
||||
<span t-field="object.team_id.master_id"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Start Date</th>
|
||||
<td>
|
||||
<span t-field="object.start_date"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>End Date</th>
|
||||
<td>
|
||||
<span t-field="object.end_date"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Estimated Velocity</th>
|
||||
<td>
|
||||
<span t-field="object.estimated_velocity"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Actual Velocity</th>
|
||||
<td>
|
||||
<span t-field="object.actual_velocity"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-xs-6 mt16">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th colspan="3">Team Member(s)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Email</th>
|
||||
<th>Role</th>
|
||||
</tr>
|
||||
<tr t-foreach="object.team_id.member_ids" t-as="member">
|
||||
<td>
|
||||
<span t-field="member.name"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="member.login"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="member.role_id"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="text-center">Task Details</h3>
|
||||
<div>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Task Seq.</th>
|
||||
<th>Task Name</th>
|
||||
<th>Velocity</th>
|
||||
<th>Start Date</th>
|
||||
<th>End Date</th>
|
||||
<th>Actual End Date</th>
|
||||
<th>Assigned to</th>
|
||||
<th>State</th>
|
||||
</tr>
|
||||
<tr t-foreach="object.get_data()" t-as="data">
|
||||
<td>
|
||||
<span t-esc="data['reference']"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-esc="data['name']"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-esc="data['velocity']"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-esc="data['start_date']"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-esc="data['end_date']"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-esc="data['actual_end_date']"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-esc="data['assigned_to']"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-esc="data['state']"/>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="oe_structure"/>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
</data>
|
||||
</flectra>
|
100
addons/project_scrum/reports/release_planning_template.xml
Executable file
@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data>
|
||||
<template id="release_planning_template_id">
|
||||
<t t-call="web.external_layout">
|
||||
<div class="page" style="page-break-after: always;" t-foreach="docs" t-as="object">
|
||||
<div class="oe_structure">
|
||||
<div class="col-xs-12 mt16">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>
|
||||
<b>Planning Name</b>
|
||||
</th>
|
||||
<th>
|
||||
<b>Sprint</b>
|
||||
</th>
|
||||
<th>
|
||||
<b>Priority</b>
|
||||
</th>
|
||||
<th>
|
||||
<b>Release Date</b>
|
||||
</th>
|
||||
<th>
|
||||
<b>Velocity</b>
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<span t-field="object.name"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="object.sprint_id"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="object.priority"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="object.release_date"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="object.velocity"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h3 class="text-center">Task Details</h3>
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Task Title</th>
|
||||
<th>Project</th>
|
||||
<th>Assigned To</th>
|
||||
<th>Sprint</th>
|
||||
<th>Branch</th>
|
||||
<th>Start Date</th>
|
||||
<th>End Date</th>
|
||||
<th>Actual End Date</th>
|
||||
<th>Velocity</th>
|
||||
<th>Stage</th>
|
||||
|
||||
</tr>
|
||||
<tr t-foreach="object.task_id" t-as="task">
|
||||
<td>
|
||||
<span t-field="task.name"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="task.project_id"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="task.user_id"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="task.sprint_id"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="task.branch_id"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="task.start_date"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="task.end_date"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="task.actual_end_date"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="task.velocity"/>
|
||||
</td>
|
||||
<td>
|
||||
<span t-field="task.stage_id"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
</data>
|
||||
</flectra>
|
36
addons/project_scrum/security/ir.model.access.csv
Executable file
@ -0,0 +1,36 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_project_sprint_user,access_project_sprint_user,model_project_sprint,project.group_project_user,1,1,0,0
|
||||
access_project_sprint_manager,access_project_sprint_manager,model_project_sprint,project.group_project_manager,1,1,1,1
|
||||
,,,,,,,
|
||||
access_project_story_user,access_project_story_user,model_project_story,project.group_project_user,1,1,0,0
|
||||
access_project_story_manager,access_project_story_manager,model_project_story,project.group_project_manager,1,1,1,1
|
||||
,,,,,,,
|
||||
access_project_team_user,access_project_team_user,model_project_team,project.group_project_user,1,1,0,0
|
||||
access_project_team_manager,access_project_team_manager,model_project_team,project.group_project_manager,1,1,1,1
|
||||
,,,,,,,
|
||||
access_role_user,access_role_user,model_user_role,project.group_project_user,1,0,0,0
|
||||
access_role_manager,access_role_manager,model_user_role,project.group_project_manager,1,1,1,1
|
||||
,,,,,,,
|
||||
access_sprint_planning_line_user,access_sprint_planning_line_user,model_sprint_planning_line,project.group_project_user,1,0,0,0
|
||||
access_sprint_planning_line_manager,access_sprint_planning_line_manager,model_sprint_planning_line,project.group_project_manager,1,1,1,1
|
||||
,,,,,,,
|
||||
access_story_priority_user,access_story_priority_user,model_story_priority,project.group_project_user,1,0,0,0
|
||||
access_story_priority_manager,access_story_priority_manager,model_story_priority,project.group_project_manager,1,1,1,1
|
||||
,,,,,,,
|
||||
access_story_type_user,access_story_priority_user,model_story_type,project.group_project_user,1,0,0,0
|
||||
access_story_type_manager,access_story_priority_manager,model_story_type,project.group_project_manager,1,1,1,1
|
||||
,,,,,,,
|
||||
access_release_planning_user,access_release_planning_user,model_release_planning,project.group_project_user,1,0,0,0
|
||||
access_release_planning_manager,access_release_planning_manager,model_release_planning,project.group_project_manager,1,1,1,1
|
||||
,,,,,,,
|
||||
access_retrospective_user,access_retrospective_user,model_retrospective,project.group_project_user,1,1,0,0
|
||||
access_retrospective_manager,access_retrospective_manager,model_retrospective,project.group_project_manager,1,1,1,1
|
||||
,,,,,,,
|
||||
access_retrospective_method_user,access_retrospective_method_user,model_retrospective_method,project.group_project_user,1,0,0,0
|
||||
access_retrospective_method_manager,access_retrospective_method_manager,model_retrospective_method,project.group_project_manager,1,1,1,1
|
||||
,,,,,,,
|
||||
access_retrospective_lines_user,access_retrospective_lines_user,model_retrospective_lines,project.group_project_user,1,1,1,1
|
||||
access_retrospective_lines_manager,access_retrospective_lines_manager,model_retrospective_lines,project.group_project_manager,1,1,1,1
|
||||
,,,,,,,
|
||||
access_project_team_manager_res_users,access_project_team_manager_res_users,base.model_res_users,project.group_project_manager,1,1,0,0
|
||||
access_project_team_user_res_users,access_project_team_user_res_users,base.model_res_users,project.group_project_user,1,1,0,0
|
|
13
addons/project_scrum/security/scrum_security.xml
Executable file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data noupdate="1">
|
||||
<record id="rule_project_sprint" model="ir.rule">
|
||||
<field name="name">Sprint: multi-company & branch</field>
|
||||
<field name="model_id" ref="project_scrum.model_project_sprint"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|','|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id]), ('company_id', 'in', user.company_ids.ids), '|', '|', ('branch_id', '=', False),
|
||||
('branch_id', '=', user.default_branch_id.id), ('branch_id', 'in', user.branch_ids.ids)]
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
BIN
addons/project_scrum/static/description/dashboard.png
Normal file
After Width: | Height: | Size: 92 KiB |
BIN
addons/project_scrum/static/description/icon.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
105
addons/project_scrum/static/description/index.html
Normal file
@ -0,0 +1,105 @@
|
||||
<section class="container">
|
||||
<div class="row oe_spaced">
|
||||
<div class="col-md-12">
|
||||
<h2 class="oe_slogan">Project Scrum</h2>
|
||||
<h3 class="oe_slogan">Attractive Dashboard</h3>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<img class="oe_screenshot" src="dashboard.png" width="350" height="350"
|
||||
alt="This should be the picture of Dashboard"/>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p class="oe_mt16 text-justify" style="font-size: 15px;">
|
||||
You can see the burndown chart of sprint as well as tasks
|
||||
related to particular sprint. User can also use smart buttons for
|
||||
traversing Projects, Sprints, Tasks and Stories</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="container">
|
||||
<div class="row oe_spaced">
|
||||
<div class="col-md-12">
|
||||
<h3 class="oe_slogan">Sprint</h3>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p class="oe_mt16 text-justify" style="font-size: 15px;">A scrum sprint is a regular, repeatable work cycle in scrum
|
||||
methodology during which work is completed and made ready for review. Scrum sprints are
|
||||
basic units of development in the scrum methodology. Generally sprints are 1-2 week(s) long...</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="oe_demo oe_picture oe_screenshot ml16">
|
||||
<img src="sprint.png" width="110%" height="300" alt="Sprint"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="container">
|
||||
<div class="row oe_spaced">
|
||||
<div class="col-md-12">
|
||||
<h3 class="oe_slogan">Release Planning</h3>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="oe_demo oe_picture oe_screenshot ml16">
|
||||
<img src="release_planning.png" alt="Release Planning"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p class="oe_mt16 text-justify" style="font-size: 15px;">
|
||||
A very high-level plan for multiple Sprints (e.g. three to twelve iteration) is created during the Release planning. It is a guideline that reflects expectations about which features will be implemented and when they are completed. It also serves as a base to monitor progress within the project.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="container">
|
||||
<div class="row oe_spaced">
|
||||
<div class="col-md-12">
|
||||
<h3 class="oe_slogan">Story</h3>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p class="oe_mt16 text-justify" style="font-size: 15px;">
|
||||
User Stories are managed in the Product Backlog. The User Stories are ordered according to priority. The most prioritized user stories are refined to granular level, while the least priority user stories are kept at a lesser detail level. For every sprint, the most prioritized and hence more granulated user stories are taken into the sprint backlog. If a user story is to be added to the product backlog, its priority is first determined, and it is placed according to its place as per the priority.
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="oe_demo oe_picture oe_screenshot ml16">
|
||||
<img src="story.png" alt="Story"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="container">
|
||||
<div class="row oe_spaced">
|
||||
<div class="col-md-12">
|
||||
<h3 class="oe_slogan">Team</h3>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="oe_demo oe_picture oe_screenshot ml16">
|
||||
<img src="team.png" alt="Team"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
Within the Scrum Framework all work delivered to the customer is done by dedicated Scrum Teams. A Scrum Team is a collection of individuals working together to deliver the requested and committed product increments.
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="container">
|
||||
<div class="row oe_spaced">
|
||||
<div class="col-md-12">
|
||||
<h3 class="oe_slogan">Retrospective</h3>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
The sprint retrospective is a meeting facilitated by the ScrumMaster at which the team discusses the just-concluded sprint and determines what could be changed that might make the next sprint more productive. The sprint review looks at what the team is building, whereas the retrospective looks at how they are building it.
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="oe_demo oe_picture oe_screenshot ml16">
|
||||
<img src="retro.png" alt="Retrospective"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
BIN
addons/project_scrum/static/description/release_planning.png
Normal file
After Width: | Height: | Size: 63 KiB |
BIN
addons/project_scrum/static/description/retro.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
addons/project_scrum/static/description/retro_method.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
addons/project_scrum/static/description/sprint.png
Normal file
After Width: | Height: | Size: 108 KiB |
BIN
addons/project_scrum/static/description/story.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
addons/project_scrum/static/description/team.png
Normal file
After Width: | Height: | Size: 41 KiB |
117
addons/project_scrum/static/src/fonts/sourcesanspro/METADATA.pb
Executable file
@ -0,0 +1,117 @@
|
||||
name: "Source Sans Pro"
|
||||
designer: "Paul D. Hunt"
|
||||
license: "OFL"
|
||||
category: "SANS_SERIF"
|
||||
date_added: "2012-07-31"
|
||||
fonts {
|
||||
name: "Source Sans Pro"
|
||||
style: "normal"
|
||||
weight: 200
|
||||
filename: "SourceSansPro-ExtraLight.ttf"
|
||||
post_script_name: "SourceSansPro-ExtraLight"
|
||||
full_name: "Source Sans Pro ExtraLight"
|
||||
copyright: "Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."
|
||||
}
|
||||
fonts {
|
||||
name: "Source Sans Pro"
|
||||
style: "italic"
|
||||
weight: 200
|
||||
filename: "SourceSansPro-ExtraLightItalic.ttf"
|
||||
post_script_name: "SourceSansPro-ExtraLightIt"
|
||||
full_name: "Source Sans Pro ExtraLight Italic"
|
||||
copyright: "Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."
|
||||
}
|
||||
fonts {
|
||||
name: "Source Sans Pro"
|
||||
style: "normal"
|
||||
weight: 300
|
||||
filename: "SourceSansPro-Light.ttf"
|
||||
post_script_name: "SourceSansPro-Light"
|
||||
full_name: "Source Sans Pro Light"
|
||||
copyright: "Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."
|
||||
}
|
||||
fonts {
|
||||
name: "Source Sans Pro"
|
||||
style: "italic"
|
||||
weight: 300
|
||||
filename: "SourceSansPro-LightItalic.ttf"
|
||||
post_script_name: "SourceSansPro-LightIt"
|
||||
full_name: "Source Sans Pro Light Italic"
|
||||
copyright: "Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."
|
||||
}
|
||||
fonts {
|
||||
name: "Source Sans Pro"
|
||||
style: "normal"
|
||||
weight: 400
|
||||
filename: "SourceSansPro-Regular.ttf"
|
||||
post_script_name: "SourceSansPro-Regular"
|
||||
full_name: "Source Sans Pro"
|
||||
copyright: "Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."
|
||||
}
|
||||
fonts {
|
||||
name: "Source Sans Pro"
|
||||
style: "italic"
|
||||
weight: 400
|
||||
filename: "SourceSansPro-Italic.ttf"
|
||||
post_script_name: "SourceSansPro-It"
|
||||
full_name: "Source Sans Pro Italic"
|
||||
copyright: "Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."
|
||||
}
|
||||
fonts {
|
||||
name: "Source Sans Pro"
|
||||
style: "normal"
|
||||
weight: 600
|
||||
filename: "SourceSansPro-Semibold.ttf"
|
||||
post_script_name: "SourceSansPro-Semibold"
|
||||
full_name: "Source Sans Pro Semibold"
|
||||
copyright: "Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."
|
||||
}
|
||||
fonts {
|
||||
name: "Source Sans Pro"
|
||||
style: "italic"
|
||||
weight: 600
|
||||
filename: "SourceSansPro-SemiboldItalic.ttf"
|
||||
post_script_name: "SourceSansPro-SemiboldIt"
|
||||
full_name: "Source Sans Pro Semibold Italic"
|
||||
copyright: "Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."
|
||||
}
|
||||
fonts {
|
||||
name: "Source Sans Pro"
|
||||
style: "normal"
|
||||
weight: 700
|
||||
filename: "SourceSansPro-Bold.ttf"
|
||||
post_script_name: "SourceSansPro-Bold"
|
||||
full_name: "Source Sans Pro Bold"
|
||||
copyright: "Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."
|
||||
}
|
||||
fonts {
|
||||
name: "Source Sans Pro"
|
||||
style: "italic"
|
||||
weight: 700
|
||||
filename: "SourceSansPro-BoldItalic.ttf"
|
||||
post_script_name: "SourceSansPro-BoldIt"
|
||||
full_name: "Source Sans Pro Bold Italic"
|
||||
copyright: "Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."
|
||||
}
|
||||
fonts {
|
||||
name: "Source Sans Pro"
|
||||
style: "normal"
|
||||
weight: 900
|
||||
filename: "SourceSansPro-Black.ttf"
|
||||
post_script_name: "SourceSansPro-Black"
|
||||
full_name: "Source Sans Pro Black"
|
||||
copyright: "Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."
|
||||
}
|
||||
fonts {
|
||||
name: "Source Sans Pro"
|
||||
style: "italic"
|
||||
weight: 900
|
||||
filename: "SourceSansPro-BlackItalic.ttf"
|
||||
post_script_name: "SourceSansPro-BlackIt"
|
||||
full_name: "Source Sans Pro Black Italic"
|
||||
copyright: "Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries."
|
||||
}
|
||||
subsets: "menu"
|
||||
subsets: "latin"
|
||||
subsets: "latin-ext"
|
||||
subsets: "vietnamese"
|
BIN
addons/project_scrum/static/src/fonts/sourcesanspro/SourceSansPro-Regular.ttf
Executable file
3739
addons/project_scrum/static/src/js/Chart.js
vendored
Executable file
321
addons/project_scrum/static/src/js/scrum_dashboard.js
Executable file
@ -0,0 +1,321 @@
|
||||
flectra.define('project_scrum.dashboard', function(require) {
|
||||
"use strict";
|
||||
|
||||
var core = require('web.core');
|
||||
var field_utils = require('web.field_utils');
|
||||
var KanbanView = require('web.KanbanView');
|
||||
var KanbanModel = require('web.KanbanModel');
|
||||
var KanbanRenderer = require('web.KanbanRenderer');
|
||||
var KanbanController = require('web.KanbanController');
|
||||
var data = require('web.data');
|
||||
var view_registry = require('web.view_registry');
|
||||
var QWeb = core.qweb;
|
||||
|
||||
var _t = core._t;
|
||||
var _lt = core._lt;
|
||||
|
||||
var ScrumDashboardRenderer = KanbanRenderer.extend({
|
||||
events: _.extend({}, KanbanRenderer.prototype.events, {
|
||||
'click .total-sprints': 'on_sprints_click',
|
||||
'click .total-tasks': 'on_tasks_click',
|
||||
'click .total-stories': 'on_stories_click',
|
||||
'click .total-projects': 'on_projects_click',
|
||||
}),
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Notifies the controller that the target has changed.
|
||||
*
|
||||
* @private
|
||||
* @param {string} target_name the name of the changed target
|
||||
* @param {string} value the new value
|
||||
*/
|
||||
_notifyTargetChange: function (target_name, value) {
|
||||
this.trigger_up('dashboard_edit_target', {
|
||||
target_name: target_name,
|
||||
target_value: value,
|
||||
});
|
||||
},
|
||||
|
||||
fetch_data: function() {
|
||||
// Overwrite this function with useful data
|
||||
return $.when();
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
_render: function() {
|
||||
var super_render = this._super;
|
||||
var self = this;
|
||||
self._rpc({
|
||||
route: '/project_scrum/get_sprints_data',
|
||||
params: {},}).done(function
|
||||
(result) {
|
||||
if (result) {
|
||||
$('#total_projects').html("<h2>" + result.total_projects + "</h2>");
|
||||
$('#total_sprints').html("<h2>" + result.total_sprints + "</h2>");
|
||||
$('#total_stories').html("<h2>" + result.total_stories + "</h2>");
|
||||
$('#total_tasks').html("<h2>" + result.total_tasks + "</h2>");
|
||||
}
|
||||
});
|
||||
self.render_line_chart();
|
||||
return this.fetch_data().then(function(result) {
|
||||
var scrum_dashboard_view = QWeb.render('ScrumDashboard');
|
||||
super_render.call(self);
|
||||
$(scrum_dashboard_view).prependTo(self.$el);
|
||||
});
|
||||
},
|
||||
|
||||
load_sprint_burndown_chart: function(result) {
|
||||
var sprint_labels = [],
|
||||
sprint_velocities = [],
|
||||
sprint_rates = [];
|
||||
for (var key in result) {
|
||||
if (result[key]) {
|
||||
sprint_labels.push(result[key].sprint_seq);
|
||||
sprint_velocities.push(result[key].velocity);
|
||||
sprint_rates.push(result[key].per);
|
||||
}
|
||||
}
|
||||
try {
|
||||
var sprint_burndown_chart = $("#scrum_chart")[0].getContext("2d");
|
||||
sprint_burndown_chart.canvas.height = 55;
|
||||
|
||||
// This will get the first returned node in the jQuery collection.
|
||||
var sprint_chart = new Chart(sprint_burndown_chart);
|
||||
|
||||
var sprint_chart_data = {
|
||||
labels: sprint_labels,
|
||||
datasets: [{
|
||||
label: "Success (%)",
|
||||
fillColor: "rgb(243, 156, 18)",
|
||||
strokeColor: "rgb(243, 156, 18)",
|
||||
pointColor: "rgb(243, 156, 18)",
|
||||
pointStrokeColor: "#c1c7d1",
|
||||
pointHighlightFill: "#fff",
|
||||
pointHighlightStroke: "rgb(243, 156, 18)",
|
||||
data: sprint_velocities
|
||||
},
|
||||
{
|
||||
label: "Estimated Velocity",
|
||||
fillColor: "rgba(60,141,188,0.9)",
|
||||
strokeColor: "rgba(60,141,188,0.8)",
|
||||
pointColor: "#3b8bba",
|
||||
pointStrokeColor: "rgba(60,141,188,1)",
|
||||
pointHighlightFill: "#fff",
|
||||
pointHighlightStroke: "rgba(60,141,188,1)",
|
||||
data: sprint_rates
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
var sprint_chart_options = {
|
||||
//Boolean - If we should show the scale at all
|
||||
showScale: true,
|
||||
//Boolean - Whether grid lines are shown across the chart
|
||||
scaleShowGridLines: false,
|
||||
//String - Colour of the grid lines
|
||||
scaleGridLineColor: "rgba(0,0,0,.05)",
|
||||
//Number - Width of the grid lines
|
||||
scaleGridLineWidth: 1,
|
||||
//Boolean - Whether to show horizontal lines (except X axis)
|
||||
scaleShowHorizontalLines: true,
|
||||
//Boolean - Whether to show vertical lines (except Y axis)
|
||||
scaleShowVerticalLines: true,
|
||||
//Boolean - Whether the line is curved between points
|
||||
bezierCurve: true,
|
||||
//Number - Tension of the bezier curve between points
|
||||
bezierCurveTension: 0.3,
|
||||
//Boolean - Whether to show a dot for each point
|
||||
pointDot: false,
|
||||
//Number - Radius of each point dot in pixels
|
||||
pointDotRadius: 4,
|
||||
//Number - Pixel width of point dot stroke
|
||||
pointDotStrokeWidth: 1,
|
||||
//Number - amount extra to add to the radius to cater for hit detection outside the drawn point
|
||||
pointHitDetectionRadius: 20,
|
||||
//Boolean - Whether to show a stroke for datasets
|
||||
datasetStroke: true,
|
||||
//Number - Pixel width of dataset stroke
|
||||
datasetStrokeWidth: 2,
|
||||
//Boolean - Whether to fill the dataset with a color
|
||||
datasetFill: true,
|
||||
//String - A legend template
|
||||
legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].lineColor%>\"></span><%=datasets[i].label%></li><%}%></ul>",
|
||||
//Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
|
||||
maintainAspectRatio: true,
|
||||
//Boolean - whether to make the chart responsive to window resizing
|
||||
responsive: true
|
||||
};
|
||||
|
||||
//Create the line chart
|
||||
sprint_chart.Line(sprint_chart_data, sprint_chart_options);
|
||||
} catch (e) {
|
||||
console.log("Something went wrong...", e);
|
||||
}
|
||||
},
|
||||
|
||||
render_line_chart: function() {
|
||||
var self = this;
|
||||
self._rpc({
|
||||
route: '/project_scrum/get_line_chart_data',
|
||||
params: {},}).done(function(result) {
|
||||
if (result) {
|
||||
self.load_sprint_burndown_chart(result); // load sprint burndown chart
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
on_sprints_click: function(event) {
|
||||
var self = this,
|
||||
context = {};
|
||||
context.search_default_group_by_project = 1;
|
||||
return self._rpc({
|
||||
route: "/web/action/load",
|
||||
params: {
|
||||
action_id: "project_scrum.action_project_sprint"
|
||||
},}).done(function(result) {
|
||||
if (result) {
|
||||
result.views = [
|
||||
[false, 'list'],
|
||||
[false, 'form']
|
||||
];
|
||||
result.context = context;
|
||||
return self.do_action(result);
|
||||
};
|
||||
})
|
||||
},
|
||||
|
||||
on_tasks_click: function(event) {
|
||||
var self = this,
|
||||
context = {};
|
||||
context.search_default_group_by_sprint = 1;
|
||||
return self._rpc({
|
||||
route:"/web/action/load",
|
||||
params: {
|
||||
action_id: "project.action_view_task"
|
||||
},}).done(function(result) {
|
||||
if (result) {
|
||||
result.views = [
|
||||
[false, 'list'],
|
||||
[false, 'form']
|
||||
];
|
||||
result.context = context;
|
||||
return self.do_action(result);
|
||||
};
|
||||
})
|
||||
},
|
||||
|
||||
on_stories_click: function() {
|
||||
var self = this,
|
||||
context = {};
|
||||
context.search_default_group_by_sprint = 1;
|
||||
return self._rpc({route:"/web/action/load",
|
||||
params: {
|
||||
action_id: "project_scrum.action_project_story_sprint"
|
||||
},}).done(function(result) {
|
||||
if (result) {
|
||||
result.views = [
|
||||
[false, 'list'],
|
||||
[false, 'form']
|
||||
];
|
||||
result.context = context;
|
||||
return self.do_action(result);
|
||||
};
|
||||
})
|
||||
},
|
||||
|
||||
on_projects_click: function() {
|
||||
var self = this,
|
||||
context = {};
|
||||
context.search_default_Manager = 1;
|
||||
return self._rpc({
|
||||
route: "/web/action/load",
|
||||
params:{
|
||||
action_id: "project.open_view_project_all_config"
|
||||
},
|
||||
}).done(function(result) {
|
||||
if (result) {
|
||||
result.views = [
|
||||
[false, 'list'],
|
||||
[false, 'form']
|
||||
];
|
||||
result.context = context;
|
||||
return self.do_action(result);
|
||||
};
|
||||
})
|
||||
},
|
||||
});
|
||||
|
||||
var ScrumDashboardModel = KanbanModel.extend({
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init: function () {
|
||||
this.dashboardValues = {};
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
get: function (localID) {
|
||||
var result = this._super.apply(this, arguments);
|
||||
return result;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @œverride
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
load: function () {
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
/**
|
||||
* @œverride
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
reload: function () {
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
var ScrumDashboardController = KanbanController.extend({
|
||||
|
||||
});
|
||||
|
||||
var MyMainDashboard = KanbanView.extend({
|
||||
config: _.extend({}, KanbanView.prototype.config, {
|
||||
Model: ScrumDashboardModel,
|
||||
Renderer: ScrumDashboardRenderer,
|
||||
Controller: ScrumDashboardController,
|
||||
}),
|
||||
display_name: _lt('Dashboard'),
|
||||
icon: 'fa-dashboard',
|
||||
searchview_hidden: true,
|
||||
});
|
||||
|
||||
view_registry.add('scrum_dashboard', MyMainDashboard);
|
||||
|
||||
return {
|
||||
Model: ScrumDashboardModel,
|
||||
Renderer: ScrumDashboardRenderer,
|
||||
Controller: ScrumDashboardController,
|
||||
};
|
||||
});
|
||||
|
191
addons/project_scrum/static/src/less/dashboard.less
Executable file
@ -0,0 +1,191 @@
|
||||
@font-face {
|
||||
font-family: customFont;
|
||||
src: url('../fonts/sourcesanspro/SourceSansPro-Regular.ttf');
|
||||
}
|
||||
|
||||
.custom-dashboard-margin {
|
||||
margin: 2px;
|
||||
width: 25%;
|
||||
background-color: #99a3a5;
|
||||
}
|
||||
|
||||
.o_form_view.o_form_editable .o_address_format .o_address_city {
|
||||
width: 31%;
|
||||
}
|
||||
|
||||
canvas#sprint_piechart {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.bg-sprint {
|
||||
background-color: #00A65A !important;
|
||||
color: #4C4C4C !important;
|
||||
}
|
||||
|
||||
.bg-task {
|
||||
background-color: #E3695A !important;
|
||||
color: #4C4C4C !important;
|
||||
}
|
||||
|
||||
.bg-story {
|
||||
background-color: #F39C12 !important;
|
||||
color: #4C4C4C !important;
|
||||
}
|
||||
|
||||
.bg-projects {
|
||||
background-color: #00C0EF !important;
|
||||
color: #4C4C4C !important;
|
||||
}
|
||||
|
||||
|
||||
#myTable > thead {
|
||||
background-color: darkgray;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#myTable > td {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.myFont {
|
||||
font-family: customFont;
|
||||
}
|
||||
|
||||
.kanban-color {
|
||||
cursor: pointer;
|
||||
background-color: #7c7bad;
|
||||
}
|
||||
|
||||
div.velocity-div {
|
||||
font-size: 15px;
|
||||
&:before {
|
||||
content: '';
|
||||
width: 21px;
|
||||
height: 21px;
|
||||
border: 1px solid #e1e1e1;
|
||||
position: absolute;
|
||||
left: 41px;
|
||||
}
|
||||
}
|
||||
|
||||
.list-color {
|
||||
content: '';
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
border: 1px solid #e1e1e1;
|
||||
position: absolute;
|
||||
left: 75px;
|
||||
}
|
||||
|
||||
#chart_names {
|
||||
li {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.blue:before {
|
||||
background-color: #4E8EAC;
|
||||
}
|
||||
|
||||
.orange:before {
|
||||
background-color: #F39C12;
|
||||
}
|
||||
|
||||
.big {
|
||||
font-size: 18px;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.panel-blue {
|
||||
border-color: #337ab7;
|
||||
}
|
||||
|
||||
.panel-green {
|
||||
border-color: #5cb85c;
|
||||
}
|
||||
|
||||
.panel-orange {
|
||||
border-color: #f0ad4e;
|
||||
}
|
||||
|
||||
.panel-red {
|
||||
border-color: #d9534f;
|
||||
}
|
||||
|
||||
.panel {
|
||||
margin-bottom: 20px;
|
||||
background-color: #fff;
|
||||
border: 1px solid transparent;
|
||||
-webkit-box-shadow: 0 1px 1px rgba(0,0,0,.05);
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,.05);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
padding: 10px 15px;
|
||||
border-bottom: 1px solid transparent;
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.panel-blue > .panel-heading {
|
||||
color: #fff;
|
||||
background-color: #337ab7;
|
||||
border-color: #337ab7;
|
||||
}
|
||||
|
||||
.panel-green > .panel-heading {
|
||||
color: #fff;
|
||||
background-color: #5cb85c;
|
||||
border-color: #5cb85c;
|
||||
}
|
||||
|
||||
.panel-orange > .panel-heading {
|
||||
color: #fff;
|
||||
background-color: #f0ad4e;
|
||||
border-color: #f0ad4e;
|
||||
}
|
||||
|
||||
.panel-red > .panel-heading {
|
||||
color: #fff;
|
||||
background-color: #d9534f;
|
||||
border-color: #d9534f;
|
||||
}
|
||||
|
||||
.custom-bg {
|
||||
background-color: #fff;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.panel-heading:hover {
|
||||
color: #ebebeb;
|
||||
}
|
||||
|
||||
#sprint_id {
|
||||
margin-left: 25px;
|
||||
width: 92%;
|
||||
}
|
||||
|
||||
.o_kanban_view .o_kanban_record.oe_kanban_global_click, .o_kanban_view .o_kanban_record.oe_kanban_global_click_edit {
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/*.o_view_manager_content {
|
||||
margin-top: 130px;
|
||||
}*/
|
||||
|
||||
.sprint_kanban {
|
||||
position: relative;
|
||||
min-width: 49% !important;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.o_kanban_view.o_kanban_ungrouped .sprint_kanban.o_kanban_record{
|
||||
margin : 4px !important;
|
||||
}
|
96
addons/project_scrum/static/src/xml/scrum_dashboard.xml
Executable file
@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<template xml:space="preserve">
|
||||
<div t-name="ScrumDashboard" class="custom-bg mb8">
|
||||
<div class="container">
|
||||
<div class="row mt32 mb32 mr0 ml0">
|
||||
<div class="col-md-3">
|
||||
<div class="panel panel-blue">
|
||||
<div class="panel-heading">
|
||||
<div class="row">
|
||||
<div class="col-xs-3">
|
||||
<i class="fa fa-pencil-square fa-5x"></i>
|
||||
</div>
|
||||
<div class="col-xs-9 text-center total-projects">
|
||||
<div class="myFont big">Total Projects</div>
|
||||
<div id="total_projects" class="myFont"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="panel panel-green">
|
||||
<div class="panel-heading">
|
||||
<div class="row">
|
||||
<div class="col-xs-3">
|
||||
<i class="fa fa-list-ol fa-5x"></i>
|
||||
</div>
|
||||
<div class="col-xs-9 text-center total-sprints">
|
||||
<div class="myFont big">Total Sprints</div>
|
||||
<div id="total_sprints" class="myFont"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="panel panel-orange">
|
||||
<div class="panel-heading">
|
||||
<div class="row">
|
||||
<div class="col-xs-3">
|
||||
<i class="fa fa-file-text fa-5x"></i>
|
||||
</div>
|
||||
<div class="col-xs-9 text-center total-stories">
|
||||
<div class="myFont big">Total Stories</div>
|
||||
<div id="total_stories" class="myFont"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="panel panel-red">
|
||||
<div class="panel-heading">
|
||||
<div class="row">
|
||||
<div class="col-xs-3">
|
||||
<i class="fa fa-tasks fa-5x"></i>
|
||||
</div>
|
||||
<div class="col-xs-9 text-center total-tasks">
|
||||
<div class="myFont big">Total Tasks</div>
|
||||
<div id="total_tasks" class="myFont"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h2 class="text-center myFont"><b>Sprint Burn Down Chart</b></h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="velocity-div orange ml48 mb8">
|
||||
<span class="text-right myFont ml8">Success (%)</span>
|
||||
</div>
|
||||
<div class="velocity-div blue ml48">
|
||||
<span class="text-right myFont ml8">Velocity</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="sprint_chart">
|
||||
<div class="chart">
|
||||
<canvas id="scrum_chart" style="padding: 25px;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
8
addons/project_scrum/tests/__init__.py
Executable file
@ -0,0 +1,8 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from .test_scrum_common import TestScrumCommon
|
||||
from .test_scrum_team import TestScrumTeam
|
||||
from .test_scrum_sprint import TestScrumSprint
|
||||
from .test_scrum_task import TestScrumTask
|
||||
from .test_scrum_release_planning import TestScrumReleasePlanning
|
||||
from .test_scrum_story import TestScrumStory
|
79
addons/project_scrum/tests/test_scrum_common.py
Normal file
@ -0,0 +1,79 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra.tests import common
|
||||
|
||||
|
||||
class TestScrumCommon(common.SavepointCase):
|
||||
def setUp(self):
|
||||
super(TestScrumCommon, self).setUp()
|
||||
|
||||
self.teams = [
|
||||
self.env.ref('project_scrum.project_team_1'),
|
||||
self.env.ref('project_scrum.project_team_2'),
|
||||
self.env.ref('project_scrum.project_team_3')
|
||||
]
|
||||
|
||||
self.user_roles = [
|
||||
self.env.ref('project_scrum.user_role_1'),
|
||||
self.env.ref('project_scrum.user_role_2'),
|
||||
self.env.ref('project_scrum.user_role_3')
|
||||
]
|
||||
|
||||
self.sprints = [
|
||||
self.env.ref('project_scrum.project_sprint_1'),
|
||||
self.env.ref('project_scrum.project_sprint_2'),
|
||||
self.env.ref('project_scrum.project_sprint_3'),
|
||||
self.env.ref('project_scrum.project_sprint_4'),
|
||||
self.env.ref('project_scrum.project_sprint_5')
|
||||
]
|
||||
|
||||
self.project_tasks = [
|
||||
self.env.ref('project_scrum.project_task_1'),
|
||||
self.env.ref('project_scrum.project_task_2'),
|
||||
self.env.ref('project_scrum.project_task_3'),
|
||||
self.env.ref('project_scrum.project_task_4'),
|
||||
self.env.ref('project_scrum.project_task_6'),
|
||||
self.env.ref('project_scrum.project_task_7'),
|
||||
self.env.ref('project_scrum.project_task_8'),
|
||||
self.env.ref('project_scrum.project_task_9'),
|
||||
self.env.ref('project_scrum.project_task_10'),
|
||||
self.env.ref('project_scrum.project_task_11'),
|
||||
self.env.ref('project_scrum.project_task_12'),
|
||||
self.env.ref('project_scrum.project_task_13'),
|
||||
self.env.ref('project_scrum.project_task_14')
|
||||
]
|
||||
|
||||
self.users = [
|
||||
self.env.ref('project_scrum.user_1'),
|
||||
self.env.ref('project_scrum.user_2'),
|
||||
self.env.ref('project_scrum.user_3')
|
||||
]
|
||||
|
||||
self.release_plans = [
|
||||
self.env.ref('project_scrum.release_planning_1'),
|
||||
self.env.ref('project_scrum.release_planning_2'),
|
||||
self.env.ref('project_scrum.release_planning_3'),
|
||||
self.env.ref('project_scrum.release_planning_4'),
|
||||
self.env.ref('project_scrum.release_planning_5')
|
||||
]
|
||||
|
||||
self.story_priorities = [
|
||||
self.env.ref('project_scrum.story_priority_1'),
|
||||
self.env.ref('project_scrum.story_priority_2'),
|
||||
self.env.ref('project_scrum.story_priority_3')
|
||||
]
|
||||
|
||||
self.story_types = [
|
||||
self.env.ref('project_scrum.story_type_1'),
|
||||
self.env.ref('project_scrum.story_type_2')
|
||||
]
|
||||
|
||||
self.stories = [
|
||||
self.env.ref('project_scrum.project_story_1'),
|
||||
self.env.ref('project_scrum.project_story_2'),
|
||||
self.env.ref('project_scrum.project_story_3')
|
||||
]
|
||||
|
||||
self.project = self.env.ref('project_scrum.demo_project_1')
|
||||
|
||||
self.sprint_planning_line = self.env['sprint.planning.line']
|
23
addons/project_scrum/tests/test_scrum_release_planning.py
Normal file
@ -0,0 +1,23 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from logging import info
|
||||
|
||||
from .test_scrum_common import TestScrumCommon
|
||||
|
||||
|
||||
class TestScrumReleasePlanning(TestScrumCommon):
|
||||
def setUp(self):
|
||||
super(TestScrumReleasePlanning, self).setUp()
|
||||
|
||||
def test_scrum_release_planning(self):
|
||||
if not self.release_plans:
|
||||
raise AssertionError(
|
||||
'Error in data. Please check for release planning.')
|
||||
info('Details of release planning:')
|
||||
for plan in self.release_plans:
|
||||
info('Release Plan : %s' % plan.name)
|
||||
info(' Release Date : %s' % plan.release_date)
|
||||
info(' Sprint : %s' % plan.sprint_id.name)
|
||||
info(' Branch : %s' % plan.branch_id.name)
|
||||
info(' Priority : %s' % plan.priority)
|
||||
info(' Sprint Velocity : %s' % plan.velocity)
|
63
addons/project_scrum/tests/test_scrum_sprint.py
Normal file
@ -0,0 +1,63 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from logging import info
|
||||
|
||||
from .test_scrum_common import TestScrumCommon
|
||||
|
||||
|
||||
class TestScrumSprint(TestScrumCommon):
|
||||
def setUp(self):
|
||||
super(TestScrumSprint, self).setUp()
|
||||
|
||||
def test_scrum_sprint(self):
|
||||
# self.check_user_roles(self.user_roles)
|
||||
self.check_sprint(self.sprints)
|
||||
|
||||
def check_user_roles(self, roles):
|
||||
if not roles:
|
||||
raise AssertionError('Error in data. Please check user role data.')
|
||||
info('Details of Roles :')
|
||||
info('Code : name')
|
||||
for role in roles:
|
||||
info(' %s : %s' % (role.code, role.name))
|
||||
|
||||
def check_sprint(self, sprints):
|
||||
if not sprints:
|
||||
raise AssertionError('Error in data. Please check sprint data.')
|
||||
info('Details of Sprints :')
|
||||
for sprint in sprints:
|
||||
info('Sprint : %s' % sprint.name)
|
||||
info(' Sequence : %s' % sprint.sprint_seq)
|
||||
info(' Project : %s' % sprint.project_id.name)
|
||||
info(' Team : %s' % sprint.team_id.name)
|
||||
info(' Date : %s - %s' % (sprint.start_date, sprint.end_date))
|
||||
info(' Planning Meeting Date : %s' % sprint.meeting_date)
|
||||
info(' Goal of Sprint : %s' % sprint.goal_of_sprint)
|
||||
info(' Branch : %s' % sprint.branch_id.name)
|
||||
info(' Daily Scrum Time : %f' % sprint.hour)
|
||||
info(' Duration (In Days): %d' % sprint.duration)
|
||||
info(' Estimated Velocity : %d' % sprint.estimated_velocity)
|
||||
info(' Actual Velocity : %d' % sprint.actual_velocity)
|
||||
info(' Business Days : %d' % sprint.working_days)
|
||||
info(' Holiday (Hours / Days) : %s' % sprint.holiday_type)
|
||||
info(' Holiday Count : %f' % sprint.holiday_count)
|
||||
info(' Productivity Hours : %s' % sprint.productivity_hours)
|
||||
info(' Productivity : %f' % sprint.productivity_per)
|
||||
|
||||
lines = self.sprint_planning_line.search(
|
||||
[('sprint_id', '=', sprint.id)])
|
||||
if not lines:
|
||||
raise AssertionError(
|
||||
'Error in data. Please check spring planning lines '
|
||||
'for sprint %s' % sprint.name)
|
||||
|
||||
info(' Spring Planning :')
|
||||
for line in lines:
|
||||
info(' User : %s' % line.user_id.name)
|
||||
info(' Role : %s' % line.role_id.name)
|
||||
info(' Available : %s' % line.available_per)
|
||||
info(' Productivity Hour : '
|
||||
'%s' % line.productivity_hours)
|
||||
info(' Sprint hour : %s' % line.sprint_hours)
|
||||
info(' Off Hour : %s' % line.off_hours)
|
||||
info(' Total Hour: %s' % line.total_hours)
|
57
addons/project_scrum/tests/test_scrum_story.py
Normal file
@ -0,0 +1,57 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from logging import info
|
||||
|
||||
from .test_scrum_common import TestScrumCommon
|
||||
|
||||
|
||||
class TestScrumStory(TestScrumCommon):
|
||||
def setUp(self):
|
||||
super(TestScrumStory, self).setUp()
|
||||
|
||||
def test_scrum_story(self):
|
||||
if not self.story_priorities:
|
||||
raise AssertionError(
|
||||
'Error in data. Please check for story priorities.')
|
||||
self.check_priority(self.story_priorities)
|
||||
|
||||
if not self.story_types:
|
||||
raise AssertionError(
|
||||
'Error in data. Please check for story types.')
|
||||
self.check_type(self.story_types)
|
||||
|
||||
if not self.stories:
|
||||
raise AssertionError(
|
||||
'Error in data. Please check for story data.')
|
||||
self.check_story(self.stories)
|
||||
|
||||
def check_priority(self, priorities):
|
||||
info('Details of Priorities :')
|
||||
info(' Code : Name')
|
||||
for priority in priorities:
|
||||
info(' %s : %s' % (priority.code, priority.name))
|
||||
|
||||
def check_type(self, types):
|
||||
info('Details of Story Types :')
|
||||
info(' Code : Name')
|
||||
for type in types:
|
||||
info(' %s : %s' % (type.code, type.name))
|
||||
|
||||
def check_story(self, stories):
|
||||
info('Details of Stories:')
|
||||
for story in stories:
|
||||
if not story.name:
|
||||
raise AssertionError(
|
||||
'Error in data. Please check for story name.')
|
||||
info('Story : %s' % story.name)
|
||||
if not story.sprint_id:
|
||||
raise AssertionError(
|
||||
'Error in data. Please check for story sprint value.')
|
||||
info(' Sprint : %s' % story.sprint_id.name)
|
||||
info(' Priority : %s' % story.priority_id.name)
|
||||
info(' Owner : %s' % story.owner_id.name)
|
||||
info(' Branch : %s' % story.branch_id.name)
|
||||
info(' Type : %s' % story.story_type_id.name)
|
||||
info(' Actual Velocity : %d' % story.actual_velocity)
|
||||
info(' Estimated Velocity : %s' % story.estimated_velocity )
|
||||
info(' Description : %s' % story.description)
|
43
addons/project_scrum/tests/test_scrum_task.py
Normal file
@ -0,0 +1,43 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from logging import info
|
||||
|
||||
from .test_scrum_common import TestScrumCommon
|
||||
|
||||
|
||||
class TestScrumTask(TestScrumCommon):
|
||||
def setUp(self):
|
||||
super(TestScrumTask, self).setUp()
|
||||
|
||||
def test_scrum_task(self):
|
||||
if not self.project_tasks:
|
||||
raise AssertionError('Error in data. Please Check Project Tasks.')
|
||||
info('Details of tasks:')
|
||||
for task in self.project_tasks:
|
||||
if not task.name:
|
||||
raise AssertionError(
|
||||
'Error in data. Please Check Project Tasks Name.')
|
||||
info('Details of : %s' % task.name)
|
||||
if not task.project_id:
|
||||
raise AssertionError(
|
||||
'Error in data. Please Check Project Tasks Project.')
|
||||
info(' Project : %s' % task.project_id.name)
|
||||
if not task.sprint_id:
|
||||
raise AssertionError(
|
||||
'Error in data. Please Check Project Tasks Sprint.')
|
||||
info(' Sprint : %s' % task.sprint_id.name)
|
||||
info(' Assigned to : %s' % task.user_id.name)
|
||||
info(' Company : %s' % task.company_id.name)
|
||||
if not task.start_date and task.end_date:
|
||||
raise AssertionError(
|
||||
'Error in data. Please Check Project Tasks Date.')
|
||||
info(' Date : %s - %s' % (task.start_date, task.end_date))
|
||||
info(' Actual End Date : %s' % task.actual_end_date)
|
||||
info(' Deadline : %s' % task.date_deadline)
|
||||
info(' Reference : %s' % task.task_seq)
|
||||
info(' Branch : %s' % task.branch_id.name)
|
||||
info(' Story : %s' % task.story_id.name)
|
||||
info(' Velocity : %d' % task.velocity)
|
||||
info(' Release Planning : %s' % task.release_planning_id.name)
|
||||
info(' Priority : %s' % task.priority)
|
||||
info(' Description : %s' % task.description)
|
31
addons/project_scrum/tests/test_scrum_team.py
Normal file
@ -0,0 +1,31 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from logging import info
|
||||
|
||||
from .test_scrum_common import TestScrumCommon
|
||||
|
||||
|
||||
class TestScrumTeam(TestScrumCommon):
|
||||
def setUp(self):
|
||||
super(TestScrumTeam, self).setUp()
|
||||
|
||||
def test_scrum_team(self):
|
||||
if not self.teams:
|
||||
raise AssertionError(
|
||||
'Error in data. Please check for Team in Scrum.')
|
||||
info('Details of Teams of Scrum.....')
|
||||
for team in self.teams:
|
||||
if not (team.name and team.project_id):
|
||||
raise AssertionError(
|
||||
'Error in data. Please check for Team in Scrum.')
|
||||
|
||||
info('Team Name : %s' % team.name)
|
||||
info(' Description : %s' % team.description)
|
||||
info(' Strength : %s' % team.strength)
|
||||
info(' Project : %s' % team.project_id.name)
|
||||
info(' Scrum Master : %s' % team.master_id.name)
|
||||
if team.member_ids:
|
||||
info(' Members : %d' % len(team.member_ids))
|
||||
for member in team.member_ids:
|
||||
info(' %s' % member.name)
|
||||
info(' Branch : %s' % team.branch_id.name)
|
19
addons/project_scrum/views/assets.xml
Executable file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<template id="scrum_assets_backend" name="scrum_enterprise_assets"
|
||||
inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<link rel="stylesheet" type="text/less"
|
||||
href="/project_scrum/static/src/less/dashboard.less"></link>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/project_scrum/static/src/js/scrum_dashboard.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="/project_scrum/static/src/js/Chart.js"
|
||||
></script>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</flectra>
|
13
addons/project_scrum/views/cron_view.xml
Executable file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<record id="cron_check_sprint_state" model="ir.cron">
|
||||
<field name="name">Sprint State</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="model_id" ref="project_scrum.model_project_sprint"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.check_sprint_state()</field>
|
||||
<field name="active" eval="False"/>
|
||||
</record>
|
||||
</flectra>
|
162
addons/project_scrum/views/other_views.xml
Executable file
@ -0,0 +1,162 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<!-- Project form inherited -->
|
||||
<record id="view_project_form_inherited" model="ir.ui.view">
|
||||
<field name="name">Project inherited form</field>
|
||||
<field name="model">project.project</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="user_id" position="replace">
|
||||
<field name="user_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</field>
|
||||
<field name="company_id" position="replace">
|
||||
<field name="company_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</field>
|
||||
<field name="branch_id" position="replace">
|
||||
<field name="branch_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</field>
|
||||
<field name="partner_id" position="replace">
|
||||
<field name="partner_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</field>
|
||||
|
||||
<xpath expr="//field[@name='user_id']" position="before">
|
||||
<field name="no_of_hours" invisible="1"/>
|
||||
<field name="no_of_days" invisible="1"/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//button[@name='attachment_tree_view']" position="after">
|
||||
<button class="oe_stat_button" name="show_sprints" type="object" icon="fa fa-dot-circle-o">
|
||||
<field string="Sprints" name="sprint_count" widget="statinfo"/>
|
||||
</button>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//group[@name='misc']/group[1]" position="replace">
|
||||
<group string="Configuration">
|
||||
<field name="sequence" position="replace">
|
||||
<field name="sequence"/>
|
||||
</field>
|
||||
</group>
|
||||
</xpath>
|
||||
<xpath expr="//group[@name='misc']/group[2]" position="replace">
|
||||
<group string="Time Scheduling">
|
||||
<field name="resource_calendar_id" position="replace">
|
||||
<field name="resource_calendar_id"/>
|
||||
</field>
|
||||
</group>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//notebook/page[@name='settings']" position="after">
|
||||
<page string="Stages">
|
||||
<field name="task_type_ids"/>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- User Inherited view -->
|
||||
<record id="view_users_form_inherited" model="ir.ui.view">
|
||||
<field name="name">Users inherited form</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='branch_ids']" position="after">
|
||||
<field name="role_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Tasks Inherited view -->
|
||||
<record id="view_tasks_form_inherited" model="ir.ui.view">
|
||||
<field name="name">Tasks inherited form</field>
|
||||
<field name="model">project.task</field>
|
||||
<field name="inherit_id" ref="project.view_task_form2"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="project_id" position="replace">
|
||||
<field name="project_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</field>
|
||||
<field name="user_id" position="replace">
|
||||
<field name="user_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</field>
|
||||
<field name="company_id" position="replace">
|
||||
<field name="company_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</field>
|
||||
<field name="branch_id" position="replace">
|
||||
<field name="branch_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</field>
|
||||
<field name="partner_id" position="replace">
|
||||
<field name="partner_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</field>
|
||||
<field name="tag_ids" position="replace">
|
||||
<field name="tag_ids" options="{'no_create': True, 'no_create_edit': True}" widget="many2many_tags"/>
|
||||
</field>
|
||||
<xpath expr="//field[@name='branch_id']" position="after">
|
||||
<field name="story_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
<field name="velocity"/>
|
||||
<field name="release_planning_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='project_id']" position="after">
|
||||
<field name="sprint_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Task Search view inherited -->
|
||||
<record id="view_tasks_search_inherited" model="ir.ui.view">
|
||||
<field name="name">Tasks inherited search</field>
|
||||
<field name="model">project.task</field>
|
||||
<field name="inherit_id" ref="project.view_task_search_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//group/filter[@name='project']" position="before">
|
||||
<filter string="Sprint" name="group_by_sprint" context="{'group_by': 'sprint_id'}"/>
|
||||
</xpath>
|
||||
<xpath expr="//search/field[@name='name']" position="after">
|
||||
<field name="sprint_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Task Tree view inherited -->
|
||||
<record id="view_tasks_tree_inherited" model="ir.ui.view">
|
||||
<field name="name">Tasks inherited tree</field>
|
||||
<field name="model">project.task</field>
|
||||
<field name="inherit_id" ref="project.view_task_tree2"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='date_deadline']" position="after">
|
||||
<field name="sprint_id"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="actual_end_date"/>
|
||||
<field name="velocity"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_inherited_task" model="ir.actions.act_window">
|
||||
<field name="name">Tasks</field>
|
||||
<field name="res_model">project.task</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="context">{
|
||||
'search_default_sprint_id': [active_id],
|
||||
'default_sprint_id': active_id,
|
||||
}
|
||||
</field>
|
||||
<field name="search_view_id" ref="project.view_task_search_form"/>
|
||||
</record>
|
||||
|
||||
<!-- Resource Calendar -->
|
||||
<record id="view_resource_calendar_inherited" model="ir.ui.view">
|
||||
<field name="name">Resource Calendar</field>
|
||||
<field name="model">resource.calendar</field>
|
||||
<field name="inherit_id" ref="resource.resource_calendar_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="name" position="after">
|
||||
<group col="4" colspan="4">
|
||||
<field name="no_of_hours"/>
|
||||
<field name="no_of_days"/>
|
||||
</group>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</flectra>
|
404
addons/project_scrum/views/project_sprint_views.xml
Executable file
@ -0,0 +1,404 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<record id="view_project_sprint_form" model="ir.ui.view">
|
||||
<field name="name">project.sprint</field>
|
||||
<field name="model">project.sprint</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Project Sprint">
|
||||
<header>
|
||||
<button name="set_state_open" string="Open" type="object"
|
||||
class="oe_highlight"
|
||||
attrs="{'invisible': [('state', '!=', 'draft')]}"/>
|
||||
<button name="set_state_cancel" string="Cancel"
|
||||
type="object" class="oe_highlight"
|
||||
attrs="{'invisible': [('state', 'in', ('done', 'cancel'))]}"/>
|
||||
<button name="set_state_pending" string="Pending"
|
||||
type="object" class="oe_highlight"
|
||||
attrs="{'invisible': [('state', 'not in', ('in_progress', 'draft'))]}"/>
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="task_button_box">
|
||||
<button name="action_view_tasks" string="Tasks"
|
||||
type="object" class="oe_stat_button"
|
||||
icon="fa-tasks"/>
|
||||
<button name="action_view_stories" string="Stories"
|
||||
type="object" class="oe_stat_button"
|
||||
icon="fa-pencil"/>
|
||||
<button name="action_view_release_planning"
|
||||
string="Release Planning"
|
||||
type="object" class="oe_stat_button"
|
||||
icon="fa-rocket"/>
|
||||
<button name="action_view_retrospective"
|
||||
string="Retrospectives"
|
||||
type="object" class="oe_stat_button"
|
||||
icon="fa-backward"/>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<h1 class="o_row">
|
||||
<field name="name" placeholder="Sprint Name"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
</h1>
|
||||
</div>
|
||||
<div col="2">
|
||||
<br/>
|
||||
<h2 class="o_row">
|
||||
<field name="sprint_seq" nolabel="1" readonly="1"/>
|
||||
</h2>
|
||||
</div>
|
||||
<group>
|
||||
<group col="2">
|
||||
<field name="project_id"
|
||||
options="{'no_create': True, 'no_create_edit': True}"
|
||||
required="1"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
<field name="start_date" required="1"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
<field name="meeting_date"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="team_id"
|
||||
options="{'no_create': True, 'no_create_edit': True}"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
<field name="end_date"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
<field name="goal_of_sprint"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="branch_id"
|
||||
options="{'no_create': True, 'no_create_edit': True}"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
<field name="duration"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<label for="hour" string="Daily Scrum Time"/>
|
||||
<div class="o_address_format">
|
||||
<field name="hour" widget="float_time"
|
||||
class="o_address_city"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
<field name="time_zone" class="o_address_city"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
</div>
|
||||
<field name="estimated_velocity"/>
|
||||
<field name="actual_velocity"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<notebook>
|
||||
<page string="Sprint Planning">
|
||||
<group name="sprint_planning" col="4">
|
||||
<field name="working_days"/>
|
||||
<field name="productivity_hours"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
<field name="holiday_type"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
<field name="productivity_per"/>
|
||||
<field name="holiday_count"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
<field name="holiday_days"
|
||||
attrs="{'invisible': [('holiday_type', '=', 'hours')]}"/>
|
||||
</group>
|
||||
<field name="sprint_planning_line" nolabel="1"
|
||||
attrs="{'readonly': [('state', '!=', 'draft')]}">
|
||||
<tree editable="bottom">
|
||||
<field name="user_id"
|
||||
options="{'no_create': True, 'no_create_edit': True}"
|
||||
required="1"/>
|
||||
<field name="role_id"/>
|
||||
<field name="available_per"/>
|
||||
<field name="productivity_hours"/>
|
||||
<field name="sprint_hours"/>
|
||||
<field name="off_hours"/>
|
||||
<field name="total_hours"
|
||||
sum="Total Capacity"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_project_sprint_tree" model="ir.ui.view">
|
||||
<field name="name">project.sprint.tree</field>
|
||||
<field name="model">project.sprint</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Project Sprint">
|
||||
<field name="sprint_seq"/>
|
||||
<field name="name"/>
|
||||
<field name="project_id"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="goal_of_sprint"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_sprint_search" model="ir.ui.view">
|
||||
<field name="name">project.sprint.search</field>
|
||||
<field name="model">project.sprint</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Sprints">
|
||||
<field name="name"/>
|
||||
<field name="project_id"/>
|
||||
<field name="branch_id"/>
|
||||
<filter string="Draft" name="filter_draft"
|
||||
domain="[('state', '=', 'draft')]"/>
|
||||
<filter string="In Progress" name="filter_progress"
|
||||
domain="[('state', '=', 'in_progress')]"/>
|
||||
<filter string="Done" name="filter_done"
|
||||
domain="[('state', '=', 'done')]"/>
|
||||
<filter string="Cancel" name="filter_cancel"
|
||||
domain="[('state', '=', 'cancel')]"/>
|
||||
<filter string="Project" name="group_by_project"
|
||||
context="{'group_by': 'project_id'}"/>
|
||||
<filter string="Branch" name="group_by_branch"
|
||||
context="{'group_by': 'branch_id'}"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
Sprint Kanban View
|
||||
-->
|
||||
<record id="view_project_sprint_kanban" model="ir.ui.view">
|
||||
<field name="name">project.sprint.kanban</field>
|
||||
<field name="model">project.sprint</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban class="o_kanban_dashboard o_kanban_mobile" js_class="scrum_dashboard">
|
||||
<field name="name"/>
|
||||
<field name="id"/>
|
||||
<field name="color"/>
|
||||
<field name="number_of_tasks"/>
|
||||
<field name="tasks_json"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div t-attf-class="#{kanban_color(record.color.raw_value)} oe_kanban_global_click sprint_kanban">
|
||||
<div class="o_project_kanban_main">
|
||||
<div class="o_kanban_card_content o_visible">
|
||||
<div class="o_kanban_primary_left">
|
||||
<div class="o_primary">
|
||||
<span class="col-md-12 bold">
|
||||
<t t-esc="record.name.value"/>
|
||||
<t t-if="record.tasks_json.raw_value">
|
||||
<t t-value="record.tasks_json.raw_value"
|
||||
t-set="data"/>
|
||||
</t>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container o_kanban_card_content o_visible mt16">
|
||||
<div class="row">
|
||||
<div class="col-sm-3 col-md-3 col-xs-3">
|
||||
<div class="chart">
|
||||
<canvas
|
||||
t-att-id="'pie_chart_' + (record.id.value)"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-9 col-md-9 col-xs-9">
|
||||
<ul
|
||||
t-att-id="'pie_list_' + (record.id.value)"
|
||||
style="list-style-type: none; margin: 10px 0 0 80px;"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 col-md-3 col-xs-3">
|
||||
<div class="chart">
|
||||
<canvas
|
||||
t-att-id="'burndown_chart_' + (record.id.value)"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" t-raw="init">
|
||||
Chart.defaults.global.showTooltips = true;
|
||||
var data = JSON.parse("<t t-esc='data'/>".replace(/u'/g,'"').replace(/'/g,'"'));
|
||||
var data_id = "<t t-esc='record.id.value'/>";
|
||||
var pie_data = [];
|
||||
var li = "";
|
||||
var colors = ['#A1887F', '#8BC34A', '#5C6BC0', '#9C27B0', '#006064', '#76FF03', '#5D4037'];
|
||||
for(var i in data) {
|
||||
pie_data.push({
|
||||
value: data[i].per,
|
||||
label: data[i].task,
|
||||
color: colors[i],
|
||||
});
|
||||
li += '<li><span class="list-color" style="margin-top: 2px;background-color:'+ colors[i] +'"></span>' + data[i].task + ' - ' + data[i].per + '%' + '</li>';
|
||||
}
|
||||
$('#pie_list_' + data_id).html(li);
|
||||
var context_pie = document.getElementById('pie_chart_' + data_id).getContext('2d');
|
||||
context_pie.canvas.width = 110;
|
||||
context_pie.canvas.height = 110;
|
||||
new Chart(context_pie).Pie(pie_data);
|
||||
var context_burndown = document.getElementById('burndown_chart_' + data_id).getContext('2d');
|
||||
context_burndown.canvas.width = 475;
|
||||
context_burndown.canvas.height = 100;
|
||||
var task_labels = [], velocities = [], per = [];
|
||||
for(var key in data) {
|
||||
if(data[key]) {
|
||||
velocities.push(data[key].velocity);
|
||||
task_labels.push(data[key].task);
|
||||
per.push(data[key].per);
|
||||
}
|
||||
}
|
||||
var sprint_chart_data = {
|
||||
labels: task_labels,
|
||||
datasets: [
|
||||
{
|
||||
label: "Success (%)",
|
||||
fillColor: "rgb(243, 156, 18)",
|
||||
strokeColor: "rgb(243, 156, 18)",
|
||||
pointColor: "rgb(243, 156, 18)",
|
||||
pointStrokeColor: "#c1c7d1",
|
||||
pointHighlightFill: "#fff",
|
||||
pointHighlightStroke:"rgb(243, 156, 18)",
|
||||
data: per
|
||||
},
|
||||
{
|
||||
label: "Velocity",
|
||||
fillColor: "rgba(60,141,188,0.9)",
|
||||
strokeColor: "rgba(60,141,188,0.9)",
|
||||
pointColor: "rgba(60,141,188,0.9)",
|
||||
pointStrokeColor: "#c1c7d1",
|
||||
pointHighlightFill: "#fff",
|
||||
pointHighlightStroke: "rgba(60,141,188,0.9)",
|
||||
data: velocities
|
||||
}
|
||||
]
|
||||
};
|
||||
new Chart(context_burndown).Line(sprint_chart_data);
|
||||
</script>
|
||||
<div class="o_kanban_card_manage_pane o_invisible">
|
||||
<div class="o_kanban_card_manage_section o_kanban_manage_reports">
|
||||
<div groups="project.group_project_manager">
|
||||
<a type="edit">Edit</a>
|
||||
</div>
|
||||
</div>
|
||||
<div t-if="widget.editable"
|
||||
class="o_project_kanban_colorpicker">
|
||||
<ul class="oe_kanban_colorpicker"
|
||||
data-field="color"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="o_project_kanban_boxes"
|
||||
style="background-color: #7c7bad; padding: 20px;">
|
||||
<div class="o_project_kanban_box text-center">
|
||||
<a name="%(action_inherited_task)d"
|
||||
type="action" class="text-white bold">
|
||||
<span class="o_value">
|
||||
<t t-esc="record.number_of_tasks.value"/>
|
||||
</span>
|
||||
<span class="o_label">Tasks</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
Sprint Calendar View
|
||||
-->
|
||||
<record id="view_project_sprint_calendar" model="ir.ui.view">
|
||||
<field name="name">project.sprint.calendar</field>
|
||||
<field name="model">project.sprint</field>
|
||||
<field name="arch" type="xml">
|
||||
<calendar string="Project Sprint" color="project_id"
|
||||
date_start="meeting_date">
|
||||
<field name="name"/>
|
||||
<field name="project_id"/>
|
||||
<field name="start_date"/>
|
||||
</calendar>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_project_sprint" model="ir.actions.act_window">
|
||||
<field name="name">Sprint</field>
|
||||
<field name="res_model">project.sprint</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">kanban,form,tree,calendar</field>
|
||||
<field name="view_id" ref="view_project_sprint_kanban"/>
|
||||
<field name="search_view_id" ref="view_sprint_search"/>
|
||||
</record>
|
||||
|
||||
<menuitem name="Scrum" id="menu_scrum" parent="project.menu_main_pm"
|
||||
sequence="1"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_sprint"
|
||||
parent="menu_scrum"
|
||||
action="action_project_sprint"
|
||||
sequence="1"
|
||||
/>
|
||||
|
||||
<!-- User Role views -->
|
||||
|
||||
<record id="view_user_role_tree" model="ir.ui.view">
|
||||
<field name="name">user.role</field>
|
||||
<field name="model">user.role</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="User Role">
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_user_role_form" model="ir.ui.view">
|
||||
<field name="name">user.role</field>
|
||||
<field name="model">user.role</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="User Role">
|
||||
<sheet>
|
||||
<group col="4">
|
||||
<field name="name" required="1"/>
|
||||
<field name="code"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_user_role" model="ir.actions.act_window">
|
||||
<field name="name">Roles</field>
|
||||
<field name="res_model">user.role</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form,tree</field>
|
||||
<field name="view_id" ref="view_user_role_tree"/>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="menu_user_role"
|
||||
parent="base.menu_users"
|
||||
action="action_user_role"
|
||||
sequence="2"
|
||||
/>
|
||||
|
||||
<record id="mail_followers_inherit_id" model="ir.ui.view">
|
||||
<field name="name">mail.followers</field>
|
||||
<field name="model">mail.followers</field>
|
||||
<field name="inherit_id" ref="mail.view_mail_subscription_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='subtype_ids']" position="after">
|
||||
<field name="team_id" invisible="1"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</flectra>
|
187
addons/project_scrum/views/project_story_views.xml
Executable file
@ -0,0 +1,187 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<record id="view_project_story_form" model="ir.ui.view">
|
||||
<field name="name">project.story</field>
|
||||
<field name="model">project.story</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Project Story">
|
||||
<header>
|
||||
<button name="set_state_active" string="Open" type="object" class="oe_highlight" states="draft,cancel"/>
|
||||
<button name="set_state_cancel" string="Cancel" type="object" class="oe_highlight" states="in_progress"/>
|
||||
<button name="set_state_done" string="Done" type="object" class="oe_highlight" states="in_progress"/>
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="task_button_box">
|
||||
<button name="action_view_tasks" string="Tasks"
|
||||
type="object" class="oe_stat_button"
|
||||
icon="fa-tasks"/>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<h1 class="o_row">
|
||||
<field name="name" placeholder="Story Title"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group name="story_main_fields" col="4">
|
||||
<field name="sprint_id" options="{'no_create': True, 'no_create_edit': True}" required="1"/>
|
||||
<field name="branch_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
<field name="priority_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
<field name="story_type_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
<field name="owner_id" readonly="1"/>
|
||||
<field name="tags"/>
|
||||
<field name="estimated_velocity"/>
|
||||
<field name="actual_velocity"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Description">
|
||||
<field name="description"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_project_story_tree" model="ir.ui.view">
|
||||
<field name="name">project.story</field>
|
||||
<field name="model">project.story</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Project Story">
|
||||
<field name="name"/>
|
||||
<field name="owner_id"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="sprint_id"/>
|
||||
<field name="priority_id"/>
|
||||
<field name="story_type_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_project_story_search" model="ir.ui.view">
|
||||
<field name="name">project.story</field>
|
||||
<field name="model">project.story</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Story">
|
||||
<field name="name"/>
|
||||
<field name="sprint_id"/>
|
||||
<filter string="Sprint" name="group_by_sprint" context="{'group_by': 'sprint_id'}"/>
|
||||
<filter string="Branch" name="group_by_branch" context="{'group_by': 'branch_id'}"/>
|
||||
<filter string="Owner" name="group_by_owner" context="{'group_by': 'owner_id'}"/>
|
||||
<filter string="Priority" name="group_by_priority" context="{'group_by': 'priority'}"/>
|
||||
<filter string="Type" name="group_by_type" context="{'group_by': 'type'}"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_project_story_sprint" model="ir.actions.act_window">
|
||||
<field name="name">Project Story</field>
|
||||
<field name="res_model">project.story</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form,tree</field>
|
||||
<field name="view_id" ref="view_project_story_tree"/>
|
||||
<field name="search_view_id" ref="view_project_story_search"/>
|
||||
</record>
|
||||
|
||||
<menuitem name="Story" id="menu_story" parent="menu_scrum" action="action_project_story_sprint" sequence="7"/>
|
||||
|
||||
<!-- Story Priority views -->
|
||||
|
||||
<record id="view_story_priority_tree" model="ir.ui.view">
|
||||
<field name="name">story.priority</field>
|
||||
<field name="model">story.priority</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Priority">
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_story_priority_form" model="ir.ui.view">
|
||||
<field name="name">story.priority</field>
|
||||
<field name="model">story.priority</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Priority">
|
||||
<sheet>
|
||||
<group col="4">
|
||||
<field name="name" required="1"/>
|
||||
<field name="code"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_story_priority" model="ir.actions.act_window">
|
||||
<field name="name">Story Priorities</field>
|
||||
<field name="res_model">story.priority</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form,tree</field>
|
||||
<field name="view_id" ref="view_story_priority_tree"/>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="menu_story_priority"
|
||||
parent="project.menu_project_config"
|
||||
action="action_story_priority"
|
||||
groups="project.group_project_manager"
|
||||
sequence="1"
|
||||
/>
|
||||
|
||||
<!-- Story Type views -->
|
||||
|
||||
<record id="view_story_type_tree" model="ir.ui.view">
|
||||
<field name="name">story.type</field>
|
||||
<field name="model">story.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Type">
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_story_type_form" model="ir.ui.view">
|
||||
<field name="name">story.type</field>
|
||||
<field name="model">story.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Type">
|
||||
<sheet>
|
||||
<group col="4">
|
||||
<field name="name" required="1"/>
|
||||
<field name="code"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_story_type" model="ir.actions.act_window">
|
||||
<field name="name">Story Types</field>
|
||||
<field name="res_model">story.type</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form,tree</field>
|
||||
<field name="view_id" ref="view_story_type_tree"/>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="menu_story_type"
|
||||
parent="project.menu_project_config"
|
||||
action="action_story_type"
|
||||
groups="project.group_project_manager"
|
||||
sequence="2"
|
||||
/>
|
||||
|
||||
</flectra>
|
61
addons/project_scrum/views/project_team_views.xml
Executable file
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<record id="view_project_team_form" model="ir.ui.view">
|
||||
<field name="name">project.team</field>
|
||||
<field name="model">project.team</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Project Team">
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1 class="o_row">
|
||||
<field name="name" placeholder="Team Name"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group col="4">
|
||||
<field name="project_id" options="{'no_create': True, 'no_create_edit': True}" required="1"/>
|
||||
<field name="member_ids" widget="many2many_tags" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
<field name="master_id" options="{'no_create': True, 'no_create_edit': True}"
|
||||
domain="[('id', 'in', member_ids)]"/>
|
||||
<field name="branch_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</group>
|
||||
<group col="2">
|
||||
<field name="strength"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Description">
|
||||
<field name="description"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_project_team_tree" model="ir.ui.view">
|
||||
<field name="name">project.team</field>
|
||||
<field name="model">project.team</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Project Team">
|
||||
<field name="name"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="master_id"/>
|
||||
<field name="strength"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_project_team" model="ir.actions.act_window">
|
||||
<field name="name">Project Team</field>
|
||||
<field name="res_model">project.team</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form,tree</field>
|
||||
<field name="view_id" ref="view_project_team_tree"/>
|
||||
</record>
|
||||
|
||||
<menuitem name="Team" id="menu_team" parent="menu_scrum" action="action_project_team" sequence="10"/>
|
||||
|
||||
</flectra>
|
73
addons/project_scrum/views/release_planning_views.xml
Executable file
@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<record id="view_release_planning_form" model="ir.ui.view">
|
||||
<field name="name">release.planning.form</field>
|
||||
<field name="model">release.planning</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Release Planning">
|
||||
<sheet>
|
||||
<group col="4">
|
||||
<field name="name" required="1"/>
|
||||
<field name="release_date"/>
|
||||
<field name="sprint_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
<field name="branch_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
<field name="priority"/>
|
||||
<field name="velocity"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Tasks">
|
||||
<field name="task_id" widget="one2many_list"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_release_planning_tree" model="ir.ui.view">
|
||||
<field name="name">release.planning.tree</field>
|
||||
<field name="model">release.planning</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Release Planning">
|
||||
<field name="name" required="1"/>
|
||||
<field name="release_date"/>
|
||||
<field name="sprint_id"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="priority"/>
|
||||
<field name="velocity"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_release_planning_calendar" model="ir.ui.view">
|
||||
<field name="name">release.planning.calendar</field>
|
||||
<field name="model">release.planning</field>
|
||||
<field name="arch" type="xml">
|
||||
<calendar string="Release Planning" color="sprint_id" date_start="release_date">
|
||||
<field name="sprint_id"/>
|
||||
<field name="release_date"/>
|
||||
<field name="priority"/>
|
||||
</calendar>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_release_planning" model="ir.actions.act_window">
|
||||
<field name="name">Release Planning</field>
|
||||
<field name="res_model">release.planning</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form,calendar</field>
|
||||
<field name="view_id" ref="view_release_planning_tree"/>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="menu_release_planning"
|
||||
parent="menu_scrum"
|
||||
action="action_release_planning"
|
||||
sequence="5"
|
||||
/>
|
||||
|
||||
</flectra>
|
56
addons/project_scrum/views/retrospective_method_views.xml
Executable file
@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<record id="retrospective_method_form_view" model="ir.ui.view">
|
||||
<field name="name">Retrospective Method</field>
|
||||
<field name="model">retrospective.method</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Retrospective Method">
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Description">
|
||||
<field name="description"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="retrospective_method_tree_view" model="ir.ui.view">
|
||||
<field name="name">Retrospective Method</field>
|
||||
<field name="model">retrospective.method</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Retrospective Methods">
|
||||
<field name="name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_retrospective_method_tree_view" model="ir.actions.act_window">
|
||||
<field name="name">Retrospective Method</field>
|
||||
<field name="res_model">retrospective.method</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form,tree</field>
|
||||
<field name="view_id" ref="retrospective_method_tree_view"/>
|
||||
</record>
|
||||
|
||||
<menuitem name="Retrospective" id="retrospective_menu_id" parent="project.menu_main_pm" sequence="1"/>
|
||||
|
||||
<menuitem
|
||||
id="retrospective_method"
|
||||
parent="retrospective_menu_id"
|
||||
groups="project.group_project_manager"
|
||||
action="action_retrospective_method_tree_view"
|
||||
sequence="5"
|
||||
/>
|
||||
|
||||
</flectra>
|
77
addons/project_scrum/views/retrospective_views.xml
Executable file
@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<record id="retrospective_form_view_id" model="ir.ui.view">
|
||||
<field name="name">Retrospective</field>
|
||||
<field name="model">retrospective</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Retrospective">
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="retrospective_method_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="sprint_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
<field name="scrum_master" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
<field name="branch_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Retrospective Lines">
|
||||
<field name="retrospective_line_ids" widget="one2many_list"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="retrospective_tree_view_id" model="ir.ui.view">
|
||||
<field name="name">Retrospective</field>
|
||||
<field name="model">retrospective</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Retrospectives">
|
||||
<field name="retrospective_method_id"/>
|
||||
<field name="scrum_master"/>
|
||||
<field name="sprint_id"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_retrospective_tree_view_id" model="ir.actions.act_window">
|
||||
<field name="name">Retrospective</field>
|
||||
<field name="res_model">retrospective</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form,tree</field>
|
||||
<field name="view_id" ref="retrospective_tree_view_id"/>
|
||||
</record>
|
||||
|
||||
<record id="retrospective_lines_tree_view_id" model="ir.ui.view">
|
||||
<field name="name">Retrospective Line</field>
|
||||
<field name="model">retrospective.lines</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree editable="bottom">
|
||||
<field name="user_id"/>
|
||||
<field name="message"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
name="Retrospective"
|
||||
id="retrospective_id"
|
||||
parent="retrospective_menu_id"
|
||||
action="action_retrospective_tree_view_id"
|
||||
sequence="1"
|
||||
/>
|
||||
</flectra>
|