[ADD]added project_scrum module
3
addons/project_scrum/__init__.py
Executable file
@@ -0,0 +1,3 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
||||
41
addons/project_scrum/__manifest__.py
Executable file
@@ -0,0 +1,41 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
'name': 'Project Scrum',
|
||||
'version': '2.0',
|
||||
'category': 'Project',
|
||||
'author': 'FlectraHQ',
|
||||
'website': 'https://flectrahq.com',
|
||||
'sequence': 40,
|
||||
'summary': 'A module for Scrum implementation',
|
||||
'depends': [
|
||||
'project', 'resource'
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'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/retrospective_method_views.xml',
|
||||
'views/retrospective_views.xml',
|
||||
'report/project_scrum_report.xml',
|
||||
'report/release_planning_template.xml',
|
||||
'report/project_sprint_template.xml',
|
||||
'data/sprint_sequence.xml',
|
||||
'data/project_sprint_data.xml',
|
||||
'data/project_task_sequence.xml',
|
||||
],
|
||||
'demo': [
|
||||
'demo/project_scrum_demo.xml',
|
||||
'demo/project_story_demo.xml',
|
||||
'demo/project_release_planning_demo.xml',
|
||||
'demo/retrospective_demo.xml',
|
||||
'demo/project_task_demo.xml',
|
||||
],
|
||||
'license': 'LGPL-3',
|
||||
'installable': True,
|
||||
'auto_install': False
|
||||
}
|
||||
88
addons/project_scrum/data/project_sprint_data.xml
Executable file
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- Sprint-related subtypes for messaging / Chatter -->
|
||||
<record id="state_sprint_draft" model="mail.message.subtype">
|
||||
<field name="name">Sprint Draft</field>
|
||||
<field name="res_model">project.sprint</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="description">Sprint Draft</field>
|
||||
</record>
|
||||
|
||||
<record id="state_sprint_in_progress" model="mail.message.subtype">
|
||||
<field name="name">Sprint In Progress</field>
|
||||
<field name="res_model">project.sprint</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="description">Sprint In Progress</field>
|
||||
</record>
|
||||
|
||||
<record id="state_sprint_pending" model="mail.message.subtype">
|
||||
<field name="name">Sprint Pending</field>
|
||||
<field name="res_model">project.sprint</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="description">Sprint Pending</field>
|
||||
</record>
|
||||
|
||||
<record id="state_sprint_done" model="mail.message.subtype">
|
||||
<field name="name">Sprint Done</field>
|
||||
<field name="res_model">project.sprint</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="description">Sprint Done</field>
|
||||
</record>
|
||||
|
||||
<record id="state_sprint_cancel" model="mail.message.subtype">
|
||||
<field name="name">Sprint Cancel</field>
|
||||
<field name="res_model">project.sprint</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="description">Sprint Cancel</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Project-related subtypes for messaging / Chatter -->
|
||||
<record id="state_project_sprint_draft" model="mail.message.subtype">
|
||||
<field name="name">Sprint Draft</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="res_model">project.team</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="parent_id" eval="ref('state_sprint_draft')"/>
|
||||
<field name="relation_field">team_id</field>
|
||||
</record>
|
||||
|
||||
<record id="state_project_sprint_in_progress" model="mail.message.subtype">
|
||||
<field name="name">Sprint In Progress</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="res_model">project.team</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="parent_id" eval="ref('state_sprint_in_progress')"/>
|
||||
<field name="relation_field">team_id</field>
|
||||
</record>
|
||||
|
||||
<record id="state_project_sprint_pending" model="mail.message.subtype">
|
||||
<field name="name">Sprint Pending</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="res_model">project.team</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="parent_id" eval="ref('state_sprint_pending')"/>
|
||||
<field name="relation_field">team_id</field>
|
||||
</record>
|
||||
|
||||
<record id="state_project_sprint_done" model="mail.message.subtype">
|
||||
<field name="name">Sprint Done</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="res_model">project.team</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="parent_id" eval="ref('state_sprint_done')"/>
|
||||
<field name="relation_field">team_id</field>
|
||||
</record>
|
||||
|
||||
<record id="state_project_sprint_cancel" model="mail.message.subtype">
|
||||
<field name="name">Sprint Cancel</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="res_model">project.team</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="parent_id" eval="ref('state_sprint_cancel')"/>
|
||||
<field name="relation_field">team_id</field>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
||||
13
addons/project_scrum/data/project_task_sequence.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data noupdate="1">
|
||||
<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="number_next">1</field>
|
||||
<field name="number_increment">1</field>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
||||
13
addons/project_scrum/data/sprint_sequence.xml
Executable file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data>
|
||||
<!-- Sequence for Sprint -->
|
||||
<record id="seq_sprint" model="ir.sequence">
|
||||
<field name="name">Sprints</field>
|
||||
<field name="code">project.sprint</field>
|
||||
<field name="prefix">SP</field>
|
||||
<field name="padding">3</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
||||
37
addons/project_scrum/demo/project_release_planning_demo.xml
Executable file
@@ -0,0 +1,37 @@
|
||||
<?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"/>
|
||||
</record>
|
||||
|
||||
<record id="release_planning_2" model="release.planning">
|
||||
<field name="name">Release of Design & Documentation</field>
|
||||
<field name="release_date" eval="DateTime.today() - relativedelta(days=3,hours=21,minutes=4,seconds=19)"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
</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"/>
|
||||
</record>
|
||||
|
||||
<record id="release_planning_4" model="release.planning">
|
||||
<field name="name">Release Mail Configuration & Improved Dashboard</field>
|
||||
<field name="release_date" eval="DateTime.today() - relativedelta(days=25,hours=23,minutes=6,seconds=34)"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_3"/>
|
||||
</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"/>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
||||
297
addons/project_scrum/demo/project_scrum_demo.xml
Executable file
@@ -0,0 +1,297 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flectra>
|
||||
<data noupdate="1">
|
||||
<!--
|
||||
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>
|
||||
<!--
|
||||
res.users Demo Data
|
||||
-->
|
||||
<record id="user_1" model="res.users">
|
||||
<field name="name">Chris Gardner</field>
|
||||
<field name="login">chris@demo.com</field>
|
||||
<field name="role_id" ref="project_scrum.user_role_1"/>
|
||||
</record>
|
||||
|
||||
<record id="user_2" model="res.users">
|
||||
<field name="name">Oskar Schindler</field>
|
||||
<field name="login">oskar@demo.com</field>
|
||||
<field name="role_id" ref="project_scrum.user_role_2"/>
|
||||
</record>
|
||||
|
||||
<record id="user_3" model="res.users">
|
||||
<field name="name">Andy Dufresne</field>
|
||||
<field name="login">andy@demo.com</field>
|
||||
<field name="role_id" ref="project_scrum.user_role_3"/>
|
||||
</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="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="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="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="strength">Technical, Functional</field>
|
||||
<field name="description">Description for the team...</field>
|
||||
</record>
|
||||
|
||||
<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>
|
||||
|
||||
<!--
|
||||
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="hour">11</field>
|
||||
<field name="time_zone">am</field>
|
||||
<field name="meeting_date" eval="(DateTime.today() - relativedelta(days=8))"/>
|
||||
<field name="productivity_hours">8.00</field>
|
||||
<field name="holiday_type">hours</field>
|
||||
<field name="holiday_count">1.00</field>
|
||||
</record>
|
||||
|
||||
<record id="project_sprint_2" model="project.sprint">
|
||||
<field name="project_id" ref="demo_project_1"/>
|
||||
<field name="name">Access Rights & Testing</field>
|
||||
<field name="state">in_progress</field>
|
||||
<field name="team_id" ref="project_scrum.project_team_2"/>
|
||||
<field name="start_date" eval="(DateTime.today() + relativedelta(days=8))"/>
|
||||
<field name="end_date" eval="(DateTime.today() + relativedelta(days=22))"/>
|
||||
<field name="goal_of_sprint">Access Rights Allocation</field>
|
||||
<field name="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="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="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="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>
|
||||
62
addons/project_scrum/demo/project_story_demo.xml
Executable file
@@ -0,0 +1,62 @@
|
||||
<?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="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="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="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>
|
||||
236
addons/project_scrum/demo/project_task_demo.xml
Executable file
@@ -0,0 +1,236 @@
|
||||
<?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">1</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=5)"/>
|
||||
<field name="company_id">1</field>
|
||||
<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">0</field>
|
||||
<field name="date_deadline" eval="DateTime.today()"/>
|
||||
<field name="company_id">1</field>
|
||||
<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">1</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=15)"/>
|
||||
<field name="company_id">1</field>
|
||||
<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">1</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=27)"/>
|
||||
<field name="company_id">1</field>
|
||||
<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">1</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=31)"/>
|
||||
<field name="company_id">1</field>
|
||||
<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">1</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=4)"/>
|
||||
<field name="company_id">1</field>
|
||||
<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">1</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=15)"/>
|
||||
<field name="company_id">1</field>
|
||||
<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">1</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=18)"/>
|
||||
<field name="company_id">1</field>
|
||||
<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">1</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=43)"/>
|
||||
<field name="company_id">1</field>
|
||||
<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">1</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=47)"/>
|
||||
<field name="company_id">1</field>
|
||||
<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">1</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=51)"/>
|
||||
<field name="company_id">1</field>
|
||||
<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">1</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=55)"/>
|
||||
<field name="company_id">1</field>
|
||||
<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">1</field>
|
||||
<field name="date_deadline" eval="DateTime.today() + relativedelta(days=58)"/>
|
||||
<field name="company_id">1</field>
|
||||
<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>
|
||||
60
addons/project_scrum/demo/retrospective_demo.xml
Executable file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flectra>
|
||||
<data noupdate="1">
|
||||
<!--
|
||||
retrospective.method Demo Data
|
||||
-->
|
||||
<record id="retrospective_method_1" model="retrospective.method">
|
||||
<field name="name">Went Well</field>
|
||||
<field name="description">Whatever we developed or improved, it went well</field>
|
||||
</record>
|
||||
<record id="retrospective_method_2" model="retrospective.method">
|
||||
<field name="name">Needs Improvement</field>
|
||||
<field name="description">We have found some some tasks or ideas, which needs improvements</field>
|
||||
</record>
|
||||
<record id="retrospective_method_3" model="retrospective.method">
|
||||
<field name="name">Stop</field>
|
||||
<field name="description">Now Stop Working of worthless task and go through new ideas we found.</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
retrospective Demo Data
|
||||
-->
|
||||
<record id="retrospective_1" model="retrospective">
|
||||
<field name="name">Sprint Module Retrospective</field>
|
||||
<field name="retrospective_method_id" ref="project_scrum.retrospective_method_1"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
</record>
|
||||
|
||||
<record id="retrospective_2" model="retrospective">
|
||||
<field name="name">Scrum Documentation Retrospective</field>
|
||||
<field name="retrospective_method_id" ref="project_scrum.retrospective_method_2"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_1"/>
|
||||
</record>
|
||||
|
||||
<record id="retrospective_3" model="retrospective">
|
||||
<field name="name">Access Right Retrospective</field>
|
||||
<field name="retrospective_method_id" ref="project_scrum.retrospective_method_2"/>
|
||||
<field name="sprint_id" ref="project_scrum.project_sprint_2"/>
|
||||
</record>
|
||||
|
||||
|
||||
<!--
|
||||
retrospective.lines Demo Data
|
||||
-->
|
||||
<record id="retrospective_line_1" model="retrospective.lines">
|
||||
<field name="message">Tasks have been done well.</field>
|
||||
<field name="retrospective_id" ref="project_scrum.retrospective_1"/>
|
||||
</record>
|
||||
|
||||
<record id="retrospective_line_2" model="retrospective.lines">
|
||||
<field name="message">Add new description as per new added modules.</field>
|
||||
<field name="retrospective_id" ref="project_scrum.retrospective_2"/>
|
||||
</record>
|
||||
|
||||
<record id="retrospective_line_3" model="retrospective.lines">
|
||||
<field name="message">Implement New Access Rights according to the new modules added</field>
|
||||
<field name="retrospective_id" ref="project_scrum.retrospective_3"/>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
||||
1071
addons/project_scrum/i18n/de.po
Normal file
1069
addons/project_scrum/i18n/project_scrum.pot
Normal file
1075
addons/project_scrum/i18n/ru.po
Normal file
8
addons/project_scrum/models/__init__.py
Executable file
@@ -0,0 +1,8 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import project_sprint
|
||||
from . import project_story
|
||||
from . import project_team
|
||||
from . import release_planning
|
||||
from . import retrospective_method
|
||||
from . import retrospective
|
||||
653
addons/project_scrum/models/project_sprint.py
Executable file
@@ -0,0 +1,653 @@
|
||||
# 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, date
|
||||
|
||||
|
||||
class ProjectSprint(models.Model):
|
||||
_name = "project.sprint"
|
||||
_inherit = '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,
|
||||
tracking=True)
|
||||
goal_of_sprint = fields.Char("Goal of Sprint", tracking=True)
|
||||
|
||||
meeting_date = fields.Datetime("Planning Meeting Date", required=True,
|
||||
tracking=True)
|
||||
hour = fields.Float(string="Hour", tracking=True)
|
||||
time_zone = fields.Selection([
|
||||
('am', 'AM'),
|
||||
('pm', 'PM'),
|
||||
], tracking=True)
|
||||
estimated_velocity = fields.Integer(
|
||||
compute="_compute_calculate_estimated_velocity", string="Estimated Velocity",
|
||||
store=True, tracking=True)
|
||||
actual_velocity = fields.Integer(
|
||||
compute="_compute_calculate_actual_velocity", string="Actual Velocity",
|
||||
store=True, tracking=True)
|
||||
sprint_planning_line = fields.One2many(
|
||||
'sprint.planning.line', 'sprint_id', string="Sprint Planning Lines")
|
||||
project_id = fields.Many2one('project.project', string="Project",
|
||||
tracking=True)
|
||||
start_date = fields.Date(string="Start Date", tracking=True)
|
||||
end_date = fields.Date(string="End Date", tracking=True)
|
||||
working_days = fields.Integer(
|
||||
compute="_compute_calculate_business_days", string="Business Days",
|
||||
store=True, tracking=True)
|
||||
productivity_hours = fields.Float(string="Productivity Hours",
|
||||
tracking=True)
|
||||
productivity_per = fields.Float(
|
||||
compute="_compute_calculate_productivity_per", string="Productivity (%)",
|
||||
store=True, tracking=True)
|
||||
holiday_type = fields.Selection(
|
||||
[('hours', 'Hours'), ('days', 'Days')],
|
||||
string="Holiday (Hours / Days)", default='hours',
|
||||
tracking=True)
|
||||
holiday_count = fields.Float(string="Holiday Count",
|
||||
tracking=True)
|
||||
holiday_days = fields.Float(
|
||||
compute="_compute_calculate_holiday_days", string="Holiday Days", store=True,
|
||||
tracking=True)
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
('in_progress', 'In Progress'),
|
||||
('pending', 'Pending'),
|
||||
('done', 'Done'),
|
||||
('cancel', 'Cancel')], string="State", default='draft',
|
||||
tracking=True)
|
||||
team_id = fields.Many2one('project.team', string="Team",
|
||||
tracking=True, required=True)
|
||||
task_line = fields.One2many('project.task', 'sprint_id', string='Tasks')
|
||||
color = fields.Integer('Color Index')
|
||||
task_count = fields.Integer(compute='_compute_task_count', store=True)
|
||||
|
||||
@api.depends("task_line")
|
||||
def _compute_task_count(self):
|
||||
for record in self:
|
||||
record.task_count = len(record.task_line)
|
||||
|
||||
duration = fields.Integer(
|
||||
"Duration (In Days)", compute='_compute_days_calculate', store=True,
|
||||
tracking=True)
|
||||
|
||||
@api.depends("start_date")
|
||||
def _compute_days_calculate(self):
|
||||
for days in self:
|
||||
if days.start_date and days.end_date:
|
||||
diff = datetime.strptime(
|
||||
str(days.end_date), '%Y-%m-%d').date() - datetime.strptime(
|
||||
str(days.start_date), '%Y-%m-%d').date()
|
||||
days.duration = diff.days
|
||||
|
||||
def _compute_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="_compute_get_task_count")
|
||||
|
||||
def _compute_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="_compute_get_story_count")
|
||||
|
||||
def _compute_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="_compute_get_retrospective_count")
|
||||
|
||||
@api.depends('task_line', 'task_line.stage_id', 'task_line.sprint_id',
|
||||
'estimated_velocity', 'start_date', 'end_date', 'project_id',
|
||||
'team_id')
|
||||
def _compute_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="_compute_calculate_tasks_json", store=True)
|
||||
|
||||
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
|
||||
|
||||
def set_state_open(self):
|
||||
self.state = 'in_progress'
|
||||
|
||||
def set_state_cancel(self):
|
||||
self.state = 'cancel'
|
||||
|
||||
def set_state_pending(self):
|
||||
self.state = 'pending'
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
def action_view_tasks(self):
|
||||
return self.redirect_to_view("project.task", "Tasks")
|
||||
|
||||
def action_view_stories(self):
|
||||
return self.redirect_to_view("project.story", "Stories")
|
||||
|
||||
def action_view_release_planning(self):
|
||||
return self.redirect_to_view("release.planning", "Release Planning")
|
||||
|
||||
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.depends('project_id', 'project_id.no_of_days', 'start_date',
|
||||
'end_date')
|
||||
def _compute_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(str(record.start_date), "%Y-%m-%d").date()
|
||||
end = datetime.strptime(str(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.depends('project_id', 'project_id.no_of_hours', 'productivity_hours')
|
||||
def _compute_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.depends('project_id', 'project_id.no_of_hours', 'holiday_count')
|
||||
def _compute_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.depends('project_id', 'task_line', 'task_line.velocity')
|
||||
def _compute_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.depends('project_id', 'end_date', 'task_line', 'task_line.velocity',
|
||||
'task_line.stage_id')
|
||||
def _compute_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(
|
||||
str(self.start_date), '%Y-%m-%d') + timedelta(days=self.duration)
|
||||
self.end_date = end_date
|
||||
|
||||
def check_sprint_state(self):
|
||||
for record in self.search([('state', '!=', 'done')]):
|
||||
if record.end_date and record.end_date < fields.Date.today():
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
def _track_subtype(self, init_values):
|
||||
self.ensure_one()
|
||||
if 'state' in init_values and self.state == 'draft':
|
||||
return self.env.ref('project_scrum.state_sprint_draft')
|
||||
elif 'state' in init_values and self.state == 'in_progress':
|
||||
return self.env.ref('project_scrum.state_sprint_in_progress')
|
||||
elif 'state' in init_values and self.state == 'pending':
|
||||
return self.env.ref('project_scrum.state_sprint_pending')
|
||||
elif 'state' in init_values and self.state == 'done':
|
||||
return self.env.ref('project_scrum.state_sprint_done')
|
||||
elif 'state' in init_values and self.state == 'cancel':
|
||||
return self.env.ref('project_scrum.state_sprint_cancel')
|
||||
return super(ProjectSprint, self)._track_subtype(init_values)
|
||||
|
||||
|
||||
class Project(models.Model):
|
||||
_inherit = "project.project"
|
||||
|
||||
def _compute_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="_compute_sprint_count", string="No. of sprints related to")
|
||||
|
||||
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.depends('available_per', 'sprint_id.project_id',
|
||||
'sprint_id.project_id.no_of_hours',
|
||||
'sprint_id', 'sprint_id.working_days')
|
||||
def _compute_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.depends('sprint_id', 'available_per', 'sprint_id.working_days',
|
||||
'sprint_id.productivity_hours')
|
||||
def _compute_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.depends('sprint_id', 'sprint_id.holiday_count',
|
||||
'sprint_id.holiday_days', 'sprint_hours', 'off_hours')
|
||||
def _compute_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="_compute_calculate_hours", string="Productivity Hour(s)", store=True)
|
||||
sprint_hours = fields.Float(
|
||||
compute="_compute_calculate_sprint_hours", string="Sprint Hour(s)", store=True)
|
||||
off_hours = fields.Float(string="Off Hour(s)")
|
||||
total_hours = fields.Float(
|
||||
compute="_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", tracking=True)
|
||||
velocity = fields.Integer(string="Velocity", tracking=True)
|
||||
story_id = fields.Many2one(
|
||||
'project.story', string="Story", tracking=True)
|
||||
release_planning_id = fields.Many2one(
|
||||
"release.planning", string="Release Planning",
|
||||
tracking=True)
|
||||
start_date = fields.Date(string="Start Date", tracking=True)
|
||||
end_date = fields.Date(string="End Date", tracking=True)
|
||||
actual_end_date = fields.Date(
|
||||
compute='_compute_calculate_actual_end_date', string="Actual End Date",
|
||||
store=True, tracking=True
|
||||
)
|
||||
task_seq = fields.Char(
|
||||
string="Reference", tracking=True,
|
||||
default=lambda self: self.env['ir.sequence'].next_by_code(
|
||||
'project.task') or '/')
|
||||
|
||||
@api.depends('stage_id')
|
||||
def _compute_calculate_actual_end_date(self):
|
||||
for stage in self:
|
||||
if stage.stage_id.name == 'Done':
|
||||
stage.actual_end_date = date.today()
|
||||
|
||||
@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
|
||||
|
||||
def write(self, vals):
|
||||
res = super(ProjectTask, self).write(vals)
|
||||
if len(self._ids) == 0:
|
||||
if self.task_seq == '/':
|
||||
vals['task_seq'] = self.env['ir.sequence'].next_by_code(
|
||||
'project.task')
|
||||
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.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))
|
||||
153
addons/project_scrum/models/project_story.py
Executable file
@@ -0,0 +1,153 @@
|
||||
# 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 = 'mail.thread'
|
||||
_description = "Project Story"
|
||||
_order = "sprint_seq,sequence"
|
||||
|
||||
name = fields.Char("Title", required=True, tracking=True)
|
||||
priority_id = fields.Many2one('story.priority', string="Priority",
|
||||
tracking=True)
|
||||
story_type_id = fields.Many2one('story.type', string="Type",
|
||||
tracking=True)
|
||||
tags = fields.Char("Tags", tracking=True)
|
||||
description = fields.Text("Description", tracking=True)
|
||||
owner_id = fields.Many2one(
|
||||
'res.users', string="Owner", default=lambda self: self.env.user.id,
|
||||
tracking=True)
|
||||
sprint_id = fields.Many2one('project.sprint', string="Sprint",
|
||||
tracking=True)
|
||||
estimated_velocity = fields.Integer(
|
||||
compute="_compute_calculate_estimated_velocity", string="Estimated Velocity",
|
||||
store=True, tracking=True)
|
||||
actual_velocity = fields.Integer(
|
||||
compute="_compute_calculate_actual_velocity", string="Actual Velocity",
|
||||
store=True, tracking=True)
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
('in_progress', 'In Progress'),
|
||||
('cancel', 'Cancel'),
|
||||
('done', 'Done'),
|
||||
], string="states", tracking=True, default="draft")
|
||||
sequence = fields.Integer(string='Sequence', default=1)
|
||||
sprint_seq = fields.Char(
|
||||
related="sprint_id.sprint_seq", string="Reference", readonly=True)
|
||||
|
||||
def set_state_active(self):
|
||||
self.state = "in_progress"
|
||||
|
||||
def set_state_cancel(self):
|
||||
self.state = "cancel"
|
||||
|
||||
def set_state_done(self):
|
||||
self.state = "done"
|
||||
|
||||
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.depends('sprint_id')
|
||||
def _compute_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.depends('sprint_id', 'sprint_id.end_date')
|
||||
def _compute_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.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
|
||||
|
||||
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", tracking=True)
|
||||
code = fields.Char("Code", tracking=True)
|
||||
|
||||
|
||||
class StoryType(models.Model):
|
||||
_name = "story.type"
|
||||
_inherit = 'mail.thread'
|
||||
|
||||
name = fields.Char("Name", tracking=True)
|
||||
code = fields.Char("Code", tracking=True)
|
||||
18
addons/project_scrum/models/project_team.py
Executable file
@@ -0,0 +1,18 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra import models, fields
|
||||
|
||||
|
||||
class ProjectTeam(models.Model):
|
||||
_name = "project.team"
|
||||
_inherit = 'mail.thread'
|
||||
_description = "Project Team"
|
||||
|
||||
name = fields.Char("Team Name", required=True, tracking=True)
|
||||
strength = fields.Text("Team Strength", tracking=True)
|
||||
member_ids = fields.Many2many("res.users", string="Members")
|
||||
master_id = fields.Many2one(
|
||||
"res.users", string="Scrum Master", tracking=True)
|
||||
description = fields.Html()
|
||||
project_id = fields.Many2one(
|
||||
'project.project', string="Project", tracking=True)
|
||||
24
addons/project_scrum/models/release_planning.py
Executable file
@@ -0,0 +1,24 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra import models, fields
|
||||
|
||||
|
||||
class ReleasePlanning(models.Model):
|
||||
_name = "release.planning"
|
||||
_inherit = 'mail.thread'
|
||||
|
||||
name = fields.Char(string="Planning Name", tracking=True)
|
||||
release_date = fields.Datetime(
|
||||
string="Release Date", tracking=True)
|
||||
sprint_id = fields.Many2one(
|
||||
'project.sprint', string="Sprint", tracking=True)
|
||||
priority = fields.Selection([
|
||||
('low', 'Low'),
|
||||
('medium', 'Medium'),
|
||||
('high', 'High')], string="Priority", default='low',
|
||||
tracking=True)
|
||||
velocity = fields.Integer(
|
||||
related="sprint_id.estimated_velocity", string="Sprint Velocity",
|
||||
tracking=True, store=True)
|
||||
task_id = fields.One2many(
|
||||
"project.task", "release_planning_id", string="Task")
|
||||
37
addons/project_scrum/models/retrospective.py
Executable file
@@ -0,0 +1,37 @@
|
||||
# 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 = 'mail.thread'
|
||||
|
||||
name = fields.Char(string="Retrospective Name", required=True,
|
||||
tracking=True)
|
||||
retrospective_method_id = fields.Many2one(
|
||||
"retrospective.method", string="Retrospective Method",
|
||||
tracking=True)
|
||||
scrum_master = fields.Many2one("res.users", string="Scrum Master",
|
||||
tracking=True)
|
||||
sprint_id = fields.Many2one(
|
||||
"project.sprint", string="Sprint", tracking=True)
|
||||
retrospective_line_ids = fields.One2many(
|
||||
"retrospective.lines", "retrospective_id",
|
||||
string="Retrospective Lines", tracking=True)
|
||||
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
|
||||
|
||||
|
||||
class RetrospectiveLines(models.Model):
|
||||
_name = "retrospective.lines"
|
||||
|
||||
user_id = fields.Many2one("res.users", string="User", readonly=True,
|
||||
required=True,
|
||||
default=lambda self: self.env.user)
|
||||
message = fields.Text(string="Message")
|
||||
retrospective_id = fields.Many2one("retrospective", string="Retrospective")
|
||||
15
addons/project_scrum/models/retrospective_method.py
Executable file
@@ -0,0 +1,15 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra import models, fields
|
||||
|
||||
|
||||
class RetrospectiveMethod(models.Model):
|
||||
_name = "retrospective.method"
|
||||
_inherit = 'mail.thread'
|
||||
_description = "Retrospective Implementation for Project Scrum"
|
||||
|
||||
name = fields.Char(
|
||||
string="Method Name", required=True, tracking=True)
|
||||
|
||||
description = fields.Text(
|
||||
string="Description", tracking=True)
|
||||
26
addons/project_scrum/report/project_scrum_report.xml
Executable file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data>
|
||||
<record id="release_planning_report" model="ir.actions.report">
|
||||
<field name="name">Release Planning Report</field>
|
||||
<field name="model">release.planning</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">project_scrum.release_planning_template_id</field>
|
||||
<field name="report_file">project_scrum.release_planning_template_id</field>
|
||||
<field name="print_report_name">'Release Planning Report - %s' % (object.name)</field>
|
||||
<field name="binding_model_id" ref="model_release_planning"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
|
||||
<record id="project_sprint_report" model="ir.actions.report">
|
||||
<field name="name">Project Sprint Report</field>
|
||||
<field name="model">project.sprint</field>
|
||||
<field name="report_type">qweb-pdf</field>
|
||||
<field name="report_name">project_scrum.project_sprint_template_id</field>
|
||||
<field name="report_file">project_scrum.project_sprint_template_id</field>
|
||||
<field name="print_report_name">'Project Sprint Report - %s' % (object.name)</field>
|
||||
<field name="binding_model_id" ref="model_project_sprint"/>
|
||||
<field name="binding_type">report</field>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
||||
134
addons/project_scrum/report/project_sprint_template.xml
Executable file
@@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data>
|
||||
<template id="project_sprint_template_id">
|
||||
<t t-call="web.html_container">
|
||||
<t t-call="web.external_layout">
|
||||
<div class="page" t-foreach="docs" t-as="object" style="page-break-after: always;">
|
||||
<div class="oe_structure"/>
|
||||
<div class="row">
|
||||
<div class="col-6 col-md-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-6 col-md-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>
|
||||
97
addons/project_scrum/report/release_planning_template.xml
Executable file
@@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data>
|
||||
<template id="release_planning_template_id">
|
||||
<t t-call="web.html_container">
|
||||
<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>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.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>
|
||||
</t>
|
||||
</template>
|
||||
</data>
|
||||
</flectra>
|
||||
36
addons/project_scrum/security/ir.model.access.csv
Executable file
@@ -0,0 +1,36 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_project_sprint_user,access_project_sprint_user,model_project_sprint,project.group_project_user,1,1,0,0
|
||||
access_project_sprint_manager,access_project_sprint_manager,model_project_sprint,project.group_project_manager,1,1,1,1
|
||||
|
||||
access_project_story_user,access_project_story_user,model_project_story,project.group_project_user,1,1,0,0
|
||||
access_project_story_manager,access_project_story_manager,model_project_story,project.group_project_manager,1,1,1,1
|
||||
|
||||
access_project_team_user,access_project_team_user,model_project_team,project.group_project_user,1,1,0,0
|
||||
access_project_team_manager,access_project_team_manager,model_project_team,project.group_project_manager,1,1,1,1
|
||||
|
||||
access_role_user,access_role_user,model_user_role,project.group_project_user,1,0,0,0
|
||||
access_role_manager,access_role_manager,model_user_role,project.group_project_manager,1,1,1,1
|
||||
|
||||
access_sprint_planning_line_user,access_sprint_planning_line_user,model_sprint_planning_line,project.group_project_user,1,0,0,0
|
||||
access_sprint_planning_line_manager,access_sprint_planning_line_manager,model_sprint_planning_line,project.group_project_manager,1,1,1,1
|
||||
|
||||
access_story_priority_user,access_story_priority_user,model_story_priority,project.group_project_user,1,0,0,0
|
||||
access_story_priority_manager,access_story_priority_manager,model_story_priority,project.group_project_manager,1,1,1,1
|
||||
|
||||
access_story_type_user,access_story_type_user,model_story_type,project.group_project_user,1,0,0,0
|
||||
access_story_type_manager,access_story_type_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
|
||||
|
BIN
addons/project_scrum/static/description/dashboard_bottom.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
addons/project_scrum/static/description/dashboard_top.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
addons/project_scrum/static/description/icon.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
108
addons/project_scrum/static/description/index.html
Normal file
@@ -0,0 +1,108 @@
|
||||
<section class="container">
|
||||
<div class="row oe_spaced">
|
||||
<div class="col-md-12">
|
||||
<h2 class="oe_slogan">Project Scrum</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="container bg-gray-lighter">
|
||||
<div class="row oe_spaced mt0">
|
||||
<div class="col-md-12">
|
||||
<h3 class="oe_slogan">Sprint</h3>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p class="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">
|
||||
<img src="sprint_scrum.png" width="100%" alt="Sprint"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="container">
|
||||
<div class="row oe_spaced mt0">
|
||||
<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">
|
||||
<img src="release_scrum.png" alt="Release Planning"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p class="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>
|
||||
</section>
|
||||
|
||||
<section class="container bg-gray-lighter">
|
||||
<div class="row oe_spaced mt0">
|
||||
<div class="col-md-12">
|
||||
<h3 class="oe_slogan">Story</h3>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p class="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">
|
||||
<img src="story_scrum.png" alt="Story"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="container">
|
||||
<div class="row oe_spaced mt0">
|
||||
<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">
|
||||
<img src="team_scrum.png" alt="Team"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p class="text-justify" style="font-size: 15px;">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="container bg-gray-lighter">
|
||||
<div class="row oe_spaced mt0">
|
||||
<div class="col-md-12">
|
||||
<h3 class="oe_slogan">Retrospective</h3>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<p class="text-justify" style="font-size: 15px;">
|
||||
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.
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="oe_demo oe_picture oe_screenshot">
|
||||
<img src="retro_scrum.png" alt="Retrospective"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
BIN
addons/project_scrum/static/description/release_scrum.png
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
addons/project_scrum/static/description/retro_scrum.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
addons/project_scrum/static/description/sprint_scrum.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
addons/project_scrum/static/description/story_scrum.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
addons/project_scrum/static/description/team_scrum.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
8
addons/project_scrum/tests/__init__.py
Executable file
@@ -0,0 +1,8 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from .test_scrum_common import TestScrumCommon
|
||||
from .test_scrum_team import TestScrumTeam
|
||||
from .test_scrum_sprint import TestScrumSprint
|
||||
from .test_scrum_task import TestScrumTask
|
||||
from .test_scrum_release_planning import TestScrumReleasePlanning
|
||||
from .test_scrum_story import TestScrumStory
|
||||
79
addons/project_scrum/tests/test_scrum_common.py
Normal file
@@ -0,0 +1,79 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra.tests import common
|
||||
|
||||
|
||||
class TestScrumCommon(common.SavepointCase):
|
||||
def setUp(self):
|
||||
super(TestScrumCommon, self).setUp()
|
||||
|
||||
self.teams = [
|
||||
self.env.ref('project_scrum.project_team_1'),
|
||||
self.env.ref('project_scrum.project_team_2'),
|
||||
self.env.ref('project_scrum.project_team_3')
|
||||
]
|
||||
|
||||
self.user_roles = [
|
||||
self.env.ref('project_scrum.user_role_1'),
|
||||
self.env.ref('project_scrum.user_role_2'),
|
||||
self.env.ref('project_scrum.user_role_3')
|
||||
]
|
||||
|
||||
self.sprints = [
|
||||
self.env.ref('project_scrum.project_sprint_1'),
|
||||
self.env.ref('project_scrum.project_sprint_2'),
|
||||
self.env.ref('project_scrum.project_sprint_3'),
|
||||
self.env.ref('project_scrum.project_sprint_4'),
|
||||
self.env.ref('project_scrum.project_sprint_5')
|
||||
]
|
||||
|
||||
self.project_tasks = [
|
||||
self.env.ref('project_scrum.project_task_1'),
|
||||
self.env.ref('project_scrum.project_task_2'),
|
||||
self.env.ref('project_scrum.project_task_3'),
|
||||
self.env.ref('project_scrum.project_task_4'),
|
||||
self.env.ref('project_scrum.project_task_6'),
|
||||
self.env.ref('project_scrum.project_task_7'),
|
||||
self.env.ref('project_scrum.project_task_8'),
|
||||
self.env.ref('project_scrum.project_task_9'),
|
||||
self.env.ref('project_scrum.project_task_10'),
|
||||
self.env.ref('project_scrum.project_task_11'),
|
||||
self.env.ref('project_scrum.project_task_12'),
|
||||
self.env.ref('project_scrum.project_task_13'),
|
||||
self.env.ref('project_scrum.project_task_14')
|
||||
]
|
||||
|
||||
self.users = [
|
||||
self.env.ref('project_scrum.user_1'),
|
||||
self.env.ref('project_scrum.user_2'),
|
||||
self.env.ref('project_scrum.user_3')
|
||||
]
|
||||
|
||||
self.release_plans = [
|
||||
self.env.ref('project_scrum.release_planning_1'),
|
||||
self.env.ref('project_scrum.release_planning_2'),
|
||||
self.env.ref('project_scrum.release_planning_3'),
|
||||
self.env.ref('project_scrum.release_planning_4'),
|
||||
self.env.ref('project_scrum.release_planning_5')
|
||||
]
|
||||
|
||||
self.story_priorities = [
|
||||
self.env.ref('project_scrum.story_priority_1'),
|
||||
self.env.ref('project_scrum.story_priority_2'),
|
||||
self.env.ref('project_scrum.story_priority_3')
|
||||
]
|
||||
|
||||
self.story_types = [
|
||||
self.env.ref('project_scrum.story_type_1'),
|
||||
self.env.ref('project_scrum.story_type_2')
|
||||
]
|
||||
|
||||
self.stories = [
|
||||
self.env.ref('project_scrum.project_story_1'),
|
||||
self.env.ref('project_scrum.project_story_2'),
|
||||
self.env.ref('project_scrum.project_story_3')
|
||||
]
|
||||
|
||||
self.project = self.env.ref('project_scrum.demo_project_1')
|
||||
|
||||
self.sprint_planning_line = self.env['sprint.planning.line']
|
||||
22
addons/project_scrum/tests/test_scrum_release_planning.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# 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(' Priority : %s' % plan.priority)
|
||||
info(' Sprint Velocity : %s' % plan.velocity)
|
||||
62
addons/project_scrum/tests/test_scrum_sprint.py
Normal file
@@ -0,0 +1,62 @@
|
||||
# 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(' 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)
|
||||
56
addons/project_scrum/tests/test_scrum_story.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# 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 typ in types:
|
||||
info(' %s : %s' % (typ.code, typ.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(' 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)
|
||||
42
addons/project_scrum/tests/test_scrum_task.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# 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(' 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)
|
||||
30
addons/project_scrum/tests/test_scrum_team.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# 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)
|
||||
13
addons/project_scrum/views/cron_view.xml
Executable file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<record id="cron_check_sprint_state" model="ir.cron">
|
||||
<field name="name">Sprint State</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="model_id" ref="project_scrum.model_project_sprint"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.check_sprint_state()</field>
|
||||
<field name="active" eval="False"/>
|
||||
</record>
|
||||
</flectra>
|
||||
155
addons/project_scrum/views/other_views.xml
Executable file
@@ -0,0 +1,155 @@
|
||||
<?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="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="//page[@name='access_rights']" position="inside">
|
||||
<group string="User Role">
|
||||
<field name="role_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</group>
|
||||
</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 name="task_seq"/>
|
||||
</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="partner_id" position="replace">
|
||||
<field name="partner_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
<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}"/>
|
||||
</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='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="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>
|
||||
320
addons/project_scrum/views/project_sprint_views.xml
Executable file
@@ -0,0 +1,320 @@
|
||||
<?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="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="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"/>
|
||||
<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'}"/>
|
||||
</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 string="Scrum Kanban"
|
||||
class="o_emphasize_colors o_kanban_dashboard oe_background_grey o_kanban_dashboard o_account_kanban o_slide_kanban breadcrumb_item active"
|
||||
edit="false">
|
||||
<field name="color"/>
|
||||
<field name="task_line"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div t-attf-class="#{kanban_color(0)} oe_kanban_global_click ">
|
||||
<div class="o_kanban_card_header">
|
||||
<div class="o_kanban_card_header_title mb16">
|
||||
<div class="o_primary">
|
||||
<a type="edit" class="mr-auto">
|
||||
<field name="name" class="o_primary"/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container o_kanban_card_content mt0">
|
||||
<div class="row mb16">
|
||||
<div class="col-12 o_kanban_primary_right">
|
||||
<div class="d-flex">
|
||||
<span class="mr-auto mb0">
|
||||
Start Date
|
||||
</span>
|
||||
<field name="start_date"/>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<span class="mr-auto mb0">
|
||||
End Date
|
||||
</span>
|
||||
<field name="end_date"/>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<span class="mr-auto mb0">
|
||||
Estimated Velocity
|
||||
</span>
|
||||
<field name="estimated_velocity"/>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<span class="mr-auto mb0">
|
||||
Duration
|
||||
</span>
|
||||
<field name="duration"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a name="action_view_tasks" type="object">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_value">
|
||||
<field name="task_count"/>
|
||||
</span>
|
||||
<span name="total_slides_label" class="o_stat_text">Tasks</span>
|
||||
</div>
|
||||
</a>
|
||||
</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_mode">kanban,tree,form,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_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>
|
||||
262
addons/project_scrum/views/project_story_views.xml
Executable file
@@ -0,0 +1,262 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<record id="view_project_story_form" model="ir.ui.view">
|
||||
<field name="name">project.story.form</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>
|
||||
<h3 class="o_row">
|
||||
<field name="name" placeholder="As a <role> I can <capability>, so that <receive benefit>"/>
|
||||
</h3>
|
||||
</div>
|
||||
<group name="story_main_fields" col="4">
|
||||
<field name="sprint_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.tree</field>
|
||||
<field name="model">project.story</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Project Story">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="owner_id"/>
|
||||
<field name="sprint_id"/>
|
||||
<field name="priority_id"/>
|
||||
<field name="story_type_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_project_story_kanban" model="ir.ui.view">
|
||||
<field name="name">view.project.story.kanban</field>
|
||||
<field name="model">project.story</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="sprint_id">
|
||||
<field name="name"/>
|
||||
<field name="sprint_id"/>
|
||||
<field name="owner_id"/>
|
||||
<field name="priority_id"/>
|
||||
<field name="story_type_id"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div class="oe_kanban_global_click">
|
||||
<div class="o_dropdown_kanban dropdown">
|
||||
<a role="button" class="dropdown-toggle btn" data-toggle="dropdown" href="#">
|
||||
<span class="fa fa-ellipsis-v" title="Options for kanban view"/>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
|
||||
<t t-if="widget.editable">
|
||||
<li>
|
||||
<a type="edit">Edit</a>
|
||||
</li>
|
||||
</t>
|
||||
<t t-if="widget.deletable">
|
||||
<li>
|
||||
<a type="delete">Delete</a>
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="o_kanban_card_header">
|
||||
<div class="o_kanban_card_header_title mb16">
|
||||
<div class="o_primary">
|
||||
<t t-esc="record.name.value"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container o_kanban_card_content">
|
||||
<div class="row">
|
||||
<div class="col-xs-6 o_kanban_primary_left">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="o_kanban_record_bottom">
|
||||
<div class="oe_kanban_bottom_left">
|
||||
<span t-if="record.priority_id.raw_value"
|
||||
class="small text-muted"><t t-esc="record.priority_id.value"/></span>
|
||||
<span t-if="record.priority_id.raw_value and record.story_type_id.raw_value"
|
||||
class="small text-muted">|</span>
|
||||
<span t-if="record.story_type_id.raw_value"
|
||||
class="small text-muted"><t t-esc="record.story_type_id.value"/></span>
|
||||
</div>
|
||||
<div class="oe_kanban_bottom_right">
|
||||
<img t-att-src="kanban_image('res.users', 'image_small', record.owner_id.raw_value)"
|
||||
t-att-title="record.owner_id.value" width="24" height="24" class="oe_kanban_avatar"
|
||||
alt="Image"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_project_story_search" model="ir.ui.view">
|
||||
<field name="name">project.story.search</field>
|
||||
<field name="model">project.story</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Story">
|
||||
<field name="name"/>
|
||||
<field name="sprint_id"/>
|
||||
<!-- <filter string="Product Backlog" domain="[('sprint_id', '=', False)]"/>-->
|
||||
<filter string="Sprint" name="group_by_sprint" context="{'group_by': 'sprint_id'}"/>
|
||||
<filter string="Owner" name="group_by_owner" context="{'group_by': 'owner_id'}"/>
|
||||
<filter string="Priority" name="group_by_priority" context="{'group_by': 'priority_id'}"/>
|
||||
<filter string="Type" name="group_by_type" context="{'group_by': 'story_type_id'}"/>
|
||||
</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_mode">tree,kanban,form</field>
|
||||
<field name="view_id" ref="view_project_story_tree"/>
|
||||
<field name="search_view_id" ref="view_project_story_search"/>
|
||||
</record>
|
||||
<record id="open_view_project_story_sprint_kanban" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="0"/>
|
||||
<field name="view_mode">kanban</field>
|
||||
<field name="act_window_id" ref="action_project_story_sprint"/>
|
||||
</record>
|
||||
<record id="open_view_project_story_sprint_tree" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="act_window_id" ref="action_project_story_sprint"/>
|
||||
</record>
|
||||
<record id="open_view_project_story_sprint_form" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="2"/>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="act_window_id" ref="action_project_story_sprint"/>
|
||||
</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_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_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>
|
||||
58
addons/project_scrum/views/project_team_views.xml
Executable file
@@ -0,0 +1,58 @@
|
||||
<?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)]"/>
|
||||
</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="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_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>
|
||||
69
addons/project_scrum/views/release_planning_views.xml
Executable file
@@ -0,0 +1,69 @@
|
||||
<?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="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="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_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>
|
||||
54
addons/project_scrum/views/retrospective_method_views.xml
Executable file
@@ -0,0 +1,54 @@
|
||||
<?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_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>
|
||||
75
addons/project_scrum/views/retrospective_views.xml
Executable file
@@ -0,0 +1,75 @@
|
||||
<?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}"/>
|
||||
</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="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_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>
|
||||