From 051d553d7002b13ed6514e02b1e139993aa29cb6 Mon Sep 17 00:00:00 2001 From: "uco (OpenERP)" Date: Mon, 3 Jan 2011 17:46:56 +0530 Subject: [PATCH 01/56] [ADD] project_long_term: Added a yaml. bzr revid: uco@tinyerp.com-20110103121656-7vywdw4s6cc5hao4 --- addons/project_long_term/__openerp__.py | 3 +- .../test/test_schedule_phases_case1.yml | 65 +++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 addons/project_long_term/test/test_schedule_phases_case1.yml diff --git a/addons/project_long_term/__openerp__.py b/addons/project_long_term/__openerp__.py index 0d03b5f7315..22dc3a2ab76 100644 --- a/addons/project_long_term/__openerp__.py +++ b/addons/project_long_term/__openerp__.py @@ -42,7 +42,8 @@ Features. "test": [ 'test/schedule_project_phases.yml', 'test/schedule_project_tasks.yml', - 'test/schedule_phase_tasks.yml' + 'test/schedule_phase_tasks.yml', + 'test/test_schedule_phases_case1.yml', ], "update_xml": [ "security/ir.model.access.csv", diff --git a/addons/project_long_term/test/test_schedule_phases_case1.yml b/addons/project_long_term/test/test_schedule_phases_case1.yml new file mode 100644 index 00000000000..214512b923f --- /dev/null +++ b/addons/project_long_term/test/test_schedule_phases_case1.yml @@ -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!' From 7513e31be320b99c1f3b1f998866379e87c239bb Mon Sep 17 00:00:00 2001 From: "Sbh (OpenERP)" Date: Tue, 4 Jan 2011 12:50:18 +0530 Subject: [PATCH 02/56] [ADD] project_timesheet: Add the on_change on account_id bzr revid: sbh@tinyerp.com-20110104072018-jr2kxvveve15tyez --- addons/project_timesheet/project_timesheet.py | 12 ++++++++++++ addons/project_timesheet/project_timesheet_view.xml | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/addons/project_timesheet/project_timesheet.py b/addons/project_timesheet/project_timesheet.py index b6ec7d069bd..00a28ce2b50 100644 --- a/addons/project_timesheet/project_timesheet.py +++ b/addons/project_timesheet/project_timesheet.py @@ -231,4 +231,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: diff --git a/addons/project_timesheet/project_timesheet_view.xml b/addons/project_timesheet/project_timesheet_view.xml index 7d55ca419be..f8c25f4cb33 100644 --- a/addons/project_timesheet/project_timesheet_view.xml +++ b/addons/project_timesheet/project_timesheet_view.xml @@ -61,7 +61,7 @@ - + From 73dd49b96ea6729266f17eed5b005e1aa1313324 Mon Sep 17 00:00:00 2001 From: jam-openerp Date: Tue, 4 Jan 2011 15:32:05 +0530 Subject: [PATCH 03/56] [IMP] Project_long_term : Refector Code of The Schduling of Phases, Resetup Frame work with Faces lib bzr revid: jam@tinyerp.com-20110104100205-m5pu0cut6qebm91t --- addons/project_long_term/project_long_term.py | 174 ++++++++++++------ .../test/schedule_project_phases.yml | 5 +- 2 files changed, 117 insertions(+), 62 deletions(-) diff --git a/addons/project_long_term/project_long_term.py b/addons/project_long_term/project_long_term.py index 45d75b16b05..7adbf0273cc 100644 --- a/addons/project_long_term/project_long_term.py +++ b/addons/project_long_term/project_long_term.py @@ -25,6 +25,9 @@ from tools.translate import _ from osv import fields, osv 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" @@ -226,12 +229,51 @@ class project_phase(osv.osv): res[phase.id] = resource_objs return res - def generate_schedule(self, cr, uid, ids, start_date=False, calendar_id=False, context=None): + 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') + 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)[::-1]: + 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 + s = ''' + def Phase_%s(): + effort = \'%s\' + resource = %s +'''%(phase.id, duration, phase_resource_obj) + if parent: + start = 'up.Phase_%s.end' % (parent.id) + s += ''' + start = %s +'''%(start) + f += s + '\n' + phase_ids.append(phase.id) + # Recursive call till all the next phases scheduled + for next_phase in phase.next_phase_ids: + 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 generate_schedule(self, cr, uid, root_phase, 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 """ + func_str = '' if context is None: context = {} resource_pool = self.pool.get('resource.resource') @@ -239,71 +281,76 @@ class project_phase(osv.osv): 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 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 + if not start_date: + start_date = root_phase.project_id.date_start or root_phase.date_start or datetime.now().strftime("%Y-%m-%d") + start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d") - project = Task.BalancedProject(Project) - - s_date = project.phase.start.to_datetime() - e_date = project.phase.end.to_datetime() + start = start_date + minimum_time_unit = 1 + 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)) + working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context) + # Create a new project for each phase + func_str += ''' +def Project_%d(): + # If project has working calendar then that + # else the default one would be considered + 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 +'''%(root_phase.project_id.id, start, minimum_time_unit, working_hours_per_day, working_days_per_week, working_days_per_month, working_days_per_year, vacation, working_days ) + phases, phase_ids = self.generate_phase(cr, uid, [root_phase.id], func_str, context=context) + exec(phases) + Project = eval('Project_%d' % root_phase.project_id.id) + project = Task.BalancedProject(Project) + for phase_id in phase_ids: + phase = eval("project.Phase_%d" % phase_id) + start_date = phase.start.to_datetime() + end_date = phase.end.to_datetime() + print start_date, end_date # 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.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.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], { +# if phase.constraint_date_start and str(s_date) < phase.constraint_date_start: +# start_date = 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.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) + }, context=context) # 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) - # 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 +# 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=context) +# # Recursive call till all the next phases scheduled def schedule_tasks(self, cr, uid, ids, context=None): """ @@ -395,7 +442,8 @@ class project(osv.osv): ]) 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) + for phase in phase_pool.browse(cr, uid, phase_ids, context=context): + phase_pool.generate_schedule(cr, uid, phase, start_date, calendar_id, context=context) return True def schedule_tasks(self, cr, uid, ids, context=None): @@ -489,9 +537,15 @@ class project_task(osv.osv): 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 + 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) # Dynamic creation of tasks diff --git a/addons/project_long_term/test/schedule_project_phases.yml b/addons/project_long_term/test/schedule_project_phases.yml index e06feaaa4ca..97b56257f26 100644 --- a/addons/project_long_term/test/schedule_project_phases.yml +++ b/addons/project_long_term/test/schedule_project_phases.yml @@ -4,6 +4,8 @@ !record {model: project.project, id: project_project_worldbanksproject0}: name: "World Bank's Project" priority: 4 + + - Create a project phase 'Defining Client's Basic Idea of Project' @@ -14,8 +16,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' - From cfeb9d39a6cfc4536a9c5d8fee7a6ccf784a0a69 Mon Sep 17 00:00:00 2001 From: "atp (Open ERP)" Date: Tue, 4 Jan 2011 15:48:19 +0530 Subject: [PATCH 04/56] [ADD]: Add yaml for project_long_term module bzr revid: atp@tinyerp.co.in-20110104101819-dm0yfjqmpghs0jz4 --- .../test/test_project_long_term.yml | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 addons/project_long_term/test/test_project_long_term.yml diff --git a/addons/project_long_term/test/test_project_long_term.yml b/addons/project_long_term/test/test_project_long_term.yml new file mode 100644 index 00000000000..feb06ed8846 --- /dev/null +++ b/addons/project_long_term/test/test_project_long_term.yml @@ -0,0 +1,136 @@ +- + Create a project 'Develop yaml Project Module' starting on 01/05/2010. +- + !record {model: project.project, id: project_project_developyamlproject0}: + name: "Develop Yaml Project Module" + date_start: '2010-01-05' +- + I have set Working Time : from Monday to Friday, from 9am to 17pm + +- + !record {model: resource.calendar, id: resource_calendar_hoursweeks0}: + attendance_ids: + - dayofweek: '0' + hour_from: 9.0 + hour_to: 17.0 + name: Monday + - dayofweek: '1' + hour_from: 9.0 + hour_to: 17.0 + name: tuesday + - dayofweek: '2' + hour_from: 9.0 + hour_to: 17.0 + name: Wednesday + - dayofweek: '3' + hour_from: 9.0 + hour_to: 17.0 + name: Thursday + - dayofweek: '4' + hour_from: 9.0 + hour_to: 17.0 + name: Friday + name: 40 hours/weeks + +- + 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 + First ,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. + First 'Analysis Flow for Yaml'Project Phase +- + !record {model: project.phase, id: project_phase_analysisflowforyaml0}: + date_start: '2010-01-05' + duration: 5.0 + name: "Analysis Flow for Yaml" + product_uom: product.uom_day + project_id: project_project_developyamlproject0 + responsible_id: project.res_users_analyst + state: draft + resource_ids: + - resource_id: resource_resource_analyst1 + +- + Create project phase 'Develop yaml' +- + !record {model: project.phase, id: project_phase_establishingprojectfeasibility0}: + date_start: '2010-01-05' + duration: 5.0 + name: Develop Yaml + product_uom: product.uom_day + project_id: project_project_developyamlproject0 + previous_phase_ids: + - project_phase_analysisflowforyaml0 + resource_ids: + - resource_id: resource_resource_develop0 +- + Create project phase 'Test Yaml' +- + !record {model: project.phase, id: project_phase_preparationofengineeringdesigns0}: + date_start: '2010-01-05' + duration: 5.0 + name: Testing Yaml + product_uom: product.uom_day + project_id: project_project_developyamlproject0 + previous_phase_ids: + - project_phase_establishingprojectfeasibility0 + resource_ids: + - resource_id: resource_resource_tester1 + +- + 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") + + From d580a80c9b3fe6a16c0927c706f2c546fc1b0b32 Mon Sep 17 00:00:00 2001 From: "atp (Open ERP)" Date: Tue, 4 Jan 2011 16:00:08 +0530 Subject: [PATCH 05/56] [IMP] bzr revid: atp@tinyerp.co.in-20110104103008-wfz8wjg0ir5lk9u3 --- addons/project_long_term/__openerp__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/project_long_term/__openerp__.py b/addons/project_long_term/__openerp__.py index 0d03b5f7315..87706efb99b 100644 --- a/addons/project_long_term/__openerp__.py +++ b/addons/project_long_term/__openerp__.py @@ -40,6 +40,7 @@ Features. "init_xml": [], "demo_xml": ["project_long_term_demo.xml"], "test": [ + 'test/test_project_long_term.yml', 'test/schedule_project_phases.yml', 'test/schedule_project_tasks.yml', 'test/schedule_phase_tasks.yml' From 643b28b9e5992a23a98fdec92cbdae81571901b3 Mon Sep 17 00:00:00 2001 From: "Sbh (OpenERP)" Date: Tue, 4 Jan 2011 16:14:12 +0530 Subject: [PATCH 06/56] [IMP] account: rename Analytic entries to Analytic items ,[project_long_term: Improve tooltips bzr revid: sbh@tinyerp.com-20110104104412-b72ptzxzr3py1k9x --- addons/account/project/project_view.xml | 2 +- addons/project_long_term/i18n/project_long_term.pot | 2 +- addons/project_long_term/project_long_term.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/account/project/project_view.xml b/addons/account/project/project_view.xml index 789c76addcf..77e03c23700 100644 --- a/addons/account/project/project_view.xml +++ b/addons/account/project/project_view.xml @@ -243,7 +243,7 @@ - Analytic Entries + Analytic Items account.analytic.line form tree,form diff --git a/addons/project_long_term/i18n/project_long_term.pot b/addons/project_long_term/i18n/project_long_term.pot index cfacf155fc5..ec82f557b91 100644 --- a/addons/project_long_term/i18n/project_long_term.pot +++ b/addons/project_long_term/i18n/project_long_term.pot @@ -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 diff --git a/addons/project_long_term/project_long_term.py b/addons/project_long_term/project_long_term.py index 45d75b16b05..da0978d3535 100644 --- a/addons/project_long_term/project_long_term.py +++ b/addons/project_long_term/project_long_term.py @@ -105,7 +105,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)]}), From 926e3de1e2ba53834bb7a006ef48b5161d9c1918 Mon Sep 17 00:00:00 2001 From: jam-openerp Date: Tue, 4 Jan 2011 18:45:11 +0530 Subject: [PATCH 07/56] [IMP] Project_long_term : Refector Code of The Schduling of Phases, Resetup Frame work with Faces lib bzr revid: jam@tinyerp.com-20110104131511-flc8m5kmc86smd03 --- addons/project_long_term/project_long_term.py | 41 ++++++++++++++----- .../test/schedule_project_phases.yml | 23 ++++++++++- addons/resource/resource.py | 19 +++++---- 3 files changed, 64 insertions(+), 19 deletions(-) diff --git a/addons/project_long_term/project_long_term.py b/addons/project_long_term/project_long_term.py index 7adbf0273cc..23ddb41c53e 100644 --- a/addons/project_long_term/project_long_term.py +++ b/addons/project_long_term/project_long_term.py @@ -23,7 +23,7 @@ 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 @@ -219,13 +219,11 @@ class project_phase(osv.osv): """ 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) + resource_objs = map(lambda x:x.resource_id.name, phase.resource_ids) res[phase.id] = resource_objs return res @@ -239,17 +237,17 @@ class project_phase(osv.osv): uom_pool = self.pool.get('product.uom') 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)[::-1]: - 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 + str_resource = ('%s,'*len(phase.resource_ids))[:-1] + str_vals = str_resource % tuple(map(lambda x: 'Resource_%s'%x.resource_id.id, phase.resource_ids)) + # Phases Defination for the Project s = ''' def Phase_%s(): effort = \'%s\' resource = %s -'''%(phase.id, duration, phase_resource_obj) +'''%(phase.id, duration, str_vals or False) if parent: start = 'up.Phase_%s.end' % (parent.id) s += ''' @@ -302,8 +300,22 @@ class project_phase(osv.osv): working_days_per_year = 200 vacation = tuple(resource_pool.compute_vacation(cr, uid, calendar_id)) working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context) + + #Creating resources using the member of the Project + u_ids = [i.id for i in root_phase.project_id.members] + resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context) + cls_str = '' + # Creating Resources for the Project + for key, vals in resource_objs.items(): + cls_str +=''' + class Resource_%s(Resource): + vacation = %s + efficiency = %s +'''%(key, vals.get('vacation', False), vals.get('efficiency', False)) + # Create a new project for each phase func_str += ''' + def Project_%d(): # If project has working calendar then that # else the default one would be considered @@ -315,16 +327,25 @@ def Project_%d(): working_days_per_year = %s vacation = %s working_days = %s + from resource.faces import Resource '''%(root_phase.project_id.id, 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 phases, phase_ids = self.generate_phase(cr, uid, [root_phase.id], func_str, context=context) + #Temp File to test the Code for the Allocation +# fn = '/home/tiny/Desktop/plt.py' +# fp = open(fn, 'w') +# fp.writelines(phases) +# fp.close() + # Allocating Memory for the required Project and Pahses and Resources exec(phases) Project = eval('Project_%d' % root_phase.project_id.id) project = Task.BalancedProject(Project) + for phase_id in phase_ids: phase = eval("project.Phase_%d" % phase_id) start_date = phase.start.to_datetime() end_date = phase.end.to_datetime() - print start_date, end_date +# print phase_id,"\n\n****Phases *********", phase.resource # 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: diff --git a/addons/project_long_term/test/schedule_project_phases.yml b/addons/project_long_term/test/schedule_project_phases.yml index 97b56257f26..2414b56d71d 100644 --- a/addons/project_long_term/test/schedule_project_phases.yml +++ b/addons/project_long_term/test/schedule_project_phases.yml @@ -4,9 +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' - @@ -26,7 +31,21 @@ name: Establishing Project Feasibility product_uom: product.uom_day project_id: project_project_worldbanksproject0 + +- + Resource1 +- + !record {model: project.resource.allocation, id: res_phase0}: + 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 + - Create project phase 'Preparation of Engineering Designs' - diff --git a/addons/resource/resource.py b/addons/resource/resource.py index 30def0c2e16..d7fe0f0774a 100644 --- a/addons/resource/resource.py +++ b/addons/resource/resource.py @@ -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,17 @@ 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 = { + '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): From 538473343f968b9b58907005121ea25b6f86389a Mon Sep 17 00:00:00 2001 From: "uco (OpenERP)" Date: Tue, 4 Jan 2011 18:45:37 +0530 Subject: [PATCH 08/56] [ADD] project_long_term: Added a yaml to test scheduling of phases. bzr revid: uco@tinyerp.com-20110104131537-f99m3nn4tzpxrem5 --- addons/project_long_term/__openerp__.py | 1 + .../test/test_schedule_phases_case2.yml | 189 ++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 addons/project_long_term/test/test_schedule_phases_case2.yml diff --git a/addons/project_long_term/__openerp__.py b/addons/project_long_term/__openerp__.py index 68d12f26e05..586c5efccd1 100644 --- a/addons/project_long_term/__openerp__.py +++ b/addons/project_long_term/__openerp__.py @@ -45,6 +45,7 @@ Features. 'test/schedule_project_tasks.yml', 'test/schedule_phase_tasks.yml', 'test/test_schedule_phases_case1.yml', + 'test/test_schedule_phases_case2.yml', ], "update_xml": [ "security/ir.model.access.csv", diff --git a/addons/project_long_term/test/test_schedule_phases_case2.yml b/addons/project_long_term/test/test_schedule_phases_case2.yml new file mode 100644 index 00000000000..a381ecb045f --- /dev/null +++ b/addons/project_long_term/test/test_schedule_phases_case2.yml @@ -0,0 +1,189 @@ +- + 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 + 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 + resource_ids: + - project_id: project_project_project0 + resource_id: resource_resource_resourcex0 + - project_id: project_project_project0 + resource_id: resource_resource_resourcey0 + 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")]) + From b1fa3dee7d5a7f3c439375f934d6f7762e9ffd02 Mon Sep 17 00:00:00 2001 From: "atp (Open ERP)" Date: Tue, 4 Jan 2011 19:05:15 +0530 Subject: [PATCH 09/56] [FIX]: Fix constrain date problem of project phase. bzr revid: atp@tinyerp.co.in-20110104133515-3b2ptv3jf0neq75c --- addons/project_long_term/__openerp__.py | 2 +- addons/project_long_term/project_long_term.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/addons/project_long_term/__openerp__.py b/addons/project_long_term/__openerp__.py index 586c5efccd1..74837a41af1 100644 --- a/addons/project_long_term/__openerp__.py +++ b/addons/project_long_term/__openerp__.py @@ -40,7 +40,7 @@ Features. "init_xml": [], "demo_xml": ["project_long_term_demo.xml"], "test": [ - 'test/test_project_long_term.yml', + 'test/test_project_long_term.yml', 'test/schedule_project_phases.yml', 'test/schedule_project_tasks.yml', 'test/schedule_phase_tasks.yml', diff --git a/addons/project_long_term/project_long_term.py b/addons/project_long_term/project_long_term.py index da0978d3535..da4b256f82f 100644 --- a/addons/project_long_term/project_long_term.py +++ b/addons/project_long_term/project_long_term.py @@ -220,6 +220,7 @@ class project_phase(osv.osv): 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) @@ -240,12 +241,13 @@ class project_phase(osv.osv): uom_pool = self.pool.get('product.uom') 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.previous_phase_ids: + start_date = False 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") + 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 ? @@ -277,6 +279,7 @@ class project_phase(osv.osv): start_date = 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.strptime(phase.constraint_date_end, '%Y-%m-%d') date_start = phase.constraint_date_end From 1d943a85625c6e48135b3dbe4cfbdb6c4f65409f Mon Sep 17 00:00:00 2001 From: "Sbh (OpenERP)" Date: Wed, 5 Jan 2011 10:50:02 +0530 Subject: [PATCH 10/56] [Fix] project_long_term:Temporary put the comment on function bzr revid: sbh@tinyerp.com-20110105052002-ie1ouev02vvtomer --- addons/project_long_term/project_long_term_demo.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/project_long_term/project_long_term_demo.xml b/addons/project_long_term/project_long_term_demo.xml index 8a37f4cc444..961b0c62c9b 100644 --- a/addons/project_long_term/project_long_term_demo.xml +++ b/addons/project_long_term/project_long_term_demo.xml @@ -233,9 +233,9 @@ This Demo data file Human Resources, Phases and Resources,Tasks allocation and - + - + From 954e0d530678bb29ce28adcb590d9808d3022c49 Mon Sep 17 00:00:00 2001 From: "Sbh (OpenERP)" Date: Wed, 5 Jan 2011 12:25:19 +0530 Subject: [PATCH 11/56] [IMP] project,resource: improve tooltips and view bzr revid: sbh@tinyerp.com-20110105065519-ee1a14p22wu9uncd --- addons/project/project.py | 2 +- addons/resource/resource_view.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/project/project.py b/addons/project/project.py index c076ed764d4..c30ddce74e9 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -126,7 +126,7 @@ 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)]}), 'parent_id': fields.many2one('project.project', 'Parent Project'), diff --git a/addons/resource/resource_view.xml b/addons/resource/resource_view.xml index 424955d0584..7663a5af5d4 100644 --- a/addons/resource/resource_view.xml +++ b/addons/resource/resource_view.xml @@ -225,7 +225,7 @@ - + From 63811761092838557dea58c8fd6dc320425091cf Mon Sep 17 00:00:00 2001 From: "atp (Open ERP)" Date: Wed, 5 Jan 2011 12:37:47 +0530 Subject: [PATCH 12/56] [ADD]: ADD YAML for Phase constraint date issue in project long term module. bzr revid: atp@tinyerp.co.in-20110105070747-44hwbcxpvc1562uk --- .../test/test_phase_constraint.yml | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 addons/project_long_term/test/test_phase_constraint.yml diff --git a/addons/project_long_term/test/test_phase_constraint.yml b/addons/project_long_term/test/test_phase_constraint.yml new file mode 100644 index 00000000000..added4782ef --- /dev/null +++ b/addons/project_long_term/test/test_phase_constraint.yml @@ -0,0 +1,127 @@ +- + I have a project 'Develop yaml Project Module' starting on 01/05/2010. +- + !record {model: project.project, id: project_project_developyamlproject0}: + name: "Develop Yaml Project Module" + date_start: '2010-01-05' + +- + I have set Working Time "from Monday to Friday, from 9am to 17pm". +- + !record {model: resource.calendar, id: resource_calendar_hoursweeks0}: + attendance_ids: + - dayofweek: '0' + hour_from: 9.0 + hour_to: 17.0 + name: Monday + - dayofweek: '1' + hour_from: 9.0 + hour_to: 17.0 + name: tuesday + - dayofweek: '2' + hour_from: 9.0 + hour_to: 17.0 + name: Wednesday + - dayofweek: '3' + hour_from: 9.0 + hour_to: 17.0 + name: Thursday + - dayofweek: '4' + hour_from: 9.0 + hour_to: 17.0 + name: Friday + name: 40 hours/weeks + +- + 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: '2010-01-05' + duration: 5.0 + name: "Analysis Flow for Yaml" + product_uom: product.uom_day + project_id: project_project_developyamlproject0 + responsible_id: project.res_users_analyst + state: draft + resource_ids: + - resource_id: resource_resource_analyst1 + +- + Create project phase 'Develop yaml' with constraint date. +- + !record {model: project.phase, id: project_phase_developyaml0}: + date_start: '2010-01-05' + constraint_date_start: '2010-01-07' + duration: 5.0 + name: Develop Yaml + product_uom: product.uom_day + project_id: project_project_developyamlproject0 + resource_ids: + - resource_id: resource_resource_develop0 +- + Create project phase 'Test Yaml' +- + !record {model: project.phase, id: project_phase_testyaml0}: + date_start: '2010-01-05' + duration: 5.0 + name: Testing Yaml + product_uom: product.uom_day + project_id: project_project_developyamlproject0 + resource_ids: + - resource_id: resource_resource_tester1 + +- + 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") From fc2d9253b5ad0f17e2bea109fcc1642516d73b9f Mon Sep 17 00:00:00 2001 From: "Sbh (OpenERP)" Date: Wed, 5 Jan 2011 14:22:27 +0530 Subject: [PATCH 13/56] [IMP] project: Imrpove the view, project_long_term: change tooltip of start_date bzr revid: sbh@tinyerp.com-20110105085227-01m5sd0jj5bxsl23 --- addons/project/project_view.xml | 9 +++------ addons/project_long_term/i18n/de.po | 4 +--- addons/project_long_term/i18n/en_US.po | 4 ++-- addons/project_long_term/i18n/es.po | 4 +--- addons/project_long_term/i18n/fr.po | 4 +--- addons/project_long_term/i18n/lv.po | 4 +--- addons/project_long_term/i18n/pl.po | 4 +--- addons/project_long_term/i18n/pt.po | 4 +--- addons/project_long_term/project_long_term_view.xml | 2 +- 9 files changed, 12 insertions(+), 27 deletions(-) diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index 8b5dfd5fa21..24e8e6fb4a1 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -29,20 +29,17 @@ - - - - - - + + + diff --git a/addons/project_long_term/i18n/de.po b/addons/project_long_term/i18n/de.po index 9c4a72f7a7c..d7f05a7a7fb 100644 --- a/addons/project_long_term/i18n/de.po +++ b/addons/project_long_term/i18n/de.po @@ -542,9 +542,7 @@ msgstr "Phase" #. 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" +"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 diff --git a/addons/project_long_term/i18n/en_US.po b/addons/project_long_term/i18n/en_US.po index 15a3bd4034b..3e64d59a5c1 100644 --- a/addons/project_long_term/i18n/en_US.po +++ b/addons/project_long_term/i18n/en_US.po @@ -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 diff --git a/addons/project_long_term/i18n/es.po b/addons/project_long_term/i18n/es.po index 97294142262..129794858f0 100644 --- a/addons/project_long_term/i18n/es.po +++ b/addons/project_long_term/i18n/es.po @@ -509,9 +509,7 @@ msgstr "Fase" #. 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" +"It's computed by the scheduler according the project date or the end date of the previous phase." msgstr "" #. module: project_long_term diff --git a/addons/project_long_term/i18n/fr.po b/addons/project_long_term/i18n/fr.po index 3b7d111daac..cf3abfec33e 100644 --- a/addons/project_long_term/i18n/fr.po +++ b/addons/project_long_term/i18n/fr.po @@ -520,9 +520,7 @@ msgstr "Phase" #. 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" +"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 diff --git a/addons/project_long_term/i18n/lv.po b/addons/project_long_term/i18n/lv.po index 508efda1634..ce5130c1a1a 100644 --- a/addons/project_long_term/i18n/lv.po +++ b/addons/project_long_term/i18n/lv.po @@ -506,9 +506,7 @@ msgstr "Fāze" #. 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" +"It's computed by the scheduler according the project date or the end date of the previous phase." msgstr "" #. module: project_long_term diff --git a/addons/project_long_term/i18n/pl.po b/addons/project_long_term/i18n/pl.po index 7f9ba5b37ef..a4047fbc04c 100644 --- a/addons/project_long_term/i18n/pl.po +++ b/addons/project_long_term/i18n/pl.po @@ -507,9 +507,7 @@ msgstr "Faza" #. 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" +"It's computed by the scheduler according the project date or the end date of the previous phase." msgstr "" #. module: project_long_term diff --git a/addons/project_long_term/i18n/pt.po b/addons/project_long_term/i18n/pt.po index 2d24cac1e7a..8ecf7c498aa 100644 --- a/addons/project_long_term/i18n/pt.po +++ b/addons/project_long_term/i18n/pt.po @@ -506,9 +506,7 @@ msgstr "Fase" #. 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" +"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 diff --git a/addons/project_long_term/project_long_term_view.xml b/addons/project_long_term/project_long_term_view.xml index ff4cfd8575b..fffd5a63576 100644 --- a/addons/project_long_term/project_long_term_view.xml +++ b/addons/project_long_term/project_long_term_view.xml @@ -322,7 +322,7 @@ form - + From 344911ad414e7977e17560bee59ddc24eb6fedba Mon Sep 17 00:00:00 2001 From: "Harry (OpenERP)" Date: Wed, 5 Jan 2011 14:35:52 +0530 Subject: [PATCH 14/56] [IMP] project_long_term: refector scheduling of phase/task process to make compatable with faces lib bzr revid: hmo@tinyerp.com-20110105090552-s65bdri5j4nr09qh --- addons/project_long_term/__openerp__.py | 2 +- addons/project_long_term/project_long_term.py | 541 ++++++++++-------- 2 files changed, 314 insertions(+), 229 deletions(-) diff --git a/addons/project_long_term/__openerp__.py b/addons/project_long_term/__openerp__.py index 74837a41af1..9417fedae36 100644 --- a/addons/project_long_term/__openerp__.py +++ b/addons/project_long_term/__openerp__.py @@ -40,9 +40,9 @@ Features. "init_xml": [], "demo_xml": ["project_long_term_demo.xml"], "test": [ - 'test/test_project_long_term.yml', 'test/schedule_project_phases.yml', 'test/schedule_project_tasks.yml', + 'test/test_project_long_term.yml', 'test/schedule_phase_tasks.yml', 'test/test_schedule_phases_case1.yml', 'test/test_schedule_phases_case2.yml', diff --git a/addons/project_long_term/project_long_term.py b/addons/project_long_term/project_long_term.py index 7a23586ffbc..18bc5495caf 100644 --- a/addons/project_long_term/project_long_term.py +++ b/addons/project_long_term/project_long_term.py @@ -215,18 +215,6 @@ 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): - resource_objs = map(lambda x:x.resource_id.name, phase.resource_ids) - res[phase.id] = resource_objs - return res - def generate_phase(self, cr, uid, ids, f, parent=False, context=None): if context is None: context = {} @@ -236,7 +224,7 @@ class project_phase(osv.osv): 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 phase in self.browse(cr, uid, ids, context=context)[::-1]: + for phase in self.browse(cr, uid, ids, context=context): avg_days = uom_pool._compute_qty(cr, uid, phase.product_uom.id, phase.duration, day_uom_id) duration = str(avg_days) + 'd' # Create a new project for each phase @@ -250,7 +238,10 @@ class project_phase(osv.osv): '''%(phase.id, duration, str_vals or False) if parent: start = 'up.Phase_%s.end' % (parent.id) - s += ''' + else: + start = phase.project_id.date_start or phase.date_start + #start = datetime.strftime((datetime.strptime(start, "%Y-%m-%d")), "%Y-%m-%d") + s += ''' start = %s '''%(start) f += s + '\n' @@ -265,114 +256,7 @@ class project_phase(osv.osv): continue return f, phase_ids - def generate_schedule(self, cr, uid, root_phase, 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 - """ - func_str = '' - if context is None: - context = {} - 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') - - - if not start_date: - start_date = root_phase.project_id.date_start or root_phase.date_start or datetime.now().strftime("%Y-%m-%d") - start_date = datetime.strftime((datetime.strptime(start_date, "%Y-%m-%d")), "%Y-%m-%d") - - start = start_date - minimum_time_unit = 1 - 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)) - working_days = resource_pool.compute_working_calendar(cr, uid, calendar_id, context=context) - - #Creating resources using the member of the Project - u_ids = [i.id for i in root_phase.project_id.members] - resource_objs = resource_pool.generate_resources(cr, uid, u_ids, calendar_id, context=context) - cls_str = '' - # Creating Resources for the Project - for key, vals in resource_objs.items(): - cls_str +=''' - class Resource_%s(Resource): - vacation = %s - efficiency = %s -'''%(key, vals.get('vacation', False), vals.get('efficiency', False)) - - # Create a new project for each phase - func_str += ''' - -def Project_%d(): - # If project has working calendar then that - # else the default one would be considered - 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 - from resource.faces import Resource -'''%(root_phase.project_id.id, 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 - phases, phase_ids = self.generate_phase(cr, uid, [root_phase.id], func_str, context=context) - #Temp File to test the Code for the Allocation -# fn = '/home/tiny/Desktop/plt.py' -# fp = open(fn, 'w') -# fp.writelines(phases) -# fp.close() - # Allocating Memory for the required Project and Pahses and Resources - exec(phases) - Project = eval('Project_%d' % root_phase.project_id.id) - project = Task.BalancedProject(Project) - - for phase_id in phase_ids: - phase = eval("project.Phase_%d" % phase_id) - start_date = phase.start.to_datetime() - end_date = phase.end.to_datetime() -# print phase_id,"\n\n****Phases *********", phase.resource - # 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.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.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=context) - # 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=context) -# # Recursive call till all the next phases scheduled + def schedule_tasks(self, cr, uid, ids, context=None): """ @@ -401,6 +285,102 @@ def Project_%d(): else: return_msg["warning"] = return_msg["warning"] + "\n" + warning_msg return return_msg + + def schedule_tasks(self, cr, uid, ids, context=None): + """ + 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') + data_pool = self.pool.get('ir.model.data') + resource_allocation_pool = self.pool.get('project.resource.allocation') + + for phase in self.browse(cr, uid, ids, context=context): + task_ids = task_pool.search(cr, uid, [('id', 'in', map(lambda x : x.id, phase.task_ids)), + ('state', 'in', ['draft', 'open', 'pending']) + ], order='sequence') + 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): + vacation = %s + efficiency = %s +'''%(key, 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 + 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, 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 + parent = False + task_ids = [] + for task in task_pool.browse(cr, uid, task_ids, context=context): + func_str += task_pool.generate_task(cr, uid, task.id, parent=parent, context=context) + if not parent: + parent = task + task_ids.append(task.id) + + #Temp File to test the Code for the Allocation + #fn = '/home/hmo/Desktop/plt.py' + #fp = open(fn, 'w') + #fp.writelines(func_str) + #fp.close() + + # 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): @@ -452,54 +432,214 @@ 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') + 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 - for phase in phase_pool.browse(cr, uid, phase_ids, context=context): - phase_pool.generate_schedule(cr, uid, phase, 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): + vacation = %s + efficiency = %s +'''%(key, 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 + 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, 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 + #Temp File to test the Code for the Allocation + #fn = '/home/hmo/Desktop/plt.py' + #fp = open(fn, 'w') + #fp.writelines(func_str) + #fp.close() + + # 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: + phase = eval("project.Phase_%d" % phase_id) + start_date = phase.start.to_datetime() + end_date = 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 = 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.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_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 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): - 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), ('state', 'in', ['draft', 'open', 'pending']) - ]) + ], order='sequence') + 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): + vacation = %s + efficiency = %s +'''%(key, 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 + 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, 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 + parent = False + task_ids = [] + for task in task_pool.browse(cr, uid, task_ids, context=context): + func_str += task_pool.generate_task(cr, uid, task.id, parent=parent, context=context) + if not parent: + parent = task + task_ids.append(task.id) - 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 + #Temp File to test the Code for the Allocation + fn = '/home/hmo/Desktop/plt.py' + fp = open(fn, 'w') + fp.writelines(func_str) + fp.close() + + # 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() @@ -523,87 +663,32 @@ class project_task(osv.osv): 'phase_id': fields.many2one('project.phase', 'Project Phase'), } - 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, 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 - 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) - # 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 + 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' + resource_ids = self.search(cr, uid, [('user_id', '=', task.user_id.id)], context=context) + resource = False + if len(resource_ids): + resource = 'Resource_%s'%resource_ids[0] + # Phases Defination for the Project + s = ''' + def Task_%s(): + effort = \'%s\' + resource = %s +'''%(task.id, duration, resource) + if parent: + start = 'up.Task_%s.end' % (parent.id) + else: + start = task.project_id.date_start or task.date_start + #start = datetime.strftime((datetime.strptime(start, "%Y-%m-%d")), "%Y-%m-%d") + s += ''' + start = %s +'''%(start) + s += '\n' + return s project_task() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From c77bdc57703520d49d1be75509dcec332015ebd9 Mon Sep 17 00:00:00 2001 From: "Sbh (OpenERP)" Date: Wed, 5 Jan 2011 14:47:13 +0530 Subject: [PATCH 15/56] [IMP] project_issue: improve view bzr revid: sbh@tinyerp.com-20110105091713-pmt84bzhn1gadxlq --- addons/project_issue/project_issue_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml index b40d0f42335..0c63698b209 100644 --- a/addons/project_issue/project_issue_view.xml +++ b/addons/project_issue/project_issue_view.xml @@ -333,7 +333,7 @@ form - + From a857948b4ebbd3162c836dcbf668db9702113937 Mon Sep 17 00:00:00 2001 From: "Sbh (OpenERP)" Date: Wed, 5 Jan 2011 14:52:34 +0530 Subject: [PATCH 16/56] project_long_term: comment the code bzr revid: sbh@tinyerp.com-20110105092234-qdcy1l0vlz6ufhet --- addons/project_long_term/project_long_term.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/project_long_term/project_long_term.py b/addons/project_long_term/project_long_term.py index 18bc5495caf..ab08247851a 100644 --- a/addons/project_long_term/project_long_term.py +++ b/addons/project_long_term/project_long_term.py @@ -620,10 +620,10 @@ def Project_%d(): task_ids.append(task.id) #Temp File to test the Code for the Allocation - fn = '/home/hmo/Desktop/plt.py' - fp = open(fn, 'w') - fp.writelines(func_str) - fp.close() +# fn = '/home/hmo/Desktop/plt.py' +# fp = open(fn, 'w') +# fp.writelines(func_str) +# fp.close() # Allocating Memory for the required Project and Pahses and Resources exec(func_str) From 18dc6f5586679dcb63e996c24e0b3363289171db Mon Sep 17 00:00:00 2001 From: "Sbh (OpenERP)" Date: Wed, 5 Jan 2011 15:02:54 +0530 Subject: [PATCH 17/56] project_long_term: set readonly on date_start and end_date bzr revid: sbh@tinyerp.com-20110105093254-yficntvrsmkqeor6 --- addons/project_long_term/project_long_term_view.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/project_long_term/project_long_term_view.xml b/addons/project_long_term/project_long_term_view.xml index fffd5a63576..8203cbfdf06 100644 --- a/addons/project_long_term/project_long_term_view.xml +++ b/addons/project_long_term/project_long_term_view.xml @@ -116,10 +116,10 @@ - + - + @@ -228,6 +228,7 @@ +