2010-01-29 07:51:40 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
##############################################################################
|
|
|
|
#
|
|
|
|
# OpenERP, Open Source Management Solution
|
|
|
|
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU Affero General Public License as
|
|
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
|
|
# License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU Affero General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
##############################################################################
|
2010-03-11 07:10:06 +00:00
|
|
|
import datetime
|
|
|
|
from resource.faces import *
|
|
|
|
from new import classobj
|
2010-01-29 07:51:40 +00:00
|
|
|
|
|
|
|
import wizard
|
|
|
|
import pooler
|
|
|
|
from tools.translate import _
|
2010-03-09 11:52:35 +00:00
|
|
|
|
|
|
|
import working_calendar as wkcal
|
2010-01-29 07:51:40 +00:00
|
|
|
|
|
|
|
compute_form = """<?xml version="1.0" ?>
|
2010-02-10 06:14:22 +00:00
|
|
|
<form string="Compute Scheduling of Phases">
|
2010-01-29 07:51:40 +00:00
|
|
|
|
2010-02-26 11:18:14 +00:00
|
|
|
<field name="project_id" colspan="4"/>
|
2010-01-29 07:51:40 +00:00
|
|
|
|
|
|
|
</form>"""
|
|
|
|
|
|
|
|
compute_fields = {
|
2010-03-09 11:52:35 +00:00
|
|
|
'project_id': {'string':'Project', 'type':'many2one', 'relation':'project.project'},
|
2010-01-29 07:51:40 +00:00
|
|
|
|
|
|
|
}
|
2010-02-10 06:14:22 +00:00
|
|
|
|
2010-03-09 11:52:35 +00:00
|
|
|
class wizard_compute_phases(wizard.interface):
|
|
|
|
def _phase_schedule(self, cr, uid, phase, start_date, calendar_id=False, context={}):
|
|
|
|
|
|
|
|
"""Schedule phase with the start date till all the next phases are completed.
|
|
|
|
|
|
|
|
Arguements: start_dsate -- start date for the phase
|
|
|
|
calendar_id -- working calendar of the project
|
|
|
|
|
|
|
|
"""
|
2010-02-10 06:14:22 +00:00
|
|
|
|
2010-02-26 11:18:14 +00:00
|
|
|
pool = pooler.get_pool(cr.dbname)
|
2010-03-09 11:52:35 +00:00
|
|
|
phase_obj = pool.get('project.phase')
|
|
|
|
resource_obj = pool.get('resource.resource')
|
|
|
|
uom_obj = pool.get('product.uom')
|
|
|
|
phase_resource_obj = False
|
2010-02-26 11:18:14 +00:00
|
|
|
if phase:
|
2010-03-09 11:52:35 +00:00
|
|
|
leaves = []
|
|
|
|
time_efficiency = 1.0
|
|
|
|
resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)])
|
2010-03-11 07:10:06 +00:00
|
|
|
|
2010-02-26 11:18:14 +00:00
|
|
|
if resource_id:
|
2010-03-09 11:52:35 +00:00
|
|
|
# Create a new resource object with
|
|
|
|
# all the attributes of the Resource Class
|
|
|
|
resource = resource_obj.browse(cr, uid, resource_id, context=context)[0]
|
|
|
|
time_efficiency = resource.time_efficiency
|
2010-03-11 07:10:06 +00:00
|
|
|
leaves = wkcal.compute_leaves(cr, uid, calendar_id , resource.id, resource.calendar_id.id)
|
2010-03-09 11:52:35 +00:00
|
|
|
phase_resource_obj = classobj(str(phase.responsible_id.name), (Resource,),
|
|
|
|
{'__doc__': phase.responsible_id.name,
|
|
|
|
'__name__': phase.responsible_id.name,
|
|
|
|
'vacation': tuple(leaves),
|
|
|
|
'efficiency': time_efficiency
|
|
|
|
})
|
|
|
|
default_uom_id = uom_obj.search(cr, uid, [('name','=','Hour')])[0]
|
|
|
|
avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
|
2010-02-26 11:18:14 +00:00
|
|
|
duration = str(avg_hours) + 'H'
|
2010-03-09 11:52:35 +00:00
|
|
|
# Create a new project for each phase
|
2010-02-26 11:18:14 +00:00
|
|
|
def Project():
|
|
|
|
start = start_date
|
|
|
|
minimum_time_unit = 1
|
2010-03-09 11:52:35 +00:00
|
|
|
resource = phase_resource_obj
|
|
|
|
# If project has working calendar then that
|
|
|
|
# else the default one would be considered
|
2010-02-26 11:18:14 +00:00
|
|
|
if calendar_id:
|
2010-03-09 11:52:35 +00:00
|
|
|
working_days = wkcal.compute_working_calendar(cr, uid, calendar_id)
|
|
|
|
vacation = tuple(wkcal.compute_leaves(cr, uid, calendar_id))
|
2010-02-26 11:18:14 +00:00
|
|
|
|
|
|
|
def phase():
|
|
|
|
effort = duration
|
|
|
|
|
|
|
|
project = BalancedProject(Project)
|
|
|
|
s_date = project.phase.start.to_datetime()
|
|
|
|
e_date = project.phase.end.to_datetime()
|
2010-03-09 11:52:35 +00:00
|
|
|
# Recalculate date_start and date_end
|
|
|
|
# according to constraints on date start and date end on phase
|
2010-02-26 11:18:14 +00:00
|
|
|
if phase.constraint_date_start and str(s_date) < phase.constraint_date_start:
|
2010-03-02 13:27:02 +00:00
|
|
|
start_date = datetime.datetime.strptime(phase.constraint_date_start, '%Y-%m-%d %H:%M:%S')
|
2010-02-26 11:18:14 +00:00
|
|
|
else:
|
|
|
|
start_date = s_date
|
|
|
|
if phase.constraint_date_end and str(e_date) > phase.constraint_date_end:
|
2010-03-02 13:27:02 +00:00
|
|
|
end_date= datetime.datetime.strptime(phase.constraint_date_end, '%Y-%m-%d %H:%M:%S')
|
2010-02-26 11:18:14 +00:00
|
|
|
date_start = phase.constraint_date_end[:-3]
|
|
|
|
else:
|
|
|
|
end_date = e_date
|
|
|
|
date_start = end_date
|
2010-03-09 11:52:35 +00:00
|
|
|
# Write the calculated dates back
|
2010-03-11 07:10:06 +00:00
|
|
|
ctx = context.copy()
|
|
|
|
ctx.update({'scheduler': True})
|
2010-03-09 11:52:35 +00:00
|
|
|
phase_obj.write(cr, uid, [phase.id], {'date_start': start_date.strftime('%Y-%m-%d %H:%M:%S'),
|
|
|
|
'date_end': end_date.strftime('%Y-%m-%d %H:%M:%S')},
|
2010-03-11 07:10:06 +00:00
|
|
|
context=ctx)
|
2010-03-09 11:52:35 +00:00
|
|
|
# Recursive call till all the next phases scheduled
|
2010-02-26 11:18:14 +00:00
|
|
|
for phase in phase.next_phase_ids:
|
|
|
|
if phase.state in ['draft','open','pending']:
|
2010-03-11 07:10:06 +00:00
|
|
|
self._phase_schedule(cr, uid, phase, date_start, phase.project_id.resource_calendar_id.id or False, context=context)
|
2010-02-26 11:18:14 +00:00
|
|
|
else:
|
|
|
|
continue
|
2010-02-10 06:14:22 +00:00
|
|
|
|
2010-03-11 07:10:06 +00:00
|
|
|
def _compute_date(self, cr, uid, data, context={}):
|
2010-03-09 11:52:35 +00:00
|
|
|
"""
|
|
|
|
Compute the phases for scheduling.
|
|
|
|
"""
|
2010-02-10 06:14:22 +00:00
|
|
|
pool = pooler.get_pool(cr.dbname)
|
2010-03-09 11:52:35 +00:00
|
|
|
project_obj = pool.get('project.project')
|
|
|
|
phase_obj = pool.get('project.phase')
|
|
|
|
if data['form']['project_id']: # If project mentioned find its phases
|
|
|
|
project_id = project_obj.browse(cr, uid, data['form']['project_id'], context=context)
|
|
|
|
phase_ids = phase_obj.search(cr, uid, [('project_id', '=', project_id.id),
|
|
|
|
('state', 'in', ['draft', 'open', 'pending']),
|
|
|
|
('previous_phase_ids', '=', False)
|
|
|
|
])
|
|
|
|
else: # Else take all the draft,open,pending states phases
|
|
|
|
phase_ids = phase_obj.search(cr, uid,[('state', 'in', ['draft', 'open', 'pending']),
|
|
|
|
('previous_phase_ids', '=', False)
|
2010-03-11 07:10:06 +00:00
|
|
|
], context=context)
|
2010-02-26 11:18:14 +00:00
|
|
|
phase_ids.sort()
|
2010-03-09 11:52:35 +00:00
|
|
|
phase_objs = phase_obj.browse(cr, uid, phase_ids, context=context)
|
2010-02-26 11:18:14 +00:00
|
|
|
for phase in phase_objs:
|
2010-02-26 12:26:17 +00:00
|
|
|
start_date = phase.project_id.date_start
|
|
|
|
if not phase.project_id.date_start:
|
|
|
|
start_date = datetime.datetime.now().strftime("%Y-%m-%d")
|
2010-03-02 13:27:02 +00:00
|
|
|
start_dt = datetime.datetime.strftime((datetime.datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d %H:%M")
|
2010-02-26 11:18:14 +00:00
|
|
|
calendar_id = phase.project_id.resource_calendar_id.id
|
2010-03-11 07:10:06 +00:00
|
|
|
self._phase_schedule(cr, uid, phase, start_dt, calendar_id or False, context=context)
|
2010-01-29 07:51:40 +00:00
|
|
|
return {}
|
2010-02-26 11:18:14 +00:00
|
|
|
|
2010-03-09 11:52:35 +00:00
|
|
|
def _open_phases_list(self, cr, uid, data, context):
|
|
|
|
"""
|
|
|
|
Return the scheduled phases list.
|
|
|
|
"""
|
2010-03-15 08:49:13 +00:00
|
|
|
pool = pooler.get_pool(cr.dbname)
|
|
|
|
mod_obj = pool.get('ir.model.data')
|
|
|
|
act_obj = pool.get('ir.actions.act_window')
|
2010-03-04 09:41:44 +00:00
|
|
|
result = mod_obj._get_id(cr, uid, 'project_long_term', 'act_project_phase')
|
|
|
|
id = mod_obj.read(cr, uid, [result], ['res_id'])[0]['res_id']
|
|
|
|
result = act_obj.read(cr, uid, [id], context=context)[0]
|
|
|
|
result['domain'] = [('state', 'not in', ['cancelled','done'])]
|
2010-03-09 11:52:35 +00:00
|
|
|
if data['form']['project_id']:
|
|
|
|
result['domain'] = [('project_id', '=', data['form']['project_id']),
|
|
|
|
('state', 'not in', ['cancelled','done'])]
|
2010-03-04 09:41:44 +00:00
|
|
|
return result
|
|
|
|
|
2010-01-29 07:51:40 +00:00
|
|
|
states = {
|
|
|
|
'init': {
|
|
|
|
'actions': [],
|
2010-03-11 07:10:06 +00:00
|
|
|
'result': {'type': 'form', 'arch': compute_form, 'fields': compute_fields, 'state':[
|
2010-01-29 07:51:40 +00:00
|
|
|
('end', 'Cancel'),
|
2010-02-10 06:14:22 +00:00
|
|
|
('compute', 'Compute')
|
2010-01-29 07:51:40 +00:00
|
|
|
|
|
|
|
]},
|
|
|
|
},
|
2010-02-10 06:14:22 +00:00
|
|
|
'compute': {
|
2010-01-29 07:51:40 +00:00
|
|
|
'actions': [_compute_date],
|
2010-03-11 07:10:06 +00:00
|
|
|
'result': {'type': 'action', 'action': _open_phases_list, 'state': 'end'},
|
2010-03-04 09:41:44 +00:00
|
|
|
},
|
2010-01-29 07:51:40 +00:00
|
|
|
}
|
|
|
|
wizard_compute_phases('wizard.compute.phases')
|
|
|
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|