[MERGE] merge with trunk
[odoo/odoo.git] / addons / project_long_term / wizard / project_schedule_tasks.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21 import datetime
22 from resource.faces import *
23 from new import classobj
24 import operator
25
26 from tools.translate import _
27 from osv import osv, fields
28
29 import working_calendar as wkcal
30
31 class project_schedule_task(osv.osv_memory):
32
33     _name = "project.schedule.tasks"
34     _description = 'project.schedule.tasks'
35     _columns = {
36         'msg': fields.char('Message', size=64)
37                 }
38     _defaults = {
39          'msg': 'Task Scheduling Completed Successfully'
40                 }
41
42     def default_get(self, cr, uid, fields_list, context=None):
43         res = super(project_schedule_task, self).default_get(cr, uid, fields_list, context)
44         self.compute_date(cr, uid, context=context)
45         return res
46
47     def create_resources(self, cr, uid, phase, context=None):
48         """
49         Return a list of  Resource Class objects for the resources allocated to the phase.
50         """
51         resource_objs = []
52
53         if context is None:
54             context = {}
55
56         for resource in phase.resource_ids:
57             res = resource.resource_id
58             leaves = []
59             resource_eff = res.time_efficiency
60             resource_cal = res.calendar_id.id
61             if resource_cal:
62                 cal_id  = phase.project_id.resource_calendar_id and phase.project_id.resource_calendar_id.id or False
63                 leaves = wkcal.compute_leaves(cr, uid, cal_id, res.id, resource_cal, context=context)
64             resource_objs.append(classobj(res.user_id.name.encode('utf8'), (Resource,),
65                                          {'__doc__': res.user_id.name,
66                                           '__name__': res.user_id.name,
67                                           'vacation': tuple(leaves),
68                                           'efficiency': resource_eff,
69                                           }))
70         return resource_objs
71
72     def compute_date(self, cr, uid, context=None):
73         """
74         Schedule the tasks according to resource available and priority.
75         """
76
77         phase_obj = self.pool.get('project.phase')
78         task_obj = self.pool.get('project.task')
79         user_obj = self.pool.get('res.users')
80
81         if context is None:
82             context = {}
83
84         if not 'active_id' in context:
85             return {}
86         phase = phase_obj.browse(cr, uid, context['active_id'], context=context)
87         task_ids = map(lambda x : x.id, (filter(lambda x : x.state in ['open', 'draft', 'pending'] , phase.task_ids)))
88         if task_ids:
89             task_ids.sort()
90             tasks = task_obj.browse(cr, uid, task_ids, context=context)
91             start_date = str(phase.date_start)[:-9]
92             if not phase.date_start:
93                 if not phase.project_id.date_start:
94                     start_date = datetime.datetime.now().strftime("%Y-%m-%d")
95                 else:
96                     start_date = phase.project_id.date_start
97             date_start = datetime.datetime.strftime(datetime.datetime.strptime(start_date, "%Y-%m-%d"), "%Y-%m-%d %H:%M")
98             calendar_id = phase.project_id.resource_calendar_id.id
99             resources = self.create_resources(cr, uid, phase)
100             priority_dict = {'0': 1000, '1': 800, '2': 500, '3': 300, '4': 100}
101             # Create dynamic no of tasks with the resource specified
102             def create_tasks(j, eff, priorty=500, obj=False):
103                 def task():
104                     """
105                     task is a dynamic method!
106                     """
107                     effort = eff
108                     if obj:
109                         resource = obj
110                     priority = priorty
111                 task.__doc__ = "TaskNO%d" %j
112                 task.__name__ = "task%d" %j
113                 return task
114
115             # Create a 'Faces' project with all the tasks and resources
116             def Project():
117                 title = "Project"
118                 start = date_start
119                 try:
120                     resource = reduce(operator.or_, resources)
121                 except:
122                     raise osv.except_osv(_('Error'), _('Phase must have resources assigned !'))
123                 minimum_time_unit = 1
124                 if calendar_id:            # If project has working calendar
125                     working_days = wkcal.compute_working_calendar(cr, uid, calendar_id)
126                     vacation = tuple(wkcal.compute_leaves(cr, uid, calendar_id))
127                 # Dynamic creation of tasks
128                 i = 0
129                 for each_task in tasks:
130                     hours = str(each_task.planned_hours )+ 'H'
131                     if each_task.priority in priority_dict.keys():
132                         priorty = priority_dict[each_task.priority]
133                     if each_task.user_id:
134                        for resrce in resources:
135                             if resrce.__name__ == each_task.user_id.name:
136                                task = create_tasks(i, hours, priorty, resrce)
137                     else:
138                         task = create_tasks(i, hours, priorty)
139                     i += 1
140
141             project = BalancedProject(Project)
142             loop_no = 0
143             # Write back the computed dates
144             for t in project:
145                 s_date = t.start.to_datetime()
146                 e_date = t.end.to_datetime()
147                 if loop_no > 0:
148                     ctx = context.copy()
149                     ctx.update({'scheduler': True})
150                     user_id = user_obj.search(cr, uid, [('name', '=', t.booked_resource[0].__name__)])
151                     task_obj.write(cr, uid, [tasks[loop_no-1].id], {'date_start': s_date.strftime('%Y-%m-%d %H:%M:%S'),
152                                                                     'date_end': e_date.strftime('%Y-%m-%d %H:%M:%S'),
153                                                                     'user_id': user_id[0]},
154                                                                     context=ctx)
155                 loop_no +=1
156         return {}
157
158 project_schedule_task()
159 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: