[MERGE] merge with main branch
bzr revid: psi@tinyerp.com-20120601113816-mmbmhklr588wj5sl
This commit is contained in:
commit
0255049b09
|
@ -0,0 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2012-today OpenERP SA (<http://openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import base_state
|
||||
import base_stage
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,42 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2012-today OpenERP SA (<http://openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
{
|
||||
'name': 'State/Stage Management',
|
||||
'version': '1.0',
|
||||
'category': 'Hidden',
|
||||
'description': """
|
||||
This module handles state and stage. It is derived from the crm_base and
|
||||
crm_case classes from crm.
|
||||
|
||||
* ``base_state``: state management
|
||||
* ``base_stage``: stage management
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'website': 'http://www.openerp.com',
|
||||
'depends': ['base'],
|
||||
'init_xml': [],
|
||||
'update_xml': [],
|
||||
'demo_xml': [],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
}
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,432 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import fields
|
||||
from tools.translate import _
|
||||
|
||||
class base_stage(object):
|
||||
""" Base utility mixin class for objects willing to manage their stages.
|
||||
Object that inherit from this class should inherit from mailgate.thread
|
||||
to have access to the mail gateway, as well as Chatter. Objects
|
||||
subclassing this class should define the following colums:
|
||||
- ``date_open`` (datetime field)
|
||||
- ``date_closed`` (datetime field)
|
||||
- ``user_id`` (many2one to res.users)
|
||||
- ``partner_id`` (many2one to res.partner)
|
||||
- ``stage_id`` (many2one to a stage definition model)
|
||||
- ``state`` (selection field, related to the stage_id.state)
|
||||
"""
|
||||
|
||||
def _get_default_partner(self, cr, uid, context=None):
|
||||
""" Gives id of partner for current user
|
||||
:param context: if portal not in context returns False
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if not context or not context.get('portal'):
|
||||
return False
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
if hasattr(user, 'partner_address_id') and user.partner_address_id:
|
||||
return user.partner_address_id
|
||||
return user.company_id.partner_id.id
|
||||
|
||||
def _get_default_email(self, cr, uid, context=None):
|
||||
""" Gives default email address for current user
|
||||
:param context: if portal not in context returns False
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if not context or not context.get('portal'):
|
||||
return False
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
return user.user_email
|
||||
|
||||
def _get_default_user(self, cr, uid, context=None):
|
||||
""" Gives current user id
|
||||
:param context: if portal not in context returns False
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if not context or not context.get('portal'):
|
||||
return False
|
||||
return uid
|
||||
|
||||
def onchange_partner_address_id(self, cr, uid, ids, add, email=False):
|
||||
""" This function returns value of partner email based on Partner Address
|
||||
:param add: Id of Partner's address
|
||||
:param email: Partner's email ID
|
||||
"""
|
||||
data = {'value': {'email_from': False, 'phone':False}}
|
||||
if add:
|
||||
address = self.pool.get('res.partner').browse(cr, uid, add)
|
||||
data['value'] = {'email_from': address and address.email or False ,
|
||||
'phone': address and address.phone or False}
|
||||
if 'phone' not in self._columns:
|
||||
del data['value']['phone']
|
||||
return data
|
||||
|
||||
def onchange_partner_id(self, cr, uid, ids, part, email=False):
|
||||
""" This function returns value of partner address based on partner
|
||||
:param part: Partner's id
|
||||
:param email: Partner's email ID
|
||||
"""
|
||||
data={}
|
||||
if part:
|
||||
addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['contact'])
|
||||
data.update(self.onchange_partner_address_id(cr, uid, ids, addr['contact'])['value'])
|
||||
return {'value': data}
|
||||
|
||||
def _get_default_section_id(self, cr, uid, context=None):
|
||||
""" Gives default section """
|
||||
return False
|
||||
|
||||
def _get_default_stage_id(self, cr, uid, context=None):
|
||||
""" Gives default stage_id """
|
||||
return self.stage_find(cr, uid, [], None, [('state', '=', 'draft')], context=context)
|
||||
|
||||
def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None):
|
||||
""" Find stage, with a given (optional) domain on the search,
|
||||
ordered by the order parameter. If several stages match the
|
||||
search criterions, the first one will be returned, according
|
||||
to the requested search order.
|
||||
This method is meant to be overriden by subclasses. That way
|
||||
specific behaviors can be achieved for every class inheriting
|
||||
from base_stage.
|
||||
|
||||
:param cases: browse_record of cases
|
||||
:param section_id: section limitating the search, given for
|
||||
a generic search (for example default search).
|
||||
A section models concepts such as Sales team
|
||||
(for CRM), ou departments (for HR).
|
||||
:param domain: a domain on the search of stages
|
||||
:param order: order of the search
|
||||
"""
|
||||
return False
|
||||
|
||||
def stage_set_with_state_name(self, cr, uid, cases, state_name, context=None):
|
||||
""" Set a new stage, with a state_name instead of a stage_id
|
||||
:param cases: browse_record of cases
|
||||
"""
|
||||
if isinstance(cases, (int, long)):
|
||||
cases = self.browse(cr, uid, cases, context=context)
|
||||
for case in cases:
|
||||
stage_id = self.stage_find(cr, uid, [case], None, [('state', '=', state_name)], context=context)
|
||||
if stage_id:
|
||||
self.stage_set(cr, uid, [case.id], stage_id, context=context)
|
||||
return True
|
||||
|
||||
def stage_set(self, cr, uid, ids, stage_id, context=None):
|
||||
""" Set the new stage. This methods is the right method to call
|
||||
when changing states. It also checks whether an onchange is
|
||||
defined, and execute it.
|
||||
"""
|
||||
value = {}
|
||||
if hasattr(self, 'onchange_stage_id'):
|
||||
value = self.onchange_stage_id(cr, uid, ids, stage_id, context=context)['value']
|
||||
value['stage_id'] = stage_id
|
||||
self.stage_set_send_note(cr, uid, ids, stage_id, context=context)
|
||||
return self.write(cr, uid, ids, value, context=context)
|
||||
|
||||
def stage_change(self, cr, uid, ids, op, order, context=None):
|
||||
""" Change the stage and take the next one, based on a condition
|
||||
writen for the 'sequence' field and an operator. This methods
|
||||
checks whether the case has a current stage, and takes its
|
||||
sequence. Otherwise, a default 0 sequence is chosen and this
|
||||
method will therefore choose the first available stage.
|
||||
For example if op is '>' and current stage has a sequence of
|
||||
10, this will call stage_find, with [('sequence', '>', '10')].
|
||||
"""
|
||||
for case in self.browse(cr, uid, ids, context=context):
|
||||
seq = 0
|
||||
if case.stage_id:
|
||||
seq = case.stage_id.sequence or 0
|
||||
section_id = None
|
||||
next_stage_id = self.stage_find(cr, uid, [case], None, [('sequence', op, seq)],order, context=context)
|
||||
if next_stage_id:
|
||||
return self.stage_set(cr, uid, [case.id], next_stage_id, context=context)
|
||||
return False
|
||||
|
||||
def stage_next(self, cr, uid, ids, context=None):
|
||||
""" This function computes next stage for case from its current stage
|
||||
using available stage for that case type
|
||||
"""
|
||||
return self.stage_change(cr, uid, ids, '>','sequence', context)
|
||||
|
||||
def stage_previous(self, cr, uid, ids, context=None):
|
||||
""" This function computes previous stage for case from its current
|
||||
stage using available stage for that case type
|
||||
"""
|
||||
return self.stage_change(cr, uid, ids, '<', 'sequence desc', context)
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
""" Overrides orm copy method to avoid copying messages,
|
||||
as well as date_closed and date_open columns if they
|
||||
exist."""
|
||||
if default is None:
|
||||
default = {}
|
||||
|
||||
if hasattr(self, '_columns'):
|
||||
if self._columns.get('date_closed'):
|
||||
default.update({ 'date_closed': False, })
|
||||
if self._columns.get('date_open'):
|
||||
default.update({ 'date_open': False })
|
||||
return super(base_stage, self).copy(cr, uid, id, default, context=context)
|
||||
|
||||
def case_escalate(self, cr, uid, ids, context=None):
|
||||
""" Escalates case to parent level """
|
||||
cases = self.browse(cr, uid, ids, context=context)
|
||||
cases[0].state # fill browse record cache, for _action having old and new values
|
||||
for case in cases:
|
||||
data = {'active': True}
|
||||
if case.section_id.parent_id:
|
||||
data['section_id'] = case.section_id.parent_id.id
|
||||
if case.section_id.parent_id.change_responsible:
|
||||
if case.section_id.parent_id.user_id:
|
||||
data['user_id'] = case.section_id.parent_id.user_id.id
|
||||
else:
|
||||
raise osv.except_osv(_('Error !'), _('You can not escalate, you are already at the top level regarding your sales-team category.'))
|
||||
self.write(cr, uid, [case.id], data, context=context)
|
||||
case.case_escalate_send_note(case.section_id.parent_id, context=context)
|
||||
cases = self.browse(cr, uid, ids, context=context)
|
||||
self._action(cr, uid, cases, 'escalate', context=context)
|
||||
return True
|
||||
|
||||
def case_open(self, cr, uid, ids, context=None):
|
||||
""" Opens case """
|
||||
cases = self.browse(cr, uid, ids, context=context)
|
||||
for case in cases:
|
||||
data = {'active': True}
|
||||
if case.stage_id and case.stage_id.state == 'draft':
|
||||
data['date_open'] = fields.datetime.now()
|
||||
if not case.user_id:
|
||||
data['user_id'] = uid
|
||||
self.case_set(cr, uid, [case.id], 'open', data, context=context)
|
||||
self.case_open_send_note(cr, uid, [case.id], context=context)
|
||||
return True
|
||||
|
||||
def case_close(self, cr, uid, ids, context=None):
|
||||
""" Closes case """
|
||||
self.case_set(cr, uid, ids, 'done', {'active': True, 'date_closed': fields.datetime.now()}, context=context)
|
||||
self.case_close_send_note(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
def case_cancel(self, cr, uid, ids, context=None):
|
||||
""" Cancels case """
|
||||
self.case_set(cr, uid, ids, 'cancel', {'active': True}, context=context)
|
||||
self.case_cancel_send_note(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
def case_pending(self, cr, uid, ids, context=None):
|
||||
""" Set case as pending """
|
||||
self.case_set(cr, uid, ids, 'pending', {'active': True}, context=context)
|
||||
self.case_pending_send_note(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
def case_reset(self, cr, uid, ids, context=None):
|
||||
""" Resets case as draft """
|
||||
self.case_set(cr, uid, ids, 'draft', {'active': True}, context=context)
|
||||
self.case_reset_send_note(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
def case_set(self, cr, uid, ids, new_state_name=None, values_to_update=None, new_stage_id=None, context=None):
|
||||
""" Generic method for setting case. This methods wraps the update
|
||||
of the record, as well as call to _action and browse_record
|
||||
case setting to fill the cache.
|
||||
|
||||
:params new_state_name: the new state of the record; this method
|
||||
will call ``stage_set_with_state_name``
|
||||
that will find the stage matching the
|
||||
new state, using the ``stage_find`` method.
|
||||
:params new_stage_id: alternatively, you may directly give the
|
||||
new stage of the record
|
||||
:params state_name: the new value of the state, such as
|
||||
'draft' or 'close'.
|
||||
:params update_values: values that will be added with the state
|
||||
update when writing values to the record.
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids, context=context)
|
||||
cases[0].state # fill browse record cache, for _action having old and new values
|
||||
# 1. update the stage
|
||||
if new_state_name:
|
||||
self.stage_set_with_state_name(cr, uid, cases, new_state_name, context=context)
|
||||
elif not (new_stage_id is None):
|
||||
self.stage_set(cr, uid, ids, new_stage_id, context=context)
|
||||
# 2. update values
|
||||
if values_to_update:
|
||||
self.write(cr, uid, ids, values_to_update, context=context)
|
||||
# 3. call _action for base action rule
|
||||
if new_state_name:
|
||||
self._action(cr, uid, cases, new_state_name, context=context)
|
||||
elif not (new_stage_id is None):
|
||||
new_state_name = self.read(cr, uid, ids, ['state'], context=context)[0]['state']
|
||||
self._action(cr, uid, cases, new_state_name, context=context)
|
||||
return True
|
||||
|
||||
def _action(self, cr, uid, cases, state_to, scrit=None, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
context['state_to'] = state_to
|
||||
rule_obj = self.pool.get('base.action.rule')
|
||||
if not rule_obj:
|
||||
return True
|
||||
model_obj = self.pool.get('ir.model')
|
||||
model_ids = model_obj.search(cr, uid, [('model','=',self._name)], context=context)
|
||||
rule_ids = rule_obj.search(cr, uid, [('model_id','=',model_ids[0])], context=context)
|
||||
return rule_obj._action(cr, uid, rule_ids, cases, scrit=scrit, context=context)
|
||||
|
||||
def remind_partner(self, cr, uid, ids, context=None, attach=False):
|
||||
return self.remind_user(cr, uid, ids, context, attach,
|
||||
destination=False)
|
||||
|
||||
def remind_user(self, cr, uid, ids, context=None, attach=False, destination=True):
|
||||
mail_message = self.pool.get('mail.message')
|
||||
for case in self.browse(cr, uid, ids, context=context):
|
||||
if not destination and not case.email_from:
|
||||
return False
|
||||
if not case.user_id.user_email:
|
||||
return False
|
||||
if destination and case.section_id.user_id:
|
||||
case_email = case.section_id.user_id.user_email
|
||||
else:
|
||||
case_email = case.user_id.user_email
|
||||
|
||||
src = case_email
|
||||
dest = case.user_id.user_email or ""
|
||||
body = case.description or ""
|
||||
for message in case.message_ids:
|
||||
if message.email_from and message.body_text:
|
||||
body = message.body_text
|
||||
break
|
||||
|
||||
if not destination:
|
||||
src, dest = dest, case.email_from
|
||||
if body and case.user_id.signature:
|
||||
if body:
|
||||
body += '\n\n%s' % (case.user_id.signature)
|
||||
else:
|
||||
body = '\n\n%s' % (case.user_id.signature)
|
||||
|
||||
body = self.format_body(body)
|
||||
|
||||
attach_to_send = {}
|
||||
|
||||
if attach:
|
||||
attach_ids = self.pool.get('ir.attachment').search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', case.id)])
|
||||
attach_to_send = self.pool.get('ir.attachment').read(cr, uid, attach_ids, ['datas_fname', 'datas'])
|
||||
attach_to_send = dict(map(lambda x: (x['datas_fname'], base64.decodestring(x['datas'])), attach_to_send))
|
||||
|
||||
# Send an email
|
||||
subject = "Reminder: [%s] %s" % (str(case.id), case.name, )
|
||||
mail_message.schedule_with_attach(cr, uid,
|
||||
src,
|
||||
[dest],
|
||||
subject,
|
||||
body,
|
||||
model=self._name,
|
||||
reply_to=case.section_id.reply_to,
|
||||
res_id=case.id,
|
||||
attachments=attach_to_send,
|
||||
context=context
|
||||
)
|
||||
return True
|
||||
|
||||
def _check(self, cr, uid, ids=False, context=None):
|
||||
""" Function called by the scheduler to process cases for date actions.
|
||||
Must be overriden by inheriting classes.
|
||||
"""
|
||||
return True
|
||||
|
||||
def format_body(self, body):
|
||||
return self.pool.get('base.action.rule').format_body(body)
|
||||
|
||||
def format_mail(self, obj, body):
|
||||
return self.pool.get('base.action.rule').format_mail(obj, body)
|
||||
|
||||
def message_thread_followers(self, cr, uid, ids, context=None):
|
||||
res = {}
|
||||
for case in self.browse(cr, uid, ids, context=context):
|
||||
l=[]
|
||||
if case.email_cc:
|
||||
l.append(case.email_cc)
|
||||
if case.user_id and case.user_id.user_email:
|
||||
l.append(case.user_id.user_email)
|
||||
res[case.id] = l
|
||||
return res
|
||||
|
||||
# ******************************
|
||||
# Notifications
|
||||
# ******************************
|
||||
|
||||
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
||||
""" Default prefix for notifications. For example: "%s has been
|
||||
<b>closed</b>.". As several models will inherit from base_stage,
|
||||
this method returns a void string. Class using base_stage
|
||||
will have to override this method to define the prefix they
|
||||
want to display.
|
||||
"""
|
||||
return ''
|
||||
|
||||
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
|
||||
""" Send a notification when the stage changes. This method has
|
||||
to be overriden, because each document will have its particular
|
||||
behavior and/or stage model (such as project.task.type or
|
||||
crm.case.stage).
|
||||
"""
|
||||
return True
|
||||
|
||||
def case_open_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = _('%s has been <b>opened</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def case_close_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = _('%s has been <b>closed</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def case_cancel_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = _('%s has been <b>canceled</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def case_pending_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = _('%s is now <b>pending</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def case_reset_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = _('%s has been <b>renewed</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def case_escalate_send_note(self, cr, uid, ids, new_section=None, context=None):
|
||||
for id in ids:
|
||||
if new_section:
|
||||
msg = '%s has been <b>escalated</b> to <b>%s</b>.' % (self.case_get_note_msg_prefix(cr, uid, id, context=context), new_section.name)
|
||||
else:
|
||||
msg = '%s has been <b>escalated</b>.' % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], 'System Notification', msg, context=context)
|
||||
return True
|
|
@ -0,0 +1,194 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import fields
|
||||
from tools.translate import _
|
||||
|
||||
class base_state(object):
|
||||
""" Base utility mixin class for objects willing to manage their state.
|
||||
Object subclassing this class should define the following colums:
|
||||
- ``date_open`` (datetime field)
|
||||
- ``date_closed`` (datetime field)
|
||||
- ``user_id`` (many2one to res.users)
|
||||
- ``partner_id`` (many2one to res.partner)
|
||||
- ``state`` (selection field)
|
||||
"""
|
||||
|
||||
def _get_default_partner(self, cr, uid, context=None):
|
||||
""" Gives id of partner for current user
|
||||
:param context: if portal not in context returns False
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if not context or not context.get('portal'):
|
||||
return False
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
if hasattr(user, 'partner_address_id') and user.partner_address_id:
|
||||
return user.partner_address_id
|
||||
return user.company_id.partner_id.id
|
||||
|
||||
def _get_default_email(self, cr, uid, context=None):
|
||||
""" Gives default email address for current user
|
||||
:param context: if portal not in context returns False
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if not context or not context.get('portal'):
|
||||
return False
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
return user.user_email
|
||||
|
||||
def _get_default_user(self, cr, uid, context=None):
|
||||
""" Gives current user id
|
||||
:param context: if portal not in context returns False
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if not context or not context.get('portal'):
|
||||
return False
|
||||
return uid
|
||||
|
||||
def onchange_partner_address_id(self, cr, uid, ids, add, email=False):
|
||||
""" This function returns value of partner email based on Partner Address
|
||||
:param add: Id of Partner's address
|
||||
:param email: Partner's email ID
|
||||
"""
|
||||
data = {'value': {'email_from': False, 'phone':False}}
|
||||
if add:
|
||||
address = self.pool.get('res.partner').browse(cr, uid, add)
|
||||
data['value'] = {'email_from': address and address.email or False ,
|
||||
'phone': address and address.phone or False}
|
||||
if 'phone' not in self._columns:
|
||||
del data['value']['phone']
|
||||
return data
|
||||
|
||||
def onchange_partner_id(self, cr, uid, ids, part, email=False):
|
||||
""" This function returns value of partner address based on partner
|
||||
:param part: Partner's id
|
||||
:param email: Partner's email ID
|
||||
"""
|
||||
data={}
|
||||
if part:
|
||||
addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['contact'])
|
||||
data.update(self.onchange_partner_address_id(cr, uid, ids, addr['contact'])['value'])
|
||||
return {'value': data}
|
||||
|
||||
def case_open(self, cr, uid, ids, context=None):
|
||||
""" Opens case """
|
||||
cases = self.browse(cr, uid, ids, context=context)
|
||||
for case in cases:
|
||||
values = {'active': True}
|
||||
if case.state == 'draft':
|
||||
values['date_open'] = fields.datetime.now()
|
||||
if not case.user_id:
|
||||
values['user_id'] = uid
|
||||
self.case_set(cr, uid, [case.id], 'open', values, context=context)
|
||||
self.case_open_send_note(cr, uid, [case.id], context=context)
|
||||
return True
|
||||
|
||||
def case_close(self, cr, uid, ids, context=None):
|
||||
""" Closes case """
|
||||
self.case_set(cr, uid, ids, 'done', {'date_closed': fields.datetime.now()}, context=context)
|
||||
self.case_close_send_note(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
def case_cancel(self, cr, uid, ids, context=None):
|
||||
""" Cancels case """
|
||||
self.case_set(cr, uid, ids, 'cancel', {'active': True}, context=context)
|
||||
self.case_cancel_send_note(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
def case_pending(self, cr, uid, ids, context=None):
|
||||
""" Sets case as pending """
|
||||
self.case_set(cr, uid, ids, 'pending', {'active': True}, context=context)
|
||||
self.case_pending_send_note(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
def case_reset(self, cr, uid, ids, context=None):
|
||||
""" Resets case as draft """
|
||||
self.case_set(cr, uid, ids, 'draft', {'active': True}, context=context)
|
||||
self.case_reset_send_note(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
def case_set(self, cr, uid, ids, state_name, update_values=None, context=None):
|
||||
""" Generic method for setting case. This methods wraps the update
|
||||
of the record, as well as call to _action and browse_record
|
||||
case setting to fill the cache.
|
||||
|
||||
:params: state_name: the new value of the state, such as
|
||||
'draft' or 'close'.
|
||||
:params: update_values: values that will be added with the state
|
||||
update when writing values to the record.
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids, context=context)
|
||||
cases[0].state # fill browse record cache, for _action having old and new values
|
||||
if update_values is None:
|
||||
update_values = {}
|
||||
update_values['state'] = state_name
|
||||
self.write(cr, uid, ids, update_values, context=context)
|
||||
self._action(cr, uid, cases, state_name, context=context)
|
||||
|
||||
def _action(self, cr, uid, cases, state_to, scrit=None, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
context['state_to'] = state_to
|
||||
rule_obj = self.pool.get('base.action.rule')
|
||||
model_obj = self.pool.get('ir.model')
|
||||
model_ids = model_obj.search(cr, uid, [('model','=',self._name)])
|
||||
rule_ids = rule_obj.search(cr, uid, [('model_id','=',model_ids[0])])
|
||||
return rule_obj._action(cr, uid, rule_ids, cases, scrit=scrit, context=context)
|
||||
|
||||
# ******************************
|
||||
# Notifications
|
||||
# ******************************
|
||||
|
||||
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
||||
return ''
|
||||
|
||||
def case_open_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = _('%s has been <b>opened</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def case_close_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = _('%s has been <b>closed</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def case_cancel_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = _('%s has been <b>canceled</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def case_pending_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = _('%s is now <b>pending</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def case_reset_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = _('%s has been <b>renewed</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
|
@ -57,6 +57,7 @@ Creates a dashboard for CRM that includes:
|
|||
'depends': [
|
||||
'base_action_rule',
|
||||
'base_setup',
|
||||
'base_status',
|
||||
'process',
|
||||
'mail',
|
||||
'base_calendar',
|
||||
|
@ -66,7 +67,6 @@ Creates a dashboard for CRM that includes:
|
|||
],
|
||||
'init_xml': [
|
||||
'crm_data.xml',
|
||||
'crm_meeting_data.xml',
|
||||
'crm_lead_data.xml',
|
||||
'crm_meeting_data.xml',
|
||||
'crm_phonecall_data.xml',
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<field name="planned_revenue" sum="Total of Planned Revenue"/>
|
||||
<field name="probability" widget="progressbar" avg="Avg. of Probability"/>
|
||||
<field name="date_deadline" invisible="1"/>
|
||||
<field name="state"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
|
@ -19,12 +19,11 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
import base64
|
||||
import tools
|
||||
|
||||
import time
|
||||
from osv import fields
|
||||
from osv import osv
|
||||
import tools
|
||||
from tools.translate import _
|
||||
|
||||
MAX_LEVEL = 15
|
||||
|
@ -57,8 +56,11 @@ class crm_case_channel(osv.osv):
|
|||
}
|
||||
|
||||
class crm_case_stage(osv.osv):
|
||||
""" Stage of case """
|
||||
|
||||
""" Model for case stages. This models the main stages of a document
|
||||
management flow. Main CRM objects (leads, opportunities, project
|
||||
issues, ...) will now use only stages, instead of state and stages.
|
||||
Stages are for example used to display the kanban view of records.
|
||||
"""
|
||||
_name = "crm.case.stage"
|
||||
_description = "Stage of case"
|
||||
_rec_name = 'name'
|
||||
|
@ -66,22 +68,34 @@ class crm_case_stage(osv.osv):
|
|||
|
||||
_columns = {
|
||||
'name': fields.char('Stage Name', size=64, required=True, translate=True),
|
||||
'sequence': fields.integer('Sequence', help="Used to order stages."),
|
||||
'sequence': fields.integer('Sequence', help="Used to order stages. Lower is better."),
|
||||
'probability': fields.float('Probability (%)', required=True, help="This percentage depicts the default/average probability of the Case for this stage to be a success"),
|
||||
'on_change': fields.boolean('Change Probability Automatically', help="Setting this stage will change the probability automatically on the opportunity."),
|
||||
'requirements': fields.text('Requirements'),
|
||||
'section_ids':fields.many2many('crm.case.section', 'section_stage_rel', 'stage_id', 'section_id', 'Sections'),
|
||||
'case_default': fields.boolean('Common to All Teams', 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."),
|
||||
'section_ids':fields.many2many('crm.case.section', 'section_stage_rel', 'stage_id', 'section_id', string='Sections',
|
||||
help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."),
|
||||
'state': fields.selection(AVAILABLE_STATES, 'State', required=True, help="The related state for the stage. The state of your document will automatically change regarding the selected stage. For example, if a stage is related to the state 'Close', when your document reaches this stage, it will be automatically have the 'closed' state."),
|
||||
'case_default': fields.boolean('Common to All Teams',
|
||||
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('Hide in Views when 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."),
|
||||
'type': fields.selection([ ('lead','Lead'),
|
||||
('opportunity', 'Opportunity'),
|
||||
('both', 'Both')],
|
||||
string='Type', size=16, required=True,
|
||||
help="This field is used to distinguish stages related to Leads from stages related to Opportunities, or to specify stages available for both types."),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'sequence': lambda *args: 1,
|
||||
'probability': lambda *args: 0.0,
|
||||
'state': 'draft',
|
||||
'fold': False,
|
||||
'type': 'both',
|
||||
}
|
||||
|
||||
class crm_case_section(osv.osv):
|
||||
"""Sales Team"""
|
||||
|
||||
""" Model for sales teams. """
|
||||
_name = "crm.case.section"
|
||||
_description = "Sales Teams"
|
||||
_order = "complete_name"
|
||||
|
@ -107,6 +121,7 @@ class crm_case_section(osv.osv):
|
|||
'working_hours': fields.float('Working Hours', digits=(16,2 )),
|
||||
'stage_ids': fields.many2many('crm.case.stage', 'section_stage_rel', 'section_id', 'stage_id', 'Stages'),
|
||||
}
|
||||
|
||||
def _get_stage_common(self, cr, uid, context):
|
||||
ids = self.pool.get('crm.case.stage').search(cr, uid, [('case_default','=',1)], context=context)
|
||||
return ids
|
||||
|
@ -171,429 +186,6 @@ class crm_case_resource_type(osv.osv):
|
|||
'section_id': fields.many2one('crm.case.section', 'Sales Team'),
|
||||
}
|
||||
|
||||
class crm_base(object):
|
||||
""" Base utility mixin class for crm objects,
|
||||
Object subclassing this should define colums:
|
||||
date_open
|
||||
date_closed
|
||||
user_id
|
||||
partner_id
|
||||
"""
|
||||
def _get_default_partner_address(self, cr, uid, context=None):
|
||||
"""Gives id of default address for current user
|
||||
:param context: if portal in context is false return false anyway
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if not context.get('portal'):
|
||||
return False
|
||||
# was user.address_id.id, but address_id has been removed
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
if hasattr(user, 'partner_address_id') and user.partner_address_id:
|
||||
return user.partner_address_id
|
||||
return False
|
||||
|
||||
def _get_default_partner(self, cr, uid, context=None):
|
||||
"""Gives id of partner for current user
|
||||
:param context: if portal in context is false return false anyway
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if not context.get('portal', False):
|
||||
return False
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
if hasattr(user, 'partner_address_id') and user.partner_address_id:
|
||||
return user.partner_address_id
|
||||
return user.company_id.partner_id.id
|
||||
|
||||
def _get_default_email(self, cr, uid, context=None):
|
||||
"""Gives default email address for current user
|
||||
:param context: if portal in context is false return false anyway
|
||||
"""
|
||||
if not context.get('portal', False):
|
||||
return False
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
return user.user_email
|
||||
|
||||
def _get_default_user(self, cr, uid, context=None):
|
||||
"""Gives current user id
|
||||
:param context: if portal in context is false return false anyway
|
||||
"""
|
||||
if context and context.get('portal', False):
|
||||
return False
|
||||
return uid
|
||||
|
||||
def _get_section(self, cr, uid, context=None):
|
||||
return False
|
||||
|
||||
def onchange_partner_address_id(self, cr, uid, ids, add, email=False):
|
||||
"""This function returns value of partner email based on Partner Address
|
||||
:param ids: List of case IDs
|
||||
:param add: Id of Partner's address
|
||||
:param email: Partner's email ID
|
||||
"""
|
||||
data = {'value': {'email_from': False, 'phone':False}}
|
||||
if add:
|
||||
address = self.pool.get('res.partner').browse(cr, uid, add)
|
||||
data['value'] = {'email_from': address and address.email or False ,
|
||||
'phone': address and address.phone or False}
|
||||
if 'phone' not in self._columns:
|
||||
del data['value']['phone']
|
||||
return data
|
||||
|
||||
def onchange_partner_id(self, cr, uid, ids, part, email=False):
|
||||
"""This function returns value of partner address based on partner
|
||||
:param ids: List of case IDs
|
||||
:param part: Partner's id
|
||||
:param email: Partner's email ID
|
||||
"""
|
||||
data={}
|
||||
if part:
|
||||
addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['contact'])
|
||||
data.update(self.onchange_partner_address_id(cr, uid, ids, addr['contact'])['value'])
|
||||
return {'value': data}
|
||||
|
||||
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
||||
return ''
|
||||
|
||||
def case_open_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = '%s has been <b>opened</b>.' % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def case_close_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = '%s has been <b>closed</b>.'% (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def case_cancel_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = '%s has been <b>canceled</b>.' % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def case_pending_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = '%s is now <b>pending</b>.' % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def case_reset_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = '%s has been <b>renewed</b>.' % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def case_open(self, cr, uid, ids, context=None):
|
||||
"""Opens Case
|
||||
:param ids: List of case Ids
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
for case in cases:
|
||||
data = {'state': 'open', 'active': True}
|
||||
if not case.user_id:
|
||||
data['user_id'] = uid
|
||||
self.write(cr, uid, [case.id], data)
|
||||
self.case_open_send_note(cr, uid, ids, context=context)
|
||||
self._action(cr, uid, cases, 'open')
|
||||
|
||||
return True
|
||||
|
||||
def case_close(self, cr, uid, ids, context=None):
|
||||
"""Closes Case
|
||||
:param ids: List of case Ids
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self.write(cr, uid, ids, {'state': 'done', 'date_closed': time.strftime('%Y-%m-%d %H:%M:%S'), })
|
||||
# We use the cache of cases to keep the old case state
|
||||
self.case_close_send_note(cr, uid, ids, context=context)
|
||||
self._action(cr, uid, cases, 'done')
|
||||
return True
|
||||
|
||||
def case_cancel(self, cr, uid, ids, context=None):
|
||||
"""Cancels Case
|
||||
:param ids: List of case Ids
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self.write(cr, uid, ids, {'state': 'cancel', 'active': True})
|
||||
# We use the cache of cases to keep the old case state
|
||||
self.case_cancel_send_note(cr, uid, ids, context=context)
|
||||
self._action(cr, uid, cases, 'cancel')
|
||||
return True
|
||||
|
||||
def case_pending(self, cr, uid, ids, context=None):
|
||||
"""Marks case as pending
|
||||
:param ids: List of case Ids
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self.write(cr, uid, ids, {'state': 'pending', 'active': True})
|
||||
self.case_pending_send_note(cr, uid, ids, context=context)
|
||||
self._action(cr, uid, cases, 'pending')
|
||||
return True
|
||||
|
||||
def case_reset(self, cr, uid, ids, context=None):
|
||||
"""Resets case as draft
|
||||
:param ids: List of case Ids
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self.write(cr, uid, ids, {'state': 'draft', 'active': True})
|
||||
self.case_reset_send_note(cr, uid, ids, context=context)
|
||||
self._action(cr, uid, cases, 'draft')
|
||||
return True
|
||||
|
||||
def _action(self, cr, uid, cases, state_to, scrit=None, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
context['state_to'] = state_to
|
||||
rule_obj = self.pool.get('base.action.rule')
|
||||
model_obj = self.pool.get('ir.model')
|
||||
model_ids = model_obj.search(cr, uid, [('model','=',self._name)])
|
||||
rule_ids = rule_obj.search(cr, uid, [('model_id','=',model_ids[0])])
|
||||
return rule_obj._action(cr, uid, rule_ids, cases, scrit=scrit, context=context)
|
||||
|
||||
class crm_case(crm_base):
|
||||
""" A simple python class to be used for common functions
|
||||
Object that inherit from this class should inherit from mailgate.thread
|
||||
And need a stage_id field
|
||||
And object that inherit (orm inheritance) from a class the overwrite copy
|
||||
"""
|
||||
|
||||
def stage_find(self, cr, uid, section_id, domain=[], order='sequence'):
|
||||
domain = list(domain)
|
||||
if section_id:
|
||||
domain.append(('section_ids', '=', section_id))
|
||||
stage_ids = self.pool.get('crm.case.stage').search(cr, uid, domain, order=order)
|
||||
if stage_ids:
|
||||
return stage_ids[0]
|
||||
return False
|
||||
|
||||
def stage_set(self, cr, uid, ids, stage_id, context=None):
|
||||
value = {}
|
||||
if hasattr(self,'onchange_stage_id'):
|
||||
value = self.onchange_stage_id(cr, uid, ids, stage_id)['value']
|
||||
value['stage_id'] = stage_id
|
||||
return self.write(cr, uid, ids, value, context=context)
|
||||
|
||||
def stage_change(self, cr, uid, ids, op, order, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
for case in self.browse(cr, uid, ids, context=context):
|
||||
seq = 0
|
||||
if case.stage_id:
|
||||
seq = case.stage_id.sequence
|
||||
section_id = None
|
||||
if case.section_id:
|
||||
section_id = case.section_id.id
|
||||
next_stage_id = self.stage_find(cr, uid, section_id, [('sequence',op,seq)],order)
|
||||
if next_stage_id:
|
||||
return self.stage_set(cr, uid, [case.id], next_stage_id, context=context)
|
||||
return False
|
||||
|
||||
def stage_next(self, cr, uid, ids, context=None):
|
||||
"""This function computes next stage for case from its current stage
|
||||
using available stage for that case type
|
||||
"""
|
||||
return self.stage_change(cr, uid, ids, '>','sequence', context)
|
||||
|
||||
def stage_previous(self, cr, uid, ids, context=None):
|
||||
"""This function computes previous stage for case from its current
|
||||
stage using available stage for that case type
|
||||
"""
|
||||
return self.stage_change(cr, uid, ids, '<', 'sequence desc', context)
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
"""Overrides orm copy method to avoid copying messages,
|
||||
as well as date_closed and date_open columns if they
|
||||
exist."""
|
||||
if default is None:
|
||||
default = {}
|
||||
|
||||
default.update({ 'message_ids': [], })
|
||||
if hasattr(self, '_columns'):
|
||||
if self._columns.get('date_closed'):
|
||||
default.update({ 'date_closed': False, })
|
||||
if self._columns.get('date_open'):
|
||||
default.update({ 'date_open': False })
|
||||
return super(crm_case, self).copy(cr, uid, id, default, context=context)
|
||||
|
||||
def case_escalate_send_note(self, cr, uid, ids, new_section=None, context=None):
|
||||
for id in ids:
|
||||
if new_section:
|
||||
msg = '%s has been <b>escalated</b> to <b>%s</b>.' % (self.case_get_note_msg_prefix(cr, uid, id, context=context), new_section.name)
|
||||
else:
|
||||
msg = '%s has been <b>escalated</b>.' % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], 'System Notification', msg, context=context)
|
||||
return True
|
||||
|
||||
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
||||
return ''
|
||||
|
||||
def case_open(self, cr, uid, ids, context=None):
|
||||
"""Opens Case"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
for case in cases:
|
||||
data = {'state': 'open', 'active': True }
|
||||
if not case.user_id:
|
||||
data['user_id'] = uid
|
||||
self.write(cr, uid, [case.id], data)
|
||||
self.case_open_send_note(cr, uid, ids, context=context)
|
||||
self._action(cr, uid, cases, 'open')
|
||||
return True
|
||||
|
||||
def case_close(self, cr, uid, ids, context=None):
|
||||
"""Closes Case"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self.write(cr, uid, ids, {'state': 'done',
|
||||
'date_closed': time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
})
|
||||
#
|
||||
# We use the cache of cases to keep the old case state
|
||||
#
|
||||
self.case_close_send_note(cr, uid, ids, context=context)
|
||||
self._action(cr, uid, cases, 'done')
|
||||
return True
|
||||
|
||||
def case_escalate(self, cr, uid, ids, context=None):
|
||||
"""Escalates case to parent level"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
for case in cases:
|
||||
data = {'active': True}
|
||||
if case.section_id.parent_id:
|
||||
data['section_id'] = case.section_id.parent_id.id
|
||||
if case.section_id.parent_id.change_responsible:
|
||||
if case.section_id.parent_id.user_id:
|
||||
data['user_id'] = case.section_id.parent_id.user_id.id
|
||||
else:
|
||||
raise osv.except_osv(_('Error !'), _('You can not escalate, you are already at the top level regarding your sales-team category.'))
|
||||
self.write(cr, uid, [case.id], data)
|
||||
case.case_escalate_send_note(case.section_id.parent_id)
|
||||
cases = self.browse(cr, uid, ids)
|
||||
self._action(cr, uid, cases, 'escalate')
|
||||
return True
|
||||
|
||||
def case_cancel(self, cr, uid, ids, context=None):
|
||||
"""Cancels Case"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self.write(cr, uid, ids, {'state': 'cancel',
|
||||
'active': True})
|
||||
self.case_cancel_send_note(cr, uid, ids, context=context)
|
||||
self._action(cr, uid, cases, 'cancel')
|
||||
return True
|
||||
|
||||
def case_pending(self, cr, uid, ids, context=None):
|
||||
"""Marks case as pending"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self.write(cr, uid, ids, {'state': 'pending', 'active': True})
|
||||
self.case_pending_send_note(cr, uid, ids, context=context)
|
||||
self._action(cr, uid, cases, 'pending')
|
||||
return True
|
||||
|
||||
def case_reset(self, cr, uid, ids, context=None):
|
||||
"""Resets case as draft"""
|
||||
state = 'draft'
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self.write(cr, uid, ids, {'state': state, 'active': True})
|
||||
self.case_reset_send_note(cr, uid, ids, context=context)
|
||||
self._action(cr, uid, cases, state)
|
||||
return True
|
||||
|
||||
def remind_partner(self, cr, uid, ids, context=None, attach=False):
|
||||
return self.remind_user(cr, uid, ids, context, attach,
|
||||
destination=False)
|
||||
|
||||
def remind_user(self, cr, uid, ids, context=None, attach=False, destination=True):
|
||||
mail_message = self.pool.get('mail.message')
|
||||
for case in self.browse(cr, uid, ids, context=context):
|
||||
if not destination and not case.email_from:
|
||||
return False
|
||||
if not case.user_id.user_email:
|
||||
return False
|
||||
if destination and case.section_id.user_id:
|
||||
case_email = case.section_id.user_id.user_email
|
||||
else:
|
||||
case_email = case.user_id.user_email
|
||||
|
||||
src = case_email
|
||||
dest = case.user_id.user_email or ""
|
||||
body = case.description or ""
|
||||
for message in case.message_ids:
|
||||
if message.email_from and message.body_text:
|
||||
body = message.body_text
|
||||
break
|
||||
|
||||
if not destination:
|
||||
src, dest = dest, case.email_from
|
||||
if body and case.user_id.signature:
|
||||
if body:
|
||||
body += '\n\n%s' % (case.user_id.signature)
|
||||
else:
|
||||
body = '\n\n%s' % (case.user_id.signature)
|
||||
|
||||
body = self.format_body(body)
|
||||
|
||||
attach_to_send = {}
|
||||
|
||||
if attach:
|
||||
attach_ids = self.pool.get('ir.attachment').search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', case.id)])
|
||||
attach_to_send = self.pool.get('ir.attachment').read(cr, uid, attach_ids, ['datas_fname', 'datas'])
|
||||
attach_to_send = dict(map(lambda x: (x['datas_fname'], base64.decodestring(x['datas'])), attach_to_send))
|
||||
|
||||
# Send an email
|
||||
subject = "Reminder: [%s] %s" % (str(case.id), case.name, )
|
||||
mail_message.schedule_with_attach(cr, uid,
|
||||
src,
|
||||
[dest],
|
||||
subject,
|
||||
body,
|
||||
model=self._name,
|
||||
reply_to=case.section_id.reply_to,
|
||||
res_id=case.id,
|
||||
attachments=attach_to_send,
|
||||
context=context
|
||||
)
|
||||
return True
|
||||
|
||||
def _check(self, cr, uid, ids=False, context=None):
|
||||
"""Function called by the scheduler to process cases for date actions
|
||||
Only works on not done and cancelled cases
|
||||
"""
|
||||
cr.execute('select * from crm_case \
|
||||
where (date_action_last<%s or date_action_last is null) \
|
||||
and (date_action_next<=%s or date_action_next is null) \
|
||||
and state not in (\'cancel\',\'done\')',
|
||||
(time.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
time.strftime('%Y-%m-%d %H:%M:%S')))
|
||||
|
||||
ids2 = map(lambda x: x[0], cr.fetchall() or [])
|
||||
cases = self.browse(cr, uid, ids2, context=context)
|
||||
return self._action(cr, uid, cases, False, context=context)
|
||||
|
||||
def format_body(self, body):
|
||||
return self.pool.get('base.action.rule').format_body(body)
|
||||
|
||||
def format_mail(self, obj, body):
|
||||
return self.pool.get('base.action.rule').format_mail(obj, body)
|
||||
|
||||
def message_thread_followers(self, cr, uid, ids, context=None):
|
||||
res = {}
|
||||
for case in self.browse(cr, uid, ids, context=context):
|
||||
l=[]
|
||||
if case.email_cc:
|
||||
l.append(case.email_cc)
|
||||
if case.user_id and case.user_id.user_email:
|
||||
l.append(case.user_id.user_email)
|
||||
res[case.id] = l
|
||||
return res
|
||||
|
||||
def _links_get(self, cr, uid, context=None):
|
||||
"""Gets links value for reference field"""
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
|
@ -19,15 +19,15 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import fields, osv
|
||||
from datetime import datetime
|
||||
import crm
|
||||
import time
|
||||
from tools.translate import _
|
||||
from crm import crm_case
|
||||
import binascii
|
||||
import tools
|
||||
from base_status.base_stage import base_stage
|
||||
import crm
|
||||
from datetime import datetime
|
||||
from mail.mail_message import to_email
|
||||
from osv import fields, osv
|
||||
import time
|
||||
import tools
|
||||
from tools.translate import _
|
||||
|
||||
CRM_LEAD_PENDING_STATES = (
|
||||
crm.AVAILABLE_STATES[2][0], # Cancelled
|
||||
|
@ -35,22 +35,68 @@ CRM_LEAD_PENDING_STATES = (
|
|||
crm.AVAILABLE_STATES[4][0], # Pending
|
||||
)
|
||||
|
||||
class crm_lead(crm_case, osv.osv):
|
||||
class crm_lead(base_stage, osv.osv):
|
||||
""" CRM Lead Case """
|
||||
_name = "crm.lead"
|
||||
_description = "Lead/Opportunity"
|
||||
_order = "priority,date_action,id desc"
|
||||
_inherit = ['ir.needaction_mixin', 'mail.thread','res.partner']
|
||||
|
||||
def _get_default_section_id(self, cr, uid, context=None):
|
||||
""" Gives default section by checking if present in the context """
|
||||
return (self._resolve_section_id_from_context(cr, uid, context=context) or False)
|
||||
|
||||
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, [('state', '=', 'draft'), ('type', '=', 'both')], context=context)
|
||||
|
||||
def _resolve_section_id_from_context(self, cr, uid, context=None):
|
||||
""" Returns ID of section based on the value of 'section_id'
|
||||
context key, or None if it cannot be resolved to a single
|
||||
Sales Team.
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if type(context.get('default_section_id')) in (int, long):
|
||||
return context.get('default_section_id')
|
||||
if isinstance(context.get('default_section_id'), basestring):
|
||||
section_name = context['default_section_id']
|
||||
section_ids = self.pool.get('crm.case.section').name_search(cr, uid, name=section_name, context=context)
|
||||
if len(section_ids) == 1:
|
||||
return int(section_ids[0][0])
|
||||
return None
|
||||
|
||||
def _resolve_type_from_context(self, cr, uid, context=None):
|
||||
""" Returns the type (lead or opportunity) from the type context
|
||||
key. Returns None if it cannot be resolved.
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
return context.get('default_type')
|
||||
|
||||
def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None):
|
||||
access_rights_uid = access_rights_uid or uid
|
||||
stage_obj = self.pool.get('crm.case.stage')
|
||||
order = stage_obj._order
|
||||
# lame hack to allow reverting search, should just work in the trivial case
|
||||
if read_group_order == 'stage_id desc':
|
||||
# lame hack to allow reverting search, should just work in the trivial case
|
||||
order = "%s desc" % order
|
||||
stage_ids = stage_obj._search(cr, uid, ['|', ('id','in',ids),('case_default','=',1)], order=order,
|
||||
access_rights_uid=access_rights_uid, context=context)
|
||||
# retrieve section_id from the context and write the domain
|
||||
# - ('id', 'in', 'ids'): add columns that should be present
|
||||
# - OR ('case_default', '=', True), ('fold', '=', False): add default columns that are not folded
|
||||
# - OR ('section_ids', '=', section_id), ('fold', '=', False) if section_id: add section columns that are not folded
|
||||
search_domain = []
|
||||
section_id = self._resolve_section_id_from_context(cr, uid, context=context)
|
||||
if section_id:
|
||||
search_domain += ['|', '&', ('section_ids', '=', section_id), ('fold', '=', False)]
|
||||
search_domain += ['|', ('id', 'in', ids), '&', ('case_default', '=', True), ('fold', '=', False)]
|
||||
# retrieve type from the context (if set: choose 'type' or 'both')
|
||||
type = self._resolve_type_from_context(cr, uid, context=context)
|
||||
if type:
|
||||
search_domain += ['|', ('type', '=', type), ('type', '=', 'both')]
|
||||
# perform search
|
||||
stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context)
|
||||
result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context)
|
||||
# restore order of the search
|
||||
result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))
|
||||
|
@ -154,7 +200,6 @@ class crm_lead(crm_case, osv.osv):
|
|||
'email_cc': fields.text('Global CC', size=252 , help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
|
||||
'description': fields.text('Notes'),
|
||||
'write_date': fields.datetime('Update Date' , readonly=True),
|
||||
|
||||
'categ_id': fields.many2one('crm.case.categ', 'Category', \
|
||||
domain="['|',('section_id','=',section_id),('section_id','=',False), ('object_id.model', '=', 'crm.lead')]"),
|
||||
'type_id': fields.many2one('crm.case.resource.type', 'Campaign', \
|
||||
|
@ -167,7 +212,8 @@ class crm_lead(crm_case, osv.osv):
|
|||
'type':fields.selection([ ('lead','Lead'), ('opportunity','Opportunity'), ],'Type', help="Type is used to separate Leads and Opportunities"),
|
||||
'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority', select=True),
|
||||
'date_closed': fields.datetime('Closed', readonly=True),
|
||||
'stage_id': fields.many2one('crm.case.stage', 'Stage', domain="[('section_ids', '=', section_id)]"),
|
||||
'stage_id': fields.many2one('crm.case.stage', 'Stage',
|
||||
domain="['&', '|', ('section_ids', '=', section_id), ('case_default', '=', True), '|', ('type', '=', type), ('type', '=', 'both')]"),
|
||||
'user_id': fields.many2one('res.users', 'Salesperson'),
|
||||
'referred': fields.char('Referred By', size=64),
|
||||
'date_open': fields.datetime('Opened', readonly=True),
|
||||
|
@ -175,11 +221,13 @@ class crm_lead(crm_case, osv.osv):
|
|||
multi='day_open', type="float", store=True),
|
||||
'day_close': fields.function(_compute_day, string='Days to Close', \
|
||||
multi='day_close', type="float", store=True),
|
||||
'state': fields.selection(crm.AVAILABLE_STATES, 'Status', size=16, readonly=True,
|
||||
help='The state is set to \'Draft\', when a case is created.\
|
||||
\nIf the case is in progress the state is set to \'In progress\'.\
|
||||
\nWhen the case is over, the state is set to \'Done\'.\
|
||||
\nIf the case needs to be reviewed then the state is set to \'Pending\'.'),
|
||||
'state': fields.related('stage_id', 'state', type="selection", store=True,
|
||||
selection=crm.AVAILABLE_STATES, string="State", readonly=True,
|
||||
help='The state is set to \'Draft\', when a case is created.\
|
||||
If the case is in progress the state is set to \'Open\'.\
|
||||
When the case is over, the state is set to \'Done\'.\
|
||||
If the case needs to be reviewed then the state is \
|
||||
set to \'Pending\'.'),
|
||||
'message_ids': fields.one2many('mail.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
|
||||
'subjects': fields.function(_get_email_subject, fnct_search=_history_search, string='Subject of Email', type='char', size=64),
|
||||
|
||||
|
@ -192,23 +240,21 @@ class crm_lead(crm_case, osv.osv):
|
|||
'date_deadline': fields.date('Expected Closing'),
|
||||
'date_action': fields.date('Next Action Date', select=True),
|
||||
'title_action': fields.char('Next Action', size=64),
|
||||
'stage_id': fields.many2one('crm.case.stage', 'Stage', domain="[('section_ids', '=', section_id)]"),
|
||||
'color': fields.integer('Color Index'),
|
||||
'partner_address_name': fields.related('partner_id', 'name', type='char', string='Partner Contact Name', readonly=True),
|
||||
'partner_address_email': fields.related('partner_id', 'email', type='char', string='Partner Contact Email', readonly=True),
|
||||
'company_currency': fields.related('company_id', 'currency_id', 'symbol', type='char', string='Company Currency', readonly=True),
|
||||
'user_email': fields.related('user_id', 'user_email', type='char', string='User Email', readonly=True),
|
||||
'user_login': fields.related('user_id', 'login', type='char', string='User Login', readonly=True),
|
||||
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'active': lambda *a: 1,
|
||||
'user_id': crm_case._get_default_user,
|
||||
'email_from': crm_case._get_default_email,
|
||||
'state': lambda *a: 'draft',
|
||||
'type': lambda *a: 'lead',
|
||||
'section_id': crm_case._get_section,
|
||||
'active': 1,
|
||||
'type': 'lead',
|
||||
'user_id': lambda s, cr, uid, c: s._get_default_user(cr, uid, c),
|
||||
'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
|
||||
'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
|
||||
'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
|
||||
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.lead', context=c),
|
||||
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
|
||||
'color': 0,
|
||||
|
@ -241,95 +287,104 @@ class crm_lead(crm_case, osv.osv):
|
|||
return {'value':{}}
|
||||
return {'value':{'probability': stage.probability}}
|
||||
|
||||
def stage_find_percent(self, cr, uid, percent, section_id):
|
||||
""" Return the first stage with a probability == percent
|
||||
def _check(self, cr, uid, ids=False, context=None):
|
||||
""" Override of the base.stage method.
|
||||
Function called by the scheduler to process cases for date actions
|
||||
Only works on not done and cancelled cases
|
||||
"""
|
||||
stage_pool = self.pool.get('crm.case.stage')
|
||||
if section_id :
|
||||
ids = stage_pool.search(cr, uid, [("probability", '=', percent), ("section_ids", 'in', [section_id])])
|
||||
else :
|
||||
ids = stage_pool.search(cr, uid, [("probability", '=', percent)])
|
||||
cr.execute('select * from crm_case \
|
||||
where (date_action_last<%s or date_action_last is null) \
|
||||
and (date_action_next<=%s or date_action_next is null) \
|
||||
and state not in (\'cancel\',\'done\')',
|
||||
(time.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
time.strftime('%Y-%m-%d %H:%M:%S')))
|
||||
|
||||
if ids:
|
||||
return ids[0]
|
||||
ids2 = map(lambda x: x[0], cr.fetchall() or [])
|
||||
cases = self.browse(cr, uid, ids2, context=context)
|
||||
return self._action(cr, uid, cases, False, context=context)
|
||||
|
||||
def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None):
|
||||
""" Override of the base.stage method
|
||||
Parameter of the stage search taken from the lead:
|
||||
- type: stage type must be the same or 'both'
|
||||
- section_id: if set, stages must belong to this section or
|
||||
be a default stage; if not set, stages must be default
|
||||
stages
|
||||
"""
|
||||
if isinstance(cases, (int, long)):
|
||||
cases = self.browse(cr, uid, cases, context=context)
|
||||
# collect all section_ids
|
||||
section_ids = []
|
||||
types = ['both']
|
||||
if section_id:
|
||||
section_ids.append(section_id)
|
||||
for lead in cases:
|
||||
if lead.section_id:
|
||||
section_ids.append(lead.section_id.id)
|
||||
if lead.type not in types:
|
||||
types.append(lead.type)
|
||||
# OR all section_ids and OR with case_default
|
||||
search_domain = []
|
||||
if section_ids:
|
||||
search_domain += [('|')] * len(section_ids)
|
||||
for section_id in section_ids:
|
||||
search_domain.append(('section_ids', '=', section_id))
|
||||
search_domain.append(('case_default', '=', True))
|
||||
# AND with cases types
|
||||
search_domain.append(('type', 'in', types))
|
||||
# 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)
|
||||
if stage_ids:
|
||||
return stage_ids[0]
|
||||
return False
|
||||
|
||||
def stage_find_lost(self, cr, uid, section_id):
|
||||
return self.stage_find_percent(cr, uid, 0.0, section_id)
|
||||
|
||||
def stage_find_won(self, cr, uid, section_id):
|
||||
return self.stage_find_percent(cr, uid, 100.0, section_id)
|
||||
|
||||
def case_open(self, cr, uid, ids, context=None):
|
||||
for lead in self.browse(cr, uid, ids, context=context):
|
||||
if lead.state == 'draft':
|
||||
value = {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')}
|
||||
self.write(cr, uid, [lead.id], value)
|
||||
if lead.type == 'opportunity' and not lead.stage_id:
|
||||
stage_id = self.stage_find(cr, uid, lead.section_id.id or False, [('sequence','>',0)])
|
||||
if stage_id:
|
||||
self.stage_set(cr, uid, [lead.id], stage_id)
|
||||
res = super(crm_lead, self).case_open(cr, uid, ids, context)
|
||||
return res
|
||||
|
||||
def case_close(self, cr, uid, ids, context=None):
|
||||
res = super(crm_lead, self).case_close(cr, uid, ids, context)
|
||||
self.write(cr, uid, ids, {'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')})
|
||||
return res
|
||||
|
||||
def case_cancel(self, cr, uid, ids, context=None):
|
||||
"""Overrides cancel for crm_case for setting probability
|
||||
"""
|
||||
res = super(crm_lead, self).case_cancel(cr, uid, ids, context)
|
||||
self.write(cr, uid, ids, {'probability' : 0.0})
|
||||
""" Overrides case_cancel from base_stage to set probability """
|
||||
res = super(crm_lead, self).case_cancel(cr, uid, ids, context=context)
|
||||
self.write(cr, uid, ids, {'probability' : 0.0}, context=context)
|
||||
return res
|
||||
|
||||
def case_reset(self, cr, uid, ids, context=None):
|
||||
"""Overrides reset as draft in order to set the stage field as empty
|
||||
"""
|
||||
res = super(crm_lead, self).case_reset(cr, uid, ids, context)
|
||||
self.write(cr, uid, ids, {'stage_id': False, 'probability': 0.0})
|
||||
""" Overrides case_reset from base_stage to set probability """
|
||||
res = super(crm_lead, self).case_reset(cr, uid, ids, context=context)
|
||||
self.write(cr, uid, ids, {'probability': 0.0}, context=context)
|
||||
return res
|
||||
|
||||
def case_mark_lost(self, cr, uid, ids, context=None):
|
||||
"""Mark the case as lost: state = done and probability = 0%
|
||||
"""
|
||||
res = super(crm_lead, self).case_close(cr, uid, ids, context)
|
||||
self.write(cr, uid, ids, {'probability' : 0.0})
|
||||
""" Mark the case as lost: state=cancel and probability=0 """
|
||||
for lead in self.browse(cr, uid, ids):
|
||||
stage_id = self.stage_find_lost(cr, uid, lead.section_id.id or False)
|
||||
stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 0.0)], context=context)
|
||||
if stage_id:
|
||||
self.stage_set(cr, uid, [lead.id], stage_id)
|
||||
return res
|
||||
self.case_set(cr, uid, [lead.id], values_to_update={'probability': 0.0}, new_stage_id=stage_id, context=context)
|
||||
self.case_mark_lost_send_note(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
def case_mark_won(self, cr, uid, ids, context=None):
|
||||
"""Mark the case as lost: state = done and probability = 0%
|
||||
"""
|
||||
res = super(crm_lead, self).case_close(cr, uid, ids, context=None)
|
||||
self.write(cr, uid, ids, {'probability' : 100.0})
|
||||
""" Mark the case as lost: state=done and probability=100 """
|
||||
for lead in self.browse(cr, uid, ids):
|
||||
stage_id = self.stage_find_won(cr, uid, lead.section_id.id or False)
|
||||
stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 100.0)], context=context)
|
||||
if stage_id:
|
||||
self.stage_set(cr, uid, [lead.id], stage_id)
|
||||
self.case_mark_won_send_note(cr, uid, [lead.id], context=context)
|
||||
return res
|
||||
self.case_set(cr, uid, [lead.id], values_to_update={'probability': 100.0}, new_stage_id=stage_id, context=context)
|
||||
self.case_mark_won_send_note(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
def set_priority(self, cr, uid, ids, priority):
|
||||
"""Set lead priority
|
||||
""" Set lead priority
|
||||
"""
|
||||
return self.write(cr, uid, ids, {'priority' : priority})
|
||||
|
||||
def set_high_priority(self, cr, uid, ids, context=None):
|
||||
"""Set lead priority to high
|
||||
""" Set lead priority to high
|
||||
"""
|
||||
return self.set_priority(cr, uid, ids, '1')
|
||||
|
||||
def set_normal_priority(self, cr, uid, ids, context=None):
|
||||
"""Set lead priority to normal
|
||||
""" Set lead priority to normal
|
||||
"""
|
||||
return self.set_priority(cr, uid, ids, '3')
|
||||
|
||||
|
||||
def _merge_data(self, cr, uid, ids, oldest, fields, context=None):
|
||||
# prepare opportunity data into dictionary for merging
|
||||
opportunities = self.browse(cr, uid, ids, context=context)
|
||||
|
@ -807,22 +862,12 @@ class crm_lead(crm_case, osv.osv):
|
|||
"You should better cancel it, instead of deleting it.") % lead.name)
|
||||
return super(crm_lead, self).unlink(cr, uid, ids, context)
|
||||
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
if 'date_closed' in vals:
|
||||
return super(crm_lead,self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
if vals.get('stage_id'):
|
||||
stage = self.pool.get('crm.case.stage').browse(cr, uid, vals['stage_id'], context=context)
|
||||
if vals.get('stage_id') and not vals.get('probability'):
|
||||
# change probability of lead(s) if required by stage
|
||||
if not vals.get('probability') and stage.on_change:
|
||||
stage = self.pool.get('crm.case.stage').browse(cr, uid, vals['stage_id'], context=context)
|
||||
if stage.on_change:
|
||||
vals['probability'] = stage.probability
|
||||
for case in self.browse(cr, uid, ids, context=context):
|
||||
message = _("Stage changed to <b>%s</b>.") % (stage.name)
|
||||
case.message_append_note(body=message)
|
||||
return super(crm_lead,self).write(cr, uid, ids, vals, context)
|
||||
|
||||
# ----------------------------------------
|
||||
|
@ -837,6 +882,11 @@ class crm_lead(crm_case, osv.osv):
|
|||
sub_ids.append(obj.user_id.id)
|
||||
return self.pool.get('res.users').read(cr, uid, sub_ids, context=context)
|
||||
|
||||
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
|
||||
""" Override of the (void) default notification method. """
|
||||
stage_name = self.pool.get('crm.case.stage').name_get(cr, uid, [stage_id], context=context)[0][1]
|
||||
return self.message_append_note(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
|
||||
|
||||
def case_get_note_msg_prefix(self, cr, uid, lead, context=None):
|
||||
if isinstance(lead, (int, long)):
|
||||
lead = self.browse(cr, uid, [lead], context=context)[0]
|
||||
|
|
|
@ -3,47 +3,81 @@
|
|||
<data noupdate="1">
|
||||
|
||||
<!-- Crm stages -->
|
||||
<record model="crm.case.stage" id="stage_lead6">
|
||||
<field name="name">Lost</field>
|
||||
<field eval="1" name="case_default"/>
|
||||
<field eval="'0'" name="probability"/>
|
||||
<field eval="'0'" name="sequence"/>
|
||||
</record>
|
||||
<record model="crm.case.stage" id="stage_lead1">
|
||||
<field name="name">New</field>
|
||||
<field eval="1" name="case_default"/>
|
||||
<field name="state">draft</field>
|
||||
<field eval="'10'" name="probability"/>
|
||||
<field eval="'11'" name="sequence"/>
|
||||
<field eval="'10'" name="sequence"/>
|
||||
<field name="type">both</field>
|
||||
</record>
|
||||
<record model="crm.case.stage" id="stage_lead2">
|
||||
<field name="name">Qualification</field>
|
||||
<field name="name">Opportunity</field>
|
||||
<field eval="1" name="case_default"/>
|
||||
<field name="state">open</field>
|
||||
<field eval="'20'" name="probability"/>
|
||||
<field eval="'12'" name="sequence"/>
|
||||
<field eval="'11'" name="sequence"/>
|
||||
<field name="type">lead</field>
|
||||
</record>
|
||||
<record model="crm.case.stage" id="stage_lead3">
|
||||
<field name="name">Proposition</field>
|
||||
<field name="name">Qualification</field>
|
||||
<field eval="1" name="case_default"/>
|
||||
<field eval="'40'" name="probability"/>
|
||||
<field eval="'13'" name="sequence"/>
|
||||
<field name="state">open</field>
|
||||
<field eval="'20'" name="probability"/>
|
||||
<field eval="'12'" name="sequence"/>
|
||||
<field name="type">opportunity</field>
|
||||
</record>
|
||||
<record model="crm.case.stage" id="stage_lead4">
|
||||
<field name="name">Negotiation</field>
|
||||
<field name="name">Proposition</field>
|
||||
<field eval="1" name="case_default"/>
|
||||
<field eval="'60'" name="probability"/>
|
||||
<field eval="'14'" name="sequence"/>
|
||||
<field name="state">open</field>
|
||||
<field eval="'40'" name="probability"/>
|
||||
<field eval="'13'" name="sequence"/>
|
||||
<field name="type">opportunity</field>
|
||||
</record>
|
||||
<record model="crm.case.stage" id="stage_lead5">
|
||||
<field name="name">Negotiation</field>
|
||||
<field eval="1" name="case_default"/>
|
||||
<field name="state">open</field>
|
||||
<field eval="'60'" name="probability"/>
|
||||
<field eval="'14'" name="sequence"/>
|
||||
<field name="type">opportunity</field>
|
||||
</record>
|
||||
<record model="crm.case.stage" id="stage_lead6">
|
||||
<field name="name">Won</field>
|
||||
<field eval="1" name="case_default"/>
|
||||
<field name="state">done</field>
|
||||
<field eval="'100'" name="probability"/>
|
||||
<field eval="'15'" name="sequence"/>
|
||||
<field eval="1" name="on_change"/>
|
||||
<field name="type">opportunity</field>
|
||||
</record>
|
||||
<record model="crm.case.stage" id="stage_lead7">
|
||||
<field name="name">Dead</field>
|
||||
<field eval="1" name="case_default"/>
|
||||
<field eval="True" name="fold"/>
|
||||
<field name="state">cancel</field>
|
||||
<field eval="'0'" name="probability"/>
|
||||
<field eval="'16'" name="sequence"/>
|
||||
<field name="type">lead</field>
|
||||
</record>
|
||||
<record model="crm.case.stage" id="stage_lead8">
|
||||
<field name="name">Lost</field>
|
||||
<field eval="1" name="case_default"/>
|
||||
<field eval="True" name="fold"/>
|
||||
<field name="state">cancel</field>
|
||||
<field eval="'0'" name="probability"/>
|
||||
<field eval="'17'" name="sequence"/>
|
||||
<field name="type">opportunity</field>
|
||||
</record>
|
||||
|
||||
<record model="crm.case.section" id="section_sales_department">
|
||||
<field name="name">Sales Department</field>
|
||||
<field name="code">Sales</field>
|
||||
<field name="stage_ids" eval="[(4, ref('stage_lead1')), (4, ref('stage_lead2')), (4, ref('stage_lead3')), (4, ref('stage_lead4')), (4, ref('stage_lead5')), (4, ref('stage_lead6'))]"/>
|
||||
<field name="stage_ids" eval="[ (4, ref('stage_lead1')), (4, ref('stage_lead2')),
|
||||
(4, ref('stage_lead3')), (4, ref('stage_lead4')),
|
||||
(4, ref('stage_lead5')), (4, ref('stage_lead6')),
|
||||
(4, ref('stage_lead7')), (4, ref('stage_lead8'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- Crm campain -->
|
||||
|
|
|
@ -8,14 +8,13 @@
|
|||
<field name="type">lead</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'The Oil Company'" name="partner_name"/>
|
||||
<field eval="'draft'" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_marketing_department"/>
|
||||
<field eval="'Luc Latour'" name="contact_name"/>
|
||||
<field name="title" ref="base.res_partner_title_sir"/>
|
||||
<field eval="'Training Manager'" name="function"/>
|
||||
<field eval="'Paris'" name="city"/>
|
||||
<field name="country_id" ref="base.fr"/>
|
||||
<field eval="'luc.latour@oilcompany.fr'" name="email_from"/>
|
||||
<field eval="'Training Manager'" name="function"/>
|
||||
<field eval="'Paris'" name="city"/>
|
||||
<field name="country_id" ref="base.fr"/>
|
||||
<field eval="'luc.latour@oilcompany.fr'" name="email_from"/>
|
||||
<field eval="'0033 621 782-0636'" name="mobile"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
|
@ -29,18 +28,17 @@
|
|||
<field name="type">lead</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'Le Club SARL'" name="partner_name"/>
|
||||
<field eval="'Marc Dufour'" name="contact_name"/>
|
||||
<field eval="'Marc Dufour'" name="contact_name"/>
|
||||
<field name="title" ref="base.res_partner_title_sir"/>
|
||||
<field eval="'Purchase Manager'" name="function"/>
|
||||
<field eval="'Bordeaux'" name="city"/>
|
||||
<field name="country_id" ref="base.fr"/>
|
||||
<field eval="'md@leclub.fr'" name="email_from"/>
|
||||
<field eval="'draft'" name="state"/>
|
||||
<field eval="'Purchase Manager'" name="function"/>
|
||||
<field eval="'Bordeaux'" name="city"/>
|
||||
<field name="country_id" ref="base.fr"/>
|
||||
<field eval="'md@leclub.fr'" name="email_from"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="'(392) 895-7917'" name="mobile"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
<field eval="'Interest in Your New Product'" name="name"/>
|
||||
<field eval="'(956) 293-2595'" name="phone"/>
|
||||
</record>
|
||||
|
@ -50,15 +48,14 @@
|
|||
<field name="type">lead</field>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval="'The Kompany'" name="partner_name"/>
|
||||
<field eval="'John Miller'" name="contact_name"/>
|
||||
<field eval="'New-York'" name="city"/>
|
||||
<field name="country_id" ref="base.us"/>
|
||||
<field eval="'draft'" name="state"/>
|
||||
<field eval="'John Miller'" name="contact_name"/>
|
||||
<field eval="'New-York'" name="city"/>
|
||||
<field name="country_id" ref="base.us"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="'(820) 167-3208'" name="mobile"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor4"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
<field eval="'Need Info about Web Design'" name="name"/>
|
||||
<field eval="'(079) 681-2139'" name="phone"/>
|
||||
<field eval="'contact@thkompany.com'" name="email_from"/>
|
||||
|
@ -68,10 +65,9 @@
|
|||
<field eval="'3'" name="priority"/>
|
||||
<field name="type">lead</field>
|
||||
<field eval="'The Gas Company'" name="partner_name"/>
|
||||
<field eval="'Henry Mc Coy'" name="contact_name"/>
|
||||
<field eval="'London'" name="city"/>
|
||||
<field name="country_id" ref="base.uk"/>
|
||||
<field eval="'draft'" name="state"/>
|
||||
<field eval="'Henry Mc Coy'" name="contact_name"/>
|
||||
<field eval="'London'" name="city"/>
|
||||
<field name="country_id" ref="base.uk"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="'(077) 582-4035'" name="mobile"/>
|
||||
<field eval="1" name="active"/>
|
||||
|
@ -87,16 +83,15 @@
|
|||
<field name="type">lead</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'Stonage IT'" name="partner_name"/>
|
||||
<field eval="'Carrie Helle'" name="contact_name"/>
|
||||
<field eval="'Purchase Manager'" name="function"/>
|
||||
<field eval="'Bruxelles'" name="city"/>
|
||||
<field name="country_id" ref="base.be"/>
|
||||
<field eval="'draft'" name="state"/>
|
||||
<field eval="'Carrie Helle'" name="contact_name"/>
|
||||
<field eval="'Purchase Manager'" name="function"/>
|
||||
<field eval="'Bruxelles'" name="city"/>
|
||||
<field name="country_id" ref="base.be"/>
|
||||
<field name="section_id" ref="crm.section_sales_marketing_department"/>
|
||||
<field eval="'(333) 715-1450'" name="mobile"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor1"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
<field eval="'Need a Quotation for PC1'" name="name"/>
|
||||
<field eval="'(855) 924-4364'" name="phone"/>
|
||||
<field eval="'helle@stonageit.be'" name="email_from"/>
|
||||
|
@ -110,15 +105,14 @@
|
|||
<field name="type">lead</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'Opensides'" name="partner_name"/>
|
||||
<field eval="'Tina Pinero'" name="contact_name"/>
|
||||
<field eval="'Consultant'" name="function"/>
|
||||
<field eval="'Roma'" name="city"/>
|
||||
<field name="country_id" ref="base.it"/>
|
||||
<field eval="'draft'" name="state"/>
|
||||
<field eval="'Tina Pinero'" name="contact_name"/>
|
||||
<field eval="'Consultant'" name="function"/>
|
||||
<field eval="'Roma'" name="city"/>
|
||||
<field name="country_id" ref="base.it"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="'(468) 017-2684'" name="mobile"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor8"/>
|
||||
<field name="stage_id" ref="crm.stage_lead6"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
<field eval="'Need Info about your Services'" name="name"/>
|
||||
<field eval="'(373) 907-1009'" name="phone"/>
|
||||
<field eval="'info@opensides.be'" name="email_from"/>
|
||||
|
@ -130,15 +124,14 @@
|
|||
<field name="type">lead</field>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval="'Gardner Group'" name="partner_name"/>
|
||||
<field eval="'Wendi Baltz'" name="contact_name"/>
|
||||
<field eval="'Journalist'" name="function"/>
|
||||
<field eval="'Kiev'" name="city"/>
|
||||
<field name="country_id" ref="base.ua"/>
|
||||
<field eval="'draft'" name="state"/>
|
||||
<field eval="'Wendi Baltz'" name="contact_name"/>
|
||||
<field eval="'Journalist'" name="function"/>
|
||||
<field eval="'Kiev'" name="city"/>
|
||||
<field name="country_id" ref="base.ua"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="'(463) 014-1208'" name="mobile"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor4"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
<field eval="'Info about Your Company ?'" name="name"/>
|
||||
<field eval="'(282) 603-7489'" name="phone"/>
|
||||
</record>
|
||||
|
@ -149,17 +142,16 @@
|
|||
<field name="type">lead</field>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval="'Survey'" name="name"/>
|
||||
<field eval="'open'" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor6"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
<field eval="'Survey Expert'" name="partner_name"/>
|
||||
<field eval="'John Smith'" name="contact_name"/>
|
||||
<field eval="'Sales'" name="function"/>
|
||||
<field eval="'Cambridge'" name="city"/>
|
||||
<field name="country_id" ref="base.uk"/>
|
||||
<field eval="'John Smith'" name="contact_name"/>
|
||||
<field eval="'Sales'" name="function"/>
|
||||
<field eval="'Cambridge'" name="city"/>
|
||||
<field name="country_id" ref="base.uk"/>
|
||||
<field eval="'smith_john@gmail.com'" name="email_from"/>
|
||||
<field eval="'(282) 596-8584'" name="phone"/>
|
||||
<field eval="'(282) 596-8584'" name="phone"/>
|
||||
</record>
|
||||
<record id="crm_case_business_card0" model="crm.lead">
|
||||
<field eval="1" name="active"/>
|
||||
|
@ -168,17 +160,16 @@
|
|||
<field name="type">lead</field>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'Partnership'" name="name"/>
|
||||
<field eval="'open'" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor5"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
<field eval="'Marketing Business'" name="partner_name"/>
|
||||
<field eval="'Laure Smith'" name="contact_name"/>
|
||||
<field eval="'Sales'" name="function"/>
|
||||
<field eval="'Oxford'" name="city"/>
|
||||
<field name="country_id" ref="base.uk"/>
|
||||
<field eval="'Laure Smith'" name="contact_name"/>
|
||||
<field eval="'Sales'" name="function"/>
|
||||
<field eval="'Oxford'" name="city"/>
|
||||
<field name="country_id" ref="base.uk"/>
|
||||
<field eval="'l.smith@marketing-business.com'" name="email_from"/>
|
||||
<field eval="'(252) 578-7894'" name="phone"/>
|
||||
<field eval="'(252) 578-7894'" name="phone"/>
|
||||
</record>
|
||||
<record id="crm_case_imported_contact0" model="crm.lead">
|
||||
<field eval="1" name="active"/>
|
||||
|
@ -186,9 +177,8 @@
|
|||
<field eval="'2'" name="priority"/>
|
||||
<field name="type">lead</field>
|
||||
<field eval="'Info'" name="name"/>
|
||||
<field eval="'cancel'" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
<field eval="'Business Group'" name="partner_name"/>
|
||||
</record>
|
||||
<record id="crm_case_employee0" model="crm.lead">
|
||||
|
@ -198,12 +188,11 @@
|
|||
<field name="type">lead</field>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval="'Need Info about Onsite Intervention'" name="name"/>
|
||||
<field eval="'draft'" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor3"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
<field eval="'Agrolait'" name="partner_name"/>
|
||||
<field eval="'Sylvie Lelitre'" name="contact_name"/>
|
||||
<field eval="'Sylvie Lelitre'" name="contact_name"/>
|
||||
</record>
|
||||
<record id="crm_case_company_partnership0" model="crm.lead">
|
||||
<field eval="1" name="active"/>
|
||||
|
@ -212,28 +201,15 @@
|
|||
<field name="type">lead</field>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval="'Need Quotation for 100 PC and 100 Keyboards'" name="name"/>
|
||||
<field eval="'done'" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor1"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
<field eval="'Centrale d\'achats 1'" name="partner_name"/>
|
||||
</record>
|
||||
|
||||
<!-- Call Function to Open the leads-->
|
||||
<function model="crm.lead" name="case_open"
|
||||
eval="[ref('crm_case_electonicgoodsdealer0'), ref('crm_case_company_partnership0'), ref('crm_case_webvisitor0'), ref('crm_case_business_card0'), ref('crm.crm_case_employee0')], {'install_mode': True}"
|
||||
/>
|
||||
<!-- Call Function to mark the lead as Pending-->
|
||||
<function model="crm.lead" name="case_pending"
|
||||
eval="[ref('crm_case_itdeveloper0')], {'install_mode': True}"
|
||||
/>
|
||||
<!-- Call Function to Close the leads-->
|
||||
<function model="crm.lead" name="case_close"
|
||||
eval="[ref('crm_case_vpoperations0'), ref('crm_case_developingwebapplications0'), ref('crm_case_webvisitor0')], {'install_mode': True}"
|
||||
/>
|
||||
<!-- Call Function to Cancel the leads-->
|
||||
<!-- Call Function to Cancel the leads (set as Dead) -->
|
||||
<function model="crm.lead" name="case_cancel"
|
||||
eval="[ref('crm_case_mgroperations0'), ref('crm_case_imported_contact0')], {'install_mode': True}"
|
||||
eval="[ref('crm_case_company_partnership0'), ref('crm_case_vpoperations0'), ref('crm_case_developingwebapplications0'), ref('crm_case_webvisitor0')], {'install_mode': True}"
|
||||
/>
|
||||
|
||||
<!-- Demo Opportunities -->
|
||||
|
@ -245,11 +221,10 @@
|
|||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field eval="'3'" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'open'" name="state"/>
|
||||
<field eval="'150000'" name="planned_revenue"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor1"/>
|
||||
<field name="stage_id" ref="crm.stage_lead3"/>
|
||||
<field name="stage_id" ref="crm.stage_lead4"/>
|
||||
<field eval="'Plan to buy 200 PC2'" name="name"/>
|
||||
<field eval="'Conf call with purchase manager'" name="title_action"/>
|
||||
</record>
|
||||
|
@ -260,12 +235,11 @@
|
|||
<field name="partner_id" ref="base.res_partner_9"/>
|
||||
<field eval="'3'" name="priority"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval="'draft'" name="state"/>
|
||||
<field eval="45000.0" name="planned_revenue"/>
|
||||
<field eval="35" name="probability"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor3"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead3"/>
|
||||
<field eval="'Pricing Information of Onsite Intervention'" name="name"/>
|
||||
<field eval="'Send price list regarding our interventions'" name="title_action"/>
|
||||
<field eval="time.strftime('%Y-%m-03')" name="date_action"/>
|
||||
|
@ -283,12 +257,11 @@
|
|||
<field name="partner_id" ref="base.res_partner_lucievonck0"/>
|
||||
<field eval="'3'" name="priority"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval="'draft'" name="state"/>
|
||||
<field eval="30000.0" name="planned_revenue"/>
|
||||
<field eval="30" name="probability"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor3"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead3"/>
|
||||
<field eval="'Interest in your Kitchen Design Project'" name="name"/>
|
||||
<field eval="'Send Catalogue by E-Mail'" name="title_action"/>
|
||||
<field eval="time.strftime('%Y-01-10')" name="date_action"/>
|
||||
|
@ -299,19 +272,18 @@
|
|||
<field eval="1367" name="zip"/>
|
||||
<field name="country_id" ref="base.be"/>
|
||||
</record>
|
||||
<record id="crm_case_unifliege" model="crm.lead">
|
||||
<record id="crm_case_unifliege" model="crm.lead">
|
||||
<field eval="1" name="active"/>
|
||||
<field name="type">opportunity</field>
|
||||
<field name="type_id" ref="crm.type_lead2"/>
|
||||
<field name="partner_id" ref="base.res_partner_accent"/>
|
||||
<field eval="'3'" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'open'" name="state"/>
|
||||
<field eval="2500.0" name="planned_revenue"/>
|
||||
<field eval="25" name="probability"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor6"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead3"/>
|
||||
<field eval="'Plan train our students on your product'" name="name"/>
|
||||
<field eval="'Call to define real needs about training'" name="title_action"/>
|
||||
<field eval="time.strftime('%Y-%m-04')" name="date_action"/>
|
||||
|
@ -323,19 +295,18 @@
|
|||
<field eval="75016" name="zip"/>
|
||||
<field name="country_id" ref="base.be"/>
|
||||
</record>
|
||||
<record id="crm_case_bankwealthy2" model="crm.lead">
|
||||
<record id="crm_case_bankwealthy2" model="crm.lead">
|
||||
<field eval="1" name="active"/>
|
||||
<field name="type">opportunity</field>
|
||||
<field name="type_id" ref="crm.type_lead2"/>
|
||||
<field name="partner_id" ref="base.res_partner_2"/>
|
||||
<field eval="'3'" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'open'" name="state"/>
|
||||
<field eval="462.0" name="planned_revenue"/>
|
||||
<field eval="40" name="probability"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead3"/>
|
||||
<field eval="'Plan to buy 66 keyboards and 66 mouses'" name="name"/>
|
||||
<field eval="'Propose the kit keyboard+mouse'" name="title_action"/>
|
||||
<field eval="time.strftime('%Y-04-12')" name="date_action"/>
|
||||
|
@ -354,12 +325,11 @@
|
|||
<field name="partner_id" ref="base.res_partner_8"/>
|
||||
<field eval="'3'" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'done'" name="state"/>
|
||||
<field eval="55000.0" name="planned_revenue"/>
|
||||
<field eval="90" name="probability"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor7"/>
|
||||
<field name="stage_id" ref="crm.stage_lead5"/>
|
||||
<field name="stage_id" ref="crm.stage_lead6"/>
|
||||
<field eval="'Need 20 Days of Consultancy'" name="name"/>
|
||||
<field eval="time.strftime('%Y-%m-%d')" name="date_deadline"/>
|
||||
<field eval="'info@mycompany.net'" name="email_from"/>
|
||||
|
@ -372,11 +342,10 @@
|
|||
<field name="partner_id" ref="base.res_partner_duboissprl0"/>
|
||||
<field eval="'3'" name="priority"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval="'open'" name="state"/>
|
||||
<field eval="45000.0" name="planned_revenue"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor5"/>
|
||||
<field name="stage_id" ref="crm.stage_lead4"/>
|
||||
<field name="stage_id" ref="crm.stage_lead5"/>
|
||||
<field eval="'Need new design for my website'" name="name"/>
|
||||
<field eval="time.strftime('%Y-05-01')" name="date_action"/>
|
||||
<field eval="time.strftime('%Y-06-30')" name="date_deadline"/>
|
||||
|
@ -395,40 +364,37 @@
|
|||
<field name="partner_id" ref="base.res_partner_maxtor"/>
|
||||
<field eval="'3'" name="priority"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval="'done'" name="state"/>
|
||||
<field eval="42000.0" name="planned_revenue"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead6"/>
|
||||
<field name="stage_id" ref="crm.stage_lead8"/>
|
||||
<field eval="'Want to subscribe to your online solution'" name="name"/>
|
||||
</record>
|
||||
<record id="crm_case_dirtminingltdunits0" model="crm.lead">
|
||||
<record id="crm_case_dirtminingltdunits0" model="crm.lead">
|
||||
<field eval="30" name="probability"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="type">opportunity</field>
|
||||
<field name="partner_id" ref="base.res_partner_tinyatwork"/>
|
||||
<field eval="'3'" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'done'" name="state"/>
|
||||
<field eval="25000.0" name="planned_revenue"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor6"/>
|
||||
<field name="stage_id" ref="crm.stage_lead6"/>
|
||||
<field name="stage_id" ref="crm.stage_lead8"/>
|
||||
<field eval="'Interest in your Partnership Contract'" name="name"/>
|
||||
</record>
|
||||
<record id="crm_case_dirtminingltdunits10" model="crm.lead">
|
||||
<record id="crm_case_dirtminingltdunits10" model="crm.lead">
|
||||
<field eval="30" name="probability"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="type">opportunity</field>
|
||||
<field name="partner_id" ref="base.res_partner_desertic_hispafuentes"/>
|
||||
<field eval="'3'" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'open'" name="state"/>
|
||||
<field eval="5000" name="planned_revenue"/>
|
||||
<field eval="30" name="probability"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
<field name="stage_id" ref="crm.stage_lead3"/>
|
||||
<field eval="'Plan to attend a training'" name="name"/>
|
||||
<field eval="time.strftime('%Y-04-10')" name="date_action"/>
|
||||
<field eval="time.strftime('%Y-06-12')" name="date_deadline"/>
|
||||
|
@ -439,7 +405,7 @@
|
|||
<field eval="77420" name="zip"/>
|
||||
<field name="country_id" ref="base.fr"/>
|
||||
</record>
|
||||
<record id="crm_case_construstazunits0" model="crm.lead">
|
||||
<record id="crm_case_construstazunits0" model="crm.lead">
|
||||
<field eval="60" name="probability"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="type">opportunity</field>
|
||||
|
@ -447,11 +413,10 @@
|
|||
<field name="partner_id" ref="base.res_partner_thymbra"/>
|
||||
<field eval="'3'" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'open'" name="state"/>
|
||||
<field eval="'150000'" name="planned_revenue"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor1"/>
|
||||
<field name="stage_id" ref="crm.stage_lead3"/>
|
||||
<field name="stage_id" ref="crm.stage_lead4"/>
|
||||
<field eval="'Need customize the solution'" name="name"/>
|
||||
<field eval="'Conf call with technical service'" name="title_action"/>
|
||||
<field name="partner_name">Thymbra</field>
|
||||
|
@ -461,7 +426,7 @@
|
|||
<field eval="1659" name="zip"/>
|
||||
<field name="country_id" ref="base.ar"/>
|
||||
</record>
|
||||
<record id="crm_case_ericdubois4" model="crm.lead">
|
||||
<record id="crm_case_ericdubois4" model="crm.lead">
|
||||
<field eval="65" name="probability"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="type">opportunity</field>
|
||||
|
@ -469,11 +434,10 @@
|
|||
<field name="partner_id" ref="base.res_partner_ericdubois0"/>
|
||||
<field eval="'3'" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'open'" name="state"/>
|
||||
<field eval="'1200'" name="planned_revenue"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor1"/>
|
||||
<field name="stage_id" ref="crm.stage_lead3"/>
|
||||
<field name="stage_id" ref="crm.stage_lead4"/>
|
||||
<field eval="'Interest in your customizable PC'" name="name"/>
|
||||
<field eval="time.strftime('%Y-08-05')" name="date_action"/>
|
||||
<field eval="time.strftime('%Y-10-10')" name="date_deadline"/>
|
||||
|
@ -484,26 +448,24 @@
|
|||
<field eval="7000" name="zip"/>
|
||||
<field name="country_id" ref="base.be"/>
|
||||
</record>
|
||||
<record id="crm_case_fabiendupont" model="crm.lead">
|
||||
<record id="crm_case_fabiendupont" model="crm.lead">
|
||||
<field eval="1" name="active"/>
|
||||
<field name="type">opportunity</field>
|
||||
<field name="type_id" ref="crm.type_lead1"/>
|
||||
<field name="partner_id" ref="base.res_partner_fabiendupont0"/>
|
||||
<field eval="'3'" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'draft'" name="state"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor4"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
<field eval="'Need more info about the onsite intervention'" name="name"/>
|
||||
</record>
|
||||
<record id="crm_case_shelvehouse" model="crm.lead">
|
||||
<record id="crm_case_shelvehouse" model="crm.lead">
|
||||
<field eval="1" name="active"/>
|
||||
<field name="type">opportunity</field>
|
||||
<field name="type_id" ref="crm.type_lead1"/>
|
||||
<field name="partner_id" ref="base.res_partner_theshelvehouse0"/>
|
||||
<field eval="'3'" name="priority"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval="'draft'" name="state"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor4"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
<field eval="'Need more info about your pc2'" name="name"/>
|
||||
|
|
|
@ -1,35 +1,41 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<data>
|
||||
|
||||
<!-- Stage Search view -->
|
||||
<record id="crm_lead_stage_search" model="ir.ui.view">
|
||||
<field name="name">Stage - Search</field>
|
||||
<field name="model">crm.case.stage</field>
|
||||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Stage Search">
|
||||
<field name="name"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
<!--
|
||||
CRM CASE STAGE
|
||||
-->
|
||||
|
||||
<!--Lead Stage Form view -->
|
||||
<record id="crm_lead_stage_act" model="ir.actions.act_window">
|
||||
<field name="name">Stages</field>
|
||||
<field name="res_model">crm.case.stage</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="crm.crm_case_stage_tree"/>
|
||||
<field name="help">Add specific stages to leads and opportunities allowing your sales to better organise their sales pipeline. Stages will allow them to easily track how a specific lead or opportunity is positioned in the sales cycle.</field>
|
||||
</record>
|
||||
<!-- Stage Search view -->
|
||||
<record id="crm_lead_stage_search" model="ir.ui.view">
|
||||
<field name="name">Stage - Search</field>
|
||||
<field name="model">crm.case.stage</field>
|
||||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Stage Search">
|
||||
<field name="name"/>
|
||||
<field name="state"/>
|
||||
<field name="type"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="crm_lead_stage_act" id="menu_crm_lead_stage_act" name="Stages"
|
||||
groups="base.group_no_one" sequence="0"
|
||||
parent="base.menu_crm_config_lead" />
|
||||
<!-- Stage Form view -->
|
||||
<record id="crm_lead_stage_act" model="ir.actions.act_window">
|
||||
<field name="name">Stages</field>
|
||||
<field name="res_model">crm.case.stage</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="crm.crm_case_stage_tree"/>
|
||||
<field name="help">Add specific stages to leads and opportunities allowing your sales to better organise their sales pipeline. Stages will allow them to easily track how a specific lead or opportunity is positioned in the sales cycle.</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="crm_lead_stage_act" id="menu_crm_lead_stage_act" name="Stages" sequence="0" parent="base.menu_crm_config_lead" />
|
||||
|
||||
<!-- Lead/Opportunity Categories Action -->
|
||||
<!--
|
||||
LEADS/OPPORTUNITIES CATEGORIES
|
||||
-->
|
||||
|
||||
<!-- Categories Form View -->
|
||||
<record id="crm_lead_categ_action" model="ir.actions.act_window">
|
||||
<field name="name">Categories</field>
|
||||
<field name="res_model">crm.case.categ</field>
|
||||
|
@ -44,6 +50,9 @@
|
|||
id="menu_crm_lead_categ" name="Categories"
|
||||
parent="base.menu_crm_config_lead" sequence="1" groups="base.group_no_one"/>
|
||||
|
||||
<!--
|
||||
LEADS
|
||||
-->
|
||||
|
||||
<!-- CRM Lead Form View -->
|
||||
<record model="ir.ui.view" id="crm_case_form_view_leads">
|
||||
|
@ -53,14 +62,17 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Leads Form" layout="manual">
|
||||
<div class="oe_form_topbar">
|
||||
<button name="case_open" string="Open" states="draft,pending" type="object" />
|
||||
<button name="case_mark_lost" string="Close" states="open,pending" type="object" />
|
||||
<button name="case_pending" string="Pending" states="open" type="object" />
|
||||
<button name="case_escalate" string="Escalate" states="open,pending" type="object" />
|
||||
<button name="case_reset" string="Reset to Draft" states="done,cancel" type="object" />
|
||||
<button name="case_cancel" string="Cancel" states="draft,open,pending" type="object" />
|
||||
<button name="%(crm.action_crm_lead2opportunity_partner)d" string="Convert to Opportunity" type="action"
|
||||
states="draft,open,pending" help="Convert to Opportunity"/>
|
||||
<button name="case_escalate" string="Escalate" type="object"
|
||||
states="draft,open,pending"/>
|
||||
<button name="case_reset" string="Reset" type="object"
|
||||
states="cancel"/>
|
||||
<button name="case_cancel" string="Cancel" type="object"
|
||||
states="draft,open,pending"/>
|
||||
<div class="oe_right">
|
||||
<field name="state" nolabel="1" widget="statusbar" statusbar_visible="draft,open,done" statusbar_colors='{"pending":"blue"}'/>
|
||||
<field name="stage_id" nolabel="1" widget="statusbar"
|
||||
on_change="onchange_stage_id(stage_id)"/>
|
||||
</div>
|
||||
<div class="oe_clear"/>
|
||||
</div>
|
||||
|
@ -71,24 +83,9 @@
|
|||
<field name="categ_id"
|
||||
widget="selection"
|
||||
domain="[('object_id.model','=','crm.lead')]"/>
|
||||
<button
|
||||
name="%(crm.action_crm_lead2opportunity_partner)d"
|
||||
string="Convert to Opportunity"
|
||||
help="Convert to Opportunity" icon="gtk-go-forward"
|
||||
type="action"
|
||||
/>
|
||||
<newline />
|
||||
<field name="user_id" />
|
||||
<field name="section_id" widget="selection" />
|
||||
<field name="stage_id" domain="section_id and [('section_ids', '=', section_id)] or []" />
|
||||
<group col="2" colspan="1">
|
||||
<button name="stage_previous" string=""
|
||||
states="open,pending,draft" type="object"
|
||||
icon="gtk-go-back" context="{'stage_type': 'lead'}" />
|
||||
<button name="stage_next" string=""
|
||||
states="open,pending,draft" type="object"
|
||||
icon="gtk-go-forward" context="{'stage_type': 'lead'}" />
|
||||
</group>
|
||||
<field name="type" invisible="1"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
|
@ -142,6 +139,7 @@
|
|||
<field name="type_id" select="1" widget="selection"/>
|
||||
<field name="channel_id" select="1" widget="selection"/>
|
||||
<field name="referred"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Mailings" colspan="2" col="2"/>
|
||||
|
@ -161,54 +159,49 @@
|
|||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</record>
|
||||
|
||||
<!-- CRM Lead Tree View -->
|
||||
<!-- CRM Lead Tree View -->
|
||||
<record model="ir.ui.view" id="crm_case_tree_view_leads">
|
||||
<field name="name">Leads</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Leads" fonts="bold:needaction_pending==True" colors="blue:state=='pending';grey:state in ('cancel', 'done')">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<field name="date_deadline" invisible="1"/>
|
||||
<field name="create_date" groups="base.group_no_one"/>
|
||||
<field name="name" string="Subject"/>
|
||||
<field name="contact_name"/>
|
||||
<field name="country_id" invisible="context.get('invisible_country', True)" />
|
||||
<field name="email_from"/>
|
||||
<field name="phone"/>
|
||||
<field name="stage_id"/>
|
||||
<field name="categ_id" invisible="1"/>
|
||||
<field name="section_id" invisible="context.get('invisible_section', True)" />
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
<field name="type_id" invisible="1"/>
|
||||
<field name="referred" invisible="1"/>
|
||||
<field name="channel_id" invisible="1"/>
|
||||
<field name="subjects" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="crm_case_tree_view_leads">
|
||||
<field name="name">Leads</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Leads" fonts="bold:needaction_pending==True" colors="blue:state=='pending';grey:state in ('cancel', 'done')">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<field name="date_deadline" invisible="1"/>
|
||||
<field name="create_date" groups="base.group_no_one"/>
|
||||
<field name="name" string="Subject"/>
|
||||
<field name="contact_name"/>
|
||||
<field name="country_id" invisible="context.get('invisible_country', True)" />
|
||||
<field name="email_from"/>
|
||||
<field name="phone"/>
|
||||
|
||||
<field name="categ_id" invisible="1"/>
|
||||
<field name="type_id" invisible="1"/>
|
||||
<field name="referred" invisible="1"/>
|
||||
<field name="channel_id" invisible="1"/>
|
||||
<field name="subjects" invisible="1"/>
|
||||
|
||||
<field name="stage_id"/>
|
||||
<field name="section_id" invisible="context.get('invisible_section', True)" />
|
||||
<field name="user_id" />
|
||||
<field name="state" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- CRM Lead Calendar View -->
|
||||
|
||||
<record model="ir.ui.view" id="crm_case_calendar_view_leads">
|
||||
<field name="name">CRM - Leads Calendar</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="type">calendar</field>
|
||||
<field name="priority" eval="2"/>
|
||||
<field name="arch" type="xml">
|
||||
<calendar string="Leads Generation"
|
||||
date_start="date_action" color="user_id">
|
||||
<field name="name" />
|
||||
<field name="partner_name" />
|
||||
</calendar>
|
||||
</field>
|
||||
</record>
|
||||
<!-- CRM Lead Calendar View -->
|
||||
<record model="ir.ui.view" id="crm_case_calendar_view_leads">
|
||||
<field name="name">CRM - Leads Calendar</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="type">calendar</field>
|
||||
<field name="priority" eval="2"/>
|
||||
<field name="arch" type="xml">
|
||||
<calendar string="Leads Generation"
|
||||
date_start="date_action" color="user_id">
|
||||
<field name="name" />
|
||||
<field name="partner_name" />
|
||||
</calendar>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- CRM Lead Kanban View -->
|
||||
<record model="ir.ui.view" id="crm_case_kanban_view_leads">
|
||||
|
@ -217,7 +210,7 @@
|
|||
<field name="type">kanban</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="stage_id">
|
||||
<field name="state"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
<field name="color"/>
|
||||
<field name="priority"/>
|
||||
<field name="planned_revenue" sum="Expected Revenues"/>
|
||||
|
@ -298,7 +291,6 @@
|
|||
</record>
|
||||
|
||||
<!-- CRM Lead Search View -->
|
||||
|
||||
<record id="view_crm_case_leads_filter" model="ir.ui.view">
|
||||
<field name="name">CRM - Leads Search</field>
|
||||
<field name="model">crm.lead</field>
|
||||
|
@ -373,6 +365,10 @@
|
|||
</record>
|
||||
|
||||
|
||||
<!--
|
||||
OPPORTUNITY
|
||||
-->
|
||||
|
||||
<!-- Opportunities Form View -->
|
||||
<record model="ir.ui.view" id="crm_case_form_view_oppor">
|
||||
<field name="name">Opportunities</field>
|
||||
|
@ -382,15 +378,23 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Opportunities" layout="manual">
|
||||
<div class="oe_form_topbar oe_form_topbar_hifirst">
|
||||
<button name="case_mark_won" string="Mark Won" states="open,pending" type="object" />
|
||||
<button name="case_open" string="Open" states="draft,pending" type="object" />
|
||||
<button name="case_pending" string="Pending" states="draft,open" type="object" />
|
||||
<button name="case_escalate" string="Escalate" states="open,pending" type="object" />
|
||||
<button name="case_mark_lost" string="Mark Lost" states="open,pending" type="object" />
|
||||
<button name="case_reset" string="Reset to Draft" states="done,cancel" type="object" />
|
||||
<button name="case_cancel" string="Cancel" states="draft" type="object" />
|
||||
<button name="case_open" string="Open" type="object"
|
||||
states="draft"/>
|
||||
<button name="case_mark_won" string="Mark Won" type="object"
|
||||
states="draft,open"/>
|
||||
<button name="case_mark_lost" string="Mark Lost" type="object"
|
||||
states="draft,open"/>
|
||||
<button name="case_reset" string="Reset to Draft" type="object"
|
||||
states="cancel"/>
|
||||
<button name="case_escalate" string="Escalate" type="object"
|
||||
states="open"/>
|
||||
<button name="stage_previous" string="Previous" type="object"
|
||||
states="open" icon="gtk-go-back" context="{'stage_type': 'opportunity'}"/>
|
||||
<button name="stage_next" string="Next" type="object"
|
||||
states="open" icon="gtk-go-forward" context="{'stage_type': 'opportunity'}"/>
|
||||
<div class="oe_right">
|
||||
<field name="state" nolabel="1" widget="statusbar" statusbar_visible="draft,open,done" statusbar_colors='{"pending":"blue"}'/>
|
||||
<field name="stage_id" nolabel="1" widget="statusbar"
|
||||
on_change="onchange_stage_id(stage_id)"/>
|
||||
</div>
|
||||
<div class="oe_clear"/>
|
||||
</div>
|
||||
|
@ -443,20 +447,8 @@
|
|||
<field name="categ_id" select="1"
|
||||
string="Category" widget="selection"
|
||||
domain="[('object_id.model', '=', 'crm.lead')]" />
|
||||
|
||||
<label string="Stage" for="stage_id" align="1.0"/>
|
||||
<group colspan="1" col="3">
|
||||
<field name="stage_id" nolabel="1"
|
||||
on_change="onchange_stage_id(stage_id)"
|
||||
domain="section_id and [('section_ids', '=', section_id)] or []" width="60%%"/>
|
||||
<button name="stage_previous"
|
||||
states="draft,open,pending" type="object"
|
||||
icon="gtk-go-back" string="" context="{'stage_type': 'opportunity'}"/>
|
||||
<button name="stage_next" states="draft,open,pending"
|
||||
type="object" icon="gtk-go-forward" string="" context="{'stage_type': 'opportunity'}"/>
|
||||
</group>
|
||||
|
||||
<field name="priority" string="Priority"/>
|
||||
<field name="state"/>
|
||||
<field name="priority"/>
|
||||
</group>
|
||||
|
||||
<separator colspan="4" string="Details"/>
|
||||
|
@ -516,35 +508,35 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Opportunities Tree View -->
|
||||
<record model="ir.ui.view" id="crm_case_tree_view_oppor">
|
||||
<field name="name">Opportunities Tree</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Opportunities" fonts="bold:needaction_pending==True" colors="blue:state=='pending' and not(date_deadline and (date_deadline < current_date));gray:state in ('cancel', 'done');red:date_deadline and (date_deadline < current_date)">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<field name="date_deadline" invisible="1"/>
|
||||
<field name="create_date" groups="base.group_no_one"/>
|
||||
<field name="name" string="Opportunity"/>
|
||||
<field name="partner_id" string="Customer"/>
|
||||
<field name="country_id" invisible="context.get('invisible_country', True)" />
|
||||
<field name="date_action"/>
|
||||
<field name="title_action" />
|
||||
<field name="channel_id" invisible="1"/>
|
||||
<field name="type_id" invisible="1"/>
|
||||
<field name="subjects" invisible="1"/>
|
||||
<field name="stage_id"/>
|
||||
<field name="planned_revenue" sum="Expected Revenues"/>
|
||||
<field name="probability" widget="progressbar" avg="Avg. of Probability"/>
|
||||
<field name="section_id" invisible="context.get('invisible_section', True)" />
|
||||
<field name="user_id"/>
|
||||
<field name="priority" invisible="1"/>
|
||||
<field name="categ_id" invisible="1"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<!-- Opportunities Tree View -->
|
||||
<record model="ir.ui.view" id="crm_case_tree_view_oppor">
|
||||
<field name="name">Opportunities Tree</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Opportunities" fonts="bold:needaction_pending==True" colors="blue:state=='pending' and not(date_deadline and (date_deadline < current_date));gray:state in ('cancel', 'done');red:date_deadline and (date_deadline < current_date)">
|
||||
<field name="needaction_pending" invisible="1"/>
|
||||
<field name="date_deadline" invisible="1"/>
|
||||
<field name="create_date" groups="base.group_no_one"/>
|
||||
<field name="name" string="Opportunity"/>
|
||||
<field name="partner_id" string="Customer"/>
|
||||
<field name="country_id" invisible="context.get('invisible_country', True)" />
|
||||
<field name="date_action"/>
|
||||
<field name="title_action" />
|
||||
<field name="channel_id" invisible="1"/>
|
||||
<field name="type_id" invisible="1"/>
|
||||
<field name="subjects" invisible="1"/>
|
||||
<field name="stage_id"/>
|
||||
<field name="planned_revenue" sum="Expected Revenues"/>
|
||||
<field name="probability" widget="progressbar" avg="Avg. of Probability"/>
|
||||
<field name="section_id" invisible="context.get('invisible_section', True)" />
|
||||
<field name="user_id"/>
|
||||
<field name="priority" invisible="1"/>
|
||||
<field name="categ_id" invisible="1"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Opportunities Search View -->
|
||||
|
@ -575,8 +567,7 @@
|
|||
help="Unassigned Opportunities" />
|
||||
</field>
|
||||
<field name="section_id"
|
||||
context="{'invisible_section': False}"
|
||||
widget="selection">
|
||||
context="{'invisible_section': False, 'default_section_id': self}">
|
||||
<filter icon="terp-personal+"
|
||||
domain="['|', ('section_id.user_id','=',uid), ('section_id.member_ids', 'in', [uid])]"
|
||||
context="{'invisible_section': False}"
|
||||
|
@ -606,19 +597,19 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<!-- crm.lead Opportunities Graph View -->
|
||||
<record model="ir.ui.view" id="crm_case_graph_view_opportunity">
|
||||
<field name="name">CRM - Opportunity Graph</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="type">graph</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Opportunity by Categories" type="bar" orientation="horizontal">
|
||||
<field name="categ_id"/>
|
||||
<field name="planned_revenue" operator="+"/>
|
||||
<field name="state" group="True"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
<!-- crm.lead Opportunities Graph View -->
|
||||
<record model="ir.ui.view" id="crm_case_graph_view_opportunity">
|
||||
<field name="name">CRM - Opportunity Graph</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="type">graph</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Opportunity by Categories" type="bar" orientation="horizontal">
|
||||
<field name="categ_id"/>
|
||||
<field name="planned_revenue" operator="+"/>
|
||||
<field name="state" group="True"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
|
@ -20,43 +20,35 @@
|
|||
##############################################################################
|
||||
|
||||
from base_calendar import base_calendar
|
||||
from crm import crm_base, crm_case
|
||||
from base_status.base_state import base_state
|
||||
from base_status.base_stage import base_stage
|
||||
import logging
|
||||
from osv import fields, osv
|
||||
import tools
|
||||
from tools.translate import _
|
||||
import logging
|
||||
|
||||
class crm_lead(crm_case, osv.osv):
|
||||
""" CRM Leads """
|
||||
_name = 'crm.lead'
|
||||
crm_lead()
|
||||
|
||||
class crm_phonecall(crm_case, osv.osv):
|
||||
""" CRM Phonecall """
|
||||
_name = 'crm.phonecall'
|
||||
crm_phonecall()
|
||||
|
||||
|
||||
class crm_meeting(crm_base, osv.osv):
|
||||
""" CRM Meeting Cases """
|
||||
class crm_lead(base_stage, osv.osv):
|
||||
""" CRM Leads """
|
||||
_name = 'crm.lead'
|
||||
|
||||
class crm_meeting(base_state, osv.Model):
|
||||
""" Model for CRM meetings """
|
||||
_name = 'crm.meeting'
|
||||
_description = "Meeting"
|
||||
_order = "id desc"
|
||||
_inherit = ["calendar.event", 'ir.needaction_mixin', "mail.thread"]
|
||||
_columns = {
|
||||
# From crm.case
|
||||
'name': fields.char('Summary', size=124, required=True, states={'done': [('readonly', True)]}),
|
||||
# base_state required fields
|
||||
'partner_id': fields.many2one('res.partner', 'Partner', states={'done': [('readonly', True)]}),
|
||||
'section_id': fields.many2one('crm.case.section', 'Sales Team', states={'done': [('readonly', True)]}, \
|
||||
select=True, help='Sales team to which Case belongs to.'),
|
||||
'email_from': fields.char('Email', size=128, states={'done': [('readonly', True)]}, help="These people will receive email."),
|
||||
'id': fields.integer('ID', readonly=True),
|
||||
'create_date': fields.datetime('Creation Date' , readonly=True),
|
||||
'write_date': fields.datetime('Write Date' , readonly=True),
|
||||
'date_action_last': fields.datetime('Last Action', readonly=1),
|
||||
'date_action_next': fields.datetime('Next Action', readonly=1),
|
||||
# Meeting fields
|
||||
'name': fields.char('Summary', size=124, required=True, states={'done': [('readonly', True)]}),
|
||||
'categ_id': fields.many2one('crm.case.categ', 'Meeting Type', \
|
||||
domain="[('object_id.model', '=', 'crm.meeting')]", \
|
||||
),
|
||||
|
@ -67,11 +59,11 @@ class crm_meeting(crm_base, osv.osv):
|
|||
'date_closed': fields.datetime('Closed', readonly=True),
|
||||
'date_deadline': fields.datetime('Deadline', states={'done': [('readonly', True)]}),
|
||||
'message_ids': fields.one2many('mail.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
|
||||
'state': fields.selection([('open', 'Confirmed'),
|
||||
('draft', 'Unconfirmed'),
|
||||
'state': fields.selection([ ('draft', 'Unconfirmed'),
|
||||
('open', 'Confirmed'),
|
||||
('cancel', 'Cancelled'),
|
||||
('done', 'Done')], 'Status', \
|
||||
size=16, readonly=True),
|
||||
('done', 'Done')],
|
||||
string='Status', size=16, readonly=True),
|
||||
}
|
||||
_defaults = {
|
||||
'state': 'draft',
|
||||
|
@ -91,6 +83,17 @@ class crm_meeting(crm_base, osv.osv):
|
|||
result[obj.id] = [obj.user_id.id]
|
||||
return result
|
||||
|
||||
def case_open(self, cr, uid, ids, context=None):
|
||||
""" Confirms meeting """
|
||||
res = super(crm_meeting, self).case_open(cr, uid, ids, context)
|
||||
for (id, name) in self.name_get(cr, uid, ids):
|
||||
id=base_calendar.base_calendar_id2real_id(id)
|
||||
return res
|
||||
|
||||
# ----------------------------------------
|
||||
# OpenChatter
|
||||
# ----------------------------------------
|
||||
|
||||
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
||||
return 'Meeting'
|
||||
|
||||
|
@ -119,32 +122,12 @@ class crm_meeting(crm_base, osv.osv):
|
|||
meeting.message_append_note(body=parent_message)
|
||||
return True
|
||||
|
||||
def case_close_send_note(self, cr, uid, ids, context=None):
|
||||
message = _("Meeting has been <b>done</b>.")
|
||||
return self.message_append_note(cr, uid, ids, body=message, context=context)
|
||||
|
||||
def case_open_send_note(self, cr, uid, ids, context=None):
|
||||
for meeting in self.browse(cr, uid, ids, context=context):
|
||||
if meeting.state != 'draft':
|
||||
return False
|
||||
message = _("Meeting has been <b>confirmed</b>.")
|
||||
meeting.message_append_note(body=message)
|
||||
return True
|
||||
return self.message_append_note(cr, uid, ids, body=_("Meeting has been <b>confirmed</b>."), context=context)
|
||||
|
||||
def case_open(self, cr, uid, ids, context=None):
|
||||
"""Confirms meeting
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Meeting Ids
|
||||
@param *args: Tuple Value for additional Params
|
||||
"""
|
||||
res = super(crm_meeting, self).case_open(cr, uid, ids, context)
|
||||
for (id, name) in self.name_get(cr, uid, ids):
|
||||
id=base_calendar.base_calendar_id2real_id(id)
|
||||
return res
|
||||
def case_close_send_note(self, cr, uid, ids, context=None):
|
||||
return self.message_append_note(cr, uid, ids, body=_("Meeting has been <b>done</b>."), context=context)
|
||||
|
||||
crm_meeting()
|
||||
|
||||
class calendar_attendee(osv.osv):
|
||||
""" Calendar Attendee """
|
||||
|
|
|
@ -25,7 +25,22 @@
|
|||
<field name="model">crm.meeting</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Meetings">
|
||||
<form string="Meetings" layout="manual">
|
||||
<div class="oe_form_topbar oe_form_topbar_hifirst">
|
||||
<button name="case_open" string="Confirm" type="object"
|
||||
states="draft"/>
|
||||
<button name="case_close" string="Done" type="object"
|
||||
states="open"/>
|
||||
<button name="case_reset" string="Reset to Unconfirmed" type="object"
|
||||
states="cancel,done"/>
|
||||
<button name="case_cancel" string="Cancel" type="object"
|
||||
states="draft,open"/>
|
||||
<div class="oe_right">
|
||||
<field name="state" nolabel="1" widget="statusbar" statusbar_visible="draft,open,done"/>
|
||||
</div>
|
||||
<div class="oe_clear"/>
|
||||
</div>
|
||||
<sheet layout="auto">
|
||||
<group col="6" colspan="4">
|
||||
<field name="name" select="1" string="Title"
|
||||
required="1" />
|
||||
|
@ -71,19 +86,6 @@
|
|||
</group>
|
||||
<separator string="Description" colspan="4" />
|
||||
<field name="description" nolabel="1" colspan="4" />
|
||||
<separator colspan="4"/>
|
||||
<group col="8" colspan="4" groups="base.group_no_one">
|
||||
<field name="state" />
|
||||
<button name="case_close" string="Done"
|
||||
states="open" type="object"
|
||||
icon="gtk-jump-to" />
|
||||
<button name="case_reset" string="Reset to Unconfirmed"
|
||||
states="open,done" type="object"
|
||||
icon="gtk-convert" />
|
||||
<button name="case_open" string="Confirm"
|
||||
states="draft" type="object"
|
||||
icon="gtk-go-forward" />
|
||||
</group>
|
||||
</page>
|
||||
<page string="Invitation Detail">
|
||||
<button string="Invite People"
|
||||
|
@ -209,7 +211,10 @@
|
|||
|
||||
</page>
|
||||
</notebook>
|
||||
<field name="message_ids_social" colspan="4" widget="ThreadView" nolabel="1"/>
|
||||
</sheet>
|
||||
<div class="oe_form_bottom">
|
||||
<field name="message_ids_social" colspan="4" widget="ThreadView" nolabel="1"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
|
@ -19,26 +19,22 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from crm import crm_base
|
||||
from osv import fields, osv
|
||||
from tools.translate import _
|
||||
from base_status.base_state import base_state
|
||||
import crm
|
||||
from datetime import datetime
|
||||
from osv import fields, osv
|
||||
import time
|
||||
from tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT, DATETIME_FORMATS_MAP
|
||||
from datetime import datetime
|
||||
|
||||
class crm_phonecall(crm_base, osv.osv):
|
||||
""" Phonecall Cases """
|
||||
from tools.translate import _
|
||||
|
||||
class crm_phonecall(base_state, osv.osv):
|
||||
""" Model for CRM phonecalls """
|
||||
_name = "crm.phonecall"
|
||||
_description = "Phonecall"
|
||||
_order = "id desc"
|
||||
_inherit = ['ir.needaction_mixin', 'mail.thread']
|
||||
_columns = {
|
||||
# From crm.case
|
||||
'id': fields.integer('ID', readonly=True),
|
||||
'name': fields.char('Call Summary', size=64, required=True),
|
||||
'active': fields.boolean('Active', required=False),
|
||||
# base_state required fields
|
||||
'date_action_last': fields.datetime('Last Action', readonly=1),
|
||||
'date_action_next': fields.datetime('Next Action', readonly=1),
|
||||
'create_date': fields.datetime('Creation Date' , readonly=True),
|
||||
|
@ -48,20 +44,21 @@ class crm_phonecall(crm_base, osv.osv):
|
|||
'partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
'company_id': fields.many2one('res.company', 'Company'),
|
||||
'description': fields.text('Description'),
|
||||
'state': fields.selection([
|
||||
('draft', 'Draft'),
|
||||
('open', 'Todo'),
|
||||
'state': fields.selection([ ('draft', 'Draft'),
|
||||
('open', 'Confirmed'),
|
||||
('pending', 'Not Held'),
|
||||
('cancel', 'Cancelled'),
|
||||
('done', 'Held'),
|
||||
], 'Status', size=16, readonly=True,
|
||||
help='The state is set to \'Todo\', when a case is created.\
|
||||
\nIf the case is in progress the state is set to \'Open\'.\
|
||||
\nWhen the call is over, the state is set to \'Held\'.\
|
||||
\nIf the call needs to be done then the state is set to \'Not Held\'.'),
|
||||
('done', 'Held'),],
|
||||
string='Status', size=16, readonly=True,
|
||||
help='The state is set to \'Todo\', when a case is created.\
|
||||
If the case is in progress the state is set to \'Open\'.\
|
||||
When the call is over, the state is set to \'Held\'.\
|
||||
If the call needs to be done then the state is set to \'Not Held\'.'),
|
||||
'email_from': fields.char('Email', size=128, help="These people will receive email."),
|
||||
'date_open': fields.datetime('Opened', readonly=True),
|
||||
# phonecall fields
|
||||
'name': fields.char('Call Summary', size=64, required=True),
|
||||
'active': fields.boolean('Active', required=False),
|
||||
'duration': fields.float('Duration', help="Duration in Minutes"),
|
||||
'categ_id': fields.many2one('crm.case.categ', 'Category', \
|
||||
domain="['|',('section_id','=',section_id),('section_id','=',False),\
|
||||
|
@ -81,11 +78,10 @@ class crm_phonecall(crm_base, osv.osv):
|
|||
return 'open'
|
||||
|
||||
_defaults = {
|
||||
'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'date': fields.datetime.now,
|
||||
'priority': crm.AVAILABLE_PRIORITIES[2][0],
|
||||
'state': _get_default_state,
|
||||
'user_id': lambda self,cr,uid,ctx: uid,
|
||||
'active': 1,
|
||||
}
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
|
@ -96,32 +92,23 @@ class crm_phonecall(crm_base, osv.osv):
|
|||
return obj_id
|
||||
|
||||
def case_close(self, cr, uid, ids, context=None):
|
||||
"""Overrides close for crm_case for setting close date
|
||||
"""
|
||||
""" Overrides close for crm_case for setting duration """
|
||||
res = True
|
||||
for phone in self.browse(cr, uid, ids):
|
||||
for phone in self.browse(cr, uid, ids, context=context):
|
||||
phone_id = phone.id
|
||||
data = {'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')}
|
||||
data = {}
|
||||
if phone.duration <=0:
|
||||
duration = datetime.now() - datetime.strptime(phone.date, '%Y-%m-%d %H:%M:%S')
|
||||
data.update({'duration': duration.seconds/float(60)})
|
||||
res = super(crm_phonecall, self).case_close(cr, uid, [phone_id], context)
|
||||
self.write(cr, uid, [phone_id], data)
|
||||
duration = datetime.now() - datetime.strptime(phone.date, DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
data['duration'] = duration.seconds/float(60)
|
||||
res = super(crm_phonecall, self).case_close(cr, uid, [phone_id], context=context)
|
||||
self.write(cr, uid, [phone_id], data, context=context)
|
||||
return res
|
||||
|
||||
def case_reset(self, cr, uid, ids, context=None):
|
||||
"""Resets case as Todo
|
||||
"""
|
||||
res = super(crm_phonecall, self).case_reset(cr, uid, ids, context)
|
||||
self.write(cr, uid, ids, {'duration': 0.0, 'state':'open'})
|
||||
return res
|
||||
|
||||
|
||||
def case_open(self, cr, uid, ids, context=None):
|
||||
"""Overrides cancel for crm_case for setting Open Date
|
||||
"""
|
||||
res = super(crm_phonecall, self).case_open(cr, uid, ids, context)
|
||||
self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')})
|
||||
self.write(cr, uid, ids, {'duration': 0.0, 'state':'open'}, context=context)
|
||||
return res
|
||||
|
||||
def schedule_another_phonecall(self, cr, uid, ids, schedule_time, call_summary, \
|
||||
|
@ -300,7 +287,7 @@ class crm_phonecall(crm_base, osv.osv):
|
|||
return value
|
||||
|
||||
# ----------------------------------------
|
||||
# OpenChatter methods and notifications
|
||||
# OpenChatter
|
||||
# ----------------------------------------
|
||||
|
||||
def get_needaction_user_ids(self, cr, uid, ids, context=None):
|
||||
|
@ -336,9 +323,6 @@ class crm_phonecall(crm_base, osv.osv):
|
|||
|
||||
def _call_set_partner_send_note(self, cr, uid, ids, context=None):
|
||||
return self.message_append_note(cr, uid, ids, body=_("Partner has been <b>created</b>"), context=context)
|
||||
|
||||
|
||||
crm_phonecall()
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -48,13 +48,16 @@
|
|||
<field name="arch" type="xml">
|
||||
<form layout="manual">
|
||||
<div class="oe_form_topbar">
|
||||
<button name="case_close" string="Held" states="open,pending" type="object" />
|
||||
<button name="case_open" string="Todo" states="pending" type="object" />
|
||||
<button name="case_pending" string="Not Held" states="open" type="object" />
|
||||
<button name="case_reset" string="Reset to Todo" states="cancel" type="object" />
|
||||
<button name="case_cancel" string="Cancel" states="open,pending" type="object" />
|
||||
<button name="case_open" string="Confirm" type="object"
|
||||
states="draft,pending" icon="gtk-go-forward"/>
|
||||
<button name="case_close" string="Held" type="object"
|
||||
states="open,pending" icon="gtk-jump-to"/>
|
||||
<button name="case_reset" string="Reset to Todo" type="object"
|
||||
states="cancel" icon="gtk-convert"/>
|
||||
<button name="case_cancel" string="Cancel" type="object"
|
||||
states="draft,open,pending" icon="gtk-cancel"/>
|
||||
<div class="oe_right">
|
||||
<field name="state" widget="statusbar" nolabel="1" statusbar_visible="open,done" statusbar_colors='{"pending":"red"}' select="1"/>
|
||||
<field name="state" widget="statusbar" nolabel="1" statusbar_visible="draft,open,done" select="1"/>
|
||||
</div>
|
||||
<div class="oe_clear"/>
|
||||
</div>
|
||||
|
|
|
@ -143,6 +143,8 @@
|
|||
<field name="sequence"/>
|
||||
<field name="name"/>
|
||||
<field name="probability"/>
|
||||
<field name="state"/>
|
||||
<field name="type"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -162,6 +164,9 @@
|
|||
<field name="on_change"/>
|
||||
<field name="case_default"/>
|
||||
<field name="sequence"/>
|
||||
<field name="state"/>
|
||||
<field name="fold"/>
|
||||
<field name="type"/>
|
||||
</group>
|
||||
<separator string="Requirements" colspan="4"/>
|
||||
<field name="requirements" nolabel="1" colspan="4"/>
|
||||
|
|
|
@ -6,8 +6,11 @@
|
|||
-
|
||||
I check cancelled lead.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm.crm_case_itisatelesalescampaign0, string: Lead is in cancel state}:
|
||||
- state == "cancel"
|
||||
!python {model: crm.lead}: |
|
||||
lead = self.browse(cr, uid, ref('crm_case_itisatelesalescampaign0'))
|
||||
assert lead.stage_id.id == ref('crm.stage_lead7'), "Stage should be 'Dead' and is %s." % (lead.stage_id.name)
|
||||
assert lead.state == 'cancel', "Opportunity is not in 'cancel' state."
|
||||
assert lead.probability == 0.0, 'Opportunity probability is wrong and should be 0.0.'
|
||||
-
|
||||
I reset cancelled lead into unqualified lead.
|
||||
-
|
||||
|
@ -19,35 +22,24 @@
|
|||
!assert {model: crm.lead, id: crm.crm_case_itisatelesalescampaign0, string: Lead is in draft state}:
|
||||
- state == "draft"
|
||||
-
|
||||
I put unqualified lead into pending.
|
||||
I re-open the lead
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_pending(cr, uid, [ref("crm_case_itisatelesalescampaign0")])
|
||||
self.case_open(cr, uid, [ref("crm_case_itisatelesalescampaign0")])
|
||||
-
|
||||
I check status of pending lead.
|
||||
I check stage and state of the re-opened lead
|
||||
-
|
||||
!assert {model: crm.lead, id: crm.crm_case_itisatelesalescampaign0, string: Lead is in pending state}:
|
||||
- state == "pending"
|
||||
!python {model: crm.lead}: |
|
||||
lead = self.browse(cr, uid, ref('crm.crm_case_itisatelesalescampaign0'))
|
||||
assert lead.stage_id.id == ref('crm.stage_lead2'), "Opportunity stage should be 'Qualification'."
|
||||
assert lead.state == 'open', "Opportunity should be in 'open' state."
|
||||
-
|
||||
I escalate the lead to parent team.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_escalate(cr, uid, [ref("crm_case_itisatelesalescampaign0")])
|
||||
-
|
||||
I check lead escalate to parent team.
|
||||
I check the lead is correctly escalated to the parent team.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm.crm_case_itisatelesalescampaign0, string: Escalate lead to parent team}:
|
||||
- section_id.name == "Sales Department"
|
||||
-
|
||||
I mark as lost the opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_mark_lost(cr, uid, [ref("crm_case_itisatelesalescampaign0")])
|
||||
-
|
||||
I check opportunity after lost.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
lead = self.browse(cr, uid, ref('crm_case_itisatelesalescampaign0'))
|
||||
assert lead.state == 'done', "lead is not done state"
|
||||
assert lead.stage_id.id == ref('crm.stage_lead6'), 'Stage is not changed!'
|
||||
assert lead.probability == 0.0, 'Probability is wrong!'
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.action_makeMeeting(cr, uid, [ref('crm_case_qrecorp0')])
|
||||
|
||||
-
|
||||
After communicated with customer, I put some notes with contract details.
|
||||
-
|
||||
|
@ -60,18 +59,18 @@
|
|||
note_id = self.create(cr, uid, {'body': "ces détails envoyés par le client sur le FAX pour la qualité"})
|
||||
self.action_add(cr, uid, [note_id], context=context)
|
||||
-
|
||||
Finally, I won this opportunity, so I close this opportunity.
|
||||
I win this opportunity
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_mark_won(cr, uid, [ref("crm_case_qrecorp0")])
|
||||
-
|
||||
I check details of the opportunity after won the opportunity.
|
||||
I check details of the opportunity after having won the opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
lead = self.browse(cr, uid, ref('crm_case_qrecorp0'))
|
||||
assert lead.state == 'done', 'Opportunity is not in done state!'
|
||||
assert lead.stage_id.name == 'Won', ' Stage of Opportunity is not win!'
|
||||
assert lead.probability == 100.0, 'probability revenue should not be 100.0!'
|
||||
assert lead.stage_id.id == ref('crm.stage_lead6'), "Opportunity stage should be 'Won'."
|
||||
assert lead.state == 'done', "Opportunity is not in 'done' state!"
|
||||
assert lead.probability == 100.0, "Revenue probability should be 100.0!"
|
||||
-
|
||||
I convert mass lead into opportunity customer.
|
||||
-
|
||||
|
@ -96,6 +95,19 @@
|
|||
assert opp.name == "Interest in Your New Product", "Opportunity name not correct"
|
||||
assert opp.type == 'opportunity', 'Lead is not converted to opportunity!'
|
||||
assert opp.stage_id.id == ref("stage_lead1"), 'Stage of probability is incorrect!'
|
||||
-
|
||||
I loose the second opportunity
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_mark_lost(cr, uid, [ref("crm_case_electonicgoodsdealer0")])
|
||||
-
|
||||
I check details of the opportunity after the loose
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
lead = self.browse(cr, uid, ref('crm_case_electonicgoodsdealer0'))
|
||||
assert lead.stage_id.id == ref('crm.stage_lead8'), "Opportunity stage should be 'Lost'."
|
||||
assert lead.state == 'cancel', "Lost opportunity is not in 'cancel' state!"
|
||||
assert lead.probability == 0.0, "Revenue probability should be 0.0!"
|
||||
-
|
||||
I confirm review needs meeting.
|
||||
-
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
|
@ -19,25 +19,57 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import fields, osv
|
||||
from crm import crm
|
||||
import time
|
||||
from crm import wizard
|
||||
from base_status.base_stage import base_stage
|
||||
import binascii
|
||||
from crm import crm
|
||||
from crm import wizard
|
||||
from osv import fields, osv
|
||||
import time
|
||||
import tools
|
||||
from tools.translate import _
|
||||
|
||||
wizard.mail_compose_message.SUPPORTED_MODELS.append('crm.claim')
|
||||
|
||||
CRM_CLAIM_PENDING_STATES = (
|
||||
crm.AVAILABLE_STATES[2][0], # Cancelled
|
||||
crm.AVAILABLE_STATES[3][0], # Done
|
||||
crm.AVAILABLE_STATES[4][0], # Pending
|
||||
)
|
||||
|
||||
|
||||
class crm_claim(crm.crm_case, osv.osv):
|
||||
class crm_claim_stage(osv.osv):
|
||||
""" Model for claim stages. This models the main stages of a claim
|
||||
management flow. Main CRM objects (leads, opportunities, project
|
||||
issues, ...) will now use only stages, instead of state and stages.
|
||||
Stages are for example used to display the kanban view of records.
|
||||
"""
|
||||
Crm claim
|
||||
_name = "crm.claim.stage"
|
||||
_description = "Claim stages"
|
||||
_rec_name = 'name'
|
||||
_order = "sequence"
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Stage Name', size=64, required=True, translate=True),
|
||||
'sequence': fields.integer('Sequence', help="Used to order stages. Lower is better."),
|
||||
'section_ids':fields.many2many('crm.case.section', 'section_claim_stage_rel', 'stage_id', 'section_id', string='Sections',
|
||||
help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."),
|
||||
'state': fields.selection(crm.AVAILABLE_STATES, 'State', required=True, help="The related state for the stage. The state of your document will automatically change regarding the selected stage. For example, if a stage is related to the state 'Close', when your document reaches this stage, it will be automatically have the 'closed' state."),
|
||||
'case_refused': fields.boolean('Refused stage',
|
||||
help='Refused stages are specific stages for done.'),
|
||||
'case_default': fields.boolean('Common to All Teams',
|
||||
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('Hide in Views when 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."),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'sequence': lambda *args: 1,
|
||||
'state': 'draft',
|
||||
'fold': False,
|
||||
'case_refused': False,
|
||||
}
|
||||
|
||||
class crm_claim(base_stage, osv.osv):
|
||||
""" Crm claim
|
||||
"""
|
||||
_name = "crm.claim"
|
||||
_description = "Claim"
|
||||
|
@ -73,31 +105,68 @@ class crm_claim(crm.crm_case, osv.osv):
|
|||
'email_cc': fields.text('Watchers Emails', size=252, help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
|
||||
'email_from': fields.char('Email', size=128, help="These people will receive email."),
|
||||
'partner_phone': fields.char('Phone', size=32),
|
||||
'stage_id': fields.many2one ('crm.case.stage', 'Stage', domain="[('section_ids','=',section_id)]"),
|
||||
'stage_id': fields.many2one ('crm.claim.stage', 'Stage',
|
||||
domain="['|', ('section_ids', '=', section_id), ('case_default', '=', True)]"),
|
||||
'cause': fields.text('Root Cause'),
|
||||
'state': fields.selection(crm.AVAILABLE_STATES, 'Status', size=16, readonly=True,
|
||||
help='The state is set to \'Draft\', when a case is created.\
|
||||
\nIf the case is in progress the state is set to \'Open\'.\
|
||||
\nWhen the case is over, the state is set to \'Done\'.\
|
||||
\nIf the case needs to be reviewed then the state is set to \'Pending\'.'),
|
||||
'state': fields.related('stage_id', 'state', type="selection", store=True,
|
||||
selection=crm.AVAILABLE_STATES, string="State", readonly=True,
|
||||
help='The state is set to \'Draft\', when a case is created.\
|
||||
If the case is in progress the state is set to \'Open\'.\
|
||||
When the case is over, the state is set to \'Done\'.\
|
||||
If the case needs to be reviewed then the state is \
|
||||
set to \'Pending\'.'),
|
||||
'message_ids': fields.one2many('mail.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'user_id': crm.crm_case._get_default_user,
|
||||
'partner_id': crm.crm_case._get_default_partner,
|
||||
'email_from':crm.crm_case. _get_default_email,
|
||||
'state': lambda *a: 'draft',
|
||||
'section_id':crm.crm_case. _get_section,
|
||||
'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'user_id': lambda s, cr, uid, c: s._get_default_user(cr, uid, c),
|
||||
'partner_id': lambda s, cr, uid, c: s._get_default_partner(cr, uid, c),
|
||||
'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
|
||||
'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
|
||||
'date': fields.datetime.now,
|
||||
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.case', context=c),
|
||||
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
|
||||
'active': lambda *a: 1
|
||||
}
|
||||
|
||||
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
||||
return 'Claim'
|
||||
def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None):
|
||||
""" Override of the base.stage method
|
||||
Parameter of the stage search taken from the lead:
|
||||
- section_id: if set, stages must belong to this section or
|
||||
be a default case
|
||||
"""
|
||||
if isinstance(cases, (int, long)):
|
||||
cases = self.browse(cr, uid, cases, context=context)
|
||||
# collect all section_ids
|
||||
section_ids = []
|
||||
if section_id:
|
||||
section_ids.append(section_id)
|
||||
for claim in cases:
|
||||
if claim.section_id:
|
||||
section_ids.append(claim.section_id.id)
|
||||
# OR all section_ids and OR with case_default
|
||||
search_domain = []
|
||||
if section_ids:
|
||||
search_domain += [('|')] * len(section_ids)
|
||||
for section_id in section_ids:
|
||||
search_domain.append(('section_ids', '=', section_id))
|
||||
search_domain.append(('case_default', '=', True))
|
||||
# AND with the domain in parameter
|
||||
search_domain += list(domain)
|
||||
# perform search, return the first found
|
||||
stage_ids = self.pool.get('crm.claim.stage').search(cr, uid, search_domain, order=order, context=context)
|
||||
if stage_ids:
|
||||
return stage_ids[0]
|
||||
return False
|
||||
|
||||
def case_refuse(self, cr, uid, ids, context=None):
|
||||
""" Mark the case as refused: state=done and case_refused=True """
|
||||
for lead in self.browse(cr, uid, ids):
|
||||
stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, ['&', ('state', '=', 'done'), ('case_refused', '=', True)], context=context)
|
||||
if stage_id:
|
||||
self.case_set(cr, uid, [lead.id], values_to_update={}, new_stage_id=stage_id, context=context)
|
||||
return self.case_refuse_send_note(cr, uid, ids, context=context)
|
||||
|
||||
def onchange_partner_id(self, cr, uid, ids, part, email=False):
|
||||
"""This function returns value of partner address based on partner
|
||||
:param part: Partner's id
|
||||
|
@ -110,19 +179,6 @@ class crm_claim(crm.crm_case, osv.osv):
|
|||
}
|
||||
address = self.pool.get('res.partner').browse(cr, uid, part)
|
||||
return {'value': {'email_from': address.email, 'partner_phone': address.phone}}
|
||||
|
||||
def case_open(self, cr, uid, ids, *args):
|
||||
"""Opens Claim"""
|
||||
for l in self.browse(cr, uid, ids):
|
||||
# When coming from draft override date and stage otherwise just set state
|
||||
if l.state == 'draft':
|
||||
message = _("The claim '%s' has been opened.") % l.name
|
||||
self.log(cr, uid, l.id, message)
|
||||
stage_id = self.stage_find(cr, uid, l.section_id.id or False, [('sequence','>',0)])
|
||||
if stage_id:
|
||||
self.stage_set(cr, uid, [l.id], stage_id)
|
||||
res = super(crm_claim, self).case_open(cr, uid, ids, *args)
|
||||
return res
|
||||
|
||||
def message_new(self, cr, uid, msg, custom_values=None, context=None):
|
||||
"""Automatically called when new email message arrives"""
|
||||
|
@ -177,6 +233,26 @@ class crm_claim(crm.crm_case, osv.osv):
|
|||
res = self.write(cr, uid, [case.id], values, context=context)
|
||||
return res
|
||||
|
||||
# ---------------------------------------------------
|
||||
# OpenChatter methods and notifications
|
||||
# ---------------------------------------------------
|
||||
|
||||
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
||||
""" Override of default prefix for notifications. """
|
||||
return 'Claim'
|
||||
|
||||
def case_refuse_send_note(self, cr, uid, ids, context=None):
|
||||
for id in ids:
|
||||
msg = _('%s has been <b>refused</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
|
||||
self.message_append_note(cr, uid, [id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
|
||||
""" Override of the (void) default notification method. """
|
||||
stage_name = self.pool.get('crm.claim.stage').name_get(cr, uid, [stage_id], context=context)[0][1]
|
||||
return self.message_append_note(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
|
||||
|
||||
|
||||
class res_partner(osv.osv):
|
||||
_inherit = 'res.partner'
|
||||
_columns = {
|
||||
|
|
|
@ -42,27 +42,39 @@
|
|||
Case Stage
|
||||
-->
|
||||
|
||||
<record model="crm.case.stage" id="stage_claim1">
|
||||
<field name="name">Accepted as Claim</field>
|
||||
<record model="crm.claim.stage" id="stage_claim1">
|
||||
<field name="name">Draft claim</field>
|
||||
<field name="state">draft</field>
|
||||
<field name="sequence">26</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
</record>
|
||||
<record model="crm.case.stage" id="stage_claim5">
|
||||
<record model="crm.claim.stage" id="stage_claim5">
|
||||
<field name="name">Actions Defined</field>
|
||||
<field name="state">open</field>
|
||||
<field name="sequence">27</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
</record>
|
||||
<record model="crm.case.stage" id="stage_claim2">
|
||||
<record model="crm.claim.stage" id="stage_claim2">
|
||||
<field name="name">Actions Done</field>
|
||||
<field name="state">done</field>
|
||||
<field name="sequence">28</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
</record>
|
||||
<record model="crm.case.stage" id="stage_claim3">
|
||||
<field name="name">Won't fix</field>
|
||||
<record model="crm.claim.stage" id="stage_claim3">
|
||||
<field name="name">Refused</field>
|
||||
<field name="state">done</field>
|
||||
<field name="sequence">29</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
<field name="case_refused" eval="True"/>
|
||||
<field name="fold" eval="True"/>
|
||||
</record>
|
||||
<record model="crm.claim.stage" id="stage_claim3">
|
||||
<field name="name">Cancelled</field>
|
||||
<field name="state">cancel</field>
|
||||
<field name="sequence">30</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
<field name="fold" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record model="crm.case.section" id="crm.section_sales_department">
|
||||
<field name="name">Sales Department</field>
|
||||
<field name="code">Sales</field>
|
||||
<field name="stage_ids" eval="[(4, ref('stage_claim1')), (4, ref('stage_claim2')), (4, ref('stage_claim3')), (4, ref('stage_claim5'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval=""Problem with the delivery of goods"" name="name"/>
|
||||
<field eval=""open"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm_claim.categ_claim1"/>
|
||||
<field name="stage_id" ref="crm_claim.stage_claim1"/>
|
||||
|
@ -25,7 +24,6 @@
|
|||
<field eval=""4"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval=""Damaged Products"" name="name"/>
|
||||
<field eval=""open"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm_claim.categ_claim2"/>
|
||||
<field name="stage_id" ref="crm_claim.stage_claim5"/>
|
||||
|
@ -38,7 +36,6 @@
|
|||
<field eval=""2"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval=""Document related problems"" name="name"/>
|
||||
<field eval=""done"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm_claim.categ_claim3"/>
|
||||
<field name="stage_id" ref="crm_claim.stage_claim2"/>
|
||||
|
@ -52,7 +49,6 @@
|
|||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval=""Product quality not maintained"" name="name"/>
|
||||
<field eval=""draft"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm_claim.categ_claim1"/>
|
||||
<field name="stage_id" ref="crm_claim.stage_claim5"/>
|
||||
|
@ -65,7 +61,6 @@
|
|||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval=""Some products missing"" name="name"/>
|
||||
<field eval=""pending"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="categ_id" ref="crm_claim.categ_claim3"/>
|
||||
<field name="stage_id" ref="crm_claim.stage_claim3"/>
|
||||
|
@ -77,7 +72,6 @@
|
|||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval=""Problem with the delivery of assignments"" name="name"/>
|
||||
<field eval=""cancel"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="time.strftime('%Y-%m-28 14:15:30')" name="date"/>
|
||||
<field name="categ_id" ref="crm_claim.categ_claim1"/>
|
||||
|
@ -91,7 +85,6 @@
|
|||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval=""Documents unclear"" name="name"/>
|
||||
<field eval=""done"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="time.strftime('%Y-%m-19 13:01:05')" name="date"/>
|
||||
<field name="categ_id" ref="crm_claim.categ_claim3"/>
|
||||
|
|
|
@ -50,5 +50,10 @@
|
|||
<menuitem name="Claims" id="menu_crm_case_claims"
|
||||
parent="base.menu_aftersale" action="crm_case_categ_claim0" sequence="1"/>
|
||||
|
||||
<!-- Claim Stages -->
|
||||
<menuitem id="menu_definitions" name="Configuration" parent="base.menu_main_pm" sequence="60"/>
|
||||
<menuitem id="menu_project_config_project" name="Stages" parent="menu_definitions" sequence="1"/>
|
||||
<menuitem id="menu_claim_stage_view" name="Claim Stages" action="crm_claim_stage_act" parent="menu_project_config_project" sequence="20"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -23,12 +23,40 @@
|
|||
|
||||
<!-- Claim Stages -->
|
||||
|
||||
<record id="crm_claim_stage_tree" model="ir.ui.view">
|
||||
<field name="name">crm.claim.stage.tree</field>
|
||||
<field name="model">crm.claim.stage</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Claim Stages">
|
||||
<field name="sequence"/>
|
||||
<field name="name"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="crm_claim_stage_form" model="ir.ui.view">
|
||||
<field name="name">crm.claim.stage.form</field>
|
||||
<field name="model">crm.claim.stage</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Claim Stage">
|
||||
<field name="name"/>
|
||||
<field name="case_default"/>
|
||||
<field name="sequence"/>
|
||||
<field name="state"/>
|
||||
<field name="case_refused"/>
|
||||
<field name="fold"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="crm_claim_stage_act" model="ir.actions.act_window">
|
||||
<field name="name">Claim Stages</field>
|
||||
<field name="res_model">crm.case.stage</field>
|
||||
<field name="res_model">crm.claim.stage</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="crm.crm_case_stage_tree"/>
|
||||
<field name="context">{'search_default_claim':1}</field>
|
||||
<field name="view_id" ref="crm_claim_stage_tree"/>
|
||||
<field name="help">You can create claim stages to categorize the status of every claim entered in the system. The stages define all the steps required for the resolution of a claim.</field>
|
||||
</record>
|
||||
|
||||
|
@ -44,13 +72,13 @@
|
|||
<field name="partner_id"/>
|
||||
<field name="user_id" />
|
||||
<field name="date"/>
|
||||
<field name="stage_id"/>
|
||||
<field name="date_action_next"/>
|
||||
<field name="action_next"/>
|
||||
<field name="categ_id" string="Type" select="1"/>
|
||||
<field name="stage_id" invisible="1"/>
|
||||
<field name="date_deadline" invisible="1"/>
|
||||
<field name="date_closed" invisible="1"/>
|
||||
<field name="state"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -62,13 +90,23 @@
|
|||
<field name="arch" type="xml">
|
||||
<form layout="manual">
|
||||
<div class="oe_form_topbar">
|
||||
<button name="case_close" string="Done" states="open,pending" type="object" />
|
||||
<button name="case_open" string="Open" states="draft,pending" type="object" />
|
||||
<button name="case_pending" string="Pending" states="draft,open" type="object" />
|
||||
<button name="case_reset" string="Reset to Draft" states="done,cancel" type="object" />
|
||||
<button name="case_cancel" string="Cancel" states="draft,open,pending" type="object" />
|
||||
<button name="case_open" string="Open" type="object"
|
||||
states="draft,pending"/>
|
||||
<button name="case_close" string="Done" type="object"
|
||||
states="open,pending"/>
|
||||
<button name="case_refuse" string="Refuse" type="object"
|
||||
states="draft,open,pending"/>
|
||||
<button name="stage_previous" string="Previous Stage" type="object"
|
||||
states="open,pending" icon="gtk-go-back" attrs="{'invisible': [('stage_id','=', False)]}"/>
|
||||
<button name="stage_next" string="Next Stage" type="object"
|
||||
states="open,pending" icon="gtk-go-forward" attrs="{'invisible': [('stage_id','=', False)]}"/>
|
||||
<button name="case_reset" string="Reset to Draft" type="object"
|
||||
states="cancel,done"/>
|
||||
<button name="case_cancel" string="Cancel" type="object"
|
||||
states="draft,open,pending"/>
|
||||
<div class="oe_right">
|
||||
<field name="state" select="1" nolabel="1" widget="statusbar" statusbar_visible="draft,open,done" statusbar_colors='{"pending":"blue"}'/>
|
||||
<field name="stage_id" nolabel="1" widget="statusbar"
|
||||
on_change="onchange_stage_id(stage_id)"/>
|
||||
</div>
|
||||
<div class="oe_clear"/>
|
||||
</div>
|
||||
|
@ -80,11 +118,7 @@
|
|||
<group colspan="4" col="6">
|
||||
<field name="user_id"/>
|
||||
<field name="section_id" widget="selection" />
|
||||
<group colspan="2" col="4">
|
||||
<field name="stage_id" domain="[('section_ids','=',section_id)]"/>
|
||||
<button name="stage_previous" string="" type="object" icon="gtk-go-back" />
|
||||
<button name="stage_next" string="" type="object" icon="gtk-go-forward" />
|
||||
</group>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
<newline />
|
||||
<field name="priority"/>
|
||||
<field name="date_deadline"/>
|
||||
|
@ -221,7 +255,7 @@
|
|||
domain="[]" context="{'group_by':'categ_id'}" />
|
||||
<filter string="Status"
|
||||
icon="terp-stock_effects-object-colorize"
|
||||
domain="[]" context="{'group_by':'state'}" />
|
||||
domain="[]" context="{'group_by':'state'}" groups="base.group_no_one"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter string="Claim Date" icon="terp-go-month"
|
||||
domain="[]" help="Claim Date"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_crm_claim_manager,crm.claim.manager,model_crm_claim,base.group_sale_manager,1,1,1,1
|
||||
access_crm_claim_user,crm.claim.user,model_crm_claim,base.group_sale_salesman,1,1,1,0
|
||||
access_crm_claim_stage_user,crm.claim.stage.user,model_crm_claim_stage,base.group_sale_salesman,1,1,1,1
|
||||
access_crm_claim_report_manager,crm.claim.report.manager,model_crm_claim_report,base.group_sale_manager,1,1,1,1
|
||||
access_crm_claim_partner_manager,crm.claim.partner.manager,model_crm_claim,base.group_partner_manager,1,0,0,0
|
||||
|
|
|
|
@ -30,7 +30,7 @@
|
|||
claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
|
||||
claim = self.browse(cr, uid, claim_ids[0])
|
||||
assert claim.state == "open", "Claim is not in Open state"
|
||||
assert claim.stage_id.id == ref("crm.stage_lead1"), "Claim is not in New stage"
|
||||
assert claim.stage_id.id == ref("crm.stage_lead2"), "Claim is not in Qualification stage"
|
||||
-
|
||||
After complete all service from our side, I close this claim.
|
||||
-
|
||||
|
|
|
@ -19,13 +19,14 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import fields, osv
|
||||
from base_status.base_stage import base_stage
|
||||
from crm import crm
|
||||
from crm import wizard
|
||||
from osv import fields, osv
|
||||
|
||||
wizard.mail_compose_message.SUPPORTED_MODELS.append('crm.fundraising')
|
||||
|
||||
class crm_fundraising(crm.crm_case, osv.osv):
|
||||
class crm_fundraising(base_stage, osv.osv):
|
||||
""" Fund Raising Cases """
|
||||
|
||||
_name = "crm.fundraising"
|
||||
|
@ -68,14 +69,58 @@ class crm_fundraising(crm.crm_case, osv.osv):
|
|||
'duration': fields.float('Duration'),
|
||||
'ref': fields.reference('Reference', selection=crm._links_get, size=128),
|
||||
'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128),
|
||||
'state': fields.selection(crm.AVAILABLE_STATES, 'Status', size=16, readonly=True,
|
||||
help='The state is set to \'Draft\', when a case is created.\
|
||||
\nIf the case is in progress the state is set to \'Open\'.\
|
||||
\nWhen the case is over, the state is set to \'Done\'.\
|
||||
\nIf the case needs to be reviewed then the state is set to \'Pending\'.'),
|
||||
'state': fields.related('stage_id', 'state', type="selection", store=True,
|
||||
selection=crm.AVAILABLE_STATES, string="State", readonly=True,
|
||||
help='The state is set to \'Draft\', when a case is created.\
|
||||
If the case is in progress the state is set to \'Open\'.\
|
||||
When the case is over, the state is set to \'Done\'.\
|
||||
If the case needs to be reviewed then the state is \
|
||||
set to \'Pending\'.'),
|
||||
'message_ids': fields.one2many('mail.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'active': 1,
|
||||
'user_id': lambda s, cr, uid, c: s._get_default_user(cr, uid, c),
|
||||
'partner_id': lambda s, cr, uid, c: s._get_default_partner(cr, uid, c),
|
||||
'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
|
||||
'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
|
||||
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.case', context=c),
|
||||
'priority': crm.AVAILABLE_PRIORITIES[2][0],
|
||||
'probability': 0.0,
|
||||
'planned_cost': 0.0,
|
||||
'planned_revenue': 0.0,
|
||||
}
|
||||
|
||||
def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None):
|
||||
""" Override of the base.stage method
|
||||
Parameter of the stage search taken from the lead:
|
||||
- section_id: if set, stages must belong to this section or
|
||||
be a default case
|
||||
"""
|
||||
if isinstance(cases, (int, long)):
|
||||
cases = self.browse(cr, uid, cases, context=context)
|
||||
# collect all section_ids
|
||||
section_ids = []
|
||||
if section_id:
|
||||
section_ids.append(section_id)
|
||||
for case in cases:
|
||||
if case.section_id:
|
||||
section_ids.append(case.section_id.id)
|
||||
# OR all section_ids and OR with case_default
|
||||
search_domain = []
|
||||
if section_ids:
|
||||
search_domain += [('|')] * len(section_ids)
|
||||
for section_id in section_ids:
|
||||
search_domain.append(('section_ids', '=', section_id))
|
||||
search_domain.append(('case_default', '=', True))
|
||||
# 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)
|
||||
if stage_ids:
|
||||
return stage_ids[0]
|
||||
return False
|
||||
|
||||
def message_new(self, cr, uid, msg, custom_values=None, context=None):
|
||||
"""Automatically called when new email message arrives"""
|
||||
|
@ -93,21 +138,18 @@ class crm_fundraising(crm.crm_case, osv.osv):
|
|||
self.write(cr, uid, [res_id], vals, context=context)
|
||||
return res_id
|
||||
|
||||
# ---------------------------------------------------
|
||||
# OpenChatter methods and notifications
|
||||
# ---------------------------------------------------
|
||||
|
||||
_defaults = {
|
||||
'active': 1,
|
||||
'user_id': crm.crm_case._get_default_user,
|
||||
'partner_id': crm.crm_case._get_default_partner,
|
||||
'email_from': crm.crm_case. _get_default_email,
|
||||
'state': 'draft',
|
||||
'section_id': crm.crm_case. _get_section,
|
||||
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.case', context=c),
|
||||
'priority': crm.AVAILABLE_PRIORITIES[2][0],
|
||||
'probability': 0.0,
|
||||
'planned_cost': 0.0,
|
||||
'planned_revenue': 0.0,
|
||||
}
|
||||
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
||||
""" Override of default prefix for notifications. """
|
||||
return 'Fundraising'
|
||||
|
||||
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
|
||||
""" Override of the (void) default notification method. """
|
||||
stage_name = self.pool.get('crm.case.stage').name_get(cr, uid, [stage_id], context=context)[0][1]
|
||||
return self.message_append_note(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
<field name="partner_id" ref="base.res_partner_9"/>
|
||||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval=""open"" name="state"/>
|
||||
<field eval="250000.0" name="planned_cost"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="time.strftime('%Y-%m-01 10:35:50')" name="date"/>
|
||||
|
@ -26,7 +25,6 @@
|
|||
<field name="partner_id" ref="base.main_partner"/>
|
||||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval=""draft"" name="state"/>
|
||||
<field eval="2000000.0" name="planned_cost"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="time.strftime('%Y-%m-05 12:35:50')" name="date"/>
|
||||
|
@ -43,7 +41,6 @@
|
|||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval=""open"" name="state"/>
|
||||
<field eval="500000.0" name="planned_cost"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="time.strftime('%Y-%m-07 13:50:50')" name="date"/>
|
||||
|
@ -59,7 +56,6 @@
|
|||
<field name="partner_id" ref="base.res_partner_4"/>
|
||||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval=""draft"" name="state"/>
|
||||
<field eval="1000000.0" name="planned_cost"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="time.strftime('%Y-%m-12 15:10:50')" name="date"/>
|
||||
|
@ -75,7 +71,6 @@
|
|||
<field name="partner_id" ref="base.res_partner_14"/>
|
||||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval=""open"" name="state"/>
|
||||
<field eval="5000000.0" name="planned_cost"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="time.strftime('%Y-%m-17 19:00:15')" name="date"/>
|
||||
|
@ -91,7 +86,6 @@
|
|||
<field name="partner_id" ref="base.res_partner_10"/>
|
||||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval=""done"" name="state"/>
|
||||
<field eval="10000000.0" name="planned_cost"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="time.strftime('%Y-%m-27 09:00:15')" name="date"/>
|
||||
|
@ -109,7 +103,6 @@
|
|||
<field name="partner_id" ref="base.res_partner_15"/>
|
||||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval=""draft"" name="state"/>
|
||||
<field eval="10000.0" name="planned_cost"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="time.strftime('%Y-%m-01 10:00:15')" name="date"/>
|
||||
|
@ -126,7 +119,6 @@
|
|||
<field name="partner_id" ref="base.res_partner_9"/>
|
||||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval=""open"" name="state"/>
|
||||
<field eval="800000.0" name="planned_cost"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="time.strftime('%Y-%m-24 22:00:15')" name="date"/>
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from base_status.base_state import base_state
|
||||
from crm import crm
|
||||
from osv import fields, osv
|
||||
import time
|
||||
from crm import wizard
|
||||
from osv import fields, osv
|
||||
import tools
|
||||
from tools.translate import _
|
||||
|
||||
|
@ -34,7 +34,7 @@ CRM_HELPDESK_STATES = (
|
|||
|
||||
wizard.mail_compose_message.SUPPORTED_MODELS.append('crm.helpdesk')
|
||||
|
||||
class crm_helpdesk(crm.crm_case, osv.osv):
|
||||
class crm_helpdesk(base_state, osv.osv):
|
||||
""" Helpdesk Cases """
|
||||
|
||||
_name = "crm.helpdesk"
|
||||
|
@ -82,12 +82,11 @@ class crm_helpdesk(crm.crm_case, osv.osv):
|
|||
|
||||
_defaults = {
|
||||
'active': lambda *a: 1,
|
||||
'user_id': crm.crm_case._get_default_user,
|
||||
'partner_id': crm.crm_case._get_default_partner,
|
||||
'email_from': crm.crm_case. _get_default_email,
|
||||
'user_id': lambda s, cr, uid, c: s._get_default_user(cr, uid, c),
|
||||
'partner_id': lambda s, cr, uid, c: s._get_default_partner(cr, uid, c),
|
||||
'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
|
||||
'state': lambda *a: 'draft',
|
||||
'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'section_id': crm.crm_case. _get_section,
|
||||
'date': lambda *a: fields.datetime.now(),
|
||||
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.helpdesk', context=c),
|
||||
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
|
||||
}
|
||||
|
@ -142,5 +141,12 @@ class crm_helpdesk(crm.crm_case, osv.osv):
|
|||
res = self.write(cr, uid, [case.id], values, context=context)
|
||||
return res
|
||||
|
||||
# ******************************
|
||||
# OpenChatter
|
||||
# ******************************
|
||||
|
||||
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
||||
return 'Helpdesk'
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
|
|
|
@ -30,12 +30,18 @@
|
|||
<field name="arch" type="xml">
|
||||
<form layout="manual">
|
||||
<div class="oe_form_topbar">
|
||||
<button name="case_close" states="open,pending" string="Close" type="object" />
|
||||
<button name="case_open" states="draft,pending" string="Open" type="object" />
|
||||
<button name="case_pending" states="draft,open" string="Pending" type="object" />
|
||||
<button name="case_reset" states="done,cancel" string="Reset to Draft" type="object" />
|
||||
<button name="case_escalate" states="open,draft,pending" string="Escalate" type="object" />
|
||||
<button name="case_cancel" states="draft,open,pending" string="Cancel" type="object" />
|
||||
<button name="case_open" string="Open" type="object"
|
||||
states="draft,pending"/>
|
||||
<button name="case_close" string="Close" type="object"
|
||||
states="open,draft,pending"/>
|
||||
<button name="case_pending" string="Pending" type="object"
|
||||
states="draft,open"/>
|
||||
<button name="case_reset" string="Reset to Draft" type="object"
|
||||
states="cancel,done"/>
|
||||
<button name="case_escalate" string="Escalate" type="object"
|
||||
states="open,draft,pending"/>
|
||||
<button name="case_cancel" string="Cancel" type="object"
|
||||
states="draft,open,pending"/>
|
||||
<div class="oe_right">
|
||||
<field name="state" select="1" nolabel="1" widget="statusbar" statusbar_visible="draft,open,done" statusbar_colors='{"pending":"blue"}'/>
|
||||
</div>
|
||||
|
@ -126,6 +132,9 @@
|
|||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_form_bottom">
|
||||
<field name="message_ids_social" colspan="4" widget="ThreadView" nolabel="1"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -37,7 +37,14 @@ system to store and search in your CV base.
|
|||
'author': 'OpenERP SA',
|
||||
'website': 'http://www.openerp.com',
|
||||
'images': ['images/hr_recruitment_analysis.jpeg','images/hr_recruitment_applicants.jpeg'],
|
||||
'depends': ['decimal_precision', 'hr', 'survey', 'crm', 'fetchmail'],
|
||||
'depends': [
|
||||
'base_status',
|
||||
'decimal_precision',
|
||||
'hr',
|
||||
'survey',
|
||||
'crm',
|
||||
'fetchmail',
|
||||
],
|
||||
'update_xml': [
|
||||
'wizard/hr_recruitment_phonecall_view.xml',
|
||||
'wizard/hr_recruitment_employee_hired.xml',
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<field name="job_id"/>
|
||||
<field name="partner_name"/>
|
||||
<field name="stage_id"/>
|
||||
<field name="state"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from base_status.base_stage import base_stage
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
@ -57,8 +58,6 @@ class hr_recruitment_source(osv.osv):
|
|||
_columns = {
|
||||
'name': fields.char('Source Name', size=64, required=True, translate=True),
|
||||
}
|
||||
hr_recruitment_source()
|
||||
|
||||
|
||||
class hr_recruitment_stage(osv.osv):
|
||||
""" Stage of HR Recruitment """
|
||||
|
@ -69,12 +68,15 @@ 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 tempy this field."),
|
||||
'requirements': fields.text('Requirements')
|
||||
'state': fields.selection(AVAILABLE_STATES, 'State', required=True, help="The related state for the stage. The state of your document will automatically change regarding the selected stage. Example, a stage is related to the state 'Close', when your document reach this stage, it will be automatically closed."),
|
||||
'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'),
|
||||
}
|
||||
_defaults = {
|
||||
'sequence': 1,
|
||||
'state': 'draft',
|
||||
'fold': False,
|
||||
}
|
||||
hr_recruitment_stage()
|
||||
|
||||
class hr_recruitment_degree(osv.osv):
|
||||
""" Degree of HR Recruitment """
|
||||
|
@ -90,14 +92,60 @@ class hr_recruitment_degree(osv.osv):
|
|||
_sql_constraints = [
|
||||
('name_uniq', 'unique (name)', 'The name of the Degree of Recruitment must be unique!')
|
||||
]
|
||||
hr_recruitment_degree()
|
||||
|
||||
class hr_applicant(crm.crm_case, osv.osv):
|
||||
class hr_applicant(base_stage, osv.Model):
|
||||
_name = "hr.applicant"
|
||||
_description = "Applicant"
|
||||
_order = "id desc"
|
||||
_inherit = ['ir.needaction_mixin', 'mail.thread']
|
||||
|
||||
def _get_default_department_id(self, cr, uid, context=None):
|
||||
""" Gives default department by checking if present in the context """
|
||||
return (self._resolve_department_id_from_context(cr, uid, context=context) or False)
|
||||
|
||||
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, [('state', '=', 'draft')], 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'
|
||||
context key, or None if it cannot be resolved to a single
|
||||
department.
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if type(context.get('default_department_id')) in (int, long):
|
||||
return context.get('default_department_id')
|
||||
if isinstance(context.get('default_department_id'), basestring):
|
||||
department_name = context['default_department_id']
|
||||
department_ids = self.pool.get('hr.department').name_search(cr, uid, name=department_name, context=context)
|
||||
if len(department_ids) == 1:
|
||||
return int(department_ids[0][0])
|
||||
return None
|
||||
|
||||
def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None):
|
||||
access_rights_uid = access_rights_uid or uid
|
||||
stage_obj = self.pool.get('hr.recruitment.stage')
|
||||
order = stage_obj._order
|
||||
# lame hack to allow reverting search, should just work in the trivial case
|
||||
if read_group_order == 'stage_id desc':
|
||||
order = "%s desc" % order
|
||||
# retrieve section_id from the context and write the domain
|
||||
# - ('id', 'in', 'ids'): add columns that should be present
|
||||
# - OR ('department_id', '=', False), ('fold', '=', False): add default columns that are not folded
|
||||
# - OR ('department_id', 'in', department_id), ('fold', '=', False) if department_id: add department columns that are not folded
|
||||
department_id = self._resolve_department_id_from_context(cr, uid, context=context)
|
||||
search_domain = []
|
||||
if department_id:
|
||||
search_domain += ['|', '&', ('department_id', '=', department_id), ('fold', '=', False)]
|
||||
search_domain += ['|', ('id', 'in', ids), '&', ('department_id', '=', False), ('fold', '=', False)]
|
||||
stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context)
|
||||
result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context)
|
||||
# restore order of the search
|
||||
result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))
|
||||
return result
|
||||
|
||||
def _compute_day(self, cr, uid, ids, fields, args, context=None):
|
||||
"""
|
||||
@param cr: the current row, from the database cursor,
|
||||
|
@ -143,12 +191,15 @@ class hr_applicant(crm.crm_case, osv.osv):
|
|||
'partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
'create_date': fields.datetime('Creation Date', readonly=True, select=True),
|
||||
'write_date': fields.datetime('Update Date', readonly=True),
|
||||
'stage_id': fields.many2one ('hr.recruitment.stage', 'Stage'),
|
||||
'state': fields.selection(AVAILABLE_STATES, 'Status', size=16, readonly=True,
|
||||
help='The state is set to \'Draft\', when a case is created.\
|
||||
\nIf the case is in progress the state is set to \'Open\'.\
|
||||
\nWhen the case is over, the state is set to \'Done\'.\
|
||||
\nIf the case needs to be reviewed then the state is set to \'Pending\'.'),
|
||||
'stage_id': fields.many2one ('hr.recruitment.stage', 'Stage',
|
||||
domain="['|', ('department_id', '=', department_id), ('department_id', '=', False)]"),
|
||||
'state': fields.related('stage_id', 'state', type="selection", store=True,
|
||||
selection=AVAILABLE_STATES, string="State", readonly=True,
|
||||
help='The state is set to \'Draft\', when a case is created.\
|
||||
If the case is in progress the state is set to \'Open\'.\
|
||||
When the case is over, the state is set to \'Done\'.\
|
||||
If the case needs to be reviewed then the state is \
|
||||
set to \'Pending\'.'),
|
||||
'company_id': fields.many2one('res.company', 'Company'),
|
||||
'user_id': fields.many2one('res.users', 'Responsible'),
|
||||
# Applicant Columns
|
||||
|
@ -169,7 +220,6 @@ class hr_applicant(crm.crm_case, osv.osv):
|
|||
'partner_mobile': fields.char('Mobile', size=32),
|
||||
'type_id': fields.many2one('hr.recruitment.degree', 'Degree'),
|
||||
'department_id': fields.many2one('hr.department', 'Department'),
|
||||
'state': fields.selection(AVAILABLE_STATES, 'Status', size=16, readonly=True),
|
||||
'survey': fields.related('job_id', 'survey_id', type='many2one', relation='survey', string='Survey'),
|
||||
'response': fields.integer("Response"),
|
||||
'reference': fields.char('Refered By', size=128),
|
||||
|
@ -185,33 +235,19 @@ class hr_applicant(crm.crm_case, osv.osv):
|
|||
|
||||
_defaults = {
|
||||
'active': lambda *a: 1,
|
||||
'user_id': lambda self, cr, uid, context: uid,
|
||||
'email_from': crm.crm_case. _get_default_email,
|
||||
'state': lambda *a: 'draft',
|
||||
'user_id': lambda s, cr, uid, c: uid,
|
||||
'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
|
||||
'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
|
||||
'department_id': lambda s, cr, uid, c: s._get_default_department_id(cr, uid, c),
|
||||
'priority': lambda *a: '',
|
||||
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.helpdesk', context=c),
|
||||
'color': 0,
|
||||
}
|
||||
|
||||
def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None):
|
||||
access_rights_uid = access_rights_uid or uid
|
||||
stage_obj = self.pool.get('hr.recruitment.stage')
|
||||
order = stage_obj._order
|
||||
if read_group_order == 'stage_id desc':
|
||||
# lame hack to allow reverting search, should just work in the trivial case
|
||||
order = "%s desc" % order
|
||||
stage_ids = stage_obj._search(cr, uid, ['|',('id','in',ids),('department_id','=',False)], order=order,
|
||||
access_rights_uid=access_rights_uid, context=context)
|
||||
result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context)
|
||||
# restore order of the search
|
||||
result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))
|
||||
return result
|
||||
|
||||
_group_by_full = {
|
||||
'stage_id': _read_group_stage_ids
|
||||
}
|
||||
|
||||
|
||||
def onchange_job(self,cr, uid, ids, job, context=None):
|
||||
result = {}
|
||||
|
||||
|
@ -229,47 +265,33 @@ class hr_applicant(crm.crm_case, osv.osv):
|
|||
stage_id = stage_ids and stage_ids[0] or False
|
||||
return {'value': {'stage_id': stage_id}}
|
||||
|
||||
def stage_previous(self, cr, uid, ids, context=None):
|
||||
"""This function computes previous stage for case from its current stage
|
||||
using available stage for that case type
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of case IDs
|
||||
@param context: A standard dictionary for contextual values"""
|
||||
stage_obj = self.pool.get('hr.recruitment.stage')
|
||||
for case in self.browse(cr, uid, ids, context=context):
|
||||
department = (case.department_id.id or False)
|
||||
st = case.stage_id.id or False
|
||||
stage_ids = stage_obj.search(cr, uid, ['|',('department_id','=',department),('department_id','=',False)], context=context)
|
||||
if st and stage_ids.index(st):
|
||||
self.write(cr, uid, [case.id], {'stage_id': stage_ids[stage_ids.index(st)-1]}, context=context)
|
||||
else:
|
||||
self.write(cr, uid, [case.id], {'stage_id': False}, context=context)
|
||||
return True
|
||||
|
||||
def stage_next(self, cr, uid, ids, context=None):
|
||||
"""This function computes next stage for case from its current stage
|
||||
using available stage for that case type
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of case IDs
|
||||
@param context: A standard dictionary for contextual values"""
|
||||
stage_obj = self.pool.get('hr.recruitment.stage')
|
||||
for case in self.browse(cr, uid, ids, context=context):
|
||||
department = (case.department_id.id or False)
|
||||
st = case.stage_id.id or False
|
||||
stage_ids = stage_obj.search(cr, uid, ['|',('department_id','=',department),('department_id','=',False)], context=context)
|
||||
val = False
|
||||
if st and len(stage_ids) != stage_ids.index(st)+1:
|
||||
val = stage_ids[stage_ids.index(st)+1]
|
||||
elif (not st) and stage_ids:
|
||||
val = stage_ids[0]
|
||||
else:
|
||||
val = False
|
||||
self.write(cr, uid, [case.id], {'stage_id': val}, context=context)
|
||||
return True
|
||||
def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None):
|
||||
""" Override of the base.stage method
|
||||
Parameter of the stage search taken from the lead:
|
||||
- department_id: if set, stages must belong to this section or
|
||||
be a default case
|
||||
"""
|
||||
if isinstance(cases, (int, long)):
|
||||
cases = self.browse(cr, uid, cases, context=context)
|
||||
# collect all section_ids
|
||||
department_ids = []
|
||||
if section_id:
|
||||
department_ids.append(section_id)
|
||||
for case in cases:
|
||||
if case.department_id:
|
||||
department_ids.append(case.department_id.id)
|
||||
# OR all section_ids and OR with case_default
|
||||
search_domain = []
|
||||
if department_ids:
|
||||
search_domain += ['|', ('department_id', 'in', department_ids)]
|
||||
search_domain.append(('department_id', '=', False))
|
||||
# AND with the domain in parameter
|
||||
search_domain += list(domain)
|
||||
# perform search, return the first found
|
||||
stage_ids = self.pool.get('hr.recruitment.stage').search(cr, uid, search_domain, order=order, context=context)
|
||||
if stage_ids:
|
||||
return stage_ids[0]
|
||||
return False
|
||||
|
||||
def action_makeMeeting(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
|
@ -474,12 +496,6 @@ class hr_applicant(crm.crm_case, osv.osv):
|
|||
"""
|
||||
return self.set_priority(cr, uid, ids, '3')
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
if 'stage_id' in vals and vals['stage_id']:
|
||||
stage = self.pool.get('hr.recruitment.stage').browse(cr, uid, vals['stage_id'], context=context)
|
||||
self.message_append_note(cr, uid, ids, body=_("Stage changed to <b>%s</b>.") % stage.name, context=context)
|
||||
return super(hr_applicant,self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
# -------------------------------------------------------
|
||||
# OpenChatter methods and notifications
|
||||
# -------------------------------------------------------
|
||||
|
@ -497,7 +513,13 @@ class hr_applicant(crm.crm_case, osv.osv):
|
|||
if obj.state == 'draft' and obj.user_id:
|
||||
result[obj.id] = [obj.user_id.id]
|
||||
return result
|
||||
|
||||
|
||||
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
|
||||
""" Override of the (void) default notification method. """
|
||||
if not stage_id: return True
|
||||
stage_name = self.pool.get('hr.recruitment.stage').name_get(cr, uid, [stage_id], context=context)[0][1]
|
||||
return self.message_append_note(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
|
||||
|
||||
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
||||
return 'Applicant'
|
||||
|
||||
|
@ -529,7 +551,6 @@ class hr_applicant(crm.crm_case, osv.osv):
|
|||
message = _("Applicant has been <b>created</b>.")
|
||||
return self.message_append_note(cr, uid, ids, body=message, context=context)
|
||||
|
||||
hr_applicant()
|
||||
|
||||
class hr_job(osv.osv):
|
||||
_inherit = "hr.job"
|
||||
|
@ -537,6 +558,6 @@ class hr_job(osv.osv):
|
|||
_columns = {
|
||||
'survey_id': fields.many2one('survey', 'Interview Form', help="Choose an interview form for this job position and you will be able to print/answer this interview from all applicants who apply for this job"),
|
||||
}
|
||||
hr_job()
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<!--
|
||||
<data noupdate="1">
|
||||
|
||||
-->
|
||||
<data>
|
||||
|
||||
<!-- HR Recruitment Source -->
|
||||
|
||||
|
@ -37,30 +39,36 @@
|
|||
<field name="name">Doctoral Degree</field>
|
||||
<field name="sequence">4</field>
|
||||
</record>
|
||||
|
||||
<record model="hr.recruitment.stage" id="stage_job1">
|
||||
<field name="name">Initial Qualification</field>
|
||||
<field name="state">draft</field>
|
||||
<field name="sequence">1</field>
|
||||
</record>
|
||||
<record model="hr.recruitment.stage" id="stage_job2">
|
||||
<field name="name">First Interview</field>
|
||||
<field name="state">open</field>
|
||||
<field name="sequence">2</field>
|
||||
</record>
|
||||
<record model="hr.recruitment.stage" id="stage_job3">
|
||||
<field name="name">Second Interview</field>
|
||||
<field name="state">open</field>
|
||||
<field name="sequence">3</field>
|
||||
</record>
|
||||
<record model="hr.recruitment.stage" id="stage_job4">
|
||||
<field name="name">Contract Proposed</field>
|
||||
<field name="state">pending</field>
|
||||
<field name="sequence">4</field>
|
||||
</record>
|
||||
<record model="hr.recruitment.stage" id="stage_job5">
|
||||
<field name="name">Contract Signed</field>
|
||||
<field name="state">done</field>
|
||||
<field name="sequence">5</field>
|
||||
</record>
|
||||
<record model="hr.recruitment.stage" id="stage_job6">
|
||||
<field name="name">Refused</field>
|
||||
<field name="state">cancel</field>
|
||||
<field name="sequence">6</field>
|
||||
<field name="fold" eval="True"/>
|
||||
</record>
|
||||
<record id="survey_job_0" model="survey">
|
||||
<field name="title">Job Survey</field>
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
<field name="availability" invisible="1"/>
|
||||
<field name="department_id" invisible="context.get('invisible_department', True)"/>
|
||||
<field name="user_id"/>
|
||||
<field name="state"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -72,14 +72,24 @@
|
|||
<field name="arch" type="xml">
|
||||
<form layout="manual">
|
||||
<div class="oe_form_topbar">
|
||||
<button name="%(action_hr_recruitment_hired_employee)d" string="Hire" states="open,pending" type="action"/>
|
||||
<button name="case_open" string="In Progress" states="draft,pending" type="object"/>
|
||||
<button name="case_pending" string="Pending" states="open" type="object"/>
|
||||
<button name="case_reset" string="Reset to New" states="done,cancel" type="object"/>
|
||||
<button name="case_cancel" string="Refuse" states="draft,open,pending" type="object"/>
|
||||
<button name="%(action_hr_recruitment_hired_employee)d" string="Hire" type="action"
|
||||
states="open,pending"/>
|
||||
<button name="case_open" string="Open" type="object"
|
||||
states="draft,pending"/>
|
||||
<button name="case_pending" string="Pending" type="object"
|
||||
states="open"/>
|
||||
<button name="case_reset" string="Reset to New" type="object"
|
||||
states="done,cancel"/>
|
||||
<button name="case_cancel" string="Refuse" type="object"
|
||||
states="draft,open,pending"/>
|
||||
<button name="stage_previous" string="Previous" type="object"
|
||||
states="open" icon="gtk-go-back"/>
|
||||
<button name="stage_next" string="Next" type="object"
|
||||
states="open" icon="gtk-go-forward"/>
|
||||
<div class="oe_right">
|
||||
<field name="state" nolabel="1" widget="statusbar" statusbar_visible="draft,open,done" statusbar_colors='{"pending":"blue"}'/>
|
||||
<field name="stage_id" nolabel="1" widget="statusbar"/>
|
||||
</div>
|
||||
<div class="oe_clear"/>
|
||||
</div>
|
||||
<sheet string="Jobs - Recruitment Form" layout="auto">
|
||||
<group colspan="4" col="4">
|
||||
|
@ -92,11 +102,7 @@
|
|||
<field name="user_id"/>
|
||||
<field name="job_id" on_change="onchange_job(job_id)"/>
|
||||
<field name="department_id" widget="selection" on_change="onchange_department_id(department_id)"/>
|
||||
<group colspan="2" col="4">
|
||||
<field name="stage_id" domain="['|',('department_id','=',department_id),('department_id','=',False)]"/>
|
||||
<button name="stage_previous" string="" type="object" icon="gtk-go-back"/>
|
||||
<button icon="gtk-go-forward" string="" name="stage_next" type="object"/>
|
||||
</group>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
<field name="date_action"/>
|
||||
<group colspan="2" col="8">
|
||||
<field name="title_action"/>
|
||||
|
@ -135,6 +141,13 @@
|
|||
<field name="source_id"/>
|
||||
<field name="reference"/>
|
||||
</group>
|
||||
<group col="2" colspan="2">
|
||||
<separator colspan="2" string="Dates"/>
|
||||
<field name="create_date"/>
|
||||
<field name="write_date"/>
|
||||
<field name="date_closed"/>
|
||||
<field name="date_open"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Notes">
|
||||
<field name="description" nolabel="1" colspan="4"/>
|
||||
|
@ -237,7 +250,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="stage_id">
|
||||
<field name="color"/>
|
||||
<field name="state"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
<field name="priority"/>
|
||||
<field name="survey"/>
|
||||
<field name="user_id"/>
|
||||
|
@ -356,6 +369,7 @@
|
|||
<field name="sequence" invisible="1"/>
|
||||
<field name="name"/>
|
||||
<field name="department_id"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -373,6 +387,7 @@
|
|||
<field name="name" select="1"/>
|
||||
<field name="department_id"/>
|
||||
<field name="sequence"/>
|
||||
<field name="state"/>
|
||||
</group>
|
||||
<separator string="Requirements" colspan="4"/>
|
||||
<field name="requirements" nolabel="1" colspan="4"/>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
-
|
||||
In Order to test process of Recruitment,
|
||||
-
|
||||
Applicant interested in job position. so He send resume by email.
|
||||
An applicant is interested in the job position. So he sends a resume by email.
|
||||
-
|
||||
!python {model: mail.thread}: |
|
||||
import addons
|
||||
|
@ -9,27 +9,42 @@
|
|||
request_message = request_file.read()
|
||||
self.message_process(cr, uid, 'hr.applicant', request_message)
|
||||
-
|
||||
After getting the mail, I check details of new applicant.
|
||||
After getting the mail, I check the details of the new applicant.
|
||||
-
|
||||
!python {model: hr.applicant}: |
|
||||
applicant_ids = self.search(cr, uid, [('email_from','=', 'Mr. Richard Anderson <Richard_Anderson@yahoo.com>')])
|
||||
assert applicant_ids, "Applicant is not created after getting the mail"
|
||||
applicant = self.browse(cr, uid, applicant_ids[0], context=context)
|
||||
resume_ids = self.pool.get('ir.attachment').search(cr, uid, [('datas_fname','=','resume.doc'),('res_model','=',self._name),('res_id','=',applicant.id)])
|
||||
assert applicant.name == "Application for the post of Jr.application Programmer.", "Subject does not match"
|
||||
assert applicant.state == "draft"
|
||||
assert len(resume_ids), "Resume does not attached."
|
||||
assert applicant.name == "Application for the post of Jr.application Programmer.", "Applicant name does not match."
|
||||
assert applicant.stage_id.id == ref('hr_recruitment.stage_job1'), "Stage should be 'Initial qualification' and is '%s'." % (applicant.stage_id.name)
|
||||
assert applicant.state == "draft", "Applicant state should be 'draft'."
|
||||
assert len(resume_ids), "Resume is not attached."
|
||||
-
|
||||
I refuse applicant for the Recruitment.
|
||||
I refuse the applicant (hr_case_programmer)
|
||||
-
|
||||
!python {model: hr.applicant}: |
|
||||
self.case_close(cr, uid, [ref("hr_case_programmer")])
|
||||
self.case_cancel(cr, uid, [ref("hr_case_programmer")])
|
||||
-
|
||||
I open applicant for the Recruitment.
|
||||
I check the details of the refused applicant.
|
||||
-
|
||||
!python {model: hr.applicant}: |
|
||||
applicant = self.browse(cr, uid, ref("hr_case_programmer"), context=context)
|
||||
assert applicant.stage_id.id == ref('hr_recruitment.stage_job6'), "Stage should be 'Refused' and is %s." % (applicant.stage_id.name)
|
||||
assert applicant.state == 'cancel', "Applicant is not in 'cancel' state."
|
||||
-
|
||||
I reset and re-open the previously refused applicant.
|
||||
-
|
||||
!python {model: hr.applicant}: |
|
||||
self.case_reset(cr, uid, [ref("hr_case_programmer")])
|
||||
self.case_open(cr, uid, [ref("hr_case_programmer")])
|
||||
-
|
||||
I check the details of the re-opened applicant.
|
||||
-
|
||||
!python {model: hr.applicant}: |
|
||||
applicant = self.browse(cr, uid, ref("hr_case_programmer"), context=context)
|
||||
assert applicant.stage_id.id == ref('hr_recruitment.stage_job2'), "Stage should be 'First interview' and is '%s'." % (applicant.stage_id.name)
|
||||
assert applicant.state == "open", "Applicant state should be 'open'."
|
||||
-
|
||||
I assign the Job position to the applicant
|
||||
-
|
||||
|
@ -91,7 +106,7 @@
|
|||
-
|
||||
I check that applicant is "Hired".
|
||||
-
|
||||
!assert {model: hr.applicant, id: hr_case_programmer}:
|
||||
!assert {model: hr.applicant, id: hr_case_programmer, string: Applicant state is done}:
|
||||
- state == 'done'
|
||||
-
|
||||
I do not give employment to the hired the applicant.
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
"category": "Project Management",
|
||||
"sequence": 8,
|
||||
"images": ["images/gantt.png", "images/project_dashboard.jpeg","images/project_task_tree.jpeg","images/project_task.jpeg","images/project.jpeg","images/task_analysis.jpeg"],
|
||||
"depends": ["base_setup", "product", "analytic", "board", "mail", "resource","web_kanban"],
|
||||
"depends": ["base_setup", "base_status", "product", "analytic", "board", "mail", "resource","web_kanban"],
|
||||
"description": """
|
||||
Project management module tracks multi-level projects, tasks, work done on tasks, eso.
|
||||
======================================================================================
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
<field name="planned_hours" widget="float_time"/>
|
||||
<field name="effective_hours" widget="float_time"/>
|
||||
<field name="progress" widget="progressbar"/>
|
||||
<field name="state" invisible="context.get('set_visible',False)"/>
|
||||
<field name="stage_id" invisible="context.get('set_visible',False)"/>
|
||||
<field name="state" invisible="context.get('set_visible',False)" groups="base.group_no_one"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -35,7 +36,8 @@
|
|||
<field name="date_deadline"/>
|
||||
<field name="total_hours" widget="float_time"/>
|
||||
<field name="progress" widget="progressbar"/>
|
||||
<field name="state" invisible="context.get('set_visible',False)"/>
|
||||
<field name="stage_id" invisible="context.get('set_visible',False)"/>
|
||||
<field name="state" invisible="context.get('set_visible',False)" groups="base.group_no_one"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
|
@ -19,18 +19,15 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from lxml import etree
|
||||
import time
|
||||
from base_status.base_stage import base_stage
|
||||
from datetime import datetime, date
|
||||
|
||||
from tools.translate import _
|
||||
from lxml import etree
|
||||
from osv import fields, osv
|
||||
from openerp.addons.resource.faces import task as Task
|
||||
import time
|
||||
from tools.translate import _
|
||||
|
||||
# I think we can remove this in v6.1 since VMT's improvements in the framework ?
|
||||
#class project_project(osv.osv):
|
||||
# _name = 'project.project'
|
||||
#project_project()
|
||||
_TASK_STATE = [('draft', 'New'),('open', 'In Progress'),('pending', 'Pending'), ('done', 'Done'), ('cancelled', 'Cancelled')]
|
||||
|
||||
class project_task_type(osv.osv):
|
||||
_name = 'project.task.type'
|
||||
|
@ -40,14 +37,20 @@ class project_task_type(osv.osv):
|
|||
'name': fields.char('Stage Name', required=True, size=64, translate=True),
|
||||
'description': fields.text('Description'),
|
||||
'sequence': fields.integer('Sequence'),
|
||||
'project_default': fields.boolean('Common to All 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."),
|
||||
'case_default': fields.boolean('Common to All 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'),
|
||||
'state': fields.selection(_TASK_STATE, 'State', required=True,
|
||||
help="The related state for the stage. The state of your document will automatically change regarding the selected stage. Example, a stage is related to the state 'Close', when your document reach this stage, it will be automatically closed."),
|
||||
'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."),
|
||||
}
|
||||
_defaults = {
|
||||
'sequence': 1
|
||||
'sequence': 1,
|
||||
'state': 'draft',
|
||||
'fold': False,
|
||||
}
|
||||
_order = 'sequence'
|
||||
project_task_type()
|
||||
|
||||
class project(osv.osv):
|
||||
_name = "project.project"
|
||||
|
@ -208,7 +211,7 @@ class project(osv.osv):
|
|||
return True
|
||||
|
||||
def _get_type_common(self, cr, uid, context):
|
||||
ids = self.pool.get('project.task.type').search(cr, uid, [('project_default','=',1)], context=context)
|
||||
ids = self.pool.get('project.task.type').search(cr, uid, [('case_default','=',1)], context=context)
|
||||
return ids
|
||||
|
||||
_order = "sequence"
|
||||
|
@ -239,7 +242,7 @@ class project(osv.osv):
|
|||
def set_done(self, cr, uid, ids, context=None):
|
||||
task_obj = self.pool.get('project.task')
|
||||
task_ids = task_obj.search(cr, uid, [('project_id', 'in', ids), ('state', 'not in', ('cancelled', 'done'))])
|
||||
task_obj.write(cr, uid, task_ids, {'state': 'done', 'date_end':time.strftime('%Y-%m-%d %H:%M:%S'), 'remaining_hours': 0.0})
|
||||
task_obj.case_close(cr, uid, task_ids, context=context)
|
||||
self.write(cr, uid, ids, {'state':'close'}, context=context)
|
||||
self.set_close_send_note(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
@ -247,7 +250,7 @@ class project(osv.osv):
|
|||
def set_cancel(self, cr, uid, ids, context=None):
|
||||
task_obj = self.pool.get('project.task')
|
||||
task_ids = task_obj.search(cr, uid, [('project_id', 'in', ids), ('state', '!=', 'done')])
|
||||
task_obj.write(cr, uid, task_ids, {'state': 'cancelled', 'date_end':time.strftime('%Y-%m-%d %H:%M:%S'), 'remaining_hours': 0.0})
|
||||
task_obj.case_cancel(cr, uid, task_ids, context=context)
|
||||
self.write(cr, uid, ids, {'state':'cancelled'}, context=context)
|
||||
self.set_cancel_send_note(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
@ -501,49 +504,61 @@ def Project():
|
|||
def set_close_send_note(self, cr, uid, ids, context=None):
|
||||
message = _("Project has been <b>closed</b>.")
|
||||
return self.message_append_note(cr, uid, ids, body=message, context=context)
|
||||
|
||||
project()
|
||||
|
||||
class task(osv.osv):
|
||||
|
||||
class task(base_stage, osv.osv):
|
||||
_name = "project.task"
|
||||
_description = "Task"
|
||||
_log_create = True
|
||||
_date_name = "date_start"
|
||||
_inherit = ['ir.needaction_mixin', 'mail.thread']
|
||||
|
||||
def _get_default_project_id(self, cr, uid, context=None):
|
||||
""" Gives default section by checking if present in the context """
|
||||
return (self._resolve_project_id_from_context(cr, uid, context=context) or False)
|
||||
|
||||
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, [('state', '=', 'draft')], context=context)
|
||||
|
||||
def _resolve_project_id_from_context(self, cr, uid, context=None):
|
||||
"""Return ID of project based on the value of 'project_id'
|
||||
context key, or None if it cannot be resolved to a single project.
|
||||
""" Returns ID of project based on the value of 'default_project_id'
|
||||
context key, or None if it cannot be resolved to a single
|
||||
project.
|
||||
"""
|
||||
if context is None: context = {}
|
||||
if type(context.get('default_project_id')) in (int, long):
|
||||
project_id = context['default_project_id']
|
||||
return project_id
|
||||
return context['default_project_id']
|
||||
if isinstance(context.get('default_project_id'), basestring):
|
||||
project_name = context['default_project_id']
|
||||
project_ids = self.pool.get('project.project').name_search(cr, uid, name=project_name)
|
||||
project_ids = self.pool.get('project.project').name_search(cr, uid, name=project_name, context=context)
|
||||
if len(project_ids) == 1:
|
||||
return project_ids[0][0]
|
||||
return None
|
||||
|
||||
def _read_group_type_id(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None):
|
||||
def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None):
|
||||
stage_obj = self.pool.get('project.task.type')
|
||||
project_id = self._resolve_project_id_from_context(cr, uid, context=context)
|
||||
order = stage_obj._order
|
||||
access_rights_uid = access_rights_uid or uid
|
||||
if read_group_order == 'type_id desc':
|
||||
# lame way to allow reverting search, should just work in the trivial case
|
||||
# lame way to allow reverting search, should just work in the trivial case
|
||||
if read_group_order == 'stage_id desc':
|
||||
order = '%s desc' % order
|
||||
# retrieve section_id from the context and write the domain
|
||||
# - ('id', 'in', 'ids'): add columns that should be present
|
||||
# - OR ('case_default', '=', True), ('fold', '=', False): add default columns that are not folded
|
||||
# - OR ('project_ids', 'in', project_id), ('fold', '=', False) if project_id: add project columns that are not folded
|
||||
search_domain = []
|
||||
project_id = self._resolve_project_id_from_context(cr, uid, context=context)
|
||||
if project_id:
|
||||
domain = ['|', ('id','in',ids), ('project_ids','in',project_id)]
|
||||
else:
|
||||
domain = ['|', ('id','in',ids), ('project_default','=',1)]
|
||||
stage_ids = stage_obj._search(cr, uid, domain, order=order, access_rights_uid=access_rights_uid, context=context)
|
||||
search_domain += ['|', '&', ('project_ids', '=', project_id), ('fold', '=', False)]
|
||||
search_domain += ['|', ('id', 'in', ids), '&', ('case_default', '=', True), ('fold', '=', False)]
|
||||
stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context)
|
||||
result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context)
|
||||
# restore order of the search
|
||||
result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))
|
||||
return result
|
||||
|
||||
|
||||
def _read_group_user_id(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None):
|
||||
res_users = self.pool.get('res.users')
|
||||
project_id = self._resolve_project_id_from_context(cr, uid, context=context)
|
||||
|
@ -562,11 +577,10 @@ class task(osv.osv):
|
|||
return result
|
||||
|
||||
_group_by_full = {
|
||||
'type_id': _read_group_type_id,
|
||||
'user_id': _read_group_user_id
|
||||
'stage_id': _read_group_stage_ids,
|
||||
'user_id': _read_group_user_id,
|
||||
}
|
||||
|
||||
|
||||
def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
|
||||
obj_project = self.pool.get('project.project')
|
||||
for domain in args:
|
||||
|
@ -597,7 +611,6 @@ class task(osv.osv):
|
|||
res[task.id]['progress'] = 100.0
|
||||
return res
|
||||
|
||||
|
||||
def onchange_remaining(self, cr, uid, ids, remaining=0.0, planned = 0.0):
|
||||
if remaining and not planned:
|
||||
return {'value':{'planned_hours': remaining}}
|
||||
|
@ -640,7 +653,7 @@ class task(osv.osv):
|
|||
if not default.get('remaining_hours', False):
|
||||
default['remaining_hours'] = float(self.read(cr, uid, id, ['planned_hours'])['planned_hours'])
|
||||
default['active'] = True
|
||||
default['type_id'] = False
|
||||
default['stage_id'] = False
|
||||
if not default.get('name', False):
|
||||
default['name'] = self.browse(cr, uid, id, context=context).name or ''
|
||||
if not context.get('copy',False):
|
||||
|
@ -670,10 +683,15 @@ class task(osv.osv):
|
|||
'description': fields.text('Description'),
|
||||
'priority': fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Important'), ('0','Very important')], 'Priority', select=True),
|
||||
'sequence': fields.integer('Sequence', select=True, help="Gives the sequence order when displaying a list of tasks."),
|
||||
'type_id': fields.many2one('project.task.type', 'Stage'),
|
||||
'state': fields.selection([('draft', 'New'),('cancelled', 'Cancelled'),('open', 'In Progress'),('pending', 'Pending'), ('done', 'Done')], 'Status', readonly=True, required=True,
|
||||
help='If the task is created the state is \'Draft\'.\n If the task is started, the state becomes \'In Progress\'.\n If review is needed the task is in \'Pending\' state.\
|
||||
\n If the task is over, the states is set to \'Done\'.'),
|
||||
'stage_id': fields.many2one('project.task.type', 'Stage',
|
||||
domain="['|', ('project_ids', '=', project_id), ('case_default', '=', True)]"),
|
||||
'state': fields.related('stage_id', 'state', type="selection", store=True,
|
||||
selection=_TASK_STATE, string="State", readonly=True,
|
||||
help='The state is set to \'Draft\', when a case is created.\
|
||||
If the case is in progress the state is set to \'Open\'.\
|
||||
When the case is over, the state is set to \'Done\'.\
|
||||
If the case needs to be reviewed then the state is \
|
||||
set to \'Pending\'.'),
|
||||
'kanban_state': fields.selection([('normal', 'Normal'),('blocked', 'Blocked'),('done', 'Ready To Pull')], 'Kanban State',
|
||||
help="A task's kanban state indicates special situations affecting it:\n"
|
||||
" * Normal is the default situation\n"
|
||||
|
@ -722,6 +740,8 @@ class task(osv.osv):
|
|||
}
|
||||
|
||||
_defaults = {
|
||||
'stage_id': _get_default_stage_id,
|
||||
'project_id': _get_default_project_id,
|
||||
'state': 'draft',
|
||||
'kanban_state': 'normal',
|
||||
'priority': '2',
|
||||
|
@ -729,7 +749,7 @@ class task(osv.osv):
|
|||
'sequence': 10,
|
||||
'active': True,
|
||||
'user_id': lambda obj, cr, uid, context: uid,
|
||||
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'project.task', context=c)
|
||||
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'project.task', context=c),
|
||||
}
|
||||
|
||||
_order = "priority, sequence, date_start, name, id"
|
||||
|
@ -828,6 +848,41 @@ class task(osv.osv):
|
|||
res['fields'][f]['string'] = res['fields'][f]['string'].replace('Hours',tm)
|
||||
return res
|
||||
|
||||
# ****************************************
|
||||
# Case management
|
||||
# ****************************************
|
||||
|
||||
def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None):
|
||||
""" Override of the base.stage method
|
||||
Parameter of the stage search taken from the lead:
|
||||
- section_id: if set, stages must belong to this section or
|
||||
be a default stage; if not set, stages must be default
|
||||
stages
|
||||
"""
|
||||
if isinstance(cases, (int, long)):
|
||||
cases = self.browse(cr, uid, cases, context=context)
|
||||
# collect all section_ids
|
||||
section_ids = []
|
||||
if section_id:
|
||||
section_ids.append(section_id)
|
||||
for task in cases:
|
||||
if task.project_id:
|
||||
section_ids.append(task.project_id.id)
|
||||
# OR all section_ids and OR with case_default
|
||||
search_domain = []
|
||||
if section_ids:
|
||||
search_domain += [('|')] * len(section_ids)
|
||||
for section_id in section_ids:
|
||||
search_domain.append(('project_ids', '=', section_id))
|
||||
search_domain.append(('case_default', '=', True))
|
||||
# AND with the domain in parameter
|
||||
search_domain += list(domain)
|
||||
# perform search, return the first found
|
||||
stage_ids = self.pool.get('project.task.type').search(cr, uid, search_domain, order=order, context=context)
|
||||
if stage_ids:
|
||||
return stage_ids[0]
|
||||
return False
|
||||
|
||||
def _check_child_task(self, cr, uid, ids, context=None):
|
||||
if context == None:
|
||||
context = {}
|
||||
|
@ -840,9 +895,9 @@ class task(osv.osv):
|
|||
return True
|
||||
|
||||
def action_close(self, cr, uid, ids, context=None):
|
||||
# This action open wizard to send email to partner or project manager after close task.
|
||||
if context == None:
|
||||
context = {}
|
||||
""" This action closes the task, then opens the wizard to send an
|
||||
email to the partner or the project manager.
|
||||
"""
|
||||
task_id = len(ids) and ids[0] or False
|
||||
self._check_child_task(cr, uid, ids, context=context)
|
||||
if not task_id: return False
|
||||
|
@ -863,12 +918,14 @@ class task(osv.osv):
|
|||
}
|
||||
return res
|
||||
|
||||
def do_close(self, cr, uid, ids, context={}):
|
||||
"""
|
||||
Close Task
|
||||
"""
|
||||
def do_close(self, cr, uid, ids, context=None):
|
||||
""" Compatibility when changing to case_close. """
|
||||
return self.case_close(cr, uid, ids, context=context)
|
||||
|
||||
def case_close(self, cr, uid, ids, context=None):
|
||||
""" Closes Task """
|
||||
request = self.pool.get('res.request')
|
||||
if not isinstance(ids,list): ids = [ids]
|
||||
if not isinstance(ids, list): ids = [ids]
|
||||
for task in self.browse(cr, uid, ids, context=context):
|
||||
vals = {}
|
||||
project = task.project_id
|
||||
|
@ -884,7 +941,6 @@ class task(osv.osv):
|
|||
'ref_doc1': 'project.task,%d'% (task.id,),
|
||||
'ref_doc2': 'project.project,%d'% (project.id,),
|
||||
}, context=context)
|
||||
|
||||
for parent_id in task.parent_ids:
|
||||
if parent_id.state in ('pending','draft'):
|
||||
reopen = True
|
||||
|
@ -893,12 +949,12 @@ class task(osv.osv):
|
|||
reopen = False
|
||||
if reopen:
|
||||
self.do_reopen(cr, uid, [parent_id.id], context=context)
|
||||
vals.update({'state': 'done'})
|
||||
vals.update({'remaining_hours': 0.0})
|
||||
# close task
|
||||
vals['remaining_hours'] = 0.0
|
||||
if not task.date_end:
|
||||
vals.update({ 'date_end':time.strftime('%Y-%m-%d %H:%M:%S')})
|
||||
self.write(cr, uid, [task.id],vals, context=context)
|
||||
self.do_close_send_note(cr, uid, [task.id], context)
|
||||
vals['date_end'] = fields.datetime.now()
|
||||
self.case_set(cr, uid, [task.id], 'done', vals, context=context)
|
||||
self.case_close_send_note(cr, uid, [task.id], context=context)
|
||||
return True
|
||||
|
||||
def do_reopen(self, cr, uid, ids, context=None):
|
||||
|
@ -916,12 +972,15 @@ class task(osv.osv):
|
|||
'ref_doc1': 'project.task,%d' % task.id,
|
||||
'ref_doc2': 'project.project,%d' % project.id,
|
||||
}, context=context)
|
||||
|
||||
self.write(cr, uid, [task.id], {'state': 'open'}, context=context)
|
||||
self.do_open_send_note(cr, uid, [task.id], context)
|
||||
self.case_set(cr, uid, [task.id], 'open', {}, context=context)
|
||||
self.case_open_send_note(cr, uid, [task.id], context)
|
||||
return True
|
||||
|
||||
def do_cancel(self, cr, uid, ids, context={}):
|
||||
def do_cancel(self, cr, uid, ids, context=None):
|
||||
""" Compatibility when changing to case_cancel. """
|
||||
return self.case_cancel(cr, uid, ids, context=context)
|
||||
|
||||
def case_cancel(self, cr, uid, ids, context=None):
|
||||
request = self.pool.get('res.request')
|
||||
tasks = self.browse(cr, uid, ids, context=context)
|
||||
self._check_child_task(cr, uid, ids, context=context)
|
||||
|
@ -937,27 +996,38 @@ class task(osv.osv):
|
|||
'ref_doc1': 'project.task,%d' % task.id,
|
||||
'ref_doc2': 'project.project,%d' % project.id,
|
||||
}, context=context)
|
||||
self.write(cr, uid, [task.id], {'state': 'cancelled', 'remaining_hours':0.0}, context=context)
|
||||
self.do_cancel_send_note(cr, uid, [task.id], context)
|
||||
# cancel task
|
||||
self.case_set(cr, uid, [task.id], 'cancelled', {'remaining_hours': 0.0}, context=context)
|
||||
self.case_cancel_send_note(cr, uid, [task.id], context=context)
|
||||
return True
|
||||
|
||||
def do_open(self, cr, uid, ids, context={}):
|
||||
def do_open(self, cr, uid, ids, context=None):
|
||||
""" Compatibility when changing to case_open. """
|
||||
return self.case_open(cr, uid, ids, context=context)
|
||||
|
||||
def case_open(self, cr, uid, ids, context=None):
|
||||
if not isinstance(ids,list): ids = [ids]
|
||||
tasks= self.browse(cr, uid, ids, context=context)
|
||||
for t in tasks:
|
||||
data = {'state': 'open'}
|
||||
if not t.date_start:
|
||||
data['date_start'] = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
self.write(cr, uid, [t.id], data, context=context)
|
||||
self.do_open_send_note(cr, uid, [t.id], context)
|
||||
self.case_set(cr, uid, ids, 'open', {'date_start': fields.datetime.now()}, context=context)
|
||||
self.case_open_send_note(cr, uid, ids, context)
|
||||
return True
|
||||
|
||||
def do_draft(self, cr, uid, ids, context={}):
|
||||
self.write(cr, uid, ids, {'state': 'draft'}, context=context)
|
||||
self.do_draft_send_note(cr, uid, ids, context)
|
||||
def do_draft(self, cr, uid, ids, context=None):
|
||||
""" Compatibility when changing to case_draft. """
|
||||
return self.case_draft(cr, uid, ids, context=context)
|
||||
|
||||
def case_draft(self, cr, uid, ids, context=None):
|
||||
self.case_set(cr, uid, ids, 'draft', {}, context=context)
|
||||
self.case_draft_send_note(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
|
||||
def do_pending(self, cr, uid, ids, context=None):
|
||||
""" Compatibility when changing to case_pending. """
|
||||
return self.case_pending(cr, uid, ids, context=context)
|
||||
|
||||
def case_pending(self, cr, uid, ids, context=None):
|
||||
self.case_set(cr, uid, ids, 'pending', {}, context=context)
|
||||
return self.case_pending_send_note(cr, uid, ids, context=context)
|
||||
|
||||
def _delegate_task_attachments(self, cr, uid, task_id, delegated_task_id, context=None):
|
||||
attachment = self.pool.get('ir.attachment')
|
||||
attachment_ids = attachment.search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', task_id)], context=context)
|
||||
|
@ -966,7 +1036,6 @@ class task(osv.osv):
|
|||
new_attachment_ids.append(attachment.copy(cr, uid, attachment_id, default={'res_id': delegated_task_id}, context=context))
|
||||
return new_attachment_ids
|
||||
|
||||
|
||||
def do_delegate(self, cr, uid, ids, delegate_data={}, context=None):
|
||||
"""
|
||||
Delegate Task to another users.
|
||||
|
@ -1000,11 +1069,6 @@ class task(osv.osv):
|
|||
delegated_tasks[task.id] = delegated_task_id
|
||||
return delegated_tasks
|
||||
|
||||
def do_pending(self, cr, uid, ids, context={}):
|
||||
self.write(cr, uid, ids, {'state': 'pending'}, context=context)
|
||||
self.do_pending_send_note(cr, uid, ids, context)
|
||||
return True
|
||||
|
||||
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.state=='draft') or (task.planned_hours==0.0):
|
||||
|
@ -1033,36 +1097,6 @@ class task(osv.osv):
|
|||
def set_kanban_state_done(self, cr, uid, ids, context=None):
|
||||
self.write(cr, uid, ids, {'kanban_state': 'done'}, context=context)
|
||||
|
||||
def _change_type(self, cr, uid, ids, next, context=None):
|
||||
"""
|
||||
go to the next stage
|
||||
if next is False, go to previous stage
|
||||
"""
|
||||
for task in self.browse(cr, uid, ids):
|
||||
if task.project_id.type_ids:
|
||||
typeid = task.type_id.id
|
||||
types_seq={}
|
||||
for type in task.project_id.type_ids :
|
||||
types_seq[type.id] = type.sequence
|
||||
if next:
|
||||
types = sorted(types_seq.items(), lambda x, y: cmp(x[1], y[1]))
|
||||
else:
|
||||
types = sorted(types_seq.items(), lambda x, y: cmp(y[1], x[1]))
|
||||
sorted_types = [x[0] for x in types]
|
||||
if not typeid:
|
||||
self.write(cr, uid, task.id, {'type_id': sorted_types[0]})
|
||||
elif typeid and typeid in sorted_types and sorted_types.index(typeid) != len(sorted_types)-1:
|
||||
index = sorted_types.index(typeid)
|
||||
self.write(cr, uid, task.id, {'type_id': sorted_types[index+1]})
|
||||
self.state_change_send_note(cr, uid, [task.id], context)
|
||||
return True
|
||||
|
||||
def next_type(self, cr, uid, ids, context=None):
|
||||
return self._change_type(cr, uid, ids, True, context=context)
|
||||
|
||||
def prev_type(self, cr, uid, ids, context=None):
|
||||
return self._change_type(cr, uid, ids, False, context=context)
|
||||
|
||||
def _store_history(self, cr, uid, ids, context=None):
|
||||
for task in self.browse(cr, uid, ids, context=context):
|
||||
self.pool.get('project.task.history').create(cr, uid, {
|
||||
|
@ -1070,7 +1104,7 @@ class task(osv.osv):
|
|||
'remaining_hours': task.remaining_hours,
|
||||
'planned_hours': task.planned_hours,
|
||||
'kanban_state': task.kanban_state,
|
||||
'type_id': task.type_id.id,
|
||||
'type_id': task.stage_id.id,
|
||||
'state': task.state,
|
||||
'user_id': task.user_id.id
|
||||
|
||||
|
@ -1084,22 +1118,25 @@ class task(osv.osv):
|
|||
return task_id
|
||||
|
||||
# Overridden to reset the kanban_state to normal whenever
|
||||
# the stage (type_id) of the task changes.
|
||||
# the stage (stage_id) of the task changes.
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
if vals and not 'kanban_state' in vals and 'type_id' in vals:
|
||||
new_stage = vals.get('type_id')
|
||||
if vals and not 'kanban_state' in vals and 'stage_id' in vals:
|
||||
new_stage = vals.get('stage_id')
|
||||
vals_reset_kstate = dict(vals, kanban_state='normal')
|
||||
for t in self.browse(cr, uid, ids, context=context):
|
||||
write_vals = vals_reset_kstate if t.type_id != new_stage else vals
|
||||
#TO FIX:Kanban view doesn't raise warning
|
||||
#stages = [stage.id for stage in t.project_id.type_ids]
|
||||
#if new_stage not in stages:
|
||||
#raise osv.except_osv(_('Warning !'), _('Stage is not defined in the project.'))
|
||||
write_vals = vals_reset_kstate if t.stage_id != new_stage else vals
|
||||
super(task,self).write(cr, uid, [t.id], write_vals, context=context)
|
||||
result = True
|
||||
else:
|
||||
result = super(task,self).write(cr, uid, ids, vals, context=context)
|
||||
if ('type_id' in vals) or ('remaining_hours' in vals) or ('user_id' in vals) or ('state' in vals) or ('kanban_state' in vals):
|
||||
if ('stage_id' in vals) or ('remaining_hours' in vals) or ('user_id' in vals) or ('state' in vals) or ('kanban_state' in vals):
|
||||
self._store_history(cr, uid, ids, context=context)
|
||||
self.state_change_send_note(cr, uid, ids, context)
|
||||
return result
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
|
@ -1139,7 +1176,11 @@ class task(osv.osv):
|
|||
# ---------------------------------------------------
|
||||
# OpenChatter methods and notifications
|
||||
# ---------------------------------------------------
|
||||
|
||||
|
||||
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
||||
""" Override of default prefix for notifications. """
|
||||
return 'Task'
|
||||
|
||||
def get_needaction_user_ids(self, cr, uid, ids, context=None):
|
||||
result = dict.fromkeys(ids, [])
|
||||
for obj in self.browse(cr, uid, ids, context=context):
|
||||
|
@ -1156,28 +1197,16 @@ class task(osv.osv):
|
|||
sub_ids.append(obj.manager_id.id)
|
||||
return self.pool.get('res.users').read(cr, uid, sub_ids, context=context)
|
||||
|
||||
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
|
||||
""" Override of the (void) default notification method. """
|
||||
stage_name = self.pool.get('project.task.type').name_get(cr, uid, [stage_id], context=context)[0][1]
|
||||
return self.message_append_note(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
|
||||
|
||||
def create_send_note(self, cr, uid, ids, context=None):
|
||||
return self.message_append_note(cr, uid, ids, body=_("Task has been <b>created</b>."), context=context)
|
||||
|
||||
def do_pending_send_note(self, cr, uid, ids, context=None):
|
||||
if not isinstance(ids,list): ids = [ids]
|
||||
msg = _('Task is now <b>pending</b>.')
|
||||
return self.message_append_note(cr, uid, ids, body=msg, context=context)
|
||||
|
||||
def do_open_send_note(self, cr, uid, ids, context=None):
|
||||
msg = _('Task has been <b>opened</b>.')
|
||||
return self.message_append_note(cr, uid, ids, body=msg, context=context)
|
||||
|
||||
def do_cancel_send_note(self, cr, uid, ids, context=None):
|
||||
msg = _('Task has been <b>canceled</b>.')
|
||||
return self.message_append_note(cr, uid, ids, body=msg, context=context)
|
||||
|
||||
def do_close_send_note(self, cr, uid, ids, context=None):
|
||||
msg = _('Task has been <b>closed</b>.')
|
||||
return self.message_append_note(cr, uid, ids, body=msg, context=context)
|
||||
|
||||
def do_draft_send_note(self, cr, uid, ids, context=None):
|
||||
msg = _('Task has been <b>renewed</b>.')
|
||||
def case_draft_send_note(self, cr, uid, ids, context=None):
|
||||
msg = _('Task has been set as <b>draft</b>.')
|
||||
return self.message_append_note(cr, uid, ids, body=msg, context=context)
|
||||
|
||||
def do_delegation_send_note(self, cr, uid, ids, context=None):
|
||||
|
@ -1186,13 +1215,6 @@ class task(osv.osv):
|
|||
self.message_append_note(cr, uid, [task.id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
def state_change_send_note(self, cr, uid, ids, context=None):
|
||||
for task in self.browse(cr, uid, ids, context=context):
|
||||
msg = _('Stage changed to <b>%s</b>') % (task.type_id.name)
|
||||
self.message_append_note(cr, uid, [task.id], body=msg, context=context)
|
||||
return True
|
||||
|
||||
task()
|
||||
|
||||
class project_work(osv.osv):
|
||||
_name = "project.task.work"
|
||||
|
@ -1231,7 +1253,7 @@ class project_work(osv.osv):
|
|||
for work in self.browse(cr, uid, ids):
|
||||
cr.execute('update project_task set remaining_hours=remaining_hours + %s where id=%s', (work.hours, work.task_id.id))
|
||||
return super(project_work,self).unlink(cr, uid, ids,*args, **kwargs)
|
||||
project_work()
|
||||
|
||||
|
||||
class account_analytic_account(osv.osv):
|
||||
|
||||
|
@ -1252,7 +1274,6 @@ class account_analytic_account(osv.osv):
|
|||
raise osv.except_osv(_('Warning !'), _('Please delete the project linked with this account first.'))
|
||||
return super(account_analytic_account, self).unlink(cr, uid, ids, *args, **kwargs)
|
||||
|
||||
account_analytic_account()
|
||||
|
||||
#
|
||||
# Tasks History, used for cumulative flow charts (Lean/Agile)
|
||||
|
@ -1313,7 +1334,7 @@ class project_task_history(osv.osv):
|
|||
_defaults = {
|
||||
'date': fields.date.context_today,
|
||||
}
|
||||
project_task_history()
|
||||
|
||||
|
||||
class project_task_history_cumulative(osv.osv):
|
||||
_name = 'project.task.history.cumulative'
|
||||
|
@ -1341,4 +1362,4 @@ class project_task_history_cumulative(osv.osv):
|
|||
) as history
|
||||
)
|
||||
""")
|
||||
project_task_history_cumulative()
|
||||
|
||||
|
|
|
@ -24,22 +24,40 @@
|
|||
<record id="project_tt_specification" model="project.task.type">
|
||||
<field name="sequence">1</field>
|
||||
<field name="name">Design</field>
|
||||
<field name="project_default" eval="1"/>
|
||||
<field name="state">draft</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
</record>
|
||||
<record id="project_tt_development" model="project.task.type">
|
||||
<field name="sequence">2</field>
|
||||
<field name="name">Development</field>
|
||||
<field name="project_default" eval="1"/>
|
||||
<field name="state">open</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
</record>
|
||||
<record id="project_tt_testing" model="project.task.type">
|
||||
<field name="sequence">3</field>
|
||||
<field name="name">Testing</field>
|
||||
<field name="project_default" eval="1"/>
|
||||
<field name="state">open</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
</record>
|
||||
<record id="project_tt_pending" model="project.task.type">
|
||||
<field name="sequence">4</field>
|
||||
<field name="name">Pending</field>
|
||||
<field name="state">pending</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
<field name="fold" eval="True"/>
|
||||
</record>
|
||||
<record id="project_tt_merge" model="project.task.type">
|
||||
<field name="sequence">4</field>
|
||||
<field name="sequence">5</field>
|
||||
<field name="name">Deployment</field>
|
||||
<field name="project_default" eval="1"/>
|
||||
<field name="state">done</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
</record>
|
||||
<record id="project_tt_cancel" model="project.task.type">
|
||||
<field name="sequence">6</field>
|
||||
<field name="name">Cancelled</field>
|
||||
<field name="state">cancelled</field>
|
||||
<field name="case_default" eval="True"/>
|
||||
<field name="fold" eval="True"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -77,7 +77,7 @@
|
|||
<field name="priority">2</field>
|
||||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Prepare Requirements Document</field>
|
||||
<field name="type_id" ref="project_tt_specification"/>
|
||||
<field name="stage_id" ref="project_tt_specification"/>
|
||||
<field name="color">3</field>
|
||||
</record>
|
||||
|
||||
|
@ -88,7 +88,7 @@
|
|||
<field name="priority">2</field>
|
||||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Make SRS</field>
|
||||
<field name="type_id" ref="project_tt_specification"/>
|
||||
<field name="stage_id" ref="project_tt_specification"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_3" model="project.task">
|
||||
|
@ -99,7 +99,7 @@
|
|||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Design Use Cases</field>
|
||||
<field name="date_deadline" eval="time.strftime('%Y-%m-24')"/>
|
||||
<field name="type_id" ref="project_tt_specification"/>
|
||||
<field name="stage_id" ref="project_tt_specification"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_4" model="project.task">
|
||||
|
@ -112,7 +112,7 @@
|
|||
<field name="description">Use the account_budget module</field>
|
||||
<field name="date_deadline" eval="time.strftime('%Y-%m-19')"/>
|
||||
<field name="color">3</field>
|
||||
<field name="type_id" ref="project_tt_specification"/>
|
||||
<field name="stage_id" ref="project_tt_specification"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_5" model="project.task">
|
||||
|
@ -125,7 +125,7 @@
|
|||
<field name="kanban_state">done</field>
|
||||
<field name="priority">0</field>
|
||||
<field name="date_deadline" eval="time.strftime('%Y-%m-%d')"/>
|
||||
<field name="type_id" ref="project_tt_specification"/>
|
||||
<field name="stage_id" ref="project_tt_specification"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_6" model="project.task">
|
||||
|
@ -135,7 +135,7 @@
|
|||
<field name="priority">2</field>
|
||||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Risk Management Planning</field>
|
||||
<field name="type_id" ref="project_tt_specification"/>
|
||||
<field name="stage_id" ref="project_tt_specification"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_7" model="project.task">
|
||||
|
@ -145,7 +145,7 @@
|
|||
<field name="priority">2</field>
|
||||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Create Project Schedules</field>
|
||||
<field name="type_id" ref="project_tt_specification"/>
|
||||
<field name="stage_id" ref="project_tt_specification"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_8" model="project.task">
|
||||
|
@ -156,7 +156,7 @@
|
|||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Dataflow Design</field>
|
||||
<field name="priority">0</field>
|
||||
<field name="type_id" ref="project_tt_specification"/>
|
||||
<field name="stage_id" ref="project_tt_specification"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_9" model="project.task">
|
||||
|
@ -166,7 +166,7 @@
|
|||
<field name="priority">2</field>
|
||||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">User Interface Design</field>
|
||||
<field name="type_id" ref="project_tt_specification"/>
|
||||
<field name="stage_id" ref="project_tt_specification"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_10" model="project.task">
|
||||
|
@ -177,7 +177,7 @@
|
|||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Develop Module in Sale Management</field>
|
||||
<field name="kanban_state">blocked</field>
|
||||
<field name="type_id" ref="project_tt_development"/>
|
||||
<field name="stage_id" ref="project_tt_development"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_11" model="project.task">
|
||||
|
@ -187,7 +187,7 @@
|
|||
<field name="priority">2</field>
|
||||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Develop module in Warehouse</field>
|
||||
<field name="type_id" ref="project_tt_merge"/>
|
||||
<field name="stage_id" ref="project_tt_merge"/>
|
||||
</record>
|
||||
|
||||
<function model="project.task" name="do_close" eval="[ref('project_task_11')], {'install_mode': True}"/>
|
||||
|
@ -199,7 +199,7 @@
|
|||
<field name="priority">2</field>
|
||||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Integrate Modules</field>
|
||||
<field name="type_id" ref="project_tt_development"/>
|
||||
<field name="stage_id" ref="project_tt_development"/>
|
||||
</record>
|
||||
|
||||
<function model="project.task" name="do_close" eval="[ref('project_task_12')], {'install_mode': True}"/>
|
||||
|
@ -211,7 +211,7 @@
|
|||
<field name="priority">2</field>
|
||||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Unit Testing</field>
|
||||
<field name="type_id" ref="project_tt_development"/>
|
||||
<field name="stage_id" ref="project_tt_development"/>
|
||||
</record>
|
||||
|
||||
<function model="project.task" name="do_pending" eval="[ref('project_task_13')], {'install_mode': True}"/>
|
||||
|
@ -223,8 +223,7 @@
|
|||
<field name="priority">2</field>
|
||||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Regression Test</field>
|
||||
<field name="type_id" ref="project_tt_development"/>
|
||||
<field name="state">pending</field>
|
||||
<field name="stage_id" ref="project_tt_development"/>
|
||||
</record>
|
||||
|
||||
<record id="project_task_15" model="project.task">
|
||||
|
@ -234,7 +233,7 @@
|
|||
<field name="priority">2</field>
|
||||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Documentation</field>
|
||||
<field name="type_id" ref="project_tt_specification"/>
|
||||
<field name="stage_id" ref="project_tt_specification"/>
|
||||
<field name="date_start">2011-02-06</field>
|
||||
</record>
|
||||
|
||||
|
@ -247,7 +246,7 @@
|
|||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Performance Tuning</field>
|
||||
<field name="description">Test on Runbot</field>
|
||||
<field name="type_id" ref="project_tt_specification"/>
|
||||
<field name="stage_id" ref="project_tt_specification"/>
|
||||
</record>
|
||||
<function model="project.task" name="do_open" eval="[ref('project_task_16')], {'install_mode': True}"/>
|
||||
|
||||
|
@ -258,7 +257,7 @@
|
|||
<field name="priority">2</field>
|
||||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Deploy and Review on Customer System</field>
|
||||
<field name="type_id" ref="project_tt_specification"/>
|
||||
<field name="stage_id" ref="project_tt_specification"/>
|
||||
</record>
|
||||
<function model="project.task" name="do_open" eval="[ref('project_task_17')], {'install_mode': True}"/>
|
||||
|
||||
|
@ -269,7 +268,7 @@
|
|||
<field name="priority">2</field>
|
||||
<field name="project_id" ref="project.project_integrate_openerp"/>
|
||||
<field name="name">Training and Presentation</field>
|
||||
<field name="type_id" ref="project_tt_specification"/>
|
||||
<field name="stage_id" ref="project_tt_specification"/>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
|
@ -322,7 +321,7 @@
|
|||
<record id="project_task_116" model="project.task">
|
||||
<field name="planned_hours">38.0</field>
|
||||
<field name="remaining_hours">38.0</field>
|
||||
<field name="type_id" ref="project_tt_development"/>
|
||||
<field name="stage_id" ref="project_tt_development"/>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="project_id" ref="project_project_22"/>
|
||||
<field name="description">BoM, After sales returns, interventions. Traceability.</field>
|
||||
|
@ -334,7 +333,7 @@
|
|||
<field name="planned_hours">16.0</field>
|
||||
<field name="remaining_hours">16.0</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="type_id" ref="project_tt_development"/>
|
||||
<field name="stage_id" ref="project_tt_development"/>
|
||||
<field name="project_id" ref="project_project_23"/>
|
||||
<field name="name">Data importation + Doc</field>
|
||||
</record>
|
||||
|
@ -344,7 +343,7 @@
|
|||
<field name="planned_hours">16.0</field>
|
||||
<field name="remaining_hours">16.0</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="type_id" ref="project_tt_development"/>
|
||||
<field name="stage_id" ref="project_tt_development"/>
|
||||
<field name="project_id" ref="project_project_23"/>
|
||||
<field name="name">Modifications asked by the customer.</field>
|
||||
</record>
|
||||
|
@ -353,7 +352,7 @@
|
|||
<record id="project_task_184" model="project.task">
|
||||
<field name="planned_hours">16.0</field>
|
||||
<field name="remaining_hours">16.0</field>
|
||||
<field name="type_id" ref="project_tt_testing"/>
|
||||
<field name="stage_id" ref="project_tt_testing"/>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="project_id" ref="project_project_21"/>
|
||||
|
@ -364,7 +363,7 @@
|
|||
<field name="sequence">15</field>
|
||||
<field name="planned_hours">8.0</field>
|
||||
<field name="remaining_hours">8.0</field>
|
||||
<field name="type_id" ref="project_tt_testing"/>
|
||||
<field name="stage_id" ref="project_tt_testing"/>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="project_id" ref="project_project_21"/>
|
||||
<field name="name">Internal testing + Software Install</field>
|
||||
|
@ -374,7 +373,7 @@
|
|||
<field name="sequence">17</field>
|
||||
<field name="planned_hours">16.0</field>
|
||||
<field name="remaining_hours">16.0</field>
|
||||
<field name="type_id" ref="project_tt_development"/>
|
||||
<field name="stage_id" ref="project_tt_development"/>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="priority">2</field>
|
||||
<field name="project_id" ref="project_project_21"/>
|
||||
|
@ -389,7 +388,7 @@
|
|||
<field name="user_id" eval="False"/>
|
||||
<field name="project_id" ref="project_project_23"/>
|
||||
<field name="name">Parameters</field>
|
||||
<field name="type_id" ref="project_tt_specification"/>
|
||||
<field name="stage_id" ref="project_tt_specification"/>
|
||||
</record>
|
||||
<function model="project.task" name="do_open" eval="[ref('project_task_189')], {'install_mode': True}"/>
|
||||
|
||||
|
@ -398,10 +397,9 @@
|
|||
<field name="planned_hours">32.0</field>
|
||||
<field name="remaining_hours">32.0</field>
|
||||
<field name="user_id" eval="False"/>
|
||||
<field name="state">open</field>
|
||||
<field name="project_id" ref="project_project_21"/>
|
||||
<field name="name">Start of the doc redaction + MRP</field>
|
||||
<field name="type_id" ref="project_tt_testing"/>
|
||||
<field name="stage_id" ref="project_tt_testing"/>
|
||||
</record>
|
||||
|
||||
<!-- Schedule tasks to assign users and dates -->
|
||||
|
|
|
@ -161,7 +161,7 @@
|
|||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<act_window
|
||||
context="{'search_default_project_id': [active_id], 'default_project_id': active_id}"
|
||||
id="act_project_project_2_project_task_all"
|
||||
|
@ -305,15 +305,26 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Project" layout="manual">
|
||||
<div class="oe_form_topbar">
|
||||
<button name="action_close" states="pending,open" string="Done" type="object"/>
|
||||
<button name="do_open" states="pending,draft" string="Start Task" type="object"/>
|
||||
<button name="%(action_project_task_reevaluate)d" states="done,cancelled" string="Reactivate" type="action" context="{'button_reactivate':True}" />
|
||||
<button name="do_pending" states="open" string="Pending" type="object"/>
|
||||
<button name="do_draft" states="open" string="Draft" type="object"/>
|
||||
<button name="%(action_project_task_delegate)d" states="pending,open,draft" string="Delegate" type="action"/>
|
||||
<button name="do_cancel" states="draft,open,pending" string="Cancel" type="object"/>
|
||||
<button name="do_open" string="Start Task" type="object"
|
||||
states="draft,pending"/>
|
||||
<button name="%(action_project_task_reevaluate)d" string="Reactivate" type="action"
|
||||
states="done,cancelled" context="{'button_reactivate':True}"/>
|
||||
<button name="do_pending" string="Pending" type="object"
|
||||
states="open"/>
|
||||
<button name="action_close" string="Done" type="object"
|
||||
states="draft,open,pending"/>
|
||||
<button name="do_draft" string="Draft" type="object"
|
||||
states="cancel,done"/>
|
||||
<button name="%(action_project_task_delegate)d" string="Delegate" type="action"
|
||||
states="pending,open,draft"/>
|
||||
<button name="do_cancel" string="Cancel" type="object"
|
||||
states="draft,open,pending" />
|
||||
<button name="stage_previous" string="Previous Stage" type="object"
|
||||
states="open,pending" icon="gtk-go-back" attrs="{'invisible': [('stage_id','=', False)]}"/>
|
||||
<button name="stage_next" string="Next Stage" type="object"
|
||||
states="open,pending" icon="gtk-go-forward" attrs="{'invisible': [('stage_id','=', False)]}"/>
|
||||
<div class="oe_right">
|
||||
<field name="state" nolabel="1" widget="statusbar" statusbar_visible="draft,open,done" statusbar_colors='{"pending":"blue"}' select="1"/>
|
||||
<field name="stage_id" nolabel="1" widget="statusbar"/>
|
||||
</div>
|
||||
<div class="oe_clear"/>
|
||||
</div>
|
||||
|
@ -362,7 +373,8 @@
|
|||
<tree string="Delegated tasks">
|
||||
<field name="name"/>
|
||||
<field name="user_id"/>
|
||||
<field name="state"/>
|
||||
<field name="stage_id"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
<field name="effective_hours" widget="float_time"/>
|
||||
<field name="progress" widget="progressbar"/>
|
||||
<field name="remaining_hours" widget="float_time"/>
|
||||
|
@ -376,16 +388,13 @@
|
|||
<separator string="Planning" colspan="2"/>
|
||||
<field name="priority"/>
|
||||
<field name="sequence"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
</group>
|
||||
|
||||
<separator string="Miscellaneous" colspan="4"/>
|
||||
<field name="partner_id" />
|
||||
<field name="company_id" select="1" groups="base.group_multi_company" widget="selection"/>
|
||||
<group col="4" colspan="2">
|
||||
<field name="type_id" widget="selection" readonly="1"/>
|
||||
<button name="prev_type" string="Previous" type="object" icon="gtk-go-back" help="Change to Previous Stage"/>
|
||||
<button name="next_type" string="Next" type="object" icon="gtk-go-forward" help="Change to Next Stage"/>
|
||||
</group>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
<separator colspan="4" string="Notes"/>
|
||||
<field colspan="4" name="notes" nolabel="1"/>
|
||||
</page>
|
||||
|
@ -397,22 +406,22 @@
|
|||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Project Task Kanban View -->
|
||||
<record model="ir.ui.view" id="view_task_kanban">
|
||||
<field name="name">project.task.kanban</field>
|
||||
<field name="model">project.task</field>
|
||||
<field name="type">kanban</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="type_id" >
|
||||
<kanban default_group_by="stage_id" >
|
||||
<field name="color"/>
|
||||
<field name="priority"/>
|
||||
<field name="type_id"/>
|
||||
<field name="stage_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="user_email"/>
|
||||
<field name="description"/>
|
||||
<field name="sequence"/>
|
||||
<field name="state"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
<field name="kanban_state"/>
|
||||
<field name="remaining_hours" sum="Remaining Time" groups="project.group_time_work_estimation_tasks"/>
|
||||
<field name="date_deadline"/>
|
||||
|
@ -508,11 +517,11 @@
|
|||
<field name="effective_hours" widget="float_time" sum="Spent Hours" invisible="1"/>
|
||||
<field name="remaining_hours" widget="float_time" sum="Remaining Hours" on_change="onchange_remaining(remaining_hours,planned_hours)" invisible="context.get('set_visible',False)" groups="project.group_time_work_estimation_tasks"/>
|
||||
<field name="date_deadline" invisible="context.get('deadline_visible',True)"/>
|
||||
<field name="type_id" invisible="context.get('set_visible',False)"/>
|
||||
<field name="stage_id" invisible="context.get('set_visible',False)"/>
|
||||
<field name="state" invisible="context.get('set_visible',False)" groups="base.group_no_one"/>
|
||||
<field name="date_start" invisible="1" groups="base.group_no_one"/>
|
||||
<field name="date_end" invisible="1" groups="base.group_no_one"/>
|
||||
<field name="progress" widget="progressbar" invisible="context.get('set_visible',False)"/>
|
||||
<field name="state" invisible="context.get('set_visible',False)"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -580,7 +589,7 @@
|
|||
<separator orientation="vertical"/>
|
||||
<filter string="Project" name="group_project_id" icon="terp-folder-violet" domain="[]" context="{'group_by':'project_id'}"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter string="Stage" name="group_stage_id" icon="terp-stage" domain="[]" context="{'group_by':'type_id'}"/>
|
||||
<filter string="Stage" name="group_stage_id" icon="terp-stage" domain="[]" context="{'group_by':'stage_id'}"/>
|
||||
<filter string="Status" name="group_state" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter string="Deadline" icon="terp-gnome-cpu-frequency-applet+" domain="[]" context="{'group_by':'date_deadline'}"/>
|
||||
|
@ -651,7 +660,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<search string="Tasks Stages">
|
||||
<group>
|
||||
<filter icon="terp-check" string="Common" name="common" domain="[('project_default', '=', 1)]" help="Stages common to all projects"/>
|
||||
<filter icon="terp-check" string="Common" name="common" domain="[('case_default', '=', 1)]" help="Stages common to all projects"/>
|
||||
<separator orientation="vertical"/>
|
||||
<field name="name"/>
|
||||
</group>
|
||||
|
@ -665,10 +674,14 @@
|
|||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Task Stage">
|
||||
<group colspan="4" col="6">
|
||||
<field name="name"/>
|
||||
<field name="project_default"/>
|
||||
<field name="sequence"/>
|
||||
<group colspan="2" col="2">
|
||||
<field name="name"/>
|
||||
<field name="state"/>
|
||||
</group>
|
||||
<group colspan="2" col="4">
|
||||
<field name="case_default"/>
|
||||
<field name="sequence"/>
|
||||
<field name="fold"/>
|
||||
</group>
|
||||
<separator string="Description" colspan="4"/>
|
||||
<field colspan="4" name="description" nolabel="1"/>
|
||||
|
@ -684,6 +697,7 @@
|
|||
<tree string="Task Stage">
|
||||
<field name="sequence"/>
|
||||
<field name="name"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -698,10 +712,10 @@
|
|||
|
||||
<menuitem id="menu_tasks_config" name="GTD" parent="project.menu_definitions" sequence="1"/>
|
||||
|
||||
<menuitem id="menu_project_config_project" name="Stages" parent="menu_definitions" sequence="1"/>
|
||||
<menuitem id="menu_project_config_project" name="Stages" parent="project.menu_definitions" sequence="1"/>
|
||||
|
||||
<menuitem action="open_task_type_form" id="menu_task_types_view" parent="menu_project_config_project" sequence="2" groups="base.group_no_one"/>
|
||||
<menuitem action="open_view_project_all" id="menu_projects" name="Projects" parent="menu_project_management" sequence="1"/>
|
||||
<menuitem action="open_task_type_form" name="Task Stages" id="menu_task_types_view" parent="menu_project_config_project" sequence="2"/>
|
||||
<menuitem action="open_view_project_all" id="menu_projects" name="Projects" parent="menu_project_management" sequence="1" groups="base.group_no_one"/>
|
||||
|
||||
<act_window context="{'search_default_user_id': [active_id], 'default_user_id': active_id}" id="act_res_users_2_project_project" name="User's projects" res_model="project.project" src_model="res.users" view_mode="tree,form" view_type="form"/>
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
<field name="user_id"/>
|
||||
<field name="remaining_hours"/>
|
||||
<field name="kanban_state"/>
|
||||
<field name="state"/>
|
||||
<field name="stage_id"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -82,7 +82,7 @@ class report_project_task_user(osv.osv):
|
|||
t.name as name,
|
||||
t.company_id,
|
||||
t.partner_id,
|
||||
t.type_id,
|
||||
t.stage_id,
|
||||
remaining_hours as remaining_hours,
|
||||
total_hours as total_hours,
|
||||
t.delay_hours as hours_delay,
|
||||
|
@ -114,7 +114,7 @@ class report_project_task_user(osv.osv):
|
|||
name,
|
||||
t.company_id,
|
||||
t.partner_id,
|
||||
t.type_id
|
||||
t.stage_id
|
||||
|
||||
""")
|
||||
|
||||
|
|
|
@ -214,7 +214,7 @@
|
|||
<tree string="Task By Days" >
|
||||
<field name="day"/>
|
||||
<field name="total_task"/>
|
||||
<field name="state"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
I change the stage of task to next stage.
|
||||
-
|
||||
!python {model: project.task}: |
|
||||
self.next_type(cr, uid, [ref("project_task_1")])
|
||||
self.stage_next(cr, uid, [ref("project_task_1")])
|
||||
-
|
||||
!record {model: project.task.reevaluate, id: reevaluate_id}:
|
||||
remaining_hours : 120
|
||||
|
@ -68,9 +68,9 @@
|
|||
I change the stage of task to previous stage.
|
||||
-
|
||||
!python {model: project.task}: |
|
||||
self.prev_type(cr, uid, [ref("project_task_1")])
|
||||
self.stage_previous(cr, uid, [ref("project_task_1")])
|
||||
-
|
||||
I cancel Task.
|
||||
-
|
||||
!python {model: project.task}: |
|
||||
self.do_cancel(cr, uid, [ref("project_task_2")])
|
||||
self.do_cancel(cr, uid, [ref("project_task_2")])
|
||||
|
|
|
@ -38,6 +38,7 @@ and decide on their status as they evolve.
|
|||
'website': 'http://www.openerp.com',
|
||||
'images': ['images/issue_analysis.jpeg','images/project_issue.jpeg'],
|
||||
'depends': [
|
||||
'base_status',
|
||||
'crm',
|
||||
'project',
|
||||
],
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
<field name="type">graph</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph orientation="vertical" string="Project Issue" type="bar">
|
||||
<field name="type_id"/>
|
||||
<field name="stage_id"/>
|
||||
<field name="nbr" operator="+"/>
|
||||
<field group="True" name="user_id"/>
|
||||
</graph>
|
||||
|
@ -96,10 +96,10 @@
|
|||
<field name="partner_id"/>
|
||||
<field name="project_id" />
|
||||
<field name="priority" string="Priority"/>
|
||||
<field name="type_id" widget="selection" readonly="1"/>
|
||||
<field name="version_id" widget="selection"/>
|
||||
<field name="progress" widget="progressbar" attrs="{'invisible':[('task_id','=',False)]}"/>
|
||||
<field name="state"/>
|
||||
<field name="stage_id" widget="selection" readonly="1"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
<field name="categ_id" invisible="1"/>
|
||||
<field name="task_id" invisible="1"/>
|
||||
</tree>
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from base_status.base_stage import base_stage
|
||||
from crm import crm
|
||||
from datetime import datetime
|
||||
from osv import fields,osv
|
||||
|
@ -42,12 +43,62 @@ class project_issue_version(osv.osv):
|
|||
}
|
||||
project_issue_version()
|
||||
|
||||
class project_issue(crm.crm_case, osv.osv):
|
||||
_ISSUE_STATE= [('draft', 'New'), ('open', 'In Progress'), ('cancel', 'Cancelled'), ('done', 'Done'),('pending', 'Pending')]
|
||||
|
||||
class project_issue(base_stage, osv.osv):
|
||||
_name = "project.issue"
|
||||
_description = "Project Issue"
|
||||
_order = "priority, create_date desc"
|
||||
_inherit = ['ir.needaction_mixin', 'mail.thread']
|
||||
|
||||
def _get_default_project_id(self, cr, uid, context=None):
|
||||
""" Gives default project by checking if present in the context """
|
||||
return self._resolve_project_id_from_context(cr, uid, context=context)
|
||||
|
||||
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, [('state', '=', 'draft')], 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'
|
||||
context key, or None if it cannot be resolved to a single
|
||||
project.
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
if type(context.get('default_project_id')) in (int, long):
|
||||
return context.get('default_project_id')
|
||||
if isinstance(context.get('default_project_id'), basestring):
|
||||
project_name = context['default_project_id']
|
||||
project_ids = self.pool.get('project.project').name_search(cr, uid, name=project_name, context=context)
|
||||
if len(project_ids) == 1:
|
||||
return int(project_ids[0][0])
|
||||
return None
|
||||
|
||||
def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None):
|
||||
access_rights_uid = access_rights_uid or uid
|
||||
stage_obj = self.pool.get('project.task.type')
|
||||
order = stage_obj._order
|
||||
# lame hack to allow reverting search, should just work in the trivial case
|
||||
if read_group_order == 'stage_id desc':
|
||||
order = "%s desc" % order
|
||||
# retrieve section_id from the context and write the domain
|
||||
# - ('id', 'in', 'ids'): add columns that should be present
|
||||
# - OR ('case_default', '=', True), ('fold', '=', False): add default columns that are not folded
|
||||
# - OR ('project_ids', 'in', project_id), ('fold', '=', False) if project_id: add project columns that are not folded
|
||||
search_domain = []
|
||||
project_id = self._resolve_project_id_from_context(cr, uid, context=context)
|
||||
if project_id:
|
||||
search_domain += ['|', '&', ('project_ids', '=', project_id), ('fold', '=', False)]
|
||||
search_domain += ['|', ('id', 'in', ids), '&', ('case_default', '=', True), ('fold', '=', False)]
|
||||
# perform search
|
||||
stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context)
|
||||
result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context)
|
||||
# restore order of the search
|
||||
result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))
|
||||
return result
|
||||
|
||||
def _compute_day(self, cr, uid, ids, fields, args, context=None):
|
||||
"""
|
||||
@param cr: the current row, from the database cursor,
|
||||
|
@ -173,11 +224,13 @@ class project_issue(crm.crm_case, osv.osv):
|
|||
'partner_id': fields.many2one('res.partner', 'Partner', select=1),
|
||||
'company_id': fields.many2one('res.company', 'Company'),
|
||||
'description': fields.text('Description'),
|
||||
'state': fields.selection([('draft', 'New'), ('cancel', 'Cancelled'), ('open', 'In Progress'),('pending', 'Pending'),('done', 'Done') ], 'Status', size=16, readonly=True,
|
||||
help='The state is set to \'Draft\', when a case is created.\
|
||||
\nIf the case is in progress the state is set to \'Open\'.\
|
||||
\nWhen the case is over, the state is set to \'Done\'.\
|
||||
\nIf the case needs to be reviewed then the state is set to \'Pending\'.'),
|
||||
'state': fields.related('stage_id', 'state', type="selection", store=True,
|
||||
selection=_ISSUE_STATE, string="State", readonly=True,
|
||||
help='The state is set to \'Draft\', when a case is created.\
|
||||
If the case is in progress the state is set to \'Open\'.\
|
||||
When the case is over, the state is set to \'Done\'.\
|
||||
If the case needs to be reviewed then the state is \
|
||||
set to \'Pending\'.'),
|
||||
'email_from': fields.char('Email', size=128, help="These people will receive email.", select=1),
|
||||
'email_cc': fields.char('Watchers Emails', size=256, help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
|
||||
'date_open': fields.datetime('Opened', readonly=True,select=True),
|
||||
|
@ -188,7 +241,8 @@ class project_issue(crm.crm_case, osv.osv):
|
|||
'categ_id': fields.many2one('crm.case.categ', 'Category', domain="[('object_id.model', '=', 'crm.project.bug')]"),
|
||||
'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority', select=True),
|
||||
'version_id': fields.many2one('project.issue.version', 'Version'),
|
||||
'type_id': fields.many2one ('project.task.type', 'Stages', domain="[('project_ids', '=', project_id)]"),
|
||||
'stage_id': fields.many2one ('project.task.type', 'Stages',
|
||||
domain="['|', ('project_ids', '=', project_id), ('case_default', '=', True)]"),
|
||||
'project_id':fields.many2one('project.project', 'Project'),
|
||||
'duration': fields.float('Duration'),
|
||||
'task_id': fields.many2one('project.task', 'Task', domain="[('project_id','=',project_id)]"),
|
||||
|
@ -221,15 +275,20 @@ class project_issue(crm.crm_case, osv.osv):
|
|||
|
||||
_defaults = {
|
||||
'active': 1,
|
||||
'partner_id': crm.crm_case._get_default_partner,
|
||||
'email_from': crm.crm_case._get_default_email,
|
||||
'partner_id': lambda s, cr, uid, c: s._get_default_partner(cr, uid, c),
|
||||
'email_from': lambda s, cr, uid, c: s._get_default_email(cr, uid, c),
|
||||
'state': 'draft',
|
||||
'section_id': crm.crm_case._get_section,
|
||||
'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
|
||||
'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
|
||||
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.helpdesk', context=c),
|
||||
'priority': crm.AVAILABLE_PRIORITIES[2][0],
|
||||
'categ_id' : lambda *a: False,
|
||||
}
|
||||
|
||||
_group_by_full = {
|
||||
'stage_id': _read_group_stage_ids
|
||||
}
|
||||
|
||||
def set_priority(self, cr, uid, ids, priority):
|
||||
"""Set lead priority
|
||||
"""
|
||||
|
@ -312,36 +371,20 @@ class project_issue(crm.crm_case, osv.osv):
|
|||
def convert_to_bug(self, cr, uid, ids, context=None):
|
||||
return self._convert(cr, uid, ids, 'bug_categ', context=context)
|
||||
|
||||
def next_type(self, cr, uid, ids, context=None):
|
||||
for task in self.browse(cr, uid, ids):
|
||||
typeid = task.type_id.id
|
||||
types = map(lambda x:x.id, task.project_id.type_ids or [])
|
||||
if types:
|
||||
if not typeid:
|
||||
self.write(cr, uid, [task.id], {'type_id': types[0]})
|
||||
elif typeid and typeid in types and types.index(typeid) != len(types)-1 :
|
||||
index = types.index(typeid)
|
||||
self.write(cr, uid, [task.id], {'type_id': types[index+1]})
|
||||
return True
|
||||
|
||||
def prev_type(self, cr, uid, ids, context=None):
|
||||
for task in self.browse(cr, uid, ids):
|
||||
typeid = task.type_id.id
|
||||
types = map(lambda x:x.id, task.project_id and task.project_id.type_ids or [])
|
||||
if types:
|
||||
if typeid and typeid in types:
|
||||
index = types.index(typeid)
|
||||
self.write(cr, uid, [task.id], {'type_id': index and types[index-1] or False})
|
||||
return True
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
issue = self.read(cr, uid, id, ['name'], context=context)
|
||||
if not default:
|
||||
default = {}
|
||||
default = default.copy()
|
||||
default['name'] = issue['name'] + _(' (copy)')
|
||||
return super(project_issue, self).copy(cr, uid, id, default=default,
|
||||
context=context)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
#Update last action date every time the user change the stage, the state or send a new email
|
||||
logged_fields = ['type_id', 'state', 'message_ids']
|
||||
logged_fields = ['stage_id', 'state', 'message_ids']
|
||||
if any([field in vals for field in logged_fields]):
|
||||
vals['date_action_last'] = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
if vals.get('type_id', False):
|
||||
stage = self.pool.get('project.task.type').browse(cr, uid, vals['type_id'], context=context)
|
||||
self.message_append_note(cr, uid, ids, body=_("Stage changed to <b>%s</b>.") % stage.name, context=context)
|
||||
return super(project_issue, self).write(cr, uid, ids, vals, context)
|
||||
|
||||
def onchange_task_id(self, cr, uid, ids, task_id, context=None):
|
||||
|
@ -363,15 +406,51 @@ class project_issue(crm.crm_case, osv.osv):
|
|||
self.create_send_note(cr, uid, [obj_id], context=context)
|
||||
return obj_id
|
||||
|
||||
def case_open(self, cr, uid, ids, context=None):
|
||||
res = super(project_issue, self).case_open(cr, uid, ids, context)
|
||||
self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S'), 'user_id' : uid})
|
||||
return res
|
||||
# -------------------------------------------------------
|
||||
# Stage management
|
||||
# -------------------------------------------------------
|
||||
|
||||
def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None):
|
||||
""" Override of the base.stage method
|
||||
Parameter of the stage search taken from the issue:
|
||||
- type: stage type must be the same or 'both'
|
||||
- section_id: if set, stages must belong to this section or
|
||||
be a default case
|
||||
"""
|
||||
if isinstance(cases, (int, long)):
|
||||
cases = self.browse(cr, uid, cases, context=context)
|
||||
# collect all section_ids
|
||||
section_ids = []
|
||||
if section_id:
|
||||
section_ids.append(section_id)
|
||||
for task in cases:
|
||||
if task.project_id:
|
||||
section_ids.append(task.project_id.id)
|
||||
# OR all section_ids and OR with case_default
|
||||
search_domain = []
|
||||
if section_ids:
|
||||
search_domain += [('|')] * len(section_ids)
|
||||
for section_id in section_ids:
|
||||
search_domain.append(('project_ids', '=', section_id))
|
||||
search_domain.append(('case_default', '=', True))
|
||||
# AND with the domain in parameter
|
||||
search_domain += list(domain)
|
||||
# perform search, return the first found
|
||||
stage_ids = self.pool.get('project.task.type').search(cr, uid, search_domain, order=order, context=context)
|
||||
if stage_ids:
|
||||
return stage_ids[0]
|
||||
return False
|
||||
|
||||
def case_cancel(self, cr, uid, ids, context=None):
|
||||
""" Cancels case """
|
||||
self.case_set(cr, uid, ids, 'cancelled', {'active': True}, context=context)
|
||||
self.case_cancel_send_note(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
def case_escalate(self, cr, uid, ids, context=None):
|
||||
cases = self.browse(cr, uid, ids)
|
||||
for case in cases:
|
||||
data = {'state' : 'draft'}
|
||||
data = {}
|
||||
if case.project_id.project_escalation_id:
|
||||
data['project_id'] = case.project_id.project_escalation_id.id
|
||||
if case.project_id.project_escalation_id.user_id:
|
||||
|
@ -380,10 +459,14 @@ class project_issue(crm.crm_case, osv.osv):
|
|||
self.pool.get('project.task').write(cr, uid, [case.task_id.id], {'project_id': data['project_id'], 'user_id': False})
|
||||
else:
|
||||
raise osv.except_osv(_('Warning !'), _('You cannot escalate this issue.\nThe relevant Project has not configured the Escalation Project!'))
|
||||
self.write(cr, uid, [case.id], data)
|
||||
self.case_escalate_send_note(cr, uid, [case.id], context)
|
||||
self.case_set(cr, uid, ids, 'draft', data, context=context)
|
||||
self.case_escalate_send_note(cr, uid, [case.id], context=context)
|
||||
return True
|
||||
|
||||
# -------------------------------------------------------
|
||||
# Mail gateway
|
||||
# -------------------------------------------------------
|
||||
|
||||
def message_new(self, cr, uid, msg, custom_values=None, context=None):
|
||||
"""Automatically called when new email message arrives"""
|
||||
if context is None:
|
||||
|
@ -434,7 +517,7 @@ class project_issue(crm.crm_case, osv.osv):
|
|||
# Reassign the 'open' state to the case if this one is in pending or done
|
||||
for record in self.browse(cr, uid, ids, context=context):
|
||||
if record.state in ('pending', 'done'):
|
||||
record.write({'state' : 'open'})
|
||||
self.case_set(cr, uid, ids, 'open', {}, context=context)
|
||||
|
||||
vls = { }
|
||||
for line in msg['body_text'].split('\n'):
|
||||
|
@ -448,15 +531,6 @@ class project_issue(crm.crm_case, osv.osv):
|
|||
res = self.write(cr, uid, ids, vals)
|
||||
self.message_append_dict(cr, uid, ids, msg, context=context)
|
||||
return res
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
issue = self.read(cr, uid, id, ['name'], context=context)
|
||||
if not default:
|
||||
default = {}
|
||||
default = default.copy()
|
||||
default['name'] = issue['name'] + _(' (copy)')
|
||||
return super(project_issue, self).copy(cr, uid, id, default=default,
|
||||
context=context)
|
||||
|
||||
# -------------------------------------------------------
|
||||
# OpenChatter methods and notifications
|
||||
|
@ -475,9 +549,15 @@ class project_issue(crm.crm_case, osv.osv):
|
|||
if obj.user_id:
|
||||
sub_ids.append(obj.user_id.id)
|
||||
return self.pool.get('res.users').read(cr, uid, sub_ids, context=context)
|
||||
|
||||
|
||||
def stage_set_send_note(self, cr, uid, ids, stage_id, context=None):
|
||||
""" Override of the (void) default notification method. """
|
||||
stage_name = self.pool.get('project.task.type').name_get(cr, uid, [stage_id], context=context)[0][1]
|
||||
return self.message_append_note(cr, uid, ids, body= _("Stage changed to <b>%s</b>.") % (stage_name), context=context)
|
||||
|
||||
def case_get_note_msg_prefix(self, cr, uid, id, context=None):
|
||||
return 'Project issue '
|
||||
""" Override of default prefix for notifications. """
|
||||
return 'Project issue'
|
||||
|
||||
def convert_to_task_send_note(self, cr, uid, ids, context=None):
|
||||
message = _("Project issue has been <b>converted</b> in to task.")
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
<field eval=""5"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_agrolait"/>
|
||||
<field eval=""open"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="categ_id" ref="bug_categ"/>
|
||||
|
@ -15,7 +14,7 @@
|
|||
<field eval="15.0" name="duration"/>
|
||||
<field eval=""Bug in Accounts module"" name="name"/>
|
||||
<field eval=""agr@agrolait.com"" name="email_from"/>
|
||||
<field name="type_id" ref="project.project_tt_specification"/>
|
||||
<field name="stage_id" ref="project.project_tt_specification"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_programnotgivingproperoutput0" model="project.issue">
|
||||
|
@ -23,28 +22,26 @@
|
|||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_asus"/>
|
||||
<field eval=""done"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="3.5" name="duration"/>
|
||||
<field name="categ_id" ref="bug_categ"/>
|
||||
<field eval=""Program not giving proper output"" name="name"/>
|
||||
<field name="project_id" ref="project.project_project_22"/>
|
||||
<field name="type_id" ref="project.project_tt_specification"/>
|
||||
<field name="stage_id" ref="project.project_tt_specification"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_outputincorrect0" model="project.issue">
|
||||
<field eval="time.strftime('%Y-%m-18 14:30:00')" name="date"/>
|
||||
<field eval=""4"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field eval=""cancel"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="2.3" name="duration"/>
|
||||
<field name="categ_id" ref="bug_categ"/>
|
||||
<field name="project_id" ref="project.project_project_23"/>
|
||||
<field eval=""Output incorrect"" name="name"/>
|
||||
<field name="type_id" ref="project.project_tt_development"/>
|
||||
<field name="stage_id" ref="project.project_tt_development"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_problemloadingpage0" model="project.issue">
|
||||
|
@ -52,14 +49,13 @@
|
|||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_14"/>
|
||||
<field eval=""cancel"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="4.0" name="duration"/>
|
||||
<field name="categ_id" ref="bug_categ"/>
|
||||
<field name="project_id" ref="project.project_project_22"/>
|
||||
<field eval=""Problem loading page"" name="name"/>
|
||||
<field name="type_id" ref="project.project_tt_testing"/>
|
||||
<field name="stage_id" ref="project.project_tt_testing"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_pagenotfound0" model="project.issue">
|
||||
|
@ -67,14 +63,13 @@
|
|||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_desertic_hispafuentes"/>
|
||||
<field eval=""draft"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="1.0" name="duration"/>
|
||||
<field name="categ_id" ref="bug_categ"/>
|
||||
<field name="project_id" ref="project.project_project_22"/>
|
||||
<field eval=""Page not Found"" name="name"/>
|
||||
<field name="type_id" ref="project.project_tt_development"/>
|
||||
<field name="stage_id" ref="project.project_tt_development"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_programmingerror0" model="project.issue">
|
||||
|
@ -82,14 +77,13 @@
|
|||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_5"/>
|
||||
<field eval=""pending"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="4.0" name="duration"/>
|
||||
<field name="categ_id" ref="bug_categ"/>
|
||||
<field name="project_id" ref="project.project_project_22"/>
|
||||
<field eval=""Programming Error"" name="name"/>
|
||||
<field name="type_id" ref="project.project_tt_testing"/>
|
||||
<field name="stage_id" ref="project.project_tt_testing"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_logicalerrorinprogram0" model="project.issue">
|
||||
|
@ -97,14 +91,13 @@
|
|||
<field eval=""2"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_6"/>
|
||||
<field eval=""pending"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="2.0" name="duration"/>
|
||||
<field name="categ_id" ref="bug_categ"/>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field eval=""Logical Error in Program"" name="name"/>
|
||||
<field name="type_id" ref="project.project_tt_testing"/>
|
||||
<field name="stage_id" ref="project.project_tt_testing"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_constrainterror0" model="project.issue">
|
||||
|
@ -112,14 +105,13 @@
|
|||
<field eval=""2"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_6"/>
|
||||
<field eval=""pending"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="7.3" name="duration"/>
|
||||
<field name="categ_id" ref="bug_categ"/>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field eval=""Constraint Error"" name="name"/>
|
||||
<field name="type_id" ref="project.project_tt_testing"/>
|
||||
<field name="stage_id" ref="project.project_tt_testing"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_errorinprogram0" model="project.issue">
|
||||
|
@ -127,13 +119,12 @@
|
|||
<field eval=""2"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="partner_id" ref="base.res_partner_5"/>
|
||||
<field eval=""open"" name="state"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="1.3" name="duration"/>
|
||||
<field name="categ_id" ref="feature_request_categ"/>
|
||||
<field name="project_id" ref="project.project_project_22"/>
|
||||
<field eval=""Error in Program"" name="name"/>
|
||||
<field name="type_id" ref="project.project_tt_testing"/>
|
||||
<field name="stage_id" ref="project.project_tt_testing"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_patcheserrorinprogram0" model="project.issue">
|
||||
|
@ -141,14 +132,13 @@
|
|||
<field eval=""2"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_2"/>
|
||||
<field eval=""open"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="13.0" name="duration"/>
|
||||
<field name="categ_id" ref="feature_request_categ"/>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field eval=""Patches Error in Program"" name="name"/>
|
||||
<field name="type_id" ref="project.project_tt_testing"/>
|
||||
<field name="stage_id" ref="project.project_tt_testing"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_newfeaturestobeadded0" model="project.issue">
|
||||
|
@ -156,14 +146,13 @@
|
|||
<field eval=""4"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_maxtor"/>
|
||||
<field eval=""open"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="3.2" name="duration"/>
|
||||
<field name="categ_id" ref="feature_request_categ"/>
|
||||
<field name="project_id" ref="project.project_project_21"/>
|
||||
<field eval=""New Features To Be Added"" name="name"/>
|
||||
<field name="type_id" ref="project.project_tt_merge"/>
|
||||
<field name="stage_id" ref="project.project_tt_merge"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_addmenustothemodule0" model="project.issue">
|
||||
|
@ -171,7 +160,6 @@
|
|||
<field eval=""1"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="partner_id" ref="base.res_partner_9"/>
|
||||
<field eval=""done"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="3.0" name="duration"/>
|
||||
|
@ -179,7 +167,7 @@
|
|||
<field name="project_id" ref="project.project_project_21"/>
|
||||
<field eval=""Add menus to the module"" name="name"/>
|
||||
<field eval=""info@opensides.be"" name="email_from"/>
|
||||
<field name="type_id" ref="project.project_tt_development"/>
|
||||
<field name="stage_id" ref="project.project_tt_development"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_includeattendancesheetinproject0" model="project.issue">
|
||||
|
@ -187,7 +175,6 @@
|
|||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_10"/>
|
||||
<field eval=""cancel"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="2.0" name="duration"/>
|
||||
|
@ -195,7 +182,7 @@
|
|||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field eval=""Include Attendance sheet in Project"" name="name"/>
|
||||
<field eval=""contact@tecsas.fr"" name="email_from"/>
|
||||
<field name="type_id" ref="project.project_tt_development"/>
|
||||
<field name="stage_id" ref="project.project_tt_development"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_createnewobject0" model="project.issue">
|
||||
|
@ -203,14 +190,13 @@
|
|||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_6"/>
|
||||
<field eval=""draft"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="2.45" name="duration"/>
|
||||
<field name="categ_id" ref="feature_request_categ"/>
|
||||
<field name="project_id" ref="project.project_project_22"/>
|
||||
<field eval=""Create new object"" name="name"/>
|
||||
<field name="type_id" ref="project.project_tt_specification"/>
|
||||
<field name="stage_id" ref="project.project_tt_specification"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_improvereportsinhrms0" model="project.issue">
|
||||
|
@ -218,14 +204,13 @@
|
|||
<field eval=""4"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="partner_id" ref="base.res_partner_11"/>
|
||||
<field eval=""pending"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="15.0" name="duration"/>
|
||||
<field name="categ_id" ref="feature_request_categ"/>
|
||||
<field name="project_id" ref="project.project_project_22"/>
|
||||
<field eval=""Improve Reports in HRMS"" name="name"/>
|
||||
<field name="type_id" ref="project.project_tt_development"/>
|
||||
<field name="stage_id" ref="project.project_tt_development"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_case_improvereportsinpms0" model="project.issue">
|
||||
|
@ -233,14 +218,13 @@
|
|||
<field eval=""2"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="partner_id" ref="base.res_partner_11"/>
|
||||
<field eval=""pending"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field eval="06.15" name="duration"/>
|
||||
<field name="categ_id" ref="feature_request_categ"/>
|
||||
<field name="project_id" ref="project.project_project_22"/>
|
||||
<field eval=""Improve Reports in PMS"" name="name"/>
|
||||
<field name="type_id" ref="project.project_tt_specification"/>
|
||||
<field name="stage_id" ref="project.project_tt_specification"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
|
|
@ -52,14 +52,26 @@
|
|||
<field name="arch" type="xml">
|
||||
<form layout="manual">
|
||||
<div class="oe_form_topbar">
|
||||
<button name="case_open" string="Open" states="draft,pending" type="object"/>
|
||||
<button name="case_close" string="Done" states="open,draft,pending" type="object"/>
|
||||
<button name="case_pending" string="Pending" states="draft,open" type="object"/>
|
||||
<button name="case_reset" string="Reset to New" states="done,cancel" type="object"/>
|
||||
<button name="case_escalate" string="Escalate" states="open,draft,pending" type="object"/>
|
||||
<button name="case_cancel" string="Cancel" states="draft,open,pending" type="object"/>
|
||||
<button name="case_open" string="Open" type="object"
|
||||
states="draft,pending"/>
|
||||
<button name="case_close" string="Done" type="object"
|
||||
states="draft,open,pending"/>
|
||||
<button name="case_pending" string="Pending" type="object"
|
||||
states="draft,open"/>
|
||||
<button name="case_escalate" string="Escalate" type="object"
|
||||
states="draft,open,pending"/>
|
||||
<button name="case_reset" string="Reset to New" type="object"
|
||||
states="cancelled,done"/>
|
||||
<button name="stage_previous" string="Previous Stage" type="object"
|
||||
states="open,pending" icon="gtk-go-back"
|
||||
attrs="{'invisible': [('stage_id','=', False)]}"/>
|
||||
<button name="stage_next" string="Next Stage" type="object"
|
||||
states="open,pending" icon="gtk-go-forward"
|
||||
attrs="{'invisible': [('stage_id','=', False)]}"/>
|
||||
<button name="case_cancel" string="Cancel" type="object"
|
||||
states="draft,open,pending"/>
|
||||
<div class="oe_right">
|
||||
<field name="state" nolabel="1" widget="statusbar" statusbar_visible="draft,open,done" statusbar_colors='{"pending":"blue"}'/>
|
||||
<field name="stage_id" nolabel="1" widget="statusbar"/>
|
||||
</div>
|
||||
<div class="oe_clear"/>
|
||||
</div>
|
||||
|
@ -75,11 +87,7 @@
|
|||
</group>
|
||||
<field name="user_id"/>
|
||||
<field name="version_id" colspan="2" widget="selection"/>
|
||||
<group colspan="2" col="4">
|
||||
<field name="type_id" string="Stages" />
|
||||
<button name="prev_type" string="Previous" type="object" icon="gtk-go-back" help="Change to Previous Stage"/>
|
||||
<button name="next_type" string="Next" type="object" icon="gtk-go-forward" help="Change to Next Stage"/>
|
||||
</group>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page string="General">
|
||||
|
@ -138,11 +146,11 @@
|
|||
<field name="partner_id"/>
|
||||
<field name="project_id" />
|
||||
<field name="priority" string="Priority"/>
|
||||
<field name="type_id" widget="selection" readonly="1" string="Stages" />
|
||||
<field name="version_id" widget="selection"/>
|
||||
<field name="user_id"/>
|
||||
<field name="progress" widget="progressbar" attrs="{'invisible':[('task_id','=',False)]}"/>
|
||||
<field name="state"/>
|
||||
<field name="stage_id" widget="selection" readonly="1"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
<field name="categ_id" invisible="1"/>
|
||||
<field name="task_id" invisible="1"/>
|
||||
</tree>
|
||||
|
@ -184,7 +192,7 @@
|
|||
<filter string="Priority" icon="terp-rating-rated" domain="[]"
|
||||
context="{'group_by':'priority'}" />
|
||||
<filter string="Stage" icon="terp-stage" domain="[]"
|
||||
context="{'group_by':'type_id'}" />
|
||||
context="{'group_by':'stage_id'}" />
|
||||
<filter string="Status" icon="terp-stock_effects-object-colorize" domain="[]"
|
||||
context="{'group_by':'state'}" />
|
||||
<separator orientation="vertical" />
|
||||
|
@ -216,9 +224,9 @@
|
|||
<field name="model">project.issue</field>
|
||||
<field name="type">kanban</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="type_id">
|
||||
<kanban default_group_by="stage_id">
|
||||
<field name="color"/>
|
||||
<field name="state"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
<field name="priority"/>
|
||||
<field name="user_email"/>
|
||||
<field name="user_id"/>
|
||||
|
@ -262,8 +270,7 @@
|
|||
<a string="Convert To Task" name="convert_issue_task" icon="gtk-index" type="object"/>
|
||||
</div>
|
||||
<div class="oe_kanban_right">
|
||||
<a name="case_open" string="Open" states="draft,pending" type="object" icon="kanban-apply" />
|
||||
<a name="case_pending" string="Pending" states="draft,open" type="object" icon="kanban-pause"/>
|
||||
<a name="case_open" string="Open" states="draft,pending" type="object" icon="kanban-apply"/>
|
||||
<a name="case_close" string="Close" states="open,draft,pending" type="object" icon="kanban-stop"/>
|
||||
</div>
|
||||
<div class="oe_kanban_clear"/>
|
||||
|
@ -296,10 +303,10 @@
|
|||
<field name="name" string="Feature description"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="priority" string="Priority"/>
|
||||
<field name="type_id" widget="selection" readonly="1"/>
|
||||
<field name="version_id"/>
|
||||
<field name="user_id"/>
|
||||
<field name="state"/>
|
||||
<field name="stage_id" widget="selection" readonly="1"/>
|
||||
<field name="state" groups="base.group_no_one"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
@ -310,13 +317,13 @@
|
|||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Feature Tracker Search">
|
||||
<filter icon="terp-go-today" string="Today"
|
||||
<filter icon="terp-go-today" string="Today"
|
||||
domain="[('date','=',time.strftime('%%Y-%%m-%%d'))]" help="Today's features"/>
|
||||
<separator orientation="vertical"/>
|
||||
<group>
|
||||
<field name="name" string="Feature description"/>
|
||||
<field name="user_id"/>
|
||||
<field name="state">
|
||||
<field name="state" groups="base.group_no_one">
|
||||
<filter icon="terp-check" domain="[('state','in',('open','draft'))]" help="Current Features" name="current_feature"/>
|
||||
<filter icon="terp-camera_test" domain="[('state','=','open')]" help="Open Features"/>
|
||||
</field>
|
||||
|
|
|
@ -51,7 +51,7 @@ class project_issue_report(osv.osv):
|
|||
'creation_date': fields.date('Creation Date', readonly=True),
|
||||
'date_closed': fields.date('Date of Closing', readonly=True),
|
||||
'categ_id': fields.many2one('crm.case.categ', 'Category', domain="[('section_id','=',section_id),('object_id.model', '=', 'project.issue')]"),
|
||||
'type_id': fields.many2one('project.task.type', 'Stage'),
|
||||
'stage_id': fields.many2one('project.task.type', 'Stage'),
|
||||
'nbr': fields.integer('# of Issues', readonly=True),
|
||||
'working_hours_open': fields.float('Avg. Working Hours to Open', readonly=True),
|
||||
'working_hours_close': fields.float('Avg. Working Hours to Close', readonly=True),
|
||||
|
@ -87,7 +87,7 @@ class project_issue_report(osv.osv):
|
|||
c.working_hours_close,
|
||||
c.section_id,
|
||||
c.categ_id,
|
||||
c.type_id,
|
||||
c.stage_id,
|
||||
to_char(c.date_closed, 'YYYY-mm-dd') as date_closed,
|
||||
c.company_id as company_id,
|
||||
c.priority as priority,
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<field name="name" invisible="1"/>
|
||||
<field name="month" invisible="1"/>
|
||||
<field name="project_id" invisible="1"/>
|
||||
<field name="type_id" invisible="1"/>
|
||||
<field name="stage_id" invisible="1"/>
|
||||
<field name="version_id" string="Version" invisible="1"/>
|
||||
<field name="priority" invisible="1"/>
|
||||
<field name="company_id" invisible="1" groups="base.group_multi_company"/>
|
||||
|
@ -103,7 +103,7 @@
|
|||
<filter string="Version" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'version_id'}"/>
|
||||
<separator orientation="vertical" />
|
||||
<filter string="Priority" icon="terp-rating-rated" domain="[]" context="{'group_by':'priority'}" />
|
||||
<filter string="Stage" icon="terp-stage" domain="[]" context="{'group_by':'type_id'}"/>
|
||||
<filter string="Stage" icon="terp-stage" domain="[]" context="{'group_by':'stage_id'}"/>
|
||||
<filter string="Status" icon="terp-stock_effects-object-colorize"
|
||||
domain="[]" context="{'group_by':'state'}" />
|
||||
<separator orientation="vertical"/>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
I check the issue is in cancel state.
|
||||
-
|
||||
!assert {model: project.issue, id: crm_case_buginaccountsmodule0, severity: error, string: Issue is in cancel state}:
|
||||
- state == 'cancel'
|
||||
- state == 'cancelled'
|
||||
-
|
||||
I re-open the Issue.
|
||||
-
|
||||
|
@ -37,7 +37,7 @@
|
|||
I check the issue is in cancel state.
|
||||
-
|
||||
!assert {model: project.issue, id: crm_case_buginaccountsmodule0, severity: error, string: Issue is in cancel state}:
|
||||
- state == 'cancel'
|
||||
- state == 'cancelled'
|
||||
-
|
||||
I close Issue.
|
||||
-
|
||||
|
@ -57,4 +57,4 @@
|
|||
I check the issue is in cancel state.
|
||||
-
|
||||
!assert {model: project.issue, id: crm_case_buginaccountsmodule0, severity: error, string: Issue is in cancel state}:
|
||||
- state == 'cancel'
|
||||
- state == 'cancelled'
|
||||
|
|
|
@ -330,7 +330,7 @@
|
|||
<field name="type">search</field>
|
||||
<field name="inherit_id" ref="project.view_task_search_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="project_id" position="after">
|
||||
<field name="user_id" position="before">
|
||||
<field name="phase_id" select="1"/>
|
||||
</field>
|
||||
</field>
|
||||
|
|
|
@ -129,7 +129,7 @@
|
|||
<field name="sequence"/>
|
||||
</group>
|
||||
<separator string="Miscellaneous" colspan="4"/>
|
||||
<field name="type_id"/>
|
||||
<field name="stage_id"/>
|
||||
<field name="active"/>
|
||||
<field name="partner_id"/>
|
||||
<separator colspan="4" string="Notes"/>
|
||||
|
|
|
@ -265,7 +265,6 @@
|
|||
<field model="res.users" name="user_id" search="[('login','=','demo')]"/>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="name">Review all English Terms</field>
|
||||
<field name="state">done</field>
|
||||
<field eval="time.strftime('%Y-%m-%d')" name="date_end"/>
|
||||
<field name="product_backlog_id" ref="scrum_product_backlog_3"/>
|
||||
</record>
|
||||
|
@ -274,7 +273,6 @@
|
|||
<field model="res.users" name="user_id" search="[('login','=','demo')]"/>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="name">Review all french terms</field>
|
||||
<field name="state">done</field>
|
||||
<field eval="time.strftime('%Y-%m-%d')" name="date_end"/>
|
||||
<field name="product_backlog_id" ref="scrum_product_backlog_3"/>
|
||||
</record>
|
||||
|
@ -283,7 +281,6 @@
|
|||
<field model="res.users" name="user_id" search="[('login','=','demo')]"/>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="name">Analytic Accounting features</field>
|
||||
<field name="state">done</field>
|
||||
<field eval="time.strftime('%Y-%m-%d')" name="date_end"/>
|
||||
<field name="product_backlog_id" ref="scrum_product_backlog_1"/>
|
||||
</record>
|
||||
|
@ -292,7 +289,6 @@
|
|||
<field model="res.users" name="user_id" search="[('login','=','demo')]"/>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="name">Test and improve automatic migration system</field>
|
||||
<field name="state">open</field>
|
||||
<field name="product_backlog_id" ref="scrum_product_backlog_0"/>
|
||||
</record>
|
||||
<record id="scrum_task_7" model="project.task">
|
||||
|
@ -300,7 +296,6 @@
|
|||
<field model="res.users" name="user_id" search="[('login','=','demo')]"/>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="name">General accounting features</field>
|
||||
<field name="state">open</field>
|
||||
<field name="product_backlog_id" ref="scrum_product_backlog_1"/>
|
||||
</record>
|
||||
<record id="scrum_task_8" model="project.task">
|
||||
|
@ -316,7 +311,6 @@
|
|||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="description">Cash book, general ledger, accounts list, aged trial balance</field>
|
||||
<field name="name">Accounting Report General</field>
|
||||
<field name="state">open</field>
|
||||
<field eval="[(6,0,[ref('scrum_task_8')])]" name="child_ids"/>
|
||||
<field name="product_backlog_id" ref="scrum_product_backlog_1"/>
|
||||
</record>
|
||||
|
@ -332,7 +326,6 @@
|
|||
<field model="res.users" name="user_id" search="[('login','=','demo')]"/>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="name">Accounting Report Analytic</field>
|
||||
<field name="state">open</field>
|
||||
<field name="product_backlog_id" ref="scrum_product_backlog_1"/>
|
||||
</record>
|
||||
<record id="scrum_task_12" model="project.task">
|
||||
|
@ -340,7 +333,6 @@
|
|||
<field model="res.users" name="user_id" search="[('login','=','demo')]"/>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="name">Bugfix - memory leak</field>
|
||||
<field name="state">done</field>
|
||||
<field eval="time.strftime('%Y-%m-%d')" name="date_end"/>
|
||||
<field name="product_backlog_id" ref="scrum_product_backlog_4"/>
|
||||
</record>
|
||||
|
@ -349,7 +341,6 @@
|
|||
<field model="res.users" name="user_id" search="[('login','=','demo')]"/>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="name">Bugfix - Translations</field>
|
||||
<field name="state">open</field>
|
||||
<field eval="[(6,0,[ref('scrum_task_12')])]" name="child_ids"/>
|
||||
<field name="product_backlog_id" ref="scrum_product_backlog_4"/>
|
||||
</record>
|
||||
|
@ -358,7 +349,6 @@
|
|||
<field model="res.users" name="user_id" search="[('login','=','demo')]"/>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="name">Finish the automated plugin system</field>
|
||||
<field name="state">pending</field>
|
||||
<field name="product_backlog_id" ref="scrum_product_backlog_2"/>
|
||||
</record>
|
||||
<record id="scrum_task_15" model="project.task">
|
||||
|
@ -373,7 +363,6 @@
|
|||
<field model="res.users" name="user_id" search="[('login','=','demo')]"/>
|
||||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="name">Test 3.2.0 before releasing</field>
|
||||
<field name="state">open</field>
|
||||
<field name="product_backlog_id" ref="scrum_product_backlog_5"/>
|
||||
</record>
|
||||
<record id="scrum_task_17" model="project.task">
|
||||
|
@ -382,7 +371,6 @@
|
|||
<field name="project_id" ref="project.project_project_9"/>
|
||||
<field name="description">default values, onchange, required, add on top or bottom and shortcuts (Ctrl S, Ctrl X, ...)</field>
|
||||
<field name="name">Editable trees</field>
|
||||
<field name="state">open</field>
|
||||
<field name="product_backlog_id" ref="scrum_product_backlog_7"/>
|
||||
</record>
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
<field name="type_id" invisible="context.get('set_visible',False)"/>
|
||||
<field name="date_start" invisible="1"/>
|
||||
<field name="date_end" invisible="1"/>
|
||||
<button name="next_type" invisible="context.get('set_visible',False)"
|
||||
<button name="stage_next" invisible="context.get('set_visible',False)"
|
||||
states="draft,open,pending"
|
||||
string="Change Stage"
|
||||
type="object"
|
||||
|
@ -568,7 +568,7 @@
|
|||
<field name="type">search</field>
|
||||
<field name="inherit_id" ref="project.view_task_search_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="project_id" position="after">
|
||||
<field name="user_id" position="before">
|
||||
<field name="sprint_id" context="{'sprint_invisible':False}">
|
||||
<filter icon="terp-check" context="{'sprint_invisible':False}" domain="[('sprint_id.state','in',('draft','open'))]" help="Current Sprints"/>
|
||||
<filter icon="gtk-find" context="{'sprint_invisible':False}" domain="[]" help="View Sprints"/>
|
||||
|
|
Loading…
Reference in New Issue