~technofluid-team/openobject-addons/technofluid_multiple_installations

« back to all changes in this revision

Viewing changes to scrum/scrum.py

  • Committer: pinky
  • Date: 2006-12-07 13:41:40 UTC
  • Revision ID: pinky-dedd7f8a42bd4557112a0513082691b8590ad6cc
New trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
##############################################################################
 
2
#
 
3
# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved.
 
4
#                    Fabien Pinckaers <fp@tiny.Be>
 
5
#
 
6
# WARNING: This program as such is intended to be used by professional
 
7
# programmers who take the whole responsability of assessing all potential
 
8
# consequences resulting from its eventual inadequacies and bugs
 
9
# End users who are looking for a ready-to-use solution with commercial
 
10
# garantees and support are strongly adviced to contract a Free Software
 
11
# Service Company
 
12
#
 
13
# This program is Free Software; you can redistribute it and/or
 
14
# modify it under the terms of the GNU General Public License
 
15
# as published by the Free Software Foundation; either version 2
 
16
# of the License, or (at your option) any later version.
 
17
#
 
18
# This program is distributed in the hope that it will be useful,
 
19
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
21
# GNU General Public License for more details.
 
22
#
 
23
# You should have received a copy of the GNU General Public License
 
24
# along with this program; if not, write to the Free Software
 
25
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
26
#
 
27
##############################################################################
 
28
 
 
29
import time
 
30
import netsvc
 
31
from osv import fields, osv, orm
 
32
 
 
33
from mx import DateTime
 
34
import re
 
35
 
 
36
class scrum_team(osv.osv):
 
37
        _name = 'scrum.team'
 
38
        _description = 'Scrum Team'
 
39
        _columns = {
 
40
                'name' : fields.char('Team Name', size=64),
 
41
                'users_id' : fields.many2many('res.users', 'scrum_team_users_rel', 'team_id','user_id', 'Users'),
 
42
        }
 
43
scrum_team()
 
44
 
 
45
class scrum_project(osv.osv):
 
46
        _name = 'scrum.project'
 
47
        _inherit = 'project.project'
 
48
        _table = 'project_project'
 
49
        _description = 'Scrum Project'
 
50
        _columns = {
 
51
                'product_owner_id': fields.many2one('res.users', 'Product Owner'),
 
52
                'tasks': fields.one2many('scrum.task', 'project_id', 'Scrum Tasks'),
 
53
                'sprint_size': fields.integer('Sprint Days'),
 
54
                'scrum': fields.integer('Is Scrum'),
 
55
        }
 
56
        _defaults = {
 
57
                'product_owner_id': lambda self,cr,uid,context={}: uid,
 
58
                'warn_manager': lambda *a: 1,
 
59
                'sprint_size': lambda *a: 14,
 
60
                'scrum': lambda *a: 1
 
61
        }
 
62
scrum_project()
 
63
 
 
64
class scrum_sprint(osv.osv):
 
65
        _name = 'scrum.sprint'
 
66
        _description = 'Scrum Sprint'
 
67
        def _calc_progress(self, cr, uid, ids, name, args, context):
 
68
                res = {}
 
69
                for sprint in self.browse(cr, uid, ids):
 
70
                        tot = 0.0
 
71
                        prog = 0.0
 
72
                        for bl in sprint.backlog_ids:
 
73
                                tot += bl.planned_hours
 
74
                                prog += bl.planned_hours * bl.progress / 100.0
 
75
                        res.setdefault(sprint.id, 0.0)
 
76
                        if tot>0:
 
77
                                res[sprint.id] = round(prog/tot*100)
 
78
                return res
 
79
        def _calc_effective(self, cr, uid, ids, name, args, context):
 
80
                res = {}
 
81
                for sprint in self.browse(cr, uid, ids):
 
82
                        res.setdefault(sprint.id, 0.0)
 
83
                        for bl in sprint.backlog_ids:
 
84
                                res[sprint.id] += bl.effective_hours
 
85
                return res
 
86
        def _calc_planned(self, cr, uid, ids, name, args, context):
 
87
                res = {}
 
88
                for sprint in self.browse(cr, uid, ids):
 
89
                        res.setdefault(sprint.id, 0.0)
 
90
                        for bl in sprint.backlog_ids:
 
91
                                res[sprint.id] += bl.planned_hours
 
92
                return res
 
93
        _columns = {
 
94
                'name' : fields.char('Sprint Name', size=64),
 
95
                'date_start': fields.date('Starting Date', required=True),
 
96
                'date_stop': fields.date('Ending Date', required=True),
 
97
                'project_id': fields.many2one('scrum.project', 'Project', required=True, domain=[('scrum','=',1)]),
 
98
                'product_owner_id': fields.many2one('res.users', 'Product Owner', required=True),
 
99
                'scrum_master_id': fields.many2one('res.users', 'Scrum Master', required=True),
 
100
                'meetings_id': fields.one2many('scrum.meeting', 'sprint_id', 'Daily Scrum'),
 
101
                'review': fields.text('Sprint Review'),
 
102
                'retrospective': fields.text('Sprint Retrospective'),
 
103
                'backlog_ids': fields.one2many('scrum.product.backlog', 'sprint_id', 'Sprint Backlog'),
 
104
                'progress': fields.function(_calc_progress, method=True, string='Progress (0-100)'),
 
105
                'effective_hours': fields.function(_calc_effective, method=True, string='Effective hours'),
 
106
                'planned_hours': fields.function(_calc_planned, method=True, string='Planned Hours'),
 
107
                'state': fields.selection([('draft','Draft'),('open','Open'),('done','Done')], 'State', required=True),
 
108
        }
 
109
        _defaults = {
 
110
                'state': lambda *a: 'draft',
 
111
                'date_start' : lambda *a:time.strftime('%Y-%m-%d'),
 
112
        }
 
113
        def onchange_project_id(self, cr, uid, ids, project_id):
 
114
                v = {}
 
115
                if project_id:
 
116
                        proj = self.pool.get('scrum.project').browse(cr, uid, [project_id])[0]
 
117
                        v['product_owner_id']= proj.product_owner_id.id
 
118
                        v['scrum_master_id']= proj.manager.id
 
119
                        v['date_stop'] = (DateTime.now() + DateTime.RelativeDateTime(days=int(proj.sprint_size or 15))).strftime('%Y-%m-%d')
 
120
                return {'value':v}
 
121
                
 
122
scrum_sprint()
 
123
 
 
124
class scrum_product_backlog(osv.osv):
 
125
        _name = 'scrum.product.backlog'
 
126
        _description = 'Product Backlog'
 
127
 
 
128
        def name_search(self, cr, uid, name, args=[], operator='ilike', context={}):
 
129
                match = re.match('^S\(([0-9]+)\)$', name)
 
130
                if match:
 
131
                        ids = self.search(cr, uid, [('sprint_id','=', int(match.group(1)))])
 
132
                        return self.name_get(cr, uid, ids, context=context)
 
133
                return super(scrum_product_backlog, self).name_search(cr, uid, name, args,operator,context)
 
134
 
 
135
        def _calc_progress(self, cr, uid, ids, name, args, context):
 
136
                res = {}
 
137
                for bl in self.browse(cr, uid, ids):
 
138
                        tot = 0.0
 
139
                        prog = 0.0
 
140
                        for task in bl.tasks_id:
 
141
                                tot += task.planned_hours
 
142
                                prog += task.planned_hours * task.progress / 100.0
 
143
                        res.setdefault(bl.id, 0.0)
 
144
                        if tot>0:
 
145
                                res[bl.id] = round(prog/tot*100)
 
146
                return res
 
147
        def _calc_effective(self, cr, uid, ids, name, args, context):
 
148
                res = {}
 
149
                for bl in self.browse(cr, uid, ids):
 
150
                        res.setdefault(bl.id, 0.0)
 
151
                        for task in bl.tasks_id:
 
152
                                res[bl.id] += task.effective_hours
 
153
                return res
 
154
        def _calc_planned(self, cr, uid, ids, name, args, context):
 
155
                res = {}
 
156
                for bl in self.browse(cr, uid, ids):
 
157
                        res.setdefault(bl.id, 0.0)
 
158
                        for task in bl.tasks_id:
 
159
                                res[bl.id] += task.planned_hours
 
160
                return res
 
161
        _columns = {
 
162
                'name' : fields.char('Feature', size=64),
 
163
                'note' : fields.text('Note'),
 
164
                'active' : fields.boolean('Active'),
 
165
                'project_id': fields.many2one('scrum.project', 'Scrum Project', required=True, domain=[('scrum','=',1)]),
 
166
                'user_id': fields.many2one('res.users', 'User'),
 
167
                'sprint_id': fields.many2one('scrum.sprint', 'Sprint'),
 
168
                'sequence' : fields.integer('Sequence'),
 
169
                'priority' : fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Urgent'), ('0','Very urgent')], 'Priority'),
 
170
                'tasks_id': fields.one2many('scrum.task', 'product_backlog_id', 'Tasks Details'),
 
171
                'state': fields.selection([('draft','Draft'),('open','Open'),('done','Done')], 'State', required=True),
 
172
                'progress': fields.function(_calc_progress, method=True, string='Progress (0-100)'),
 
173
                'effective_hours': fields.function(_calc_effective, method=True, string='Effective hours'),
 
174
                'planned_hours': fields.function(_calc_planned, method=True, string='Planned Hours')
 
175
        }
 
176
        _defaults = {
 
177
                'priority': lambda *a: '4',
 
178
                'state': lambda *a: 'draft',
 
179
                'active': lambda *a: 1
 
180
        }
 
181
        _order = "priority,sequence"
 
182
scrum_product_backlog()
 
183
 
 
184
class scrum_task(osv.osv):
 
185
        _name = 'scrum.task'
 
186
        _inherit = 'project.task'
 
187
        _table = 'project_task'
 
188
        _description = 'Scrum Task'
 
189
        _columns = {
 
190
                'product_backlog_id': fields.many2one('scrum.product.backlog', 'Product Backlog'),
 
191
                'scrum': fields.integer('Is Scrum'),
 
192
        }
 
193
        _defaults = {
 
194
                'scrum': lambda *a: 1,
 
195
        }
 
196
        def onchange_backlog_id(self, cr, uid, backlog_id):
 
197
                if not backlog_id:
 
198
                        return {}
 
199
                project_id = self.pool.get('scrum.product.backlog').browse(cr, uid, backlog_id).project_id.id
 
200
                return {'value': {'project_id': project_id}}
 
201
scrum_task()
 
202
 
 
203
class scrum_meeting(osv.osv):
 
204
        _name = 'scrum.meeting'
 
205
        _description = 'Scrum Meeting'
 
206
        _columns = {
 
207
                'name' : fields.char('Meeting Name', size=64, required=True),
 
208
                'date': fields.date('Meeting Date', required=True),
 
209
                'sprint_id': fields.many2one('scrum.sprint', 'Sprint', required=True),
 
210
                'question_yesterday': fields.text('Tasks since yesterday'),
 
211
                'question_today': fields.text('Tasks for today'),
 
212
                'question_blocks': fields.text('Blocks encountered'),
 
213
                #
 
214
                # Should be more formal.
 
215
                #
 
216
                'question_backlog': fields.text('Backlog Accurate'),
 
217
        }
 
218
        #
 
219
        # Find the right sprint thanks to users and date
 
220
        #
 
221
        _defaults = {
 
222
                'date' : lambda *a:time.strftime('%Y-%m-%d'),
 
223
        }
 
224
scrum_meeting()
 
225