[MERGE] project related modules improvements
bzr revid: mra@mra-laptop-20100729092715-vog7b7epwp8uc2c3
This commit is contained in:
@@ -152,17 +152,17 @@ where prp.id in %s''',(tuple(ids),))
|
||||
'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."),
|
||||
'priority': fields.integer('Sequence', help="Gives the sequence order when displaying a list of task"),
|
||||
'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."),
|
||||
'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."),
|
||||
'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)]}),
|
||||
'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."),
|
||||
'effective_hours': fields.function(_progress_rate, multi="progress", method=True, string='Time Spent', help="Sum of spent hours of all tasks related to this project and its child projects."),
|
||||
'total_hours': fields.function(_progress_rate, multi="progress", method=True, string='Total Time', help="Sum of total hours of all tasks related to this project and its child projects."),
|
||||
'progress_rate': fields.function(_progress_rate, multi="progress", method=True, string='Progress', type='float', help="Percent of tasks closed according to the total of tasks todo."),
|
||||
'warn_customer': fields.boolean('Warn Partner', help="If you check this, the user will have a popup when closing a task that propose a message to send by email to the customer."),
|
||||
'warn_header': fields.text('Mail Header', help="Header added at the beginning of the email for the warning message sent to the customer when a task is closed."),
|
||||
'warn_footer': fields.text('Mail Footer', help="Footer added at the beginning of the email for the warning message sent to the customer when a task is closed."),
|
||||
'type_ids': fields.many2many('project.task.type', 'project_task_type_rel', 'project_id', 'type_id', 'Tasks Stages'),
|
||||
'warn_customer': fields.boolean('Warn Partner', help="If you check this, the user will have a popup when closing a task that propose a message to send by email to the customer.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'warn_header': fields.text('Mail Header', help="Header added at the beginning of the email for the warning message sent to the customer when a task is closed.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'warn_footer': fields.text('Mail Footer', help="Footer added at the beginning of the email for the warning message sent to the customer when a task is closed.", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'type_ids': fields.many2many('project.task.type', 'project_task_type_rel', 'project_id', 'type_id', 'Tasks Stages', states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
}
|
||||
|
||||
_order = "sequence"
|
||||
@@ -480,7 +480,8 @@ class task(osv.osv):
|
||||
'ref_doc1': 'project.task,%d'% (task.id,),
|
||||
'ref_doc2': 'project.project,%d'% (project.id,),
|
||||
})
|
||||
elif project.warn_manager and cntx.get('mail_send',True):
|
||||
elif (project.warn_manager or project.warn_customer) and cntx.get('mail_send',True):
|
||||
cntx.update({'send_manager': project.warn_manager, 'send_partner': project.warn_customer})
|
||||
mail_send = True
|
||||
message = _('Task ') + " '" + task.name + "' "+ _("is Done.")
|
||||
self.log(cr, uid, task.id, message)
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
<group colspan="6" col="6">
|
||||
<field name="name" string="Project Name" select="1"/>
|
||||
<field name="parent_id" string="Parent Project"/>
|
||||
<field name="user_id" string="Project Manager" select="1"/>
|
||||
<field name="date_start"/>
|
||||
<field name="date"/>
|
||||
<field name="user_id" string="Project Manager" select="1" attrs="{'readonly':[('state','in',['close', 'cancelled'])]}"/>
|
||||
<field name="date_start" attrs="{'readonly':[('state','in',['close', 'cancelled'])]}"/>
|
||||
<field name="date" attrs="{'readonly':[('state','in',['close', 'cancelled'])]}"/>
|
||||
<field name="progress_rate" widget="progressbar"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
@@ -48,8 +48,8 @@
|
||||
<button name="set_template" string="Set as Template" type="object" states="open" icon="gtk-convert"/>
|
||||
<button name="set_open" string="Reactivate Project" type="object" states="pending,cancelled,close" icon="gtk-ok"/>
|
||||
<button name="set_pending" string="Pending" type="object" states="open" icon="gtk-media-pause"/>
|
||||
<button name="set_cancel" string="Cancel" type="object" states="open,pending" icon="gtk-cancel"/>
|
||||
<button name="set_done" string="Done" type="object" states="open,pending" icon="gtk-jump-to"/>
|
||||
<button name="set_cancel" string="Cancel" type="object" states="open,pending" icon="gtk-cancel"/>
|
||||
<button name="reset_project" string="Reset as Project" type="object" states="template" icon="gtk-convert"/>
|
||||
<button
|
||||
string="New Project Based on Template"
|
||||
@@ -247,8 +247,8 @@
|
||||
<field name="name" select="1"/>
|
||||
<field name="project_id" required="1" select="1" domain="[('user_id','=',uid)]"/>
|
||||
<field name="total_hours" widget="float_time"/>
|
||||
<field name="date_deadline"/>
|
||||
<field name="user_id" select="1"/>
|
||||
<field name="date_deadline" attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"/>
|
||||
<field name="user_id" select="1" attrs="{'readonly':[('state','in',['done', 'cancelled'])]}"/>
|
||||
<field name="progress" widget="progressbar"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
|
||||
@@ -48,7 +48,10 @@
|
||||
if not new_prj:
|
||||
raise Exception( "New project based on template not created")
|
||||
new_id = new_prj['res_id']
|
||||
state = self.read(cr, uid, [new_id], ['state'])[0]['state']
|
||||
new_prj = self.read(cr, uid, [new_id], ['name', 'state'])[0]
|
||||
state = new_prj['state']
|
||||
name = new_prj['name']
|
||||
print "Project '%s' created"%name
|
||||
assert state == 'open', "Project in %s state. Project created from template project must be in open state"%state
|
||||
-
|
||||
Reset project template to normal project
|
||||
@@ -275,7 +278,7 @@
|
||||
name: Training on yml
|
||||
user_id: base.user_root
|
||||
-
|
||||
Check for effective hours and remaining hours
|
||||
Check for effective hours and remaining hours, remaining_hours must be 5, effective_hours must be 45
|
||||
-
|
||||
!assert {model: project.task, id: project_task_technicaltraining0, severity: error, string: After work task of 5 hours effective_hours must be equal to 45 and remaining_hours is 5}:
|
||||
- planned_hours == 30
|
||||
@@ -312,6 +315,6 @@
|
||||
-
|
||||
Check if project in close state
|
||||
-
|
||||
!assert {model: project.project, id: project_project_openerptrainingprogramme0, severity: error}:
|
||||
!assert {model: project.project, id: project_project_openerptrainingprogramme0, severity: error, string: "Project must be in closed state"}:
|
||||
- state == "close"
|
||||
|
||||
|
||||
@@ -43,8 +43,10 @@
|
||||
{"lang": "en_US", "active_model": "ir.ui.menu", "active_ids": [ref("project.menu_action_view_task")],
|
||||
"tz": False, "active_id": ref("project.menu_action_view_task"), })
|
||||
|
||||
-
|
||||
Test the delegate wizard
|
||||
-
|
||||
Creating a project.task.delegate record
|
||||
Creating a delegate task 'Publish the References' of 15 hours, renaming parent task to 'CHECK Publish the References' of 1 hour
|
||||
-
|
||||
!record {model: project.task.delegate, id: project_task_publish_book_delegate}:
|
||||
name: Publish the References
|
||||
@@ -56,14 +58,19 @@
|
||||
user_id: base.user_demo
|
||||
|
||||
-
|
||||
Performing an osv_memory action validate on module project.task.delegate
|
||||
Validating the delegate task
|
||||
-
|
||||
!python {model: project.task.delegate}: |
|
||||
self.validate(cr, uid, [ref("project_task_publish_book_delegate")],
|
||||
{"lang": "en_US", "active_model": "project.task", "tz": False, "record_id":
|
||||
4, "active_ids": [ref("project_task_publish_book")], "active_id": ref("project_task_publish_book"),
|
||||
})
|
||||
|
||||
|
||||
-
|
||||
Check if parent task 'CHECK Publish the References' is in pending state
|
||||
-
|
||||
!assert {model: project.task, id: project_task_publish_book, severity: error, string: "Task must be in pending state after delegation"}:
|
||||
- state == "pending"
|
||||
-
|
||||
Creating a delegate task 'Prepare a book that gives functional overview of OpenERP'
|
||||
-
|
||||
@@ -160,7 +167,7 @@
|
||||
-
|
||||
Check if 'Prepare a technical reference for creating your modules' in pending state
|
||||
-
|
||||
!assert {model: project.task, id: project_task_delegate_developer_book, severity: error, string: Task is in pending state}:
|
||||
!assert {model: project.task, id: project_task_delegate_developer_book, severity: error, string: Task must be in pending state}:
|
||||
- state == "pending"
|
||||
|
||||
-
|
||||
|
||||
@@ -32,15 +32,28 @@ class project_close_task(osv.osv_memory):
|
||||
_name = "close.task"
|
||||
_description = "Project Close Task"
|
||||
_columns = {
|
||||
'email': fields.char('E-Mail', size=64, help="Email Address"),
|
||||
'manager_email': fields.char('Manager E-Mail ID', size=64, help="Email Address of Project's Manager"),
|
||||
'partner_email': fields.char('Partner E-Mail ID', size=64, help="Email Address of Partner"),
|
||||
'description': fields.text('Description'),
|
||||
}
|
||||
|
||||
def _get_email(self, cr, uid, context=None):
|
||||
def _get_manager_email(self, cr, uid, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
email = ''
|
||||
if 'task_id' in context:
|
||||
if context.get('send_manager', False) and ('task_id' in context):
|
||||
project_id = self.pool.get('project.task').read(cr, uid, context['task_id'], ['project_id'])['project_id'][0]
|
||||
project = self.pool.get('project.project').browse(cr, uid, project_id)
|
||||
manager_id = project.user_id or False
|
||||
if manager_id and manager_id.user_email:
|
||||
email = manager_id.user_email
|
||||
return email
|
||||
|
||||
def _get_partner_email(self, cr, uid, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
email = ''
|
||||
if context.get('send_partner', False) and ('task_id' in context):
|
||||
task = self.pool.get('project.task').browse(cr, uid, context['task_id'])
|
||||
partner_id = task.partner_id or task.project_id.partner_id
|
||||
if partner_id and len(partner_id.address) and partner_id.address[0].email:
|
||||
@@ -56,7 +69,8 @@ class project_close_task(osv.osv_memory):
|
||||
return ''
|
||||
|
||||
_defaults = {
|
||||
'email': _get_email,
|
||||
'manager_email': _get_manager_email,
|
||||
'partner_email': _get_partner_email,
|
||||
'description': _get_desc,
|
||||
}
|
||||
|
||||
@@ -71,12 +85,19 @@ class project_close_task(osv.osv_memory):
|
||||
if not 'task_id' in context:
|
||||
return {}
|
||||
close_task = self.read(cr, uid, ids[0], [])
|
||||
to_adr = close_task['email']
|
||||
to_adr = []
|
||||
description = close_task['description']
|
||||
|
||||
if 'task_id' in context:
|
||||
task_obj = self.pool.get('project.task')
|
||||
for task in task_obj.browse(cr, uid, [context['task_id']], context=context):
|
||||
if context.get('send_manager', False) and not close_task.get('manager_email', False):
|
||||
raise osv.except_osv(_('Error'), _("Please specify the email address of Manager."))
|
||||
|
||||
elif context.get('send_partner', False) and not close_task.get('partner_email', False):
|
||||
raise osv.except_osv(_('Error'), _("Please specify the email address of partner."))
|
||||
|
||||
else:
|
||||
task_obj = self.pool.get('project.task')
|
||||
task = task_obj.browse(cr, uid, context['task_id'], context=context)
|
||||
project = task.project_id
|
||||
subject = "Task '%s' closed" % task.name
|
||||
if task.user_id and task.user_id.address_id and task.user_id.address_id.email:
|
||||
@@ -84,8 +105,7 @@ class project_close_task(osv.osv_memory):
|
||||
signature = task.user_id.signature
|
||||
else:
|
||||
raise osv.except_osv(_('Error'), _("Couldn't send mail because your email address is not configured!"))
|
||||
if to_adr:
|
||||
val = {
|
||||
val = {
|
||||
'name': task.name,
|
||||
'user_id': task.user_id.name,
|
||||
'task_id': "%d/%d" % (project.id, task.id),
|
||||
@@ -93,15 +113,17 @@ class project_close_task(osv.osv_memory):
|
||||
'date_end': task.date_end,
|
||||
'state': task.state
|
||||
}
|
||||
header = (project.warn_header or '') % val
|
||||
footer = (project.warn_footer or '') % val
|
||||
body = u'%s\n%s\n%s\n\n-- \n%s' % (header, description, footer, signature)
|
||||
email(from_adr, [to_adr], subject, body.encode('utf-8'), email_bcc=[from_adr])
|
||||
task_obj.write(cr, uid, [task.id], {'state': 'done', 'date_end':time.strftime('%Y-%m-%d %H:%M:%S'), 'remaining_hours': 0.0})
|
||||
message = _('Task ') + " '" + task.name + "' "+ _("is Done.")
|
||||
self.log(cr, uid, task.id, message)
|
||||
else:
|
||||
raise osv.except_osv(_('Error'), _("Please specify the email address of partner."))
|
||||
|
||||
header = (project.warn_header or '') % val
|
||||
footer = (project.warn_footer or '') % val
|
||||
body = u'%s\n%s\n%s\n\n-- \n%s' % (header, description, footer, signature)
|
||||
to_adr.append(context.get('send_manager', '') and close_task.get('manager_email', '') or '')
|
||||
to_adr.append(context.get('send_partner', '') and close_task.get('partner_email', '') or '')
|
||||
email(from_adr, to_adr, subject, body.encode('utf-8'), email_bcc=[from_adr])
|
||||
task_obj.write(cr, uid, [task.id], {'state': 'done', 'date_end':time.strftime('%Y-%m-%d %H:%M:%S'), 'remaining_hours': 0.0})
|
||||
message = _('Task ') + " '" + task.name + "' "+ _("is Done.")
|
||||
self.log(cr, uid, task.id, message)
|
||||
|
||||
return {}
|
||||
|
||||
project_close_task()
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
<separator string="" colspan="4"/>
|
||||
<group colspan="4" col="6">
|
||||
<newline/>
|
||||
<field name="email"/>
|
||||
<field name="manager_email" invisible="not context.get('send_manager',False)"/>
|
||||
<newline/>
|
||||
<field name="partner_email" invisible="not context.get('send_partner',False)"/>
|
||||
<newline/>
|
||||
<field name="description" />
|
||||
</group>
|
||||
|
||||
@@ -406,8 +406,8 @@ project_issue()
|
||||
class project(osv.osv):
|
||||
_inherit = "project.project"
|
||||
_columns = {
|
||||
'resource_calendar_id' : fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report"),
|
||||
'project_escalation_id' : fields.many2one('project.project','Project Escalation', help='If any issue is escalated from the current Project, it will be listed under the project selected here.'),
|
||||
'resource_calendar_id' : fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report", states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'project_escalation_id' : fields.many2one('project.project','Project Escalation', help='If any issue is escalated from the current Project, it will be listed under the project selected here.', states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'reply_to' : fields.char('Reply-To Email Address', size=256)
|
||||
}
|
||||
|
||||
|
||||
@@ -93,19 +93,19 @@ class project_phase(osv.osv):
|
||||
|
||||
_columns = {
|
||||
'name': fields.char("Name", size=64, required=True),
|
||||
'date_start': fields.date('Start Date', help="Starting Date of the phase"),
|
||||
'date_end': fields.date('End Date', help="Ending Date of the phase"),
|
||||
'constraint_date_start': fields.datetime('Start Date', help='force the phase to start after this date'),
|
||||
'constraint_date_end': fields.datetime('End Date', help='force the phase to finish before this date'),
|
||||
'date_start': fields.date('Start Date', help="Starting Date of the phase", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'date_end': fields.date('End Date', help="Ending Date of the phase", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'constraint_date_start': fields.date('Start Date', help='force the phase to start after this date', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'constraint_date_end': fields.date('End Date', help='force the phase to finish before this date', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'project_id': fields.many2one('project.project', 'Project', required=True),
|
||||
'next_phase_ids': fields.many2many('project.phase', 'project_phase_rel', 'prv_phase_id', 'next_phase_id', 'Next Phases'),
|
||||
'previous_phase_ids': fields.many2many('project.phase', 'project_phase_rel', 'next_phase_id', 'prv_phase_id', 'Previous Phases'),
|
||||
'next_phase_ids': fields.many2many('project.phase', 'project_phase_rel', 'prv_phase_id', 'next_phase_id', 'Next Phases', states={'cancelled':[('readonly',True)]}),
|
||||
'previous_phase_ids': fields.many2many('project.phase', 'project_phase_rel', 'next_phase_id', 'prv_phase_id', 'Previous Phases', states={'cancelled':[('readonly',True)]}),
|
||||
'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of phases."),
|
||||
'duration': fields.float('Duration', required=True, help="By default in days"),
|
||||
'product_uom': fields.many2one('product.uom', 'Duration UoM', required=True, help="UoM (Unit of Measure) is the unit of measurement for Duration"),
|
||||
'task_ids': fields.one2many('project.task', 'phase_id', "Project Tasks"),
|
||||
'resource_ids': fields.one2many('project.resource.allocation', 'phase_id', "Project Resources"),
|
||||
'responsible_id': fields.many2one('res.users', 'Responsible'),
|
||||
'duration': fields.float('Duration', required=True, help="By default in days", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'product_uom': fields.many2one('product.uom', 'Duration UoM', required=True, help="UoM (Unit of Measure) is the unit of measurement for Duration", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'task_ids': fields.one2many('project.task', 'phase_id', "Project Tasks", states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'resource_ids': fields.one2many('project.resource.allocation', 'phase_id', "Project Resources",states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'responsible_id': fields.many2one('res.users', 'Responsible', states={'done':[('readonly',True)], 'cancelled':[('readonly',True)]}),
|
||||
'state': fields.selection([('draft', 'Draft'), ('open', 'In Progress'), ('pending', 'Pending'), ('cancelled', 'Cancelled'), ('done', 'Done')], 'State', readonly=True, required=True,
|
||||
help='If the phase is created the state \'Draft\'.\n If the phase is started, the state becomes \'In Progress\'.\n If review is needed the phase is in \'Pending\' state.\
|
||||
\n If the phase is over, the states is set to \'Done\'.')
|
||||
@@ -130,7 +130,7 @@ class project_phase(osv.osv):
|
||||
if project:
|
||||
project_id = project_obj.browse(cr, uid, project, context=context)
|
||||
if project_id.date_start:
|
||||
result['date_start'] = mx.DateTime.strptime(project_id.date_start, "%Y-%m-%d").strftime('%Y-%m-%d %H:%M:%S')
|
||||
result['date_start'] = mx.DateTime.strptime(project_id.date_start, "%Y-%m-%d").strftime('%Y-%m-%d')
|
||||
return {'value': result}
|
||||
return {'value': {'date_start': []}}
|
||||
|
||||
@@ -147,15 +147,15 @@ class project_phase(osv.osv):
|
||||
resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)])
|
||||
if resource_id:
|
||||
# cal_id = resource_obj.browse(cr, uid, resource_id[0], context=context).calendar_id.id
|
||||
res = resource_obj.read(cr, uid, resource_id[0], ['calendar_id'], context=context)[0]
|
||||
res = resource_obj.read(cr, uid, resource_id, ['calendar_id'], context=context)[0]
|
||||
cal_id = res.get('calendar_id', False) and res.get('calendar_id')[0] or False
|
||||
if cal_id:
|
||||
calendar_id = cal_id
|
||||
default_uom_id = self._get_default_uom_id(cr, uid)
|
||||
avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
|
||||
work_times = cal_obj.interval_min_get(cr, uid, calendar_id, date_end, avg_hours or 0.0, resource_id and resource_id[0] or False)
|
||||
dt_start = work_times[0][0].strftime('%Y-%m-%d %H:%M:%S')
|
||||
self.write(cr, uid, [phase.id], {'date_start': dt_start, 'date_end': date_end.strftime('%Y-%m-%d %H:%M:%S')}, context=context)
|
||||
dt_start = work_times[0][0].strftime('%Y-%m-%d')
|
||||
self.write(cr, uid, [phase.id], {'date_start': dt_start, 'date_end': date_end.strftime('%Y-%m-%d')}, context=context)
|
||||
|
||||
def _check_date_end(self, cr, uid, phase, date_start, context=None):
|
||||
if context is None:
|
||||
@@ -170,15 +170,15 @@ class project_phase(osv.osv):
|
||||
resource_id = resource_obj.search(cr, uid, [('user_id', '=', phase.responsible_id.id)], context=context)
|
||||
if resource_id:
|
||||
# cal_id = resource_obj.browse(cr, uid, resource_id[0], context=context).calendar_id.id
|
||||
res = resource_obj.read(cr, uid, resource_id[0], ['calendar_id'], context=context)[0]
|
||||
res = resource_obj.read(cr, uid, resource_id, ['calendar_id'], context=context)[0]
|
||||
cal_id = res.get('calendar_id', False) and res.get('calendar_id')[0] or False
|
||||
if cal_id:
|
||||
calendar_id = cal_id
|
||||
default_uom_id = self._get_default_uom_id(cr, uid)
|
||||
avg_hours = uom_obj._compute_qty(cr, uid, phase.product_uom.id, phase.duration, default_uom_id)
|
||||
work_times = cal_obj.interval_get(cr, uid, calendar_id, date_start, avg_hours or 0.0, resource_id and resource_id[0] or False)
|
||||
dt_end = work_times[-1][1].strftime('%Y-%m-%d %H:%M:%S')
|
||||
self.write(cr, uid, [phase.id], {'date_start': date_start.strftime('%Y-%m-%d %H:%M:%S'), 'date_end': dt_end}, context=context)
|
||||
dt_end = work_times[-1][1].strftime('%Y-%m-%d')
|
||||
self.write(cr, uid, [phase.id], {'date_start': date_start.strftime('%Y-%m-%d'), 'date_end': dt_end}, context=context)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
resource_calendar_obj = self.pool.get('resource.calendar')
|
||||
@@ -203,17 +203,17 @@ class project_phase(osv.osv):
|
||||
# Change the date_start and date_end
|
||||
# for previous and next phases respectively based on valid condition
|
||||
if vals.get('date_start', False) and vals['date_start'] < phase.date_start:
|
||||
dt_start = mx.DateTime.strptime(vals['date_start'], '%Y-%m-%d %H:%M:%S')
|
||||
dt_start = mx.DateTime.strptime(vals['date_start'], '%Y-%m-%d')
|
||||
work_times = resource_calendar_obj.interval_get(cr, uid, calendar_id, dt_start, avg_hours or 0.0, resource_id and resource_id[0] or False)
|
||||
if work_times:
|
||||
vals['date_end'] = work_times[-1][1].strftime('%Y-%m-%d %H:%M:%S')
|
||||
vals['date_end'] = work_times[-1][1].strftime('%Y-%m-%d')
|
||||
for prv_phase in phase.previous_phase_ids:
|
||||
self._check_date_start(cr, uid, prv_phase, dt_start, context=context)
|
||||
if vals.get('date_end', False) and vals['date_end'] > phase.date_end:
|
||||
dt_end = mx.DateTime.strptime(vals['date_end'],'%Y-%m-%d %H:%M:%S')
|
||||
dt_end = mx.DateTime.strptime(vals['date_end'],'%Y-%m-%d')
|
||||
work_times = resource_calendar_obj.interval_min_get(cr, uid, calendar_id, dt_end, avg_hours or 0.0, resource_id and resource_id[0] or False)
|
||||
if work_times:
|
||||
vals['date_start'] = work_times[0][0].strftime('%Y-%m-%d %H:%M:%S')
|
||||
vals['date_start'] = work_times[0][0].strftime('%Y-%m-%d')
|
||||
for next_phase in phase.next_phase_ids:
|
||||
self._check_date_end(cr, uid, next_phase, dt_end, context=context)
|
||||
return super(project_phase, self).write(cr, uid, ids, vals, context=context)
|
||||
@@ -261,7 +261,7 @@ class project(osv.osv):
|
||||
_inherit = "project.project"
|
||||
_columns = {
|
||||
'phase_ids': fields.one2many('project.phase', 'project_id', "Project Phases"),
|
||||
'resource_calendar_id': fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report"),
|
||||
'resource_calendar_id': fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report", states={'close':[('readonly',True)]} ),
|
||||
}
|
||||
|
||||
project()
|
||||
|
||||
@@ -269,14 +269,14 @@
|
||||
<field name="name">Information Gathering and Understanding</field>
|
||||
<field name="product_uom" ref="product.uom_day"/>
|
||||
<field eval="10" name="sequence"/>
|
||||
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(18-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="date_start" eval="(DateTime.now()-timedelta(70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(18-70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="date_start" eval="(DateTime.now()-timedelta(70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="state">draft</field>
|
||||
<field name="responsible_id" ref="res_users_demouser1"/>
|
||||
<field eval="15.0" name="duration"/>
|
||||
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
|
||||
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(2-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="date_end" eval="(DateTime.now()+timedelta(15-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(2-70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="date_end" eval="(DateTime.now()+timedelta(15-70)).strftime('%Y-%m-%d')"/>
|
||||
</record>
|
||||
|
||||
<record id="project_phase_planning0" model="project.phase">
|
||||
@@ -284,59 +284,59 @@
|
||||
<field name="name">Planning</field>
|
||||
<field name="product_uom" ref="product.uom_day"/>
|
||||
<field eval="10" name="sequence"/>
|
||||
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(28-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="date_start" eval="(DateTime.now()+timedelta(10-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(28-70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="date_start" eval="(DateTime.now()+timedelta(10-70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="state">draft</field>
|
||||
<field name="responsible_id" ref="res_users_manager0"/>
|
||||
<field eval="15.0" name="duration"/>
|
||||
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
|
||||
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(13-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="date_end" eval="(DateTime.now()+timedelta(25-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(13-70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="date_end" eval="(DateTime.now()+timedelta(25-70)).strftime('%Y-%m-%d')"/>
|
||||
</record>
|
||||
|
||||
<record id="project_phase_webdesign0" model="project.phase">
|
||||
<field eval="[(6, 0, [ref('project_phase_informationgatheringandunderstanding0'), ref('project_phase_planning0')])]" name="previous_phase_ids"/>
|
||||
<field eval="[(6, 0, [ref('project_phase_planning0')])]" name="previous_phase_ids"/>
|
||||
<field name="name">Web Design </field>
|
||||
<field name="product_uom" ref="product.uom_day"/>
|
||||
<field eval="10" name="sequence"/>
|
||||
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(45-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="date_start" eval="(DateTime.now()+timedelta(20-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(45-70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="date_start" eval="(DateTime.now()+timedelta(20-70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="state">draft</field>
|
||||
<field name="responsible_id" ref="res_users_userdesign0"/>
|
||||
<field eval="20.0" name="duration"/>
|
||||
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
|
||||
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(25-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="date_end" eval="(DateTime.now()+timedelta(40-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(25-70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="date_end" eval="(DateTime.now()+timedelta(40-70)).strftime('%Y-%m-%d')"/>
|
||||
</record>
|
||||
|
||||
<record id="project_phase_developmentintegrationandtesting0" model="project.phase">
|
||||
<field eval="[(6, 0, [ref('project_phase_informationgatheringandunderstanding0'), ref('project_phase_planning0'), ref('project_phase_webdesign0')])]" name="previous_phase_ids"/>
|
||||
<field eval="[(6, 0, [ref('project_phase_webdesign0')])]" name="previous_phase_ids"/>
|
||||
<field name="name">Development, Integration and Testing</field>
|
||||
<field name="product_uom" ref="product.uom_day"/>
|
||||
<field eval="10" name="sequence"/>
|
||||
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(57-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="date_start" eval="(DateTime.now()+timedelta(30-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(57-70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="date_start" eval="(DateTime.now()+timedelta(30-70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="state">draft</field>
|
||||
<field name="responsible_id" ref="res_users_manager0"/>
|
||||
<field eval="22.0" name="duration"/>
|
||||
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
|
||||
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(35-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="date_end" eval="(DateTime.now()+timedelta(52-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(35-70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="date_end" eval="(DateTime.now()+timedelta(52-70)).strftime('%Y-%m-%d')"/>
|
||||
</record>
|
||||
|
||||
<record id="project_phase_websitedeployment0" model="project.phase">
|
||||
<field eval="[(6, 0, [ref('project_phase_informationgatheringandunderstanding0'), ref('project_phase_planning0'), ref('project_phase_webdesign0'), ref('project_phase_developmentintegrationandtesting0')])]" name="previous_phase_ids"/>
|
||||
<field eval="[(6, 0, [ref('project_phase_developmentintegrationandtesting0')])]" name="previous_phase_ids"/>
|
||||
<field name="name">Website Deployment</field>
|
||||
<field name="product_uom" ref="product.uom_day"/>
|
||||
<field eval="10" name="sequence"/>
|
||||
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(63-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="date_start" eval="(DateTime.now()+timedelta(55-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="constraint_date_end" eval="(DateTime.now()+timedelta(63-70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="date_start" eval="(DateTime.now()+timedelta(55-70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="state">draft</field>
|
||||
<field name="responsible_id" ref="res_users_manager0"/>
|
||||
<field eval="5.0" name="duration"/>
|
||||
<field name="project_id" ref="project_project_openerpwebsitedevelopment0"/>
|
||||
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(58-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="date_end" eval="(DateTime.now()+timedelta(60-70)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="constraint_date_start" eval="(DateTime.now()+timedelta(58-70)).strftime('%Y-%m-%d')"/>
|
||||
<field name="date_end" eval="(DateTime.now()+timedelta(60-70)).strftime('%Y-%m-%d')"/>
|
||||
</record>
|
||||
|
||||
<!-- Project Resource Allocation -->
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
Create phase 'Develop GUI' in Outlook
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_phase0}:
|
||||
date_start: '2010-06-02 00:00:00'
|
||||
date_start: '2010-06-02'
|
||||
duration: 200.0
|
||||
name: phase123
|
||||
product_uom: product.uom_day
|
||||
@@ -36,7 +36,6 @@
|
||||
-
|
||||
!record {model: project.task, id: project_task_t0}:
|
||||
name: t1
|
||||
occupation_rate: 1.0
|
||||
planned_hours: 20.0
|
||||
remaining_hours: 20.0
|
||||
state: draft
|
||||
@@ -49,7 +48,6 @@
|
||||
-
|
||||
!record {model: project.task, id: project_task_t1}:
|
||||
name: t2
|
||||
occupation_rate: 1.0
|
||||
planned_hours: 25.0
|
||||
remaining_hours: 25.0
|
||||
state: draft
|
||||
@@ -61,7 +59,6 @@
|
||||
-
|
||||
!record {model: project.task, id: project_task_t2}:
|
||||
name: t3
|
||||
occupation_rate: 1.0
|
||||
planned_hours: 30.0
|
||||
remaining_hours: 30.0
|
||||
state: draft
|
||||
@@ -74,7 +71,6 @@
|
||||
-
|
||||
!record {model: project.task, id: project_task_3}:
|
||||
name: t4
|
||||
occupation_rate: 1.0
|
||||
planned_hours: 25.0
|
||||
remaining_hours: 25.0
|
||||
state: draft
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
Create a project phase 'Defining Client's Basic Idea of Project'
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_definingclientsbasicideaofproject0}:
|
||||
date_start: '2010-06-02 00:00:00'
|
||||
date_start: '2010-06-02'
|
||||
duration: 15.0
|
||||
name: "Defining Client's Basic Idea of Project"
|
||||
product_uom: product.uom_day
|
||||
@@ -22,7 +22,7 @@
|
||||
Create project phase 'Establishing Project Feasibility'
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_establishingprojectfeasibility0}:
|
||||
date_start: '2010-06-02 00:00:00'
|
||||
date_start: '2010-06-02'
|
||||
duration: 30.0
|
||||
name: Establishing Project Feasibility
|
||||
product_uom: product.uom_day
|
||||
@@ -33,7 +33,7 @@
|
||||
Create project phase 'Preparation of Engineering Designs'
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_preparationofengineeringdesigns0}:
|
||||
date_start: '2010-06-02 00:00:00'
|
||||
date_start: '2010-06-02'
|
||||
duration: 100.0
|
||||
name: Preparation of Engineering Designs
|
||||
product_uom: product.uom_hour
|
||||
@@ -45,7 +45,7 @@
|
||||
Create project phase 'Procurement of Works and Goods'
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_procurementofworksandgoods0}:
|
||||
date_start: '2010-06-02 00:00:00'
|
||||
date_start: '2010-06-02'
|
||||
duration: 24.0
|
||||
name: Procurement of Works and Goods
|
||||
product_uom: product.uom_hour
|
||||
@@ -57,7 +57,7 @@
|
||||
Create project phase 'Project Construction'
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_projectconstruction0}:
|
||||
date_start: '2010-06-02 00:00:00'
|
||||
date_start: '2010-06-02'
|
||||
duration: 4320.0
|
||||
name: Project Construction
|
||||
product_uom: product.uom_hour
|
||||
@@ -69,7 +69,7 @@
|
||||
Create project phase 'Project Completion'
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_projectcompletion0}:
|
||||
date_start: '2010-06-02 00:00:00'
|
||||
date_start: '2010-06-02'
|
||||
duration: 240.0
|
||||
name: Project Completion
|
||||
product_uom: product.uom_hour
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
Create phase 'Develop GUI' in Thunderbird
|
||||
-
|
||||
!record {model: project.phase, id: project_phase_phase1}:
|
||||
date_start: '2010-06-02 00:00:00'
|
||||
date_start: '2010-06-02'
|
||||
duration: 100.0
|
||||
name: phase22
|
||||
product_uom: product.uom_day
|
||||
|
||||
@@ -103,20 +103,20 @@ class project_compute_phases(osv.osv_memory):
|
||||
# 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 = datetime.datetime.strptime(phase.constraint_date_start, '%Y-%m-%d %H:%M:%S')
|
||||
start_date = datetime.datetime.strptime(phase.constraint_date_start, '%Y-%m-%d')
|
||||
else:
|
||||
start_date = s_date
|
||||
if phase.constraint_date_end and str(e_date) > phase.constraint_date_end:
|
||||
end_date= datetime.datetime.strptime(phase.constraint_date_end, '%Y-%m-%d %H:%M:%S')
|
||||
date_start = phase.constraint_date_end[:-3]
|
||||
end_date= datetime.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})
|
||||
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')},
|
||||
phase_obj.write(cr, uid, [phase.id], {'date_start': start_date.strftime('%Y-%m-%d'),
|
||||
'date_end': end_date.strftime('%Y-%m-%d')},
|
||||
context=ctx)
|
||||
# Recursive call till all the next phases scheduled
|
||||
for phase in phase.next_phase_ids:
|
||||
|
||||
@@ -92,7 +92,7 @@ class project_schedule_task(osv.osv_memory):
|
||||
if task_ids:
|
||||
task_ids.sort()
|
||||
tasks = task_obj.browse(cr, uid, task_ids, context=context)
|
||||
start_date = str(phase.date_start)[:-9]
|
||||
start_date = str(phase.date_start)
|
||||
if not phase.date_start:
|
||||
if not phase.project_id.date_start:
|
||||
start_date = datetime.datetime.now().strftime("%Y-%m-%d")
|
||||
|
||||
Reference in New Issue
Block a user