[ADD]: Project Scrum.

This commit is contained in:
Kunjal 2018-01-17 16:54:31 +05:30
parent 804e929e28
commit 88c85b8291
59 changed files with 8347 additions and 37 deletions

View File

@ -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>

View File

@ -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, [

View File

@ -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

View File

@ -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>

View File

@ -0,0 +1,4 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from . import models
from . import controllers

View 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,
}

View File

@ -0,0 +1,3 @@
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from . import backend

View 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

View 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>

View 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>

View 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 &amp; 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 &amp; 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>

View 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 &amp; 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>

View 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>

View 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>

View 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>

View 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>

View 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

View 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))

View 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")

View 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

View 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

View 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")

View 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')

View 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>

View 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>

View 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>

View 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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_project_sprint_user access_project_sprint_user model_project_sprint project.group_project_user 1 1 0 0
3 access_project_sprint_manager access_project_sprint_manager model_project_sprint project.group_project_manager 1 1 1 1
4
5 access_project_story_user access_project_story_user model_project_story project.group_project_user 1 1 0 0
6 access_project_story_manager access_project_story_manager model_project_story project.group_project_manager 1 1 1 1
7
8 access_project_team_user access_project_team_user model_project_team project.group_project_user 1 1 0 0
9 access_project_team_manager access_project_team_manager model_project_team project.group_project_manager 1 1 1 1
10
11 access_role_user access_role_user model_user_role project.group_project_user 1 0 0 0
12 access_role_manager access_role_manager model_user_role project.group_project_manager 1 1 1 1
13
14 access_sprint_planning_line_user access_sprint_planning_line_user model_sprint_planning_line project.group_project_user 1 0 0 0
15 access_sprint_planning_line_manager access_sprint_planning_line_manager model_sprint_planning_line project.group_project_manager 1 1 1 1
16
17 access_story_priority_user access_story_priority_user model_story_priority project.group_project_user 1 0 0 0
18 access_story_priority_manager access_story_priority_manager model_story_priority project.group_project_manager 1 1 1 1
19
20 access_story_type_user access_story_priority_user model_story_type project.group_project_user 1 0 0 0
21 access_story_type_manager access_story_priority_manager model_story_type project.group_project_manager 1 1 1 1
22
23 access_release_planning_user access_release_planning_user model_release_planning project.group_project_user 1 0 0 0
24 access_release_planning_manager access_release_planning_manager model_release_planning project.group_project_manager 1 1 1 1
25
26 access_retrospective_user access_retrospective_user model_retrospective project.group_project_user 1 1 0 0
27 access_retrospective_manager access_retrospective_manager model_retrospective project.group_project_manager 1 1 1 1
28
29 access_retrospective_method_user access_retrospective_method_user model_retrospective_method project.group_project_user 1 0 0 0
30 access_retrospective_method_manager access_retrospective_method_manager model_retrospective_method project.group_project_manager 1 1 1 1
31
32 access_retrospective_lines_user access_retrospective_lines_user model_retrospective_lines project.group_project_user 1 1 1 1
33 access_retrospective_lines_manager access_retrospective_lines_manager model_retrospective_lines project.group_project_manager 1 1 1 1
34
35 access_project_team_manager_res_users access_project_team_manager_res_users base.model_res_users project.group_project_manager 1 1 0 0
36 access_project_team_user_res_users access_project_team_user_res_users base.model_res_users project.group_project_user 1 1 0 0

View 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 &amp; 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View 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"

3739
addons/project_scrum/static/src/js/Chart.js vendored Executable file

File diff suppressed because it is too large Load Diff

View 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,
};
});

View 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;
}

View 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>

View 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

View 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']

View 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)

View 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)

View 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)

View 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)

View 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)

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>