[FIX] project_long_term : Scheduling, test yaml, few fix
bzr revid: tfr@openerp.com-20110110094856-bxaohl1jmc6u8re0
This commit is contained in:
commit
b0e1baae57
|
@ -243,7 +243,7 @@
|
|||
<!-- Entries by Line -->
|
||||
|
||||
<record id="action_account_tree1" model="ir.actions.act_window">
|
||||
<field name="name">Analytic Entries</field>
|
||||
<field name="name">Analytic Items</field>
|
||||
<field name="res_model">account.analytic.line</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
|
|
|
@ -288,6 +288,7 @@ class XMLRpcConn(object):
|
|||
headers[line[:split_here]] = line[split_here:]
|
||||
temp1 = headers.get('Message-ID')
|
||||
temp2 = headers.get('Message-Id')
|
||||
referances = headers.get('References')
|
||||
if temp1 == None: message_id = temp2
|
||||
if temp2 == None: message_id = temp1
|
||||
startCut = message_id.find("<")
|
||||
|
|
|
@ -126,9 +126,11 @@ class project(osv.osv):
|
|||
'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the project without removing it."),
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of Projects."),
|
||||
'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account', help="Link this project to an analytic account if you need financial management on projects. It enables you to connect projects with budgets, planning, cost and revenue analysis, timesheets on projects, etc.", ondelete="cascade", required=True),
|
||||
'priority': fields.integer('Sequence', help="Gives the sequence order when displaying a list of task"),
|
||||
'priority': fields.integer('Sequence', help="Gives the sequence order when displaying the list of projects"),
|
||||
'warn_manager': fields.boolean('Warn Manager', help="If you check this field, the project manager will receive a request each time a task is completed by his team.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'members': fields.many2many('res.users', 'project_user_rel', 'project_id', 'uid', 'Project Members', help="Project's member. Not used in any computation, just for information purpose.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
|
||||
'members': fields.many2many('res.users', 'project_user_rel', 'project_id', 'uid', 'Project Members', help="Project's member. Not used in any computation, just for information purpose, but a user has to be member of a project to add a the to this project.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'parent_id': fields.many2one('project.project', 'Parent Project'),
|
||||
'tasks': fields.one2many('project.task', 'project_id', "Project tasks"),
|
||||
'planned_hours': fields.function(_progress_rate, multi="progress", method=True, string='Planned Time', help="Sum of planned hours of all tasks related to this project and its child projects.",
|
||||
store = {
|
||||
|
|
|
@ -29,20 +29,17 @@
|
|||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="Administration">
|
||||
<group col="2" colspan="2" groups="base.group_extended">
|
||||
<separator colspan="2" string="Scheduling"/>
|
||||
<field name="priority"/>
|
||||
<field name="active"/>
|
||||
</group>
|
||||
<group col="2" colspan="2">
|
||||
<separator colspan="2" string="Performance"/>
|
||||
<field name="planned_hours" widget="float_time"/>
|
||||
<field name="effective_hours" widget="float_time" />
|
||||
</group>
|
||||
<group col="2" colspan="2" name="misc">
|
||||
<separator colspan="2" string="Miscelleanous"/>
|
||||
<separator colspan="4" string="Miscelleanous"/>
|
||||
<field name="company_id" select="1" groups="base.group_multi_company" widget="selection" required="1"/>
|
||||
<field name="warn_manager"/>
|
||||
<field name="priority"/>
|
||||
<field name="active"/>
|
||||
</group>
|
||||
<newline/>
|
||||
<separator colspan="4"/>
|
||||
|
@ -226,7 +223,7 @@
|
|||
<form string="Task edition">
|
||||
<group colspan="6" col="6">
|
||||
<field name="name" select="1"/>
|
||||
<field name="project_id" select="1" on_change="onchange_project(project_id)" domain="[('user_id','=',uid)]"/>
|
||||
<field name="project_id" select="1" on_change="onchange_project(project_id)" domain="['|',('user_id','=',uid),('members','=',uid)]" />
|
||||
<field name="total_hours" widget="float_time"/>
|
||||
<field name="date_deadline" attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"/>
|
||||
<field name="user_id" select="1" attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"/>
|
||||
|
|
|
@ -333,7 +333,7 @@
|
|||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="priority" position="before">
|
||||
<field name="priority" position="after">
|
||||
<field name="resource_calendar_id"/>
|
||||
</field>
|
||||
|
||||
|
|
|
@ -40,9 +40,15 @@ Features.
|
|||
"init_xml": [],
|
||||
"demo_xml": ["project_long_term_demo.xml"],
|
||||
"test": [
|
||||
'test/project_schedule_consecutive_day.yml',
|
||||
'test/project_schedule_without_wroking_hour.yml',
|
||||
'test/schedule_project_phases.yml',
|
||||
'test/phase_constraint.yml',
|
||||
'test/test_schedule_phases_case2.yml',
|
||||
'test/test_schedule_phases_case1.yml',
|
||||
'test/schedule_project_tasks.yml',
|
||||
'test/schedule_phase_tasks.yml'
|
||||
'test/schedule_phase_tasks.yml',
|
||||
'test/test_schedule_tasks_case1.yml'
|
||||
],
|
||||
"update_xml": [
|
||||
"security/ir.model.access.csv",
|
||||
|
|
|
@ -546,6 +546,12 @@ msgstr "Berechne Aufgabenterminierung für spezifiziertes Projekt."
|
|||
msgid "Phase"
|
||||
msgstr "Phase"
|
||||
|
||||
#. module: project_long_term
|
||||
#: help:project.phase,date_start:0
|
||||
msgid ""
|
||||
"It's computed by the scheduler according the project date or the end date of the previous phase."
|
||||
msgstr "Beginn der Phase"
|
||||
|
||||
#. module: project_long_term
|
||||
#: help:project.phase,state:0
|
||||
msgid ""
|
||||
|
|
|
@ -451,8 +451,8 @@ msgstr "Phase"
|
|||
#. module: project_long_term
|
||||
#: help:project.phase,date_start:0
|
||||
#: field:project.resource.allocation,phase_id_date_start:0
|
||||
msgid "It's computed according to the phases order : the start date of the 1st phase is set by you while the other start dates depend on the end date of their previous phases"
|
||||
msgstr "It's computed according to the phases order : the start date of the 1st phase is set by you while the other start dates depend on the end date of their previous phases"
|
||||
msgid "It's computed by the scheduler according the project date or the end date of the previous phase."
|
||||
msgstr "It's computed by the scheduler according the project date or the end date of the previous phase."
|
||||
|
||||
#. module: project_long_term
|
||||
#: help:project.phase,state:0
|
||||
|
|
|
@ -522,6 +522,12 @@ msgstr ""
|
|||
msgid "Phase"
|
||||
msgstr "Fase"
|
||||
|
||||
#. module: project_long_term
|
||||
#: help:project.phase,date_start:0
|
||||
msgid ""
|
||||
"It's computed by the scheduler according the project date or the end date of the previous phase."
|
||||
msgstr ""
|
||||
|
||||
#. module: project_long_term
|
||||
#: help:project.phase,state:0
|
||||
msgid ""
|
||||
|
|
|
@ -555,6 +555,12 @@ msgstr "Calculer l'ordonnancement des tâches pour un projet spécifié."
|
|||
msgid "Phase"
|
||||
msgstr "Phase"
|
||||
|
||||
#. module: project_long_term
|
||||
#: help:project.phase,date_start:0
|
||||
msgid ""
|
||||
"It's computed by the scheduler according the project date or the end date of the previous phase."
|
||||
msgstr "Date de début de la phase"
|
||||
|
||||
#. module: project_long_term
|
||||
#: help:project.phase,state:0
|
||||
msgid ""
|
||||
|
|
|
@ -519,6 +519,12 @@ msgstr "Aprēķināt uzdevumu grafiku norādītajām projektam."
|
|||
msgid "Phase"
|
||||
msgstr "Fāze"
|
||||
|
||||
#. module: project_long_term
|
||||
#: help:project.phase,date_start:0
|
||||
msgid ""
|
||||
"It's computed by the scheduler according the project date or the end date of the previous phase."
|
||||
msgstr ""
|
||||
|
||||
#. module: project_long_term
|
||||
#: help:project.phase,state:0
|
||||
msgid ""
|
||||
|
|
|
@ -520,6 +520,12 @@ msgstr "Oblicz planowanie zadań dla projektu"
|
|||
msgid "Phase"
|
||||
msgstr "Faza"
|
||||
|
||||
#. module: project_long_term
|
||||
#: help:project.phase,date_start:0
|
||||
msgid ""
|
||||
"It's computed by the scheduler according the project date or the end date of the previous phase."
|
||||
msgstr ""
|
||||
|
||||
#. module: project_long_term
|
||||
#: help:project.phase,state:0
|
||||
msgid ""
|
||||
|
|
|
@ -369,7 +369,7 @@ msgstr ""
|
|||
|
||||
#. module: project_long_term
|
||||
#: help:project.phase,date_start:0
|
||||
msgid "It's computed according to the phases order : the start date of the 1st phase is set by you while the other start dates depend on the end date of their previous phases"
|
||||
msgid "It's computed by the scheduler according the project date or the end date of the previous phase."
|
||||
msgstr ""
|
||||
|
||||
#. module: project_long_term
|
||||
|
|
|
@ -519,6 +519,12 @@ msgstr ""
|
|||
msgid "Phase"
|
||||
msgstr "Fase"
|
||||
|
||||
#. module: project_long_term
|
||||
#: help:project.phase,date_start:0
|
||||
msgid ""
|
||||
"It's computed by the scheduler according the project date or the end date of the previous phase."
|
||||
msgstr "Data de início da fase"
|
||||
|
||||
#. module: project_long_term
|
||||
#: help:project.phase,state:0
|
||||
msgid ""
|
||||
|
|
|
@ -23,8 +23,11 @@ from datetime import datetime, timedelta
|
|||
from dateutil.relativedelta import relativedelta
|
||||
from tools.translate import _
|
||||
from osv import fields, osv
|
||||
from resource.faces import task as Task
|
||||
from resource.faces import task as Task
|
||||
import operator
|
||||
from new import classobj
|
||||
import types
|
||||
import new
|
||||
|
||||
class project_phase(osv.osv):
|
||||
_name = "project.phase"
|
||||
|
@ -105,7 +108,7 @@ class project_phase(osv.osv):
|
|||
|
||||
_columns = {
|
||||
'name': fields.char("Name", size=64, required=True),
|
||||
'date_start': fields.date('Start Date', help="It's computed according to the phases order : the start date of the 1st phase is set by you while the other start dates depend on the end date of their previous phases", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'date_start': fields.date('Start Date', help="It's computed by the scheduler according the project date or the end date of the previous phase.", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'date_end': fields.date('End Date', help=" It's computed by the scheduler according to the start date and the duration.", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'constraint_date_start': fields.date('Minimum Start Date', help='force the phase to start after this date', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'constraint_date_end': fields.date('Deadline', help='force the phase to finish before this date', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
|
@ -212,126 +215,177 @@ class project_phase(osv.osv):
|
|||
self.write(cr, uid, ids, {'state': 'done'})
|
||||
return True
|
||||
|
||||
def generate_resources(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Return a list of Resource Class objects for the resources allocated to the phase.
|
||||
"""
|
||||
res = {}
|
||||
resource_pool = self.pool.get('resource.resource')
|
||||
for phase in self.browse(cr, uid, ids, context=context):
|
||||
user_ids = map(lambda x:x.resource_id.user_id.id, phase.resource_ids)
|
||||
project = phase.project_id
|
||||
calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
|
||||
resource_objs = resource_pool.generate_resources(cr, uid, user_ids, calendar_id, context=context)
|
||||
res[phase.id] = resource_objs
|
||||
return res
|
||||
|
||||
def generate_schedule(self, cr, uid, ids, start_date=False, calendar_id=False, context=None):
|
||||
"""
|
||||
Schedule phase with the start date till all the next phases are completed.
|
||||
@param: start_date (datetime.datetime) : start date for the phase. It would be either Start date of phase or start date of project or system current date
|
||||
@param: calendar_id : working calendar of the project
|
||||
"""
|
||||
def generate_phase(self, cr, uid, ids, f, parent=False, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
phase_ids = []
|
||||
resource_pool = self.pool.get('resource.resource')
|
||||
data_pool = self.pool.get('ir.model.data')
|
||||
resource_allocation_pool = self.pool.get('project.resource.allocation')
|
||||
uom_pool = self.pool.get('product.uom')
|
||||
task_pool = self.pool.get('project.task')
|
||||
data_model, day_uom_id = data_pool.get_object_reference(cr, uid, 'product', 'uom_day')
|
||||
for phase in self.browse(cr, uid, ids, context=context):
|
||||
if not phase.responsible_id:
|
||||
raise osv.except_osv(_('No responsible person assigned !'),_("You must assign a responsible person for phase '%s' !") % (phase.name,))
|
||||
|
||||
if not start_date:
|
||||
start_date = phase.project_id.date_start or phase.date_start or datetime.now().strftime("%Y-%m-%d")
|
||||
start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
|
||||
phase_resource_obj = self.generate_resources(cr, uid, [phase.id], context=context)[phase.id]
|
||||
avg_days = uom_pool._compute_qty(cr, uid, phase.product_uom.id, phase.duration, day_uom_id)
|
||||
if not phase_resource_obj: #TOCHECK: why need this ?
|
||||
avg_days = avg_days - 1
|
||||
duration = str(avg_days) + 'd'
|
||||
# Create a new project for each phase
|
||||
def Project():
|
||||
# If project has working calendar then that
|
||||
# else the default one would be considered
|
||||
start = start_date
|
||||
minimum_time_unit = 1
|
||||
resource = phase_resource_obj
|
||||
working_hours_per_day = 24
|
||||
vacation = []
|
||||
if calendar_id:
|
||||
working_hours_per_day = 8 #TODO: it should be come from calendars
|
||||
vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id))
|
||||
working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
|
||||
def phase():
|
||||
effort = duration
|
||||
str_resource = ('%s & '*len(phase.resource_ids))[:-2]
|
||||
str_vals = str_resource % tuple(map(lambda x: 'Resource_%s'%x.resource_id.id, phase.resource_ids))
|
||||
|
||||
project = Task.BalancedProject(Project)
|
||||
# Phases Defination for the Project
|
||||
s = '''
|
||||
def Phase_%s():
|
||||
title = \"%s\"
|
||||
effort = \'%s\'
|
||||
resource = %s
|
||||
'''%(phase.id, phase.name, duration, str_vals or False)
|
||||
|
||||
s_date = project.phase.start.to_datetime()
|
||||
e_date = project.phase.end.to_datetime()
|
||||
# Recalculate date_start and date_end
|
||||
# according to constraints on date start and date end on phase
|
||||
if phase.constraint_date_start and str(s_date) < phase.constraint_date_start:
|
||||
start_date = ''
|
||||
end_date = ''
|
||||
if phase.constraint_date_start:
|
||||
start_date = datetime.strptime(phase.constraint_date_start, '%Y-%m-%d')
|
||||
s += '''
|
||||
start = \"%s\"
|
||||
'''%(datetime.strftime(start_date, "%Y-%m-%d"))
|
||||
else:
|
||||
start_date = s_date
|
||||
if phase.constraint_date_end and str(e_date) > phase.constraint_date_end:
|
||||
if parent:
|
||||
start = 'up.Phase_%s.end' % (parent.id)
|
||||
s += '''
|
||||
start = %s
|
||||
'''%(start)
|
||||
else:
|
||||
start = phase.project_id.date_start or phase.date_start
|
||||
s += '''
|
||||
start = \"%s\"
|
||||
'''%(start)
|
||||
|
||||
if phase.constraint_date_end :
|
||||
end_date= datetime.strptime(phase.constraint_date_end, '%Y-%m-%d')
|
||||
date_start = phase.constraint_date_end
|
||||
else:
|
||||
end_date = e_date
|
||||
date_start = end_date
|
||||
# Write the calculated dates back
|
||||
ctx = context.copy()
|
||||
ctx.update({'scheduler': True})
|
||||
self.write(cr, uid, [phase.id], {
|
||||
'date_start': start_date.strftime('%Y-%m-%d'),
|
||||
'date_end': end_date.strftime('%Y-%m-%d')
|
||||
}, context=ctx)
|
||||
# write dates into Resources Allocation
|
||||
for resource in phase.resource_ids:
|
||||
resource_allocation_pool.write(cr, uid, [resource.id], {
|
||||
'date_start': start_date.strftime('%Y-%m-%d'),
|
||||
'date_end': end_date.strftime('%Y-%m-%d')
|
||||
}, context=ctx)
|
||||
s += '''
|
||||
end = \"%s\"
|
||||
'''%(datetime.strftime(end_date, "%Y-%m-%d"))
|
||||
|
||||
|
||||
#start = datetime.strftime((datetime.strptime(start, "%Y-%m-%d")), "%Y-%m-%d")
|
||||
|
||||
phase_ids.append(phase.id)
|
||||
parent = False
|
||||
task_ids = []
|
||||
todo_task_ids = task_pool.search(cr, uid, [('id', 'in', map(lambda x : x.id, phase.task_ids)),
|
||||
('state', 'in', ['draft', 'open', 'pending'])
|
||||
], order='sequence')
|
||||
if todo_task_ids :
|
||||
for task in task_pool.browse(cr, uid, todo_task_ids, context=context):
|
||||
s += task_pool.generate_task(cr, uid, task.id, parent=parent, flag=False, context=context)
|
||||
if not parent:
|
||||
parent = task
|
||||
task_ids.append(task.id)
|
||||
|
||||
f += s + '\n'
|
||||
# Recursive call till all the next phases scheduled
|
||||
for next_phase in phase.next_phase_ids:
|
||||
if next_phase.state in ['draft', 'open', 'pending']:
|
||||
id_cal = next_phase.project_id.resource_calendar_id and next_phase.project_id.resource_calendar_id.id or False
|
||||
self.generate_schedule(cr, uid, [next_phase.id], date_start+timedelta(days=1), id_cal, context=context)
|
||||
else:
|
||||
continue
|
||||
return True
|
||||
if next_phase.state in ['draft', 'open', 'pending']:
|
||||
rf, rphase_ids = self.generate_phase(cr, uid, [next_phase.id], f = '', parent=phase, context=context)
|
||||
f += rf +'\n'
|
||||
phase_ids += rphase_ids
|
||||
else:
|
||||
continue
|
||||
return f, phase_ids
|
||||
|
||||
def schedule_tasks(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Schedule the tasks according to resource available and priority.
|
||||
Schedule tasks base on faces lib
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if type(ids) in (long, int,):
|
||||
ids = [ids]
|
||||
task_pool = self.pool.get('project.task')
|
||||
resource_pool = self.pool.get('resource.resource')
|
||||
resources_list = self.generate_resources(cr, uid, ids, context=context)
|
||||
return_msg = {}
|
||||
for phase in self.browse(cr, uid, ids, context=context):
|
||||
start_date = phase.date_start
|
||||
if not start_date and phase.project_id.date_start:
|
||||
start_date = phase.project_id.date_start
|
||||
if not start_date:
|
||||
start_date = datetime.now().strftime("%Y-%m-%d")
|
||||
resources = resources_list.get(phase.id, [])
|
||||
calendar_id = phase.project_id.resource_calendar_id.id
|
||||
task_ids = map(lambda x : x.id, (filter(lambda x : x.state in ['draft'] , phase.task_ids))) #reassign only task not yet started
|
||||
if task_ids:
|
||||
task_pool.generate_schedule(cr, uid, task_ids, resources, calendar_id, start_date, context=context)
|
||||
data_pool = self.pool.get('ir.model.data')
|
||||
resource_allocation_pool = self.pool.get('project.resource.allocation')
|
||||
|
||||
if not task_ids:
|
||||
warning_msg = _("No tasks to compute for Phase '%s'.") % (phase.name)
|
||||
if "warning" not in return_msg:
|
||||
return_msg["warning"] = warning_msg
|
||||
else:
|
||||
return_msg["warning"] = return_msg["warning"] + "\n" + warning_msg
|
||||
return return_msg
|
||||
for phase in self.browse(cr, uid, ids, context=context):
|
||||
project = phase.project_id
|
||||
calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
|
||||
start_date = project.date_start
|
||||
#Creating resources using the member of the Project
|
||||
u_ids = [i.id for i in project.members]
|
||||
resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
|
||||
start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
|
||||
func_str = ''
|
||||
start = start_date
|
||||
minimum_time_unit = 1
|
||||
# default values
|
||||
working_hours_per_day = 24
|
||||
working_days_per_week = 7
|
||||
working_days_per_month = 30
|
||||
working_days_per_year = 365
|
||||
|
||||
vacation = []
|
||||
if calendar_id:
|
||||
working_hours_per_day = 8 #TODO: it should be come from calendars
|
||||
working_days_per_week = 5
|
||||
working_days_per_month = 20
|
||||
working_days_per_year = 200
|
||||
vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
|
||||
|
||||
working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
|
||||
|
||||
cls_str = ''
|
||||
# Creating Resources for the Project
|
||||
for key, vals in resource_objs.items():
|
||||
cls_str +='''
|
||||
class Resource_%s(Resource):
|
||||
title = \"%s\"
|
||||
vacation = %s
|
||||
efficiency = %s
|
||||
'''%(key, vals.get('name',False), vals.get('vacation', False), vals.get('efficiency', False))
|
||||
|
||||
# Create a new project for each phase
|
||||
func_str += '''
|
||||
def Phase_%d():
|
||||
from resource.faces import Resource
|
||||
title = \"%s\"
|
||||
start = \'%s\'
|
||||
minimum_time_unit = %s
|
||||
working_hours_per_day = %s
|
||||
working_days_per_week = %s
|
||||
working_days_per_month = %s
|
||||
working_days_per_year = %s
|
||||
vacation = %s
|
||||
working_days = %s
|
||||
'''%(phase.id, phase.name, start, minimum_time_unit, working_hours_per_day, working_days_per_week, working_days_per_month, working_days_per_year, vacation, working_days )
|
||||
|
||||
parent = False
|
||||
task_ids = []
|
||||
todo_task_ids = task_pool.search(cr, uid, [('id', 'in', map(lambda x : x.id, phase.task_ids)),
|
||||
('state', 'in', ['draft', 'open', 'pending'])
|
||||
], order='sequence')
|
||||
for task in task_pool.browse(cr, uid, todo_task_ids, context=context):
|
||||
func_str += task_pool.generate_task(cr, uid, task.id, parent=parent, flag=True, context=context)
|
||||
if not parent:
|
||||
parent = task
|
||||
task_ids.append(task.id)
|
||||
func_str += cls_str
|
||||
|
||||
# Allocating Memory for the required Project and Pahses and Resources
|
||||
exec(func_str)
|
||||
Phase = eval('Phase_%d' % phase.id)
|
||||
phase = Task.BalancedProject(Phase)
|
||||
|
||||
for task_id in task_ids:
|
||||
task = eval("phase.Task_%d" % task_id)
|
||||
start_date = task.start.to_datetime()
|
||||
end_date = task.end.to_datetime()
|
||||
|
||||
task_pool.write(cr, uid, [task_id], {
|
||||
'date_start': start_date.strftime('%Y-%m-%d'),
|
||||
'date_end': end_date.strftime('%Y-%m-%d')
|
||||
}, context=context)
|
||||
return True
|
||||
project_phase()
|
||||
|
||||
class project_resource_allocation(osv.osv):
|
||||
|
@ -383,53 +437,224 @@ class project(osv.osv):
|
|||
|
||||
def schedule_phases(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Schedule the phases.
|
||||
Schedule phase base on faces lib
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if type(ids) in (long, int,):
|
||||
ids = [ids]
|
||||
phase_pool = self.pool.get('project.phase')
|
||||
task_pool = self.pool.get('project.task')
|
||||
resource_pool = self.pool.get('resource.resource')
|
||||
data_pool = self.pool.get('ir.model.data')
|
||||
resource_allocation_pool = self.pool.get('project.resource.allocation')
|
||||
uom_pool = self.pool.get('product.uom')
|
||||
data_model, day_uom_id = data_pool.get_object_reference(cr, uid, 'product', 'uom_day')
|
||||
|
||||
for project in self.browse(cr, uid, ids, context=context):
|
||||
phase_ids = phase_pool.search(cr, uid, [('project_id', '=', project.id),
|
||||
root_phase_ids = phase_pool.search(cr, uid, [('project_id', '=', project.id),
|
||||
('state', 'in', ['draft', 'open', 'pending']),
|
||||
('previous_phase_ids', '=', False)
|
||||
])
|
||||
calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
|
||||
start_date = False
|
||||
phase_pool.generate_schedule(cr, uid, phase_ids, start_date, calendar_id, context=context)
|
||||
return True
|
||||
start_date = project.date_start
|
||||
#if start_date:
|
||||
# start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
|
||||
#Creating resources using the member of the Project
|
||||
u_ids = [i.id for i in project.members]
|
||||
resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
|
||||
func_str = ''
|
||||
start = start_date
|
||||
minimum_time_unit = 1
|
||||
# default values
|
||||
working_hours_per_day = 24
|
||||
working_days_per_week = 7
|
||||
working_days_per_month = 30
|
||||
working_days_per_year = 365
|
||||
|
||||
vacation = []
|
||||
if calendar_id:
|
||||
working_hours_per_day = 8 #TODO: it should be come from calendars
|
||||
working_days_per_week = 5
|
||||
working_days_per_month = 20
|
||||
working_days_per_year = 200
|
||||
vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
|
||||
|
||||
working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
|
||||
|
||||
cls_str = ''
|
||||
# Creating Resources for the Project
|
||||
for key, vals in resource_objs.items():
|
||||
cls_str +='''
|
||||
class Resource_%s(Resource):
|
||||
title = \"%s\"
|
||||
vacation = %s
|
||||
efficiency = %s
|
||||
'''%(key, vals.get('name',False), vals.get('vacation', False), vals.get('efficiency', False))
|
||||
|
||||
# Create a new project for each phase
|
||||
func_str += '''
|
||||
def Project_%d():
|
||||
from resource.faces import Resource
|
||||
title = \"%s\"
|
||||
start = \'%s\'
|
||||
minimum_time_unit = %s
|
||||
working_hours_per_day = %s
|
||||
working_days_per_week = %s
|
||||
working_days_per_month = %s
|
||||
working_days_per_year = %s
|
||||
vacation = %s
|
||||
working_days = %s
|
||||
'''%(project.id, project.name, start, minimum_time_unit, working_hours_per_day, working_days_per_week, working_days_per_month, working_days_per_year, vacation, working_days )
|
||||
|
||||
func_str += cls_str
|
||||
phase_ids = []
|
||||
for root_phase in phase_pool.browse(cr, uid, root_phase_ids, context=context):
|
||||
phases, child_phase_ids = phase_pool.generate_phase(cr, uid, [root_phase.id], '', context=context)
|
||||
func_str += phases
|
||||
phase_ids += child_phase_ids
|
||||
|
||||
# Allocating Memory for the required Project and Pahses and Resources
|
||||
exec(func_str)
|
||||
Project = eval('Project_%d' % project.id)
|
||||
project = Task.BalancedProject(Project)
|
||||
|
||||
for phase_id in phase_ids:
|
||||
act_phase = phase_pool.browse(cr, uid, phase_id, context=context)
|
||||
resources = act_phase.resource_ids
|
||||
phase = eval("project.Phase_%d" % phase_id)
|
||||
start_date = phase.start.to_datetime()
|
||||
end_date = phase.end.to_datetime()
|
||||
|
||||
if resources:
|
||||
for res in resources:
|
||||
vals = {}
|
||||
vals.update({'date_start' : start_date })
|
||||
vals.update({'date_end' : end_date})
|
||||
resource_allocation_pool.write(cr, uid, res.id, vals, context=context)
|
||||
if act_phase.task_ids:
|
||||
for task in act_phase.task_ids:
|
||||
vals = {}
|
||||
#Getting values of the Tasks
|
||||
temp = eval("phase.Task_%s"%task.id)
|
||||
if temp.booked_resource:
|
||||
res_name = temp.booked_resource[0].title
|
||||
res_id = resource_pool.search(cr, uid,[('name','=',res_name)], context = context)
|
||||
if res_id:
|
||||
res = resource_pool.browse(cr, uid, res_id[0], context = context)
|
||||
vals.update({'user_id' : res.user_id.id})
|
||||
|
||||
vals.update({'date_start' : temp.start.strftime('%Y-%m-%d %H:%M:%S')})
|
||||
vals.update({'date_end' : temp.end.strftime('%Y-%m-%d %H:%M:%S')})
|
||||
task_pool.write(cr, uid, task.id, vals, context=context)
|
||||
|
||||
|
||||
phase_pool.write(cr, uid, [phase_id], {
|
||||
'date_start': start_date.strftime('%Y-%m-%d'),
|
||||
'date_end': end_date.strftime('%Y-%m-%d')
|
||||
}, context=context)
|
||||
return True
|
||||
|
||||
#TODO: DO Resource allocation and compute availability
|
||||
def compute_allocation(self, rc, uid, ids, start_date, end_date, context=None):
|
||||
if context == None:
|
||||
contex = {}
|
||||
allocation = {}
|
||||
return allocation
|
||||
|
||||
def schedule_tasks(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Schedule the tasks according to resource available and priority.
|
||||
Schedule task base on faces lib
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if type(ids) in (long, int,):
|
||||
ids = [ids]
|
||||
user_pool = self.pool.get('res.users')
|
||||
task_pool = self.pool.get('project.task')
|
||||
resource_pool = self.pool.get('resource.resource')
|
||||
resources_list = self.generate_members(cr, uid, ids, context=context)
|
||||
return_msg = {}
|
||||
data_pool = self.pool.get('ir.model.data')
|
||||
resource_allocation_pool = self.pool.get('project.resource.allocation')
|
||||
uom_pool = self.pool.get('product.uom')
|
||||
data_model, day_uom_id = data_pool.get_object_reference(cr, uid, 'product', 'uom_day')
|
||||
|
||||
for project in self.browse(cr, uid, ids, context=context):
|
||||
calendar_id = project.resource_calendar_id and project.resource_calendar_id.id or False
|
||||
start_date = project.date_start
|
||||
if not start_date:
|
||||
start_date = datetime.now().strftime("%Y-%m-%d")
|
||||
resources = resources_list.get(project.id, [])
|
||||
calendar_id = project.resource_calendar_id.id
|
||||
task_ids = task_pool.search(cr, uid, [('project_id', '=', project.id),
|
||||
#Creating resources using the member of the Project
|
||||
u_ids = [i.id for i in project.members]
|
||||
resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context)
|
||||
start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d")
|
||||
func_str = ''
|
||||
start = start_date
|
||||
minimum_time_unit = 1
|
||||
# default values
|
||||
working_hours_per_day = 24
|
||||
working_days_per_week = 7
|
||||
working_days_per_month = 30
|
||||
working_days_per_year = 365
|
||||
|
||||
vacation = []
|
||||
if calendar_id:
|
||||
working_hours_per_day = 8 #TODO: it should be come from calendars
|
||||
working_days_per_week = 5
|
||||
working_days_per_month = 20
|
||||
working_days_per_year = 200
|
||||
vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
|
||||
|
||||
working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
|
||||
|
||||
cls_str = ''
|
||||
# Creating Resources for the Project
|
||||
for key, vals in resource_objs.items():
|
||||
cls_str +='''
|
||||
class Resource_%s(Resource):
|
||||
title = \"%s\"
|
||||
vacation = %s
|
||||
efficiency = %s
|
||||
'''%(key, vals.get('name',False), vals.get('vacation', False), vals.get('efficiency', False))
|
||||
|
||||
# Create a new project for each phase
|
||||
func_str += '''
|
||||
def Project_%d():
|
||||
from resource.faces import Resource
|
||||
title = \"%s\"
|
||||
start = \'%s\'
|
||||
minimum_time_unit = %s
|
||||
working_hours_per_day = %s
|
||||
working_days_per_week = %s
|
||||
working_days_per_month = %s
|
||||
working_days_per_year = %s
|
||||
vacation = %s
|
||||
working_days = %s
|
||||
'''%(project.id, project.name, start, minimum_time_unit, working_hours_per_day, working_days_per_week, working_days_per_month, working_days_per_year, vacation, working_days )
|
||||
|
||||
parent = False
|
||||
task_ids = []
|
||||
todo_task_ids = task_pool.search(cr, uid, [('project_id', '=', project.id),
|
||||
('state', 'in', ['draft', 'open', 'pending'])
|
||||
])
|
||||
], order='sequence')
|
||||
if todo_task_ids:
|
||||
for task in task_pool.browse(cr, uid, todo_task_ids, context=context):
|
||||
func_str += task_pool.generate_task(cr, uid, task.id, parent=parent, flag=True,context=context)
|
||||
if not parent:
|
||||
parent = task
|
||||
task_ids.append(task.id)
|
||||
func_str += cls_str
|
||||
|
||||
|
||||
if task_ids:
|
||||
task_pool.generate_schedule(cr, uid, task_ids, resources, calendar_id, start_date, context=context)
|
||||
else:
|
||||
warning_msg = _("No tasks to compute for Project '%s'.") % (project.name)
|
||||
if "warning" not in return_msg:
|
||||
return_msg["warning"] = warning_msg
|
||||
else:
|
||||
return_msg["warning"] = return_msg["warning"] + "\n" + warning_msg
|
||||
|
||||
return return_msg
|
||||
# Allocating Memory for the required Project and Pahses and Resources
|
||||
exec(func_str)
|
||||
Project = eval('Project_%d' % project.id)
|
||||
project = Task.BalancedProject(Project)
|
||||
for task_id in task_ids:
|
||||
task = eval("project.Task_%d" % task_id)
|
||||
start_date = task.start.to_datetime()
|
||||
end_date = task.end.to_datetime()
|
||||
|
||||
task_pool.write(cr, uid, [task_id], {
|
||||
'date_start': start_date.strftime('%Y-%m-%d'),
|
||||
'date_end': end_date.strftime('%Y-%m-%d')
|
||||
}, context=context)
|
||||
return True
|
||||
|
||||
project()
|
||||
|
||||
|
@ -452,82 +677,39 @@ class project_task(osv.osv):
|
|||
_columns = {
|
||||
'phase_id': fields.many2one('project.phase', 'Project Phase'),
|
||||
}
|
||||
_defaults = {
|
||||
'user_id' : False
|
||||
}
|
||||
|
||||
def generate_schedule(self, cr, uid, ids, resources, calendar_id, start_date, context=None):
|
||||
"""
|
||||
Schedule the tasks according to resource available and priority.
|
||||
"""
|
||||
resource_pool = self.pool.get('resource.resource')
|
||||
if not ids:
|
||||
return False
|
||||
def generate_task(self, cr, uid, task_id, parent=False, flag=False, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
user_pool = self.pool.get('res.users')
|
||||
project_pool = self.pool.get('project.project')
|
||||
priority_dict = {'0': 1000, '1': 800, '2': 500, '3': 300, '4': 100}
|
||||
# Create dynamic no of tasks with the resource specified
|
||||
def create_tasks(task_number, eff, priorty=500, obj=False):
|
||||
def task():
|
||||
"""
|
||||
task is a dynamic method!
|
||||
"""
|
||||
effort = eff
|
||||
if obj:
|
||||
resource = obj
|
||||
priority = priorty
|
||||
task.__doc__ = "TaskNO%d" %task_number
|
||||
task.__name__ = "task%d" %task_number
|
||||
return task
|
||||
|
||||
# Create a 'Faces' project with all the tasks and resources
|
||||
def Project():
|
||||
title = "Project"
|
||||
start = datetime.strftime(datetime.strptime(start_date, "%Y-%m-%d"), "%Y-%m-%d %H:%M")
|
||||
try:
|
||||
resource = reduce(operator.or_, resources)
|
||||
except:
|
||||
raise osv.except_osv(_('Error'), _('Resources should be allocated to your phases and Members should be assigned to your Project!'))
|
||||
minimum_time_unit = 1
|
||||
working_hours_per_day = 24
|
||||
vacation = []
|
||||
if calendar_id:
|
||||
working_hours_per_day = 8 #TODO: it should be come from calendars
|
||||
vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id, context=context))
|
||||
working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context)
|
||||
# Dynamic creation of tasks
|
||||
task_number = 0
|
||||
for openobect_task in self.browse(cr, uid, ids, context=context):
|
||||
hours = str(openobect_task.planned_hours )+ 'H'
|
||||
if openobect_task.priority in priority_dict.keys():
|
||||
priorty = priority_dict[openobect_task.priority]
|
||||
real_resource = False
|
||||
if openobect_task.user_id:
|
||||
for task_resource in resources:
|
||||
if task_resource.__name__ == task_resource:
|
||||
real_resource = task_resource
|
||||
break
|
||||
|
||||
task = create_tasks(task_number, hours, priorty, real_resource)
|
||||
task_number += 1
|
||||
|
||||
|
||||
face_projects = Task.BalancedProject(Project)
|
||||
loop_no = 0
|
||||
# Write back the computed dates
|
||||
for face_project in face_projects:
|
||||
s_date = face_project.start.to_datetime()
|
||||
e_date = face_project.end.to_datetime()
|
||||
if loop_no > 0:
|
||||
ctx = context.copy()
|
||||
ctx.update({'scheduler': True})
|
||||
user_id = user_pool.search(cr, uid, [('name', '=', face_project.booked_resource[0].__name__)])
|
||||
self.write(cr, uid, [ids[loop_no-1]], {
|
||||
'date_start': s_date.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'date_end': e_date.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'user_id': user_id[0]
|
||||
}, context=ctx)
|
||||
|
||||
loop_no += 1
|
||||
return True
|
||||
phase_pool = self.pool.get('project.phase')
|
||||
resource_pool = self.pool.get('resource.resource')
|
||||
resource_allocation_pool = self.pool.get('project.resource.allocation')
|
||||
task = self.browse(cr, uid, task_id, context=context)
|
||||
duration = str(task.planned_hours )+ 'H'
|
||||
str_resource = False
|
||||
if task.phase_id.resource_ids:
|
||||
str_resource = ('%s | '*len(task.phase_id.resource_ids))[:-2]
|
||||
str_resource = str_resource % tuple(map(lambda x: 'Resource_%s'%x.resource_id.id, task.phase_id.resource_ids))
|
||||
# Task Defination for the Phase of the Project
|
||||
if not flag:
|
||||
s = '''
|
||||
def Task_%s():
|
||||
title = \"%s\"
|
||||
effort = \'%s\'
|
||||
resource = %s
|
||||
'''%(task.id, task.name, duration, str_resource)
|
||||
#start = datetime.strftime((datetime.strptime(start, "%Y-%m-%d")), "%Y-%m-%d")
|
||||
else:
|
||||
s = '''
|
||||
def Task_%s():
|
||||
title = \"%s\"
|
||||
effort = \'%s\'
|
||||
resource = %s
|
||||
'''%(task.id, task.name, duration, str_resource)
|
||||
s += '\n'
|
||||
return s
|
||||
project_task()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -233,9 +233,9 @@ This Demo data file Human Resources, Phases and Resources,Tasks allocation and
|
|||
</record>
|
||||
|
||||
<!-- run scheduling of phase -->
|
||||
<function model="project.project" name="schedule_phases" eval="(ref('project.project_integrate_openerp'),)"/>
|
||||
<!--<function model="project.project" name="schedule_phases" eval="(ref('project.project_integrate_openerp'),)"/>-->
|
||||
<!-- run scheduling of tasks -->
|
||||
<function model="project.project" name="schedule_tasks" eval="(ref('project.project_integrate_openerp'),)"/>
|
||||
<!--<function model="project.project" name="schedule_tasks" eval="(ref('project.project_integrate_openerp'),)"/>-->
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -116,10 +116,10 @@
|
|||
<field name="responsible_id"/>
|
||||
</group>
|
||||
<group colspan="6" col="6">
|
||||
<field name="date_start"/>
|
||||
<field name="date_start" readonly="1"/>
|
||||
<field name="duration"/>
|
||||
<field name="product_uom" nolabel="1" domain="[('category_id.name', '=', 'Working Time')]"/>
|
||||
<field name="date_end"/>
|
||||
<field name="date_end" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
|
@ -228,6 +228,7 @@
|
|||
<field name="date_end"/>
|
||||
<field name="duration"/>
|
||||
<field name="state"/>
|
||||
<button name="%(action_project_schedule_tasks)d" string="Schedule Tasks" type="action" icon="gtk-jump-to"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -322,7 +323,7 @@
|
|||
<field name="type">form</field>
|
||||
<field name="inherit_id" ref="project.edit_project"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="priority" position="before">
|
||||
<field name="effective_hours" position="after">
|
||||
<field name="resource_calendar_id"/>
|
||||
</field>
|
||||
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
-
|
||||
I have a project 'Develop yaml Project Module'.
|
||||
-
|
||||
!record {model: project.project, id: project_project_developyamlproject0}:
|
||||
name: "Develop Yaml Project Module"
|
||||
date_start: !eval time.strftime('%Y-%m-%d')
|
||||
-
|
||||
I have set Working Time from Monday to Friday from 9am to 17pm.
|
||||
-
|
||||
!record {model: resource.calendar, id: resource_calendar_hoursweeks0}:
|
||||
name: "from Monday to Friday, from 9am to 17pm"
|
||||
|
||||
-
|
||||
I have set Day1 Working Time for Monday to Friday from 9am to 17pm working hour
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_atendanceday1}:
|
||||
name: "Day1"
|
||||
hour_from : 09.00
|
||||
hour_to : 17.00
|
||||
dayofweek : "0"
|
||||
calendar_id : resource_calendar_hoursweeks0
|
||||
|
||||
-
|
||||
I have set Day2 Working Time for Monday to Friday from 9am to 17pm working hour
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_atendanceday1}:
|
||||
name: "Day2"
|
||||
hour_from : 09.00
|
||||
hour_to : 17.00
|
||||
dayofweek : "1"
|
||||
calendar_id : resource_calendar_hoursweeks0
|
||||
|
||||
-
|
||||
I have set Day3 Working Time for Monday to Friday from 9am to 17pm working hour
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_atendanceday1}:
|
||||
name: "Day3"
|
||||
hour_from : 09.00
|
||||
hour_to : 17.00
|
||||
dayofweek : "2"
|
||||
calendar_id : resource_calendar_hoursweeks0
|
||||
|
||||
-
|
||||
I have set Day4 Working Time for Monday to Friday from 9am to 17pm working hour
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_atendanceday1}:
|
||||
name: "Day4"
|
||||
hour_from : 09.00
|
||||
hour_to : 17.00
|
||||
dayofweek : "3"
|
||||
calendar_id : resource_calendar_hoursweeks0
|
||||
|
||||
-
|
||||
I have set Day5 Working Time for Monday to Friday from 9am to 17pm working hour
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_atendanceday1}:
|
||||
name: "Day5"
|
||||
hour_from : 09.00
|
||||
hour_to : 17.00
|
||||
dayofweek : "4"
|
||||
calendar_id : resource_calendar_hoursweeks0
|
||||
|
||||
|
||||
-
|
||||
Now Set working period to Project 'Develop yaml Project Module'
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
self.write(cr, uid, [ref("project_project_developyamlproject0")], {'resource_calendar_id': ref("resource_calendar_hoursweeks0")})
|
||||
|
||||
|
||||
-
|
||||
Creating 3 consecutive 5-days phases.
|
||||
For that Creating a Analyst Human resource to analyst Project Yaml.
|
||||
-
|
||||
!record {model: resource.resource, id: resource_resource_analyst1}:
|
||||
calendar_id: project_long_term.resource_calendar_hoursweeks0
|
||||
name: Analyst
|
||||
resource_type: user
|
||||
time_efficiency: 1.0
|
||||
user_id: base.user_admin
|
||||
|
||||
-
|
||||
Creating Developer Human resource who develop Yaml
|
||||
-
|
||||
!record {model: resource.resource, id: resource_resource_develop0}:
|
||||
calendar_id: project_long_term.resource_calendar_hoursweeks0
|
||||
name: Developer
|
||||
resource_type: user
|
||||
time_efficiency: 1.0
|
||||
user_id: base.user_admin
|
||||
-
|
||||
Creating a Tester Human resource for testing Yaml
|
||||
-
|
||||
!record {model: resource.resource, id: resource_resource_tester1}:
|
||||
calendar_id: project_long_term.resource_calendar_hoursweeks0
|
||||
name: tester
|
||||
resource_type: user
|
||||
time_efficiency: 1.0
|
||||
user_id: base.user_admin
|
||||
|
||||
-
|
||||
Create 3 a project phase and NO one depends on other one.
|
||||
so,they should start on the same day.
|
||||
Creating First 'Analysis Flow for Yaml' Project Phase.
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_analysisflowforyaml0}:
|
||||
date_start: !eval time.strftime('%Y-%m-%d')
|
||||
duration: 6.0
|
||||
name: "Analysis Flow for Yaml"
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_developyamlproject0
|
||||
responsible_id: project.res_users_analyst
|
||||
state: draft
|
||||
|
||||
-
|
||||
I update the Constrain Date Start adn Date End for phase Analysis Flow for Yaml
|
||||
-
|
||||
!python {model : project.phase }: |
|
||||
import datetime
|
||||
from dateutil.relativedelta import *
|
||||
start = datetime.date.today() - relativedelta(days=2)
|
||||
end = datetime.date.today() + relativedelta(days=6)
|
||||
self.write(cr,uid, [(ref("project_phase_analysisflowforyaml0"))], {'constraint_date_start': start, 'constraint_date_end':end})
|
||||
|
||||
-
|
||||
Create project phase 'Develop yaml' with constraint date.
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_developyaml0}:
|
||||
duration: 6.0
|
||||
name: Develop Yaml
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_developyamlproject0
|
||||
previous_phase_ids:
|
||||
- project_phase_analysisflowforyaml0
|
||||
|
||||
-
|
||||
I update the Constrain Date Start adn Date End for phase Develop yaml
|
||||
-
|
||||
!python {model : project.phase }: |
|
||||
import datetime
|
||||
from dateutil.relativedelta import *
|
||||
start = datetime.date.today() - relativedelta(days=5)
|
||||
end = datetime.date.today() + relativedelta(days=10)
|
||||
self.write(cr,uid, [(ref("project_phase_developyaml0"))], {'constraint_date_start': start, 'constraint_date_end':end})
|
||||
-
|
||||
Create project phase 'Test Yaml'
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_testyaml0}:
|
||||
duration: 6.0
|
||||
name: Testing Yaml
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_developyamlproject0
|
||||
previous_phase_ids:
|
||||
- project_phase_developyaml0
|
||||
constraint_date_start :
|
||||
constraint_date_end :
|
||||
-
|
||||
Compute Schedule of phases For One project
|
||||
-
|
||||
!record {model: project.compute.phases, id: project_compute_phases_0}:
|
||||
project_id: project_project_developyamlproject0
|
||||
target_project: one
|
||||
|
||||
-
|
||||
Schedule project phases using "Compute Phase Scheduling"
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
self.schedule_phases(cr, uid, [ref("project_project_developyamlproject0")])
|
||||
|
||||
-
|
||||
After scheduling,check that
|
||||
Phase "Analysis Flow for Yaml" and "Test Yaml" Phase should start on the project start date while "Develop yaml" Phase should respect the constraint.
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
proj=self.browse(cr, uid, [ref("project_project_developyamlproject0")])[0]
|
||||
for phase in proj.phase_ids:
|
||||
for phase1 in proj.phase_ids:
|
||||
if phase1.id != phase.id and phase.constraint_date_start == phase1.date_start:
|
||||
raise AssertionError("Phases not scheduled")
|
|
@ -0,0 +1,126 @@
|
|||
-
|
||||
Create a project 'Develop yaml Project Module'.
|
||||
-
|
||||
!record {model: project.project, id: project_project_developyamlproject123}:
|
||||
name: "Develop Yaml Project Module"
|
||||
date_start: !eval time.strftime('%Y-%m-%d')
|
||||
|
||||
-
|
||||
I have set Working Time from Monday to Friday from 9am to 17pm.
|
||||
-
|
||||
!record {model: resource.calendar, id: resource_calendar_hoursweekstest2}:
|
||||
name: "from Monday to Friday, from 9am to 17pm"
|
||||
|
||||
-
|
||||
I have set Day1 Working Time for Monday to Friday from 9am to 17pm working hour
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_atendanceday1}:
|
||||
name: "Day1"
|
||||
hour_from : 09.00
|
||||
hour_to : 17.00
|
||||
dayofweek : "0"
|
||||
calendar_id : resource_calendar_hoursweekstest2
|
||||
|
||||
-
|
||||
I have set Day2 Working Time for Monday to Friday from 9am to 17pm working hour
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_atendanceday2}:
|
||||
name: "Day2"
|
||||
hour_from : 09.00
|
||||
hour_to : 17.00
|
||||
dayofweek : "1"
|
||||
calendar_id : resource_calendar_hoursweekstest2
|
||||
|
||||
-
|
||||
I have set Day3 Working Time for Monday to Friday from 9am to 17pm working hour
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_atendanceday3}:
|
||||
name: "Day3"
|
||||
hour_from : 09.00
|
||||
hour_to : 17.00
|
||||
dayofweek : "2"
|
||||
calendar_id : resource_calendar_hoursweekstest2
|
||||
|
||||
-
|
||||
I have set Day4 Working Time for Monday to Friday from 9am to 17pm working hour
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_atendanceday4}:
|
||||
name: "Day4"
|
||||
hour_from : 09.00
|
||||
hour_to : 17.00
|
||||
dayofweek : "3"
|
||||
calendar_id : resource_calendar_hoursweekstest2
|
||||
|
||||
-
|
||||
I have set Day5 Working Time for Monday to Friday from 9am to 17pm working hour
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_atendanceday5}:
|
||||
name: "Day5"
|
||||
hour_from : 09.00
|
||||
hour_to : 17.00
|
||||
dayofweek : "4"
|
||||
calendar_id : resource_calendar_hoursweekstest2
|
||||
|
||||
-
|
||||
Now Set working period to Project 'Develop yaml Project Module'
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
self.write(cr, uid, [ref("project_project_developyamlproject123")], {'resource_calendar_id': ref("resource_calendar_hoursweekstest2")})
|
||||
|
||||
-
|
||||
Create 3 a project phase.
|
||||
First 'Analysis Flow for Yaml'Project Phase
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_analysisflowforyaml0}:
|
||||
date_start: !eval time.strftime('%Y-%m-%d')
|
||||
duration: 5.0
|
||||
name: "Analysis Flow for Yaml"
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_developyamlproject123
|
||||
state: draft
|
||||
|
||||
-
|
||||
Create project phase 'Develop yaml'
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_establishingprojectfeasibility0}:
|
||||
duration: 5.0
|
||||
name: Develop Yaml
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_developyamlproject123
|
||||
previous_phase_ids:
|
||||
- project_phase_analysisflowforyaml0
|
||||
|
||||
-
|
||||
Create project phase 'Test Yaml'
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_preparationofengineeringdesigns0}:
|
||||
duration: 5.0
|
||||
name: Testing Yaml
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_developyamlproject123
|
||||
previous_phase_ids:
|
||||
- project_phase_establishingprojectfeasibility0
|
||||
|
||||
-
|
||||
Compute Schedule of phases For One project
|
||||
-
|
||||
!record {model: project.compute.phases, id: project_compute_phases_0}:
|
||||
project_id: project_project_developyamlproject123
|
||||
target_project: one
|
||||
|
||||
-
|
||||
Schedule project phases using Compute Phase Scheduling
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
self.schedule_phases(cr, uid, [ref("project_project_developyamlproject123")])
|
||||
|
||||
-
|
||||
After scheduling, Check that phases scheduled, check that either of phase's start_date, end_date not null.
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
proj=self.browse(cr, uid, [ref("project_project_developyamlproject123")])[0]
|
||||
for phase in proj.phase_ids:
|
||||
if (not phase.responsible_id) or (not phase.date_start) or (not phase.date_end):
|
||||
raise AssertionError("Phases not scheduled")
|
||||
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
-
|
||||
Create a project 'Develop yaml Implementation Module'.
|
||||
-
|
||||
!record {model: project.project, id: project_project_developyamlproject0}:
|
||||
name: "Develop Yaml Project Module"
|
||||
date_start: !eval time.strftime('%Y-%m-%d')
|
||||
|
||||
-
|
||||
Create 4 Project phase.
|
||||
First Project Phase 'Analysis Flow for Yaml'
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_analysisflowforyaml0}:
|
||||
date_start: !eval time.strftime('%Y-%m-%d')
|
||||
duration: 6.0
|
||||
product_uom: product.uom_day
|
||||
name: "Analysis Flow for Yaml"
|
||||
project_id: project_project_developyamlproject0
|
||||
responsible_id: project.res_users_analyst
|
||||
state: draft
|
||||
|
||||
-
|
||||
Create project phase 'Develop yaml'
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_establishingprojectfeasibility0}:
|
||||
duration: 6.0
|
||||
name: "Develop yaml"
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_developyamlproject0
|
||||
previous_phase_ids:
|
||||
- project_phase_analysisflowforyaml0
|
||||
state: draft
|
||||
-
|
||||
Create project phase 'Test Yaml'
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_preparationofengineeringdesigns0}:
|
||||
duration: 6.0
|
||||
name: Testing Yaml
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_developyamlproject0
|
||||
previous_phase_ids:
|
||||
- project_phase_establishingprojectfeasibility0
|
||||
state: draft
|
||||
|
||||
-
|
||||
Create project phase 'Implement Yaml'
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_implementingreadycase0}:
|
||||
duration: 6.0
|
||||
name: Testing Yaml
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_developyamlproject0
|
||||
previous_phase_ids:
|
||||
- project_phase_preparationofengineeringdesigns0
|
||||
state: draft
|
||||
-
|
||||
Compute Schedule of phases For One project
|
||||
-
|
||||
!record {model: project.compute.phases, id: project_compute_phases_0}:
|
||||
project_id: project_project_developyamlproject0
|
||||
target_project: one
|
||||
|
||||
-
|
||||
Schedule project phases using Compute Phase Scheduling
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
self.schedule_phases(cr, uid, [ref("project_project_developyamlproject0")])
|
||||
|
||||
-
|
||||
After scheduling, Check that phases scheduled, check that either of phase's start_date, end_date not null.
|
||||
-
|
||||
!python {model: project.project}: |
|
||||
proj=self.browse(cr, uid, [ref("project_project_developyamlproject0")])[0]
|
||||
for phase in proj.phase_ids:
|
||||
if (not phase.responsible_id) or (not phase.date_start) or (not phase.date_end):
|
||||
raise AssertionError("Phases not scheduled")
|
||||
|
||||
|
|
@ -23,12 +23,8 @@
|
|||
state: draft
|
||||
resource_ids:
|
||||
- resource_id: project_long_term.resource_analyst
|
||||
useability: 80.0
|
||||
- resource_id: project_long_term.resource_developer
|
||||
useability: 30.0
|
||||
- resource_id: project_long_term.resource_designer
|
||||
useability: 30.0
|
||||
|
||||
|
||||
-
|
||||
Create the phase task 'Develop GUI for Server Configuration'
|
||||
|
|
|
@ -4,7 +4,14 @@
|
|||
!record {model: project.project, id: project_project_worldbanksproject0}:
|
||||
name: "World Bank's Project"
|
||||
priority: 4
|
||||
|
||||
members:
|
||||
- project.res_users_analyst
|
||||
- project.res_users_project_manager
|
||||
- project.res_users_technical_leader
|
||||
- project.res_users_developer
|
||||
- project.res_users_designer
|
||||
- project.res_users_tester
|
||||
|
||||
-
|
||||
Create a project phase 'Defining Client's Basic Idea of Project'
|
||||
-
|
||||
|
@ -14,8 +21,7 @@
|
|||
name: "Defining Client's Basic Idea of Project"
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_worldbanksproject0
|
||||
|
||||
|
||||
|
||||
-
|
||||
Create project phase 'Establishing Project Feasibility'
|
||||
-
|
||||
|
@ -25,7 +31,49 @@
|
|||
name: Establishing Project Feasibility
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_worldbanksproject0
|
||||
|
||||
-
|
||||
Resource1
|
||||
-
|
||||
!record {model: project.resource.allocation, id: res_phase1}:
|
||||
resource_id: project_long_term.resource_project_manager
|
||||
phase_id: project_phase_definingclientsbasicideaofproject0
|
||||
|
||||
-
|
||||
Resource2
|
||||
-
|
||||
!record {model: project.resource.allocation, id: res_phase2}:
|
||||
resource_id: project_long_term.resource_analyst
|
||||
phase_id: project_phase_definingclientsbasicideaofproject0
|
||||
|
||||
-
|
||||
Resource3
|
||||
-
|
||||
!record {model: project.resource.allocation, id: res_phase3}:
|
||||
resource_id: project_long_term.resource_technical_leader
|
||||
phase_id: project_phase_definingclientsbasicideaofproject0
|
||||
|
||||
-
|
||||
Create the phase task 'Develop GUI for Server Configuration'
|
||||
-
|
||||
!record {model: project.task, id: project_task_t0}:
|
||||
name: Develop GUI for Server Configuration
|
||||
planned_hours: 20.0
|
||||
state: draft
|
||||
phase_id: project_phase_definingclientsbasicideaofproject0
|
||||
project_id: project_project_worldbanksproject0
|
||||
|
||||
-
|
||||
Create the phase task 'Develop GUI for Modules Configuration'
|
||||
-
|
||||
!record {model: project.task, id: project_task_t1}:
|
||||
name: Develop GUI for Modules Configuration
|
||||
planned_hours: 25.0
|
||||
remaining_hours: 25.0
|
||||
state: draft
|
||||
phase_id: project_phase_definingclientsbasicideaofproject0
|
||||
project_id: project_project_worldbanksproject0
|
||||
|
||||
-
|
||||
Create project phase 'Preparation of Engineering Designs'
|
||||
-
|
||||
|
@ -36,7 +84,43 @@
|
|||
product_uom: product.uom_hour
|
||||
project_id: project_project_worldbanksproject0
|
||||
|
||||
|
||||
-
|
||||
Resource4
|
||||
-
|
||||
!record {model: project.resource.allocation, id: res_phase4}:
|
||||
resource_id: project_long_term.resource_developer
|
||||
phase_id: project_phase_preparationofengineeringdesigns0
|
||||
|
||||
-
|
||||
Resource5
|
||||
-
|
||||
!record {model: project.resource.allocation, id: res_phase5}:
|
||||
resource_id: project_long_term.resource_designer
|
||||
phase_id: project_phase_preparationofengineeringdesigns0
|
||||
|
||||
-
|
||||
Create the phase task 'Develop GUI for Client Configuration'
|
||||
-
|
||||
!record {model: project.task, id: project_task_t2}:
|
||||
name: Develop GUI for Server Configuration
|
||||
planned_hours: 20.0
|
||||
remaining_hours: 20.0
|
||||
state: draft
|
||||
phase_id: project_phase_preparationofengineeringdesigns0
|
||||
project_id: project_project_worldbanksproject0
|
||||
|
||||
-
|
||||
Create the phase task 'Develop GUI for Client Module Configuration'
|
||||
-
|
||||
!record {model: project.task, id: project_task_t3}:
|
||||
name: Develop GUI for Modules Configuration
|
||||
planned_hours: 25.0
|
||||
remaining_hours: 25.0
|
||||
state: draft
|
||||
phase_id: project_phase_preparationofengineeringdesigns0
|
||||
project_id: project_project_worldbanksproject0
|
||||
|
||||
|
||||
-
|
||||
Create project phase 'Procurement of Works and Goods'
|
||||
-
|
||||
|
@ -46,14 +130,13 @@
|
|||
name: Procurement of Works and Goods
|
||||
product_uom: product.uom_hour
|
||||
project_id: project_project_worldbanksproject0
|
||||
|
||||
|
||||
|
||||
-
|
||||
Create project phase 'Project Construction'
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_projectconstruction0}:
|
||||
date_start: '2010-06-02'
|
||||
duration: 4320.0
|
||||
duration: 20.0
|
||||
name: Project Construction
|
||||
product_uom: product.uom_hour
|
||||
project_id: project_project_worldbanksproject0
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
-
|
||||
In order to test scheduling of project phases, I create two different phases and
|
||||
test it with two different dates for scheduling.
|
||||
-
|
||||
I create a project 'Development and Testing'.
|
||||
-
|
||||
!record {model: project.project, id: project_project_project0}:
|
||||
date_start: '2010-12-30'
|
||||
balance: 0.0
|
||||
credit: 0.0
|
||||
currency_id: base.EUR
|
||||
debit: 0.0
|
||||
effective_hours: 0.0
|
||||
members:
|
||||
- base.user_admin
|
||||
name: Development and Testing
|
||||
planned_hours: 0.0
|
||||
progress_rate: 0.0
|
||||
quantity: 0.0
|
||||
quantity_max: 0.0
|
||||
state: open
|
||||
type_ids:
|
||||
- project.project_tt_specification
|
||||
- project.project_tt_development
|
||||
- project.project_tt_testing
|
||||
- project.project_tt_merge
|
||||
-
|
||||
I create first phase of the project.
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_firstphase0}:
|
||||
duration: 2.0
|
||||
name: First Phase
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_project0
|
||||
state: draft
|
||||
-
|
||||
I create second phase of the project.
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_secondphase0}:
|
||||
duration: 3.0
|
||||
name: Second Phase
|
||||
previous_phase_ids:
|
||||
- project_phase_firstphase0
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_project0
|
||||
state: draft
|
||||
-
|
||||
Now I create a record to compute the phase of project.
|
||||
-
|
||||
!record {model: project.compute.phases, id: project_compute_phases0}:
|
||||
target_project: 'one'
|
||||
project_id: project_project_project0
|
||||
-
|
||||
I schedule the phases.
|
||||
-
|
||||
!python {model: project.compute.phases}: |
|
||||
self.check_selection(cr, uid, [ref("project_compute_phases0")])
|
||||
-
|
||||
I check the starting and ending dates of both phases.
|
||||
-
|
||||
!python {model: project.phase}: |
|
||||
first_phase = self.browse(cr, uid, ref('project_phase_firstphase0'))
|
||||
assert (first_phase.date_start == '2010-12-30' and first_phase.date_end == '2010-12-31'),'Dates are wrong!'
|
||||
second_phase = self.browse(cr, uid, ref('project_phase_secondphase0'))
|
||||
assert (second_phase.date_start == '2011-01-01' and second_phase.date_end == '2011-01-03'),'Dates are wrong!'
|
|
@ -0,0 +1,193 @@
|
|||
-
|
||||
In order to test scheduling of project phases, I create two different
|
||||
working periods and resources. And schedule the phases.
|
||||
-
|
||||
I create first working period 'Working Time A'.
|
||||
-
|
||||
!record {model: resource.calendar, id: resource_calendar_workingtimea0}:
|
||||
attendance_ids:
|
||||
- dayofweek: '0'
|
||||
hour_from: 10.0
|
||||
hour_to: 16.0
|
||||
name: Monday
|
||||
- dayofweek: '1'
|
||||
hour_from: 10.0
|
||||
hour_to: 16.0
|
||||
name: Tuesday
|
||||
- dayofweek: '2'
|
||||
hour_from: 10.0
|
||||
hour_to: 16.0
|
||||
name: Wednesday
|
||||
- dayofweek: '3'
|
||||
hour_from: 10.0
|
||||
hour_to: 16.0
|
||||
name: Thursday
|
||||
name: Working Time A
|
||||
|
||||
-
|
||||
Creating a resource.calendar.attendance record
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_attendance_monday0}:
|
||||
calendar_id: resource_calendar_workingtimea0
|
||||
dayofweek: '0'
|
||||
hour_from: 10.0
|
||||
hour_to: 16.0
|
||||
name: Monday
|
||||
-
|
||||
Creating a resource.calendar.attendance record
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_attendance_tuesday0}:
|
||||
calendar_id: resource_calendar_workingtimea0
|
||||
dayofweek: '1'
|
||||
hour_from: 10.0
|
||||
hour_to: 16.0
|
||||
name: Tuesday
|
||||
-
|
||||
Creating a resource.calendar.attendance record
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_attendance_wednesday0}:
|
||||
calendar_id: resource_calendar_workingtimea0
|
||||
dayofweek: '2'
|
||||
hour_from: 10.0
|
||||
hour_to: 16.0
|
||||
name: Wednesday
|
||||
-
|
||||
Creating a resource.calendar.attendance record
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_attendance_thursday0}:
|
||||
calendar_id: resource_calendar_workingtimea0
|
||||
dayofweek: '3'
|
||||
hour_from: 10.0
|
||||
hour_to: 16.0
|
||||
name: Thursday
|
||||
-
|
||||
I create second working period 'Working Time B'.
|
||||
-
|
||||
!record {model: resource.calendar, id: resource_calendar_workingtimeb0}:
|
||||
attendance_ids:
|
||||
- dayofweek: '4'
|
||||
hour_from: 9.0
|
||||
hour_to: 18.0
|
||||
name: Friday
|
||||
name: Working Time B
|
||||
-
|
||||
Creating a resource.calendar.attendance record
|
||||
-
|
||||
!record {model: resource.calendar.attendance, id: resource_calendar_attendance_friday0}:
|
||||
calendar_id: resource_calendar_workingtimeb0
|
||||
dayofweek: '4'
|
||||
hour_from: 9.0
|
||||
hour_to: 18.0
|
||||
name: Friday
|
||||
-
|
||||
I create first resource say 'Resource X' without assigning working period.
|
||||
-
|
||||
!record {model: resource.resource, id: resource_resource_resourcex0}:
|
||||
name: Resource X
|
||||
resource_type: user
|
||||
time_efficiency: 1.0
|
||||
user_id: base.user_admin
|
||||
-
|
||||
I create first resource say 'Resource Y' with working period 'Working Time B'.
|
||||
-
|
||||
!record {model: resource.resource, id: resource_resource_resourcey0}:
|
||||
calendar_id: resource_calendar_workingtimeb0
|
||||
name: Resource Y
|
||||
resource_type: user
|
||||
time_efficiency: 1.0
|
||||
user_id: base.user_admin
|
||||
-
|
||||
I create a project 'Development and Testing' and assign working period 'Working Time A'.
|
||||
-
|
||||
!record {model: project.project, id: project_project_project0}:
|
||||
balance: 0.0
|
||||
credit: 0.0
|
||||
currency_id: base.EUR
|
||||
debit: 0.0
|
||||
effective_hours: 0.0
|
||||
members:
|
||||
- base.user_admin
|
||||
name: Development and Testing
|
||||
planned_hours: 20.0
|
||||
progress_rate: 0.0
|
||||
quantity: 0.0
|
||||
quantity_max: 0.0
|
||||
resource_calendar_id: resource_calendar_workingtimea0
|
||||
state: open
|
||||
tasks:
|
||||
- delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task 1
|
||||
planned_hours: 10.0
|
||||
remaining_hours: 10.0
|
||||
state: draft
|
||||
total_hours: 10.0
|
||||
- delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task 2
|
||||
planned_hours: 10.0
|
||||
remaining_hours: 10.0
|
||||
state: draft
|
||||
total_hours: 10.0
|
||||
total_hours: 10.0
|
||||
members:
|
||||
- project.res_users_analyst
|
||||
- project.res_users_project_manager
|
||||
- project.res_users_technical_leader
|
||||
- project.res_users_developer
|
||||
- project.res_users_designer
|
||||
- project.res_users_tester
|
||||
type_ids:
|
||||
- project.project_tt_specification
|
||||
- project.project_tt_development
|
||||
- project.project_tt_testing
|
||||
- project.project_tt_merge
|
||||
|
||||
-
|
||||
I create a phase 'Initial Phase' for project 'Development and Testing'.
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_phase0}:
|
||||
date_start: '2011-01-03'
|
||||
duration: 0.0
|
||||
name: Initial Phase
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_project0
|
||||
state: draft
|
||||
-
|
||||
I create first task 'Developing module' and assign 10h.
|
||||
-
|
||||
!record {model: project.task, id: project_task_task0}:
|
||||
delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Developing module
|
||||
planned_hours: 10.0
|
||||
project_id: project_project_project0
|
||||
remaining_hours: 10.0
|
||||
state: draft
|
||||
total_hours: 10.0
|
||||
phase_id: project_phase_phase0
|
||||
-
|
||||
I create first task 'Testing module' and assign 10h.
|
||||
-
|
||||
!record {model: project.task, id: project_task_task1}:
|
||||
delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Testing module
|
||||
planned_hours: 10.0
|
||||
project_id: project_project_project0
|
||||
remaining_hours: 10.0
|
||||
state: draft
|
||||
total_hours: 10.0
|
||||
phase_id: project_phase_phase0
|
||||
-
|
||||
Now I create a record to compute the phase of project.
|
||||
-
|
||||
!record {model: project.compute.phases, id: project_compute_phases0}:
|
||||
target_project: 'one'
|
||||
project_id: project_project_project0
|
||||
-
|
||||
I schedule the phases.
|
||||
-
|
||||
!python {model: project.compute.phases}: |
|
||||
self.check_selection(cr, uid, [ref("project_compute_phases0")])
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
-
|
||||
In order to test scheduling of tasks, I create four tasks with different sequences and schedule them.
|
||||
-
|
||||
I create address for first user.
|
||||
-
|
||||
!record {model: res.partner.address, id: res_partner_address_user0}:
|
||||
name: User 1
|
||||
-
|
||||
I create address for second user.
|
||||
-
|
||||
!record {model: res.partner.address, id: res_partner_address_user1}:
|
||||
name: User 2
|
||||
-
|
||||
I create first user.
|
||||
-
|
||||
!record {model: res.users, id: res_users_user0}:
|
||||
address_id: res_partner_address_user0
|
||||
company_id: base.main_company
|
||||
context_lang: en_US
|
||||
groups_id:
|
||||
- base.group_partner_manager
|
||||
- base.group_user
|
||||
login: user1
|
||||
name: User 1
|
||||
password: user1
|
||||
-
|
||||
I create second user.
|
||||
-
|
||||
!record {model: res.users, id: res_users_user1}:
|
||||
address_id: res_partner_address_user1
|
||||
company_id: base.main_company
|
||||
context_lang: en_US
|
||||
groups_id:
|
||||
- base.group_partner_manager
|
||||
- base.group_user
|
||||
login: user2
|
||||
name: User 2
|
||||
password: user2
|
||||
-
|
||||
I create a Project.
|
||||
-
|
||||
!record {model: project.project, id: project_project_projecta0}:
|
||||
balance: 0.0
|
||||
credit: 0.0
|
||||
currency_id: base.EUR
|
||||
debit: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Project A
|
||||
members:
|
||||
- res_users_user0
|
||||
- res_users_user1
|
||||
phase_ids:
|
||||
- date_start: '2011-01-06'
|
||||
duration: 2.0
|
||||
name: Phase A
|
||||
product_uom: product.uom_day
|
||||
state: draft
|
||||
task_ids:
|
||||
- delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task D
|
||||
planned_hours: 5.0
|
||||
remaining_hours: 5.0
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
- delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task C
|
||||
planned_hours: 5.0
|
||||
remaining_hours: 5.0
|
||||
sequence: 11
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
- delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task B
|
||||
planned_hours: 5.0
|
||||
remaining_hours: 5.0
|
||||
sequence: 13
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
- delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task A
|
||||
planned_hours: 5.0
|
||||
remaining_hours: 5.0
|
||||
sequence: 14
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
planned_hours: 20.0
|
||||
progress_rate: 0.0
|
||||
quantity: 0.0
|
||||
quantity_max: 0.0
|
||||
state: open
|
||||
tasks:
|
||||
- delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task D
|
||||
planned_hours: 5.0
|
||||
remaining_hours: 5.0
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
- delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task C
|
||||
planned_hours: 5.0
|
||||
remaining_hours: 5.0
|
||||
sequence: 11
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
- delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task B
|
||||
planned_hours: 5.0
|
||||
remaining_hours: 5.0
|
||||
sequence: 13
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
- delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task A
|
||||
planned_hours: 5.0
|
||||
remaining_hours: 5.0
|
||||
sequence: 14
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
total_hours: 15.0
|
||||
-
|
||||
I create first task with highest sequence.
|
||||
-
|
||||
!record {model: project.task, id: project_task_taska0}:
|
||||
delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task A
|
||||
planned_hours: 5.0
|
||||
project_id: project_project_projecta0
|
||||
remaining_hours: 5.0
|
||||
sequence: 14
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
-
|
||||
I create second task.
|
||||
-
|
||||
!record {model: project.task, id: project_task_taskb0}:
|
||||
delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task B
|
||||
planned_hours: 5.0
|
||||
project_id: project_project_projecta0
|
||||
remaining_hours: 5.0
|
||||
sequence: 13
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
-
|
||||
I create third task.
|
||||
-
|
||||
!record {model: project.task, id: project_task_taskc0}:
|
||||
delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task C
|
||||
planned_hours: 5.0
|
||||
project_id: project_project_projecta0
|
||||
remaining_hours: 5.0
|
||||
sequence: 11
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
-
|
||||
I create fourth task with lowest sequence.
|
||||
-
|
||||
!record {model: project.task, id: project_task_taskd0}:
|
||||
delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task D
|
||||
planned_hours: 5.0
|
||||
project_id: project_project_projecta0
|
||||
remaining_hours: 5.0
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
-
|
||||
Now I create a resource for first user.
|
||||
-
|
||||
!record {model: resource.resource, id: resource_resource_user0}:
|
||||
name: User 1
|
||||
resource_type: user
|
||||
time_efficiency: 1.0
|
||||
user_id: res_users_user0
|
||||
-
|
||||
I create a resource for second user.
|
||||
-
|
||||
!record {model: resource.resource, id: resource_resource_user1}:
|
||||
name: User 2
|
||||
resource_type: user
|
||||
time_efficiency: 1.0
|
||||
user_id: res_users_user1
|
||||
-
|
||||
Now I create one phase for the project.
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_phasea0}:
|
||||
date_start: '2011-01-06'
|
||||
duration: 2.0
|
||||
name: Phase A
|
||||
product_uom: product.uom_day
|
||||
project_id: project_project_projecta0
|
||||
resource_ids:
|
||||
- project_id: project_project_projecta0
|
||||
resource_id: resource_resource_user0
|
||||
- project_id: project_project_projecta0
|
||||
resource_id: resource_resource_user1
|
||||
state: draft
|
||||
task_ids:
|
||||
- delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task D
|
||||
planned_hours: 5.0
|
||||
project_id: project_project_projecta0
|
||||
remaining_hours: 5.0
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
- delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task C
|
||||
planned_hours: 5.0
|
||||
project_id: project_project_projecta0
|
||||
remaining_hours: 5.0
|
||||
sequence: 11
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
- delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task B
|
||||
planned_hours: 5.0
|
||||
project_id: project_project_projecta0
|
||||
remaining_hours: 5.0
|
||||
sequence: 13
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
- delay_hours: 0.0
|
||||
effective_hours: 0.0
|
||||
name: Task A
|
||||
planned_hours: 5.0
|
||||
project_id: project_project_projecta0
|
||||
remaining_hours: 5.0
|
||||
sequence: 14
|
||||
state: draft
|
||||
total_hours: 5.0
|
||||
-
|
||||
Now I create a record to schedule the tasks of project.
|
||||
-
|
||||
!record {model: project.compute.tasks, id: project_compute_tasks0}:
|
||||
project_id: project_project_projecta0
|
||||
-
|
||||
I schedule the tasks.
|
||||
-
|
||||
!python {model: project.compute.tasks}: |
|
||||
self.compute_date(cr, uid, [ref("project_compute_tasks0")])
|
||||
-
|
||||
I check that whether the tasks now allocated to respected resources or not.
|
||||
-
|
||||
!python {model: project.task}: |
|
||||
task_ids = self.search(cr, uid, [('project_id','=',ref('project_project_projecta0'))])
|
||||
for task in self.browse(cr, uid, task_ids):
|
||||
if (not task.user_id) or (not task.date_start) or (not task.date_end):
|
||||
raise AssertionError("Tasks are not scheduled.")
|
|
@ -28,16 +28,7 @@ from tools.translate import _
|
|||
|
||||
class project_project(osv.osv):
|
||||
_inherit = 'project.project'
|
||||
def onchange_partner_id(self, cr, uid, ids, part=False, context=None):
|
||||
result = super(project_project, self).onchange_partner_id(cr, uid, ids, part, context=context)
|
||||
if result.get('value', False):
|
||||
try:
|
||||
d = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'hr_timesheet_invoice', 'timesheet_invoice_factor1')
|
||||
if d:
|
||||
result['value']['to_invoice'] = d[1]
|
||||
except ValueError, e:
|
||||
pass
|
||||
return result
|
||||
|
||||
project_project()
|
||||
|
||||
class project_work(osv.osv):
|
||||
|
@ -231,4 +222,16 @@ class res_partner(osv.osv):
|
|||
context=context)
|
||||
res_partner()
|
||||
|
||||
class account_analytic_line(osv.osv):
|
||||
_inherit = "account.analytic.line"
|
||||
def on_change_account_id(self, cr, uid, ids, account_id):
|
||||
res = {}
|
||||
if not account_id:
|
||||
return res
|
||||
res.setdefault('value',{})
|
||||
acc = self.pool.get('account.analytic.account').browse(cr, uid, account_id)
|
||||
st = acc.to_invoice.id
|
||||
res['value']['to_invoice'] = st or False
|
||||
return res
|
||||
account_analytic_line()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<group colspan="4" col="4">
|
||||
<separator colspan="4" string="Invoicing Data"/>
|
||||
<field name="pricelist_id" domain="[('type','=','sale')]" widget="selection"/>
|
||||
<field name="to_invoice" widget="selection" string="Invoice Task Work"/>
|
||||
<field name="to_invoice" widget="selection" string="Invoice Task Work" attrs="{'required':[('partner_id','!=',False)]}"/>
|
||||
<field name="amount_max" groups="base.group_extended"/>
|
||||
<field name="amount_invoiced" groups="base.group_extended"/>
|
||||
</group>
|
||||
|
@ -61,7 +61,7 @@
|
|||
<field name="inherit_id" ref="account.view_account_analytic_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="account_id" position="replace">
|
||||
<field name="account_id" string="Project"/>
|
||||
<field name="account_id" string="Analytic account/project" on_change="on_change_account_id(account_id)"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -250,7 +250,7 @@ class resource_resource(osv.osv):
|
|||
"""
|
||||
Return a list of Resource Class objects for the resources allocated to the phase.
|
||||
"""
|
||||
resource_objs = []
|
||||
resource_objs = {}
|
||||
user_pool = self.pool.get('res.users')
|
||||
for user in user_pool.browse(cr, uid, user_ids, context=context):
|
||||
resource_ids = self.search(cr, uid, [('user_id', '=', user.id)], context=context)
|
||||
|
@ -264,12 +264,18 @@ class resource_resource(osv.osv):
|
|||
resource_cal = resource.calendar_id.id
|
||||
if resource_cal:
|
||||
leaves = self.compute_vacation(cr, uid, calendar_id, resource.id, resource_cal, context=context)
|
||||
resource_objs.append(classobj(str(user.name), (Resource,),{
|
||||
'__doc__': user.name,
|
||||
'__name__': user.name,
|
||||
'vacation': tuple(leaves),
|
||||
'efficiency': resource_eff,
|
||||
}))
|
||||
temp = {
|
||||
'name' : resource.name,
|
||||
'vacation': tuple(leaves),
|
||||
'efficiency': resource_eff,
|
||||
}
|
||||
resource_objs[resource_id] = temp
|
||||
# resource_objs.append(classobj(str(user.name), (Resource,),{
|
||||
# '__doc__': user.name,
|
||||
# '__name__': user.name,
|
||||
# 'vacation': tuple(leaves),
|
||||
# 'efficiency': resource_eff,
|
||||
# }))
|
||||
return resource_objs
|
||||
|
||||
def compute_vacation(self, cr, uid, calendar_id, resource_id=False, resource_calendar=False, context=None):
|
||||
|
@ -322,6 +328,7 @@ class resource_resource(osv.osv):
|
|||
# and create a list like [('mon', '8:00-12:00'), ('mon', '13:00-18:00')]
|
||||
for week in weeks:
|
||||
res_str = ""
|
||||
day = None
|
||||
if week_days.has_key(week['dayofweek']):
|
||||
day = week_days[week['dayofweek']]
|
||||
wk_days[week['dayofweek']] = week_days[week['dayofweek']]
|
||||
|
@ -348,6 +355,13 @@ class resource_resource(osv.osv):
|
|||
wktime_cal.append((non_working[:-1], time_range))
|
||||
return wktime_cal
|
||||
|
||||
#TODO: Write optimized alogrothem for resource availability. : Method Yet not implemented
|
||||
def check_availability(self, cr, uid, ids, start, end, context=None):
|
||||
if context == None:
|
||||
contex = {}
|
||||
allocation = {}
|
||||
return allocation
|
||||
|
||||
resource_resource()
|
||||
|
||||
class resource_calendar_leaves(osv.osv):
|
||||
|
|
|
@ -225,7 +225,7 @@
|
|||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<field name="date_from"/>
|
||||
<field name="calendar_id" string="Working Period"/>
|
||||
<field name="calendar_id" string="Working Period" readonly='1'/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
|
|
Loading…
Reference in New Issue