diff --git a/addons/crm/board_crm_view.xml b/addons/crm/board_crm_view.xml index 6bbd450ca38..8bbbece18cb 100644 --- a/addons/crm/board_crm_view.xml +++ b/addons/crm/board_crm_view.xml @@ -20,10 +20,7 @@ graph,tree,form - ['|', - '!', '&', ('probability', '=', 100), ('stage_id.on_change', '=', 1), - '!', '&', ('probability', '=', 0), ('stage_id.sequence', '!=', 1), - ('type', '=', 'opportunity')] + ['&', ('stage_id.fold', '=', False), ('type', '=', 'opportunity')] {'search_default_Stage':1} @@ -48,7 +45,7 @@ graph,tree,form - ['!', '&', ('probability', '=', 0), ('stage_id.sequence', '!=', 1)] + ['|', ('stage_id.fold', '=', False), ('stage_id.probability', '=', 100)] {'search_default_user': 1, 'search_default_Stage': 1} diff --git a/addons/crm/crm.py b/addons/crm/crm.py index 6c2db63b0be..b09dc8faa2b 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -68,8 +68,9 @@ class crm_case_stage(osv.osv): help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."), 'case_default': fields.boolean('Default to New Sales Team', help="If you check this field, this stage will be proposed by default on each sales team. It will not assign this stage to existing teams."), - 'fold': fields.boolean('Fold by Default', - help="This stage is not visible, for example in status bar or kanban view, when there are no records in that stage to display."), + 'fold': fields.boolean('Folded in Kanban View', + help='This stage is folded in the kanban view when' + 'there are no records in that stage to display.'), 'type': fields.selection([('lead', 'Lead'), ('opportunity', 'Opportunity'), ('both', 'Both')], diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 046d4419809..5f52980c8b0 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -71,10 +71,11 @@ class crm_lead(format_address, osv.osv): _track = { 'stage_id': { - 'crm.mt_lead_create': lambda self, cr, uid, obj, ctx=None: obj.probability == 0 and obj.stage_id and obj.stage_id.sequence == 1, - 'crm.mt_lead_stage': lambda self, cr, uid, obj, ctx=None: (obj.stage_id and obj.stage_id.sequence != 1) and obj.probability < 100, - 'crm.mt_lead_won': lambda self, cr, uid, obj, ctx=None: obj.probability == 100 and obj.stage_id and obj.stage_id.on_change, - 'crm.mt_lead_lost': lambda self, cr, uid, obj, ctx=None: obj.probability == 0 and obj.stage_id and obj.stage_id.sequence != 1, + # this is only an heuristics; depending on your particular stage configuration it may not match all 'new' stages + 'crm.mt_lead_create': lambda self, cr, uid, obj, ctx=None: obj.probability == 0 and obj.stage_id and obj.stage_id.sequence <= 1, + 'crm.mt_lead_stage': lambda self, cr, uid, obj, ctx=None: (obj.stage_id and obj.stage_id.sequence > 1) and obj.probability < 100, + 'crm.mt_lead_won': lambda self, cr, uid, obj, ctx=None: obj.probability == 100 and obj.stage_id and obj.stage_id.fold, + 'crm.mt_lead_lost': lambda self, cr, uid, obj, ctx=None: obj.probability == 0 and obj.stage_id and obj.stage_id.fold and obj.stage_id.sequence > 1, }, } @@ -92,7 +93,7 @@ class crm_lead(format_address, osv.osv): def _get_default_stage_id(self, cr, uid, context=None): """ Gives default stage_id """ section_id = self._get_default_section_id(cr, uid, context=context) - return self.stage_find(cr, uid, [], section_id, [('sequence', '=', '1')], context=context) + return self.stage_find(cr, uid, [], section_id, [('fold', '=', False)], context=context) def _resolve_section_id_from_context(self, cr, uid, context=None): """ Returns ID of section based on the value of 'section_id' @@ -381,15 +382,17 @@ class crm_lead(format_address, osv.osv): # AND with the domain in parameter search_domain += list(domain) # perform search, return the first found - stage_ids = self.pool.get('crm.case.stage').search(cr, uid, search_domain, order=order, context=context) + stage_ids = self.pool.get('crm.case.stage').search(cr, uid, search_domain, order=order, limit=1, context=context) if stage_ids: return stage_ids[0] return False def case_mark_lost(self, cr, uid, ids, context=None): - """ Mark the case as lost: state=cancel and probability=0 """ + """ Mark the case as lost: state=cancel and probability=0 + :deprecated: this method will be removed in OpenERP v8. + """ for lead in self.browse(cr, uid, ids): - stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 0.0), ('on_change', '=', True), ('sequence', '>', 1)], context=context) + stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 0.0), ('fold', '=', True), ('sequence', '>', 1)], context=context) if stage_id: return self.write(cr, uid, [lead.id], {'stage_id': stage_id}, context=context) else: @@ -399,9 +402,11 @@ class crm_lead(format_address, osv.osv): 'Create a specific stage or edit an existing one by editing columns of your opportunity pipe.')) def case_mark_won(self, cr, uid, ids, context=None): - """ Mark the case as won: state=done and probability=100 """ + """ Mark the case as won: state=done and probability=100 + :deprecated: this method will be removed in OpenERP v8. + """ for lead in self.browse(cr, uid, ids): - stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 100.0), ('on_change', '=', True), ('sequence', '>', 1)], context=context) + stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 100.0), ('fold', '=', True)], context=context) if stage_id: return self.write(cr, uid, [lead.id], {'stage_id': stage_id}, context=context) else: @@ -616,7 +621,7 @@ class crm_lead(format_address, osv.osv): # An Opportunity always has higher confidence level than a lead, unless its stage probability is 0.0 for opportunity in opportunities: sequence = -1 - if opportunity.stage_id and (opportunity.stage_id.probability != 0 or opportunity.stage_id.sequence == 1): + if opportunity.stage_id and not opportunity.stage_id.fold: sequence = opportunity.stage_id.sequence sequenced_opps.append(((int(sequence != -1 and opportunity.type == 'opportunity'), sequence, -opportunity.id), opportunity)) @@ -677,7 +682,7 @@ class crm_lead(format_address, osv.osv): 'phone': customer and customer.phone or lead.phone, } if not lead.stage_id or lead.stage_id.type=='lead': - val['stage_id'] = self.stage_find(cr, uid, [lead], section_id, [('sequence', '=', '1'), ('type', 'in', ('opportunity','both'))], context=context) + val['stage_id'] = self.stage_find(cr, uid, [lead], section_id, [('type', 'in', ('opportunity', 'both'))], context=context) return val def convert_opportunity(self, cr, uid, ids, partner_id, user_ids=False, section_id=False, context=None): @@ -687,7 +692,7 @@ class crm_lead(format_address, osv.osv): customer = partner.browse(cr, uid, partner_id, context=context) for lead in self.browse(cr, uid, ids, context=context): # TDE: was if lead.state in ('done', 'cancel'): - if (lead.probability == '100') or (lead.probability == '0' and lead.stage_id.sequence != '1'): + if lead.probability == 100 or (lead.probability == 0 and lead.stage_id.fold): continue vals = self._convert_opportunity_data(cr, uid, lead, customer, section_id, context=context) self.write(cr, uid, [lead.id], vals, context=context) diff --git a/addons/crm/crm_lead_data.xml b/addons/crm/crm_lead_data.xml index 3c299fef704..1cd3d51be90 100644 --- a/addons/crm/crm_lead_data.xml +++ b/addons/crm/crm_lead_data.xml @@ -44,6 +44,7 @@ Won 1 + 1 100 1 70 diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index c0eefcc8d4c..5a3a0aa34fe 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -341,7 +341,7 @@ domain="[('section_id.member_ids', 'in', [uid])]" context="{'invisible_section': False}" help="Leads that are assigned to any sales teams I am member of"/> + domain="[('probability', '=', '0'), ('stage_id.fold', '=', True)]"/>
+
@@ -550,12 +552,10 @@ - + domain="[('probability', '=', 100), ('stage_id.fold', '=', True)]"/> + domain="[('probability', '=', 0), ('stage_id.fold', '=', True)]"/> - - - - - - - - + + + + + + + + + + + + + diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py index 8664a2c1166..780c4390a09 100644 --- a/addons/hr_recruitment/hr_recruitment.py +++ b/addons/hr_recruitment/hr_recruitment.py @@ -52,12 +52,13 @@ class hr_recruitment_stage(osv.osv): 'name': fields.char('Name', size=64, required=True, translate=True), 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of stages."), 'department_id':fields.many2one('hr.department', 'Specific to a Department', help="Stages of the recruitment process may be different per department. If this stage is common to all departments, keep this field empty."), - 'fold': fields.boolean('Hide in views if empty', help="This stage is not visible, for example in status bar or kanban view, when there are no records in that stage to display."), 'requirements': fields.text('Requirements'), + 'fold': fields.boolean('Folded in Kanban View', + help='This stage is folded in the kanban view when' + 'there are no records in that stage to display.'), } _defaults = { 'sequence': 1, - 'fold': False, } class hr_recruitment_degree(osv.osv): @@ -82,8 +83,9 @@ class hr_applicant(osv.Model): _inherit = ['mail.thread', 'ir.needaction_mixin'] _track = { 'stage_id': { - 'hr_recruitment.mt_applicant_new': lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.sequence == 1, - 'hr_recruitment.mt_applicant_stage_changed': lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.sequence != 1, + # this is only an heuristics; depending on your particular stage configuration it may not match all 'new' stages + 'hr_recruitment.mt_applicant_new': lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.sequence <= 1, + 'hr_recruitment.mt_applicant_stage_changed': lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.sequence > 1, }, } @@ -94,7 +96,7 @@ class hr_applicant(osv.Model): def _get_default_stage_id(self, cr, uid, context=None): """ Gives default stage_id """ department_id = self._get_default_department_id(cr, uid, context=context) - return self.stage_find(cr, uid, [], department_id, [('sequence', '=', '1')], context=context) + return self.stage_find(cr, uid, [], department_id, [('fold', '=', False)], context=context) def _resolve_department_id_from_context(self, cr, uid, context=None): """ Returns ID of department based on the value of 'default_department_id' @@ -225,7 +227,7 @@ class hr_applicant(osv.Model): 'department_id': lambda s, cr, uid, c: s._get_default_department_id(cr, uid, c), 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'hr.applicant', context=c), 'color': 0, - 'date_last_stage_update': fields.datetime.now(), + 'date_last_stage_update': fields.datetime.now, } _group_by_full = { @@ -241,7 +243,7 @@ class hr_applicant(osv.Model): def onchange_department_id(self, cr, uid, ids, department_id=False, stage_id=False, context=None): if not stage_id: - stage_id = self.stage_find(cr, uid, [], department_id, [('sequence', '=', '1')], context=context) + stage_id = self.stage_find(cr, uid, [], department_id, [('fold', '=', False)], context=context) return {'value': {'stage_id': stage_id}} def onchange_partner_id(self, cr, uid, ids, partner_id, context=None): diff --git a/addons/hr_recruitment/hr_recruitment_data.xml b/addons/hr_recruitment/hr_recruitment_data.xml index 854dea0548f..219f36405b5 100644 --- a/addons/hr_recruitment/hr_recruitment_data.xml +++ b/addons/hr_recruitment/hr_recruitment_data.xml @@ -71,12 +71,14 @@ Contract Signed 5 + Refused 6 + Job Survey 20 diff --git a/addons/hr_recruitment/hr_recruitment_view.xml b/addons/hr_recruitment/hr_recruitment_view.xml index 3bf09d21a17..7553a24ff3c 100644 --- a/addons/hr_recruitment/hr_recruitment_view.xml +++ b/addons/hr_recruitment/hr_recruitment_view.xml @@ -342,6 +342,7 @@ + diff --git a/addons/hr_recruitment/report/hr_recruitment_report.py b/addons/hr_recruitment/report/hr_recruitment_report.py index 0292875a2c7..908b701d928 100644 --- a/addons/hr_recruitment/report/hr_recruitment_report.py +++ b/addons/hr_recruitment/report/hr_recruitment_report.py @@ -90,7 +90,7 @@ class hr_recruitment_report(osv.Model): (sum(salary_proposed)/count(*)) as salary_prop_avg, sum(salary_expected) as salary_exp, (sum(salary_expected)/count(*)) as salary_exp_avg, - extract('epoch' from (s.date_closed-s.create_date))/(3600*24) as delay_close, + extract('epoch' from (s.write_date-s.create_date))/(3600*24) as delay_close, count(*) as nbr from hr_applicant s group by @@ -101,6 +101,7 @@ class hr_recruitment_report(osv.Model): date_trunc('day',s.date_closed), s.date_open, s.create_date, + s.write_date, s.date_closed, s.date_last_stage_update, s.partner_id, diff --git a/addons/project/project.py b/addons/project/project.py index d153a849dc7..9173318366e 100644 --- a/addons/project/project.py +++ b/addons/project/project.py @@ -41,14 +41,13 @@ class project_task_type(osv.osv): 'case_default': fields.boolean('Default for New Projects', help="If you check this field, this stage will be proposed by default on each new project. It will not assign this stage to existing projects."), 'project_ids': fields.many2many('project.project', 'project_task_type_rel', 'type_id', 'project_id', 'Projects'), - 'fold': fields.boolean('Folded by Default', - help="This stage is not visible, for example in status bar or kanban view, when there are no records in that stage to display."), + 'fold': fields.boolean('Folded in Kanban View', + help='This stage is folded in the kanban view when' + 'there are no records in that stage to display.'), } _defaults = { 'sequence': 1, - 'fold': False, - 'case_default': False, 'project_ids': lambda self, cr, uid, ctx=None: self.pool['project.task']._get_default_project_id(cr, uid, context=ctx), } _order = 'sequence' @@ -189,6 +188,8 @@ class project(osv.osv): return res def _task_count(self, cr, uid, ids, field_name, arg, context=None): + """ :deprecated: this method will be removed with OpenERP v8. Use task_ids + fields instead. """ if context is None: context = {} res = dict.fromkeys(ids, 0) @@ -263,7 +264,10 @@ class project(osv.osv): }), 'resource_calendar_id': fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report", states={'close':[('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)]}), - 'task_count': fields.function(_task_count, type='integer', string="Open Tasks"), + 'task_count': fields.function(_task_count, type='integer', string="Open Tasks", + deprecated="This field will be removed in OpenERP v8. Use task_ids one2many field instead."), + 'task_ids': fields.one2many('project.task', 'project_id', + domain=[('stage_id.fold', '=', False)]), 'color': fields.integer('Color Index'), 'alias_id': fields.many2one('mail.alias', 'Alias', ondelete="restrict", required=True, help="Internal email associated with this project. Incoming emails are automatically synchronized" @@ -555,8 +559,9 @@ class task(osv.osv): _mail_post_access = 'read' _track = { 'stage_id': { - 'project.mt_task_new': lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.sequence == 1, - 'project.mt_task_stage': lambda self, cr, uid, obj, ctx=None: obj.stage_id.sequence != 1, + # this is only an heuristics; depending on your particular stage configuration it may not match all 'new' stages + 'project.mt_task_new': lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.sequence <= 1, + 'project.mt_task_stage': lambda self, cr, uid, obj, ctx=None: obj.stage_id.sequence > 1, }, 'user_id': { 'project.mt_task_assigned': lambda self, cr, uid, obj, ctx=None: obj.user_id and obj.user_id.id, @@ -581,7 +586,7 @@ class task(osv.osv): def _get_default_stage_id(self, cr, uid, context=None): """ Gives default stage_id """ project_id = self._get_default_project_id(cr, uid, context=context) - return self.stage_find(cr, uid, [], project_id, [('sequence', '=', '1')], context=context) + return self.stage_find(cr, uid, [], project_id, [('fold', '=', False)], context=context) def _resolve_project_id_from_context(self, cr, uid, context=None): """ Returns ID of project based on the value of 'default_project_id' @@ -804,7 +809,7 @@ class task(osv.osv): _defaults = { 'stage_id': _get_default_stage_id, 'project_id': _get_default_project_id, - 'date_last_stage_update': lambda *a: fields.datetime.now(), + 'date_last_stage_update': fields.datetime.now, 'kanban_state': 'normal', 'priority': '2', 'progress': 0, @@ -993,7 +998,7 @@ class task(osv.osv): def set_remaining_time(self, cr, uid, ids, remaining_time=1.0, context=None): for task in self.browse(cr, uid, ids, context=context): - if (task.stage_id and task.stage_id.sequence == 1) or (task.planned_hours == 0.0): + if (task.stage_id and task.stage_id.sequence <= 1) or (task.planned_hours == 0.0): self.write(cr, uid, [task.id], {'planned_hours': remaining_time}, context=context) self.write(cr, uid, ids, {'remaining_hours': remaining_time}, context=context) return True diff --git a/addons/project/project_data.xml b/addons/project/project_data.xml index 0f48dfe9a2b..1f49451a377 100644 --- a/addons/project/project_data.xml +++ b/addons/project/project_data.xml @@ -63,12 +63,14 @@ Done + 30 Cancelled + diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml index 4d025d15cb4..d5e6a216149 100644 --- a/addons/project/project_view.xml +++ b/addons/project/project_view.xml @@ -19,7 +19,7 @@ - + @@ -240,6 +240,7 @@ + @@ -259,9 +260,10 @@ %%
@@ -684,10 +686,10 @@ - + - + diff --git a/addons/project/report/project_report.py b/addons/project/report/project_report.py index 15b26507ff3..ed086b4318d 100644 --- a/addons/project/report/project_report.py +++ b/addons/project/report/project_report.py @@ -75,7 +75,7 @@ class report_project_task_user(osv.osv): date_trunc('day',t.date_last_stage_update) as date_last_stage_update, to_date(to_char(t.date_deadline, 'dd-MM-YYYY'),'dd-MM-YYYY') as date_deadline, -- sum(cast(to_char(date_trunc('day',t.date_end) - date_trunc('day',t.date_start),'DD') as int)) as no_of_days, - abs((extract('epoch' from (t.date_end-t.date_start)))/(3600*24)) as no_of_days, + abs((extract('epoch' from (t.write_date-t.date_start)))/(3600*24)) as no_of_days, t.user_id, progress as progress, t.project_id, @@ -89,9 +89,9 @@ class report_project_task_user(osv.osv): total_hours as total_hours, t.delay_hours as hours_delay, planned_hours as hours_planned, - (extract('epoch' from (t.date_end-t.create_date)))/(3600*24) as closing_days, + (extract('epoch' from (t.write_date-t.create_date)))/(3600*24) as closing_days, (extract('epoch' from (t.date_start-t.create_date)))/(3600*24) as opening_days, - abs((extract('epoch' from (t.date_deadline-t.date_end)))/(3600*24)) as delay_endings_days + abs((extract('epoch' from (t.date_deadline-t.write_date)))/(3600*24)) as delay_endings_days FROM project_task t WHERE t.active = 'true' GROUP BY @@ -106,6 +106,7 @@ class report_project_task_user(osv.osv): month, day, create_date, + write_date, date_start, date_end, date_deadline, diff --git a/addons/project/report/project_report.xml b/addons/project/report/project_report.xml index 59d0fd28220..4ff7e852620 100644 --- a/addons/project/report/project_report.xml +++ b/addons/project/report/project_report.xml @@ -17,7 +17,6 @@ - diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py index cf0f79e18a5..4de3c9f54ad 100644 --- a/addons/project_issue/project_issue.py +++ b/addons/project_issue/project_issue.py @@ -572,6 +572,8 @@ class project(osv.Model): return [('project.task', "Tasks"), ("project.issue", "Issues")] def _issue_count(self, cr, uid, ids, field_name, arg, context=None): + """ :deprecated: this method will be removed with OpenERP v8. Use issue_ids + fields instead. """ res = dict.fromkeys(ids, 0) issue_ids = self.pool.get('project.issue').search(cr, uid, [('project_id', 'in', ids)]) for issue in self.pool.get('project.issue').browse(cr, uid, issue_ids, context): @@ -583,7 +585,10 @@ class project(osv.Model): '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)]}), - 'issue_count': fields.function(_issue_count, type='integer', string="Unclosed Issues"), + 'issue_count': fields.function(_issue_count, type='integer', string="Unclosed Issues", + deprecated="This field will be removed in OpenERP v8. Use issue_ids one2many field instead."), + 'issue_ids': fields.one2many('project.issue', 'project_id', + domain=[('stage_id.fold', '=', False)]) } def _check_escalation(self, cr, uid, ids, context=None): diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml index 3e90a2a43d6..02db9114bdb 100644 --- a/addons/project_issue/project_issue_view.xml +++ b/addons/project_issue/project_issue_view.xml @@ -325,13 +325,14 @@ - + - Issues - Issue + + Issue + Issues diff --git a/addons/sale_crm/sale_crm_view.xml b/addons/sale_crm/sale_crm_view.xml index 34f32e0b58b..8c008339903 100644 --- a/addons/sale_crm/sale_crm_view.xml +++ b/addons/sale_crm/sale_crm_view.xml @@ -8,7 +8,7 @@ - +