[IMP]: crm: Major changes in crm
* Removed crm.case * Inherited other cases from mailgate.thread * Changes in lead and opportunity: Removed dependency from crm.case and added for mailgate.thread * still lot of things to fix(TODO): meeting, phonecall/reports bzr revid: rpa@tinyerp.com-20100503123048-642v3gt4gorubmrs
This commit is contained in:
parent
8c6721d3ab
commit
ee4052bc1a
|
@ -30,7 +30,7 @@ import crm_opportunity
|
|||
import crm_phonecall
|
||||
|
||||
import crm_installer
|
||||
import report
|
||||
#import report
|
||||
import wizard
|
||||
|
||||
|
||||
|
|
|
@ -91,12 +91,12 @@ between mails and Open ERP.""",
|
|||
'crm_opportunity_menu.xml',
|
||||
|
||||
'security/crm_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
# 'security/ir.model.access.csv',
|
||||
|
||||
'report/crm_report_view.xml',
|
||||
'report/crm_lead_report_view.xml',
|
||||
# 'report/crm_opportunity_report_view.xml' ,
|
||||
'report/crm_phonecall_report_view.xml',
|
||||
## 'report/crm_report_view.xml',
|
||||
# 'report/crm_lead_report_view.xml',
|
||||
## 'report/crm_opportunity_report_view.xml' ,
|
||||
# 'report/crm_phonecall_report_view.xml',
|
||||
|
||||
'process/crm_configuration_process.xml',
|
||||
'crm_installer_view.xml'
|
||||
|
|
|
@ -241,503 +241,6 @@ def _links_get(self, cr, uid, context=None):
|
|||
res = obj.read(cr, uid, ids, ['object', 'name'], context)
|
||||
return [(r['object'], r['name']) for r in res]
|
||||
|
||||
class crm_case(osv.osv):
|
||||
""" CRM Case """
|
||||
|
||||
_name = "crm.case"
|
||||
_description = "Case"
|
||||
|
||||
def _email_last(self, cursor, user, ids, name, arg, context=None):
|
||||
"""Return last email from History
|
||||
@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’s IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
res = {}
|
||||
for case in self.browse(cursor, user, ids):
|
||||
if case.history_line:
|
||||
res[case.id] = case.history_line[0].description
|
||||
else:
|
||||
res[case.id] = False
|
||||
return res
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
"""Overrides orm copy method
|
||||
@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’s IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
if not default:
|
||||
default = {}
|
||||
default.update({'state': 'draft', 'id': False})
|
||||
return super(crm_case, self).copy(cr, uid, id, default, context)
|
||||
|
||||
def _get_log_ids(self, cr, uid, ids, field_names, arg, context=None):
|
||||
"""Gets id for case log from history of particular case
|
||||
@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
|
||||
@return:Dictionary of History Ids
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
result = {}
|
||||
history_obj = False
|
||||
model_obj = self.pool.get('ir.model')
|
||||
|
||||
if 'history_line' in field_names:
|
||||
history_obj = self.pool.get('crm.case.history')
|
||||
name = 'history_line'
|
||||
|
||||
if 'log_ids' in field_names:
|
||||
history_obj = self.pool.get('crm.case.log')
|
||||
name = 'log_ids'
|
||||
|
||||
if not history_obj:
|
||||
return result
|
||||
|
||||
for case in self.browse(cr, uid, ids, context):
|
||||
model_ids = model_obj.search(cr, uid, [('model', '=', case._name)])
|
||||
history_ids = history_obj.search(cr, uid, [('model_id', '=', model_ids[0]), \
|
||||
('res_id', '=', case.id)])
|
||||
if history_ids:
|
||||
result[case.id] = {name: history_ids}
|
||||
else:
|
||||
result[case.id] = {name: []}
|
||||
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'id': fields.integer('ID', readonly=True),
|
||||
'name': fields.char('Description', size=1024, required=True),
|
||||
'active': fields.boolean('Active', help="If the active field is set to\
|
||||
true, it will allow you to hide the case without removing it."),
|
||||
'description': fields.text('Description'),
|
||||
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
|
||||
select=True, help='Sales team to which Case belongs to.\
|
||||
Define Responsible user and Email account for mail gateway.'),
|
||||
'email_from': fields.char('Email', size=128, help="These people will receive email."),
|
||||
'email_cc': fields.text('Watchers Emails', size=252 , help="These people\
|
||||
will receive a copy of the future" \
|
||||
" communication between partner and users by email"),
|
||||
'probability': fields.float('Probability'),
|
||||
'email_last': fields.function(_email_last, method=True,
|
||||
string='Latest E-Mail', type='text'),
|
||||
'partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \
|
||||
domain="[('partner_id','=',partner_id)]"),
|
||||
'create_date': fields.datetime('Creation Date' , readonly=True),
|
||||
'write_date': fields.datetime('Update Date' , readonly=True),
|
||||
'date_deadline': fields.date('Deadline'),
|
||||
'user_id': fields.many2one('res.users', 'Responsible'),
|
||||
'history_line': fields.function(_get_log_ids, method=True, type='one2many', \
|
||||
multi="history_line", relation="crm.case.history", string="Communication"),
|
||||
'log_ids': fields.function(_get_log_ids, method=True, type='one2many', \
|
||||
multi="log_ids", relation="crm.case.log", string="Logs History"),
|
||||
'stage_id': fields.many2one ('crm.case.stage', 'Stage', \
|
||||
domain="[('section_id','=',section_id),\
|
||||
('object_id.model', '=', 'crm.lead')]"),
|
||||
'state': fields.selection(AVAILABLE_STATES, 'State', 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\'.'),
|
||||
'company_id': fields.many2one('res.company', 'Company'),
|
||||
}
|
||||
def _get_default_partner_address(self, cr, uid, context):
|
||||
"""Gives id of default address for current user
|
||||
@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 context: A standard dictionary for contextual values
|
||||
"""
|
||||
if not context.get('portal', False):
|
||||
return False
|
||||
return self.pool.get('res.users').browse(cr, uid, uid, context).address_id.id
|
||||
|
||||
def _get_default_partner(self, cr, uid, context):
|
||||
"""Gives id of partner for current user
|
||||
@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 context: A standard dictionary for contextual values
|
||||
"""
|
||||
if not context.get('portal', False):
|
||||
return False
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context)
|
||||
if not user.address_id:
|
||||
return False
|
||||
return user.address_id.partner_id.id
|
||||
|
||||
def _get_default_email(self, cr, uid, context):
|
||||
"""Gives default email address for current user
|
||||
@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 context: A standard dictionary for contextual values
|
||||
"""
|
||||
if not context.get('portal', False):
|
||||
return False
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context)
|
||||
if not user.address_id:
|
||||
return False
|
||||
return user.address_id.email
|
||||
|
||||
def _get_default_user(self, cr, uid, context):
|
||||
"""Gives current user id
|
||||
@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 context: A standard dictionary for contextual values
|
||||
"""
|
||||
if context.get('portal', False):
|
||||
return False
|
||||
return uid
|
||||
|
||||
def _get_section(self, cr, uid, context):
|
||||
"""Gives section id for current User
|
||||
@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 context: A standard dictionary for contextual values
|
||||
"""
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
return user.context_section_id.id or False
|
||||
|
||||
_defaults = {
|
||||
'active': lambda *a: 1,
|
||||
'user_id': _get_default_user,
|
||||
'partner_id': _get_default_partner,
|
||||
'partner_address_id': _get_default_partner_address,
|
||||
'email_from': _get_default_email,
|
||||
'state': lambda *a: 'draft',
|
||||
'section_id': _get_section,
|
||||
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.case', context=c),
|
||||
}
|
||||
|
||||
_order = 'date_deadline desc, create_date desc,id desc'
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
"""Overrides orm unlink method
|
||||
@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
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
hist_obj = self.pool.get('crm.case.history')
|
||||
log_obj = self.pool.get('crm.case.log')
|
||||
|
||||
for case in self.browse(cr, uid, ids, context):
|
||||
if (not case.section_id.allow_unlink) and (case.state <> 'draft'):
|
||||
raise osv.except_osv(_('Warning !'),
|
||||
_('You can not delete this case. You should better cancel it.'))
|
||||
|
||||
# Also removing history and logs
|
||||
history_ids = map(lambda x: x.id, case.history_line)
|
||||
log_ids = map(lambda x: x.id, case.log_ids)
|
||||
hist_obj.unlink(cr, uid, history_ids, context=context)
|
||||
log_obj.unlink(cr, uid, log_ids, context=context)
|
||||
return super(crm_case, self).unlink(cr, uid, ids, context)
|
||||
|
||||
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"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
s = self.get_stage_dict(cr, uid, ids, context=context)
|
||||
for case in self.browse(cr, uid, ids, context):
|
||||
section = (case.section_id.id or False)
|
||||
if section in s:
|
||||
st = case.stage_id.id or False
|
||||
if st in s[section]:
|
||||
self.write(cr, uid, [case.id], {'stage_id': s[section][st]})
|
||||
return True
|
||||
|
||||
def get_stage_dict(self, cr, uid, ids, context=None):
|
||||
"""This function gives dictionary for stage according to stage levels
|
||||
@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"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
sid = self.pool.get('crm.case.stage').search(cr, uid, \
|
||||
[('object_id.model', '=', self._name)], context=context)
|
||||
s = {}
|
||||
previous = {}
|
||||
for stage in self.pool.get('crm.case.stage').browse(cr, uid, sid, context=context):
|
||||
section = stage.section_id.id or False
|
||||
s.setdefault(section, {})
|
||||
s[section][previous.get(section, False)] = stage.id
|
||||
previous[section] = stage.id
|
||||
return s
|
||||
|
||||
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"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
s = self.get_stage_dict(cr, uid, ids, context=context)
|
||||
for case in self.browse(cr, uid, ids, context):
|
||||
section = (case.section_id.id or False)
|
||||
|
||||
if section in s:
|
||||
st = case.stage_id.id or False
|
||||
s[section] = dict([(v, k) for (k, v) in s[section].iteritems()])
|
||||
if st in s[section]:
|
||||
self.write(cr, uid, [case.id], {'stage_id': s[section][st]})
|
||||
return True
|
||||
|
||||
def __history(self, cr, uid, cases, keyword, history=False, email=False, details=None, email_from=False, message_id=False, context={}):
|
||||
"""
|
||||
@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 cases: a browse record list
|
||||
@param keyword: Case action keyword e.g.: If case is closed "Close" keyword is used
|
||||
@param history: Value True/False, If True it makes entry in case History otherwise in Case Log
|
||||
@param email: Email address if any
|
||||
@param details: Details of case history if any
|
||||
@param context: A standard dictionary for contextual values"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
# The mailgate sends the ids of the cases and not the object list
|
||||
if all(isinstance(case_id, (int, long)) for case_id in cases) and context.get('model'):
|
||||
cases = self.pool.get(context['model']).browse(cr, uid, cases, context=context)
|
||||
|
||||
model_obj = self.pool.get('ir.model')
|
||||
obj = self.pool.get('crm.case.log')
|
||||
for case in cases:
|
||||
model_ids = model_obj.search(cr, uid, [('model', '=', case._name)])
|
||||
data = {
|
||||
'name': keyword,
|
||||
'user_id': uid,
|
||||
'date': time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'model_id' : model_ids and model_ids[0] or False,
|
||||
'res_id': case.id,
|
||||
'section_id': case.section_id.id,
|
||||
'message_id':message_id
|
||||
}
|
||||
|
||||
if history:
|
||||
obj = self.pool.get('crm.case.history')
|
||||
data['description'] = details or case.description
|
||||
data['email_to'] = email or \
|
||||
(case.section_id and case.section_id.reply_to) or \
|
||||
(case.user_id and case.user_id.address_id and \
|
||||
case.user_id.address_id.email) or tools.config.get('email_from', False)
|
||||
data['email_from'] = email_from or \
|
||||
(case.section_id and case.section_id.reply_to) or \
|
||||
(case.user_id and case.user_id.address_id and \
|
||||
case.user_id.address_id.email) or tools.config.get('email_from', False)
|
||||
res = obj.create(cr, uid, data, context)
|
||||
return True
|
||||
|
||||
_history = __history
|
||||
history = __history
|
||||
|
||||
def create(self, cr, uid, *args, **argv):
|
||||
"""Overrides orm create method
|
||||
@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 *args: Tuple Value for additional Params
|
||||
@param **argv: Dictionay of Keyword Params
|
||||
"""
|
||||
res = super(crm_case, self).create(cr, uid, *args, **argv)
|
||||
cases = self.browse(cr, uid, [res])
|
||||
cases[0].state # to fill the browse record cache
|
||||
self._action(cr, uid, cases, 'draft')
|
||||
return res
|
||||
|
||||
def add_reply(self, cursor, user, ids, context=None):
|
||||
"""This function finds last email and gives its description value for reply mail
|
||||
@param self: The object pointer
|
||||
@param cursor: the current row, from the database cursor,
|
||||
@param user: the current user’s ID for security checks
|
||||
@param ids: List of case IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
for case in self.browse(cursor, user, ids, context=context):
|
||||
if case.email_last:
|
||||
description = case.email_last
|
||||
self.write(cursor, user, case.id, {
|
||||
'description': '> ' + description.replace('\n', '\n> '),
|
||||
}, context=context)
|
||||
return True
|
||||
|
||||
def onchange_partner_id(self, cr, uid, ids, part, email=False):
|
||||
"""This function returns value of partner address based on partner
|
||||
@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 part: Partner's id
|
||||
@email: Partner's email ID
|
||||
"""
|
||||
if not part:
|
||||
return {'value': {'partner_address_id': False,
|
||||
'email_from': False,
|
||||
}}
|
||||
addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['contact'])
|
||||
data = {'partner_address_id': addr['contact']}
|
||||
data.update(self.onchange_partner_address_id(cr, uid, ids, addr['contact'])['value'])
|
||||
return {'value': data}
|
||||
|
||||
def onchange_partner_address_id(self, cr, uid, ids, add, email=False):
|
||||
"""This function returns value of partner email based on Partner Address
|
||||
@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 add: Id of Partner's address
|
||||
@email: Partner's email ID
|
||||
"""
|
||||
if not add:
|
||||
return {'value': {'email_from': False}}
|
||||
address = self.pool.get('res.partner.address').browse(cr, uid, add)
|
||||
return {'value': {'email_from': address.email}}
|
||||
|
||||
def case_close(self, cr, uid, ids, *args):
|
||||
"""Closes Case
|
||||
@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 *args: Tuple Value for additional Params
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self.__history(cr, uid, cases, _('Close'))
|
||||
self.write(cr, uid, ids, {'state': 'done',
|
||||
'date_closed': time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'probability' : 100.0})
|
||||
#
|
||||
# We use the cache of cases to keep the old case state
|
||||
#
|
||||
self._action(cr, uid, cases, 'done')
|
||||
return True
|
||||
|
||||
def case_escalate(self, cr, uid, ids, *args):
|
||||
"""Escalates case to top level
|
||||
@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 *args: Tuple Value for additional Params
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
for case in cases:
|
||||
data = {'active': True, 'user_id': False}
|
||||
|
||||
if case.section_id.parent_id:
|
||||
data['section_id'] = case.section_id.parent_id.id
|
||||
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 this case.\nYou are already at the top level.'))
|
||||
self.write(cr, uid, [case.id], data)
|
||||
cases = self.browse(cr, uid, ids)
|
||||
self.__history(cr, uid, cases, _('Escalate'))
|
||||
self._action(cr, uid, cases, 'escalate')
|
||||
return True
|
||||
|
||||
def case_open(self, cr, uid, ids, *args):
|
||||
"""Opens Case
|
||||
@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 *args: Tuple Value for additional Params
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
self.__history(cr, uid, cases, _('Open'))
|
||||
|
||||
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._action(cr, uid, cases, 'open')
|
||||
return True
|
||||
|
||||
def case_cancel(self, cr, uid, ids, *args):
|
||||
"""Cancels Case
|
||||
@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 *args: Tuple Value for additional Params
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self.__history(cr, uid, cases, _('Cancel'))
|
||||
self.write(cr, uid, ids, {'state': 'cancel',
|
||||
'active': True,
|
||||
'probability' : 0.0})
|
||||
self._action(cr, uid, cases, 'cancel')
|
||||
return True
|
||||
|
||||
def case_pending(self, cr, uid, ids, *args):
|
||||
"""Marks case as pending
|
||||
@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 *args: Tuple Value for additional Params
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self.__history(cr, uid, cases, _('Pending'))
|
||||
self.write(cr, uid, ids, {'state': 'pending', 'active': True})
|
||||
self._action(cr, uid, cases, 'pending')
|
||||
return True
|
||||
|
||||
def case_reset(self, cr, uid, ids, *args):
|
||||
"""Resets case as draft
|
||||
@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 *args: Tuple Value for additional Params
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self.__history(cr, uid, cases, _('Draft'))
|
||||
self.write(cr, uid, ids, {'state': 'draft', 'active': True})
|
||||
self._action(cr, uid, cases, 'draft')
|
||||
return True
|
||||
|
||||
crm_case()
|
||||
|
||||
|
||||
class crm_case_log(osv.osv):
|
||||
""" Case Communication History """
|
||||
|
|
|
@ -37,7 +37,7 @@ import crm
|
|||
class case(osv.osv):
|
||||
""" Case """
|
||||
|
||||
_inherit = 'crm.case'
|
||||
_inherit = 'mailgate.thread'
|
||||
_description = 'case'
|
||||
|
||||
_columns = {
|
||||
|
@ -89,7 +89,7 @@ class case(osv.osv):
|
|||
attach_to_send = None
|
||||
|
||||
if attach:
|
||||
attach_ids = self.pool.get('ir.attachment').search(cr, uid, [('res_model', '=', 'crm.case'), ('res_id', '=', case.id)])
|
||||
attach_ids = self.pool.get('ir.attachment').search(cr, uid, [('res_model', '=', 'mailgate.thread'), ('res_id', '=', case.id)])
|
||||
attach_to_send = self.pool.get('ir.attachment').read(cr, uid, attach_ids, ['datas_fname','datas'])
|
||||
attach_to_send = map(lambda x: (x['datas_fname'], base64.decodestring(x['datas'])), attach_to_send)
|
||||
|
||||
|
@ -195,16 +195,18 @@ class base_action_rule(osv.osv):
|
|||
ok = ok and (not action.trg_section_id or action.trg_section_id.id==obj.section_id.id)
|
||||
if hasattr(obj, 'categ_id'):
|
||||
ok = ok and (not action.trg_categ_id or action.trg_categ_id.id==obj.categ_id.id)
|
||||
if hasattr(obj, 'history_line'):
|
||||
ok = ok and (not action.trg_max_history or action.trg_max_history<=(len(obj.history_line)+1))
|
||||
reg_history = action.regex_history
|
||||
result_history = True
|
||||
if reg_history:
|
||||
ptrn = re.compile(str(reg_history))
|
||||
if obj.history_line:
|
||||
_result = ptrn.search(str(obj.history_line[0].description))
|
||||
if not _result:
|
||||
result_history = False
|
||||
|
||||
# TODO: history_line is removed
|
||||
# if hasattr(obj, 'history_line'):
|
||||
# ok = ok and (not action.trg_max_history or action.trg_max_history<=(len(obj.history_line)+1))
|
||||
# reg_history = action.regex_history
|
||||
# result_history = True
|
||||
# if reg_history:
|
||||
# ptrn = re.compile(str(reg_history))
|
||||
# if obj.history_line:
|
||||
# _result = ptrn.search(str(obj.history_line[0].description))
|
||||
# if not _result:
|
||||
# result_history = False
|
||||
regex_h = not reg_history or result_history
|
||||
ok = ok and regex_h
|
||||
return ok
|
||||
|
|
|
@ -33,7 +33,7 @@ class crm_lead(osv.osv):
|
|||
_name = "crm.lead"
|
||||
_description = "Leads Cases"
|
||||
_order = "priority, id desc"
|
||||
_inherit = ['res.partner.address', 'crm.case']
|
||||
_inherit = ['res.partner.address', 'mailgate.thread']
|
||||
|
||||
def case_open(self, cr, uid, ids, *args):
|
||||
"""
|
||||
|
@ -106,7 +106,19 @@ class crm_lead(osv.osv):
|
|||
return res
|
||||
|
||||
_columns = {
|
||||
|
||||
# From crm.case
|
||||
'email_from': fields.char('Email', size=128, help="These people will receive email."),
|
||||
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
|
||||
select=True, help='Sales team to which Case belongs to.\
|
||||
Define Responsible user and Email account for mail gateway.'),
|
||||
'create_date': fields.datetime('Creation Date' , readonly=True),
|
||||
'email_cc': fields.text('Watchers Emails', size=252 , help="These people\
|
||||
will receive a copy of the future" \
|
||||
" communication between partner and users by email"),
|
||||
'description': fields.text('Description'),
|
||||
'write_date': fields.datetime('Update Date' , readonly=True),
|
||||
|
||||
# Lead fields
|
||||
'categ_id': fields.many2one('crm.case.categ', 'Lead Source', \
|
||||
domain="[('section_id','=',section_id),\
|
||||
('object_id.model', '=', 'crm.lead')]"),
|
||||
|
@ -139,7 +151,69 @@ class crm_lead(osv.osv):
|
|||
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
|
||||
}
|
||||
|
||||
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"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
s = self.get_stage_dict(cr, uid, ids, context=context)
|
||||
for case in self.browse(cr, uid, ids, context):
|
||||
section = (case.section_id.id or False)
|
||||
if section in s:
|
||||
st = case.stage_id.id or False
|
||||
if st in s[section]:
|
||||
self.write(cr, uid, [case.id], {'stage_id': s[section][st]})
|
||||
return True
|
||||
|
||||
def get_stage_dict(self, cr, uid, ids, context=None):
|
||||
"""This function gives dictionary for stage according to stage levels
|
||||
@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"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
sid = self.pool.get('crm.case.stage').search(cr, uid, \
|
||||
[('object_id.model', '=', self._name)], context=context)
|
||||
s = {}
|
||||
previous = {}
|
||||
for stage in self.pool.get('crm.case.stage').browse(cr, uid, sid, context=context):
|
||||
section = stage.section_id.id or False
|
||||
s.setdefault(section, {})
|
||||
s[section][previous.get(section, False)] = stage.id
|
||||
previous[section] = stage.id
|
||||
return s
|
||||
|
||||
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"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
s = self.get_stage_dict(cr, uid, ids, context=context)
|
||||
for case in self.browse(cr, uid, ids, context):
|
||||
section = (case.section_id.id or False)
|
||||
|
||||
if section in s:
|
||||
st = case.stage_id.id or False
|
||||
s[section] = dict([(v, k) for (k, v) in s[section].iteritems()])
|
||||
if st in s[section]:
|
||||
self.write(cr, uid, [case.id], {'stage_id': s[section][st]})
|
||||
return True
|
||||
|
||||
def convert_opportunity(self, cr, uid, ids, context=None):
|
||||
""" Precomputation for converting lead to opportunity
|
||||
@param cr: the current row, from the database cursor,
|
||||
|
@ -193,6 +267,118 @@ class crm_lead(osv.osv):
|
|||
'nodestroy': True
|
||||
}
|
||||
return value
|
||||
|
||||
# From crm.case
|
||||
|
||||
def case_close(self, cr, uid, ids, *args):
|
||||
"""Closes Case
|
||||
@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 *args: Tuple Value for additional Params
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self._history(cr, uid, cases, _('Close'))
|
||||
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._action(cr, uid, cases, 'done')
|
||||
return True
|
||||
|
||||
def case_escalate(self, cr, uid, ids, *args):
|
||||
"""Escalates case to top level
|
||||
@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 *args: Tuple Value for additional Params
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
for case in cases:
|
||||
data = {'active': True, 'user_id': False}
|
||||
|
||||
if case.section_id.parent_id:
|
||||
data['section_id'] = case.section_id.parent_id.id
|
||||
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 this case.\nYou are already at the top level.'))
|
||||
self.write(cr, uid, [case.id], data)
|
||||
cases = self.browse(cr, uid, ids)
|
||||
self._history(cr, uid, cases, _('Escalate'))
|
||||
self._action(cr, uid, cases, 'escalate')
|
||||
return True
|
||||
|
||||
def case_open(self, cr, uid, ids, *args):
|
||||
"""Opens Case
|
||||
@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 *args: Tuple Value for additional Params
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
self._history(cr, uid, cases, _('Open'))
|
||||
|
||||
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._action(cr, uid, cases, 'open')
|
||||
return True
|
||||
|
||||
def case_cancel(self, cr, uid, ids, *args):
|
||||
"""Cancels Case
|
||||
@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 *args: Tuple Value for additional Params
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self._history(cr, uid, cases, _('Cancel'))
|
||||
self.write(cr, uid, ids, {'state': 'cancel',
|
||||
'active': True})
|
||||
self._action(cr, uid, cases, 'cancel')
|
||||
return True
|
||||
|
||||
def case_pending(self, cr, uid, ids, *args):
|
||||
"""Marks case as pending
|
||||
@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 *args: Tuple Value for additional Params
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self._history(cr, uid, cases, _('Pending'))
|
||||
self.write(cr, uid, ids, {'state': 'pending', 'active': True})
|
||||
self._action(cr, uid, cases, 'pending')
|
||||
return True
|
||||
|
||||
def case_reset(self, cr, uid, ids, *args):
|
||||
"""Resets case as draft
|
||||
@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 *args: Tuple Value for additional Params
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self._history(cr, uid, cases, _('Draft'))
|
||||
self.write(cr, uid, ids, {'state': 'draft', 'active': True})
|
||||
self._action(cr, uid, cases, 'draft')
|
||||
return True
|
||||
|
||||
|
||||
crm_lead()
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
<field name="arch" type="xml">
|
||||
<form string="Leads Form">
|
||||
<group colspan="4" col="7">
|
||||
<field name="name" required="1" string="Name"/>
|
||||
<field name="name" required="1"/>
|
||||
<field name="priority"/>
|
||||
<field name="date_deadline"/>
|
||||
<button
|
||||
|
@ -48,8 +48,7 @@
|
|||
string="Convert"
|
||||
help="Convert to Opportunity"
|
||||
icon="gtk-index"
|
||||
type="object"
|
||||
attrs="{'invisible':[('opportunity_id','!=',False)]}"/>
|
||||
type="object"/>
|
||||
<newline />
|
||||
<field name="section_id" colspan="1"
|
||||
widget="selection" />
|
||||
|
@ -153,7 +152,8 @@
|
|||
<group colspan="4">
|
||||
<field colspan="4" name="email_cc" string="CC"/>
|
||||
</group>
|
||||
<field name="history_line" colspan="4" nolabel="1" mode="form,tree">
|
||||
<!-- TODO-->
|
||||
<field name="message_ids" colspan="4" nolabel="1" mode="form,tree">
|
||||
<form string="Communication history">
|
||||
<group col="7" colspan="4">
|
||||
<field name="date"/>
|
||||
|
@ -179,7 +179,7 @@
|
|||
<field name="email_to"/>
|
||||
<field name="description"/>
|
||||
</tree>
|
||||
</field>
|
||||
</field>
|
||||
<button colspan="2" string="Send New Email"
|
||||
name="%(action_crm_send_mail)d"
|
||||
context="{'mail':'new', 'model': 'crm.lead'}"
|
||||
|
|
|
@ -38,8 +38,8 @@ from tools import command_re
|
|||
class crm_cases(osv.osv):
|
||||
""" crm cases """
|
||||
|
||||
_name = "crm.case"
|
||||
_inherit = "crm.case"
|
||||
_name = "mailgate.thread"
|
||||
_inherit = "mailgate.thread"
|
||||
|
||||
def message_new(self, cr, uid, msg, context):
|
||||
"""
|
||||
|
|
|
@ -26,10 +26,6 @@ from datetime import datetime, timedelta
|
|||
from tools.translate import _
|
||||
from base_calendar import base_calendar
|
||||
|
||||
class crm_opportunity(osv.osv):
|
||||
_name = 'crm.opportunity'
|
||||
crm_opportunity()
|
||||
|
||||
|
||||
class crm_phonecall(osv.osv):
|
||||
""" CRM Phonecall """
|
||||
|
@ -43,14 +39,20 @@ class crm_meeting(osv.osv):
|
|||
_name = 'crm.meeting'
|
||||
_description = "Meeting Cases"
|
||||
_order = "id desc"
|
||||
_inherit = ["crm.case", "calendar.event"]
|
||||
_inherit = ["mailgate.thread", "calendar.event"]
|
||||
|
||||
_columns = {
|
||||
# From crm.case
|
||||
'partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
|
||||
select=True, help='Sales team to which Case belongs to.\
|
||||
Define Responsible user and Email account for mail gateway.'),
|
||||
# Meeting fields
|
||||
'categ_id': fields.many2one('crm.case.categ', 'Meeting Type', \
|
||||
domain="[('object_id.model', '=', 'crm.meeting')]", \
|
||||
),
|
||||
'phonecall_id': fields.many2one ('crm.phonecall', 'Phonecall'),
|
||||
'opportunity_id': fields.many2one ('crm.opportunity', 'Opportunity'),
|
||||
'opportunity_id': fields.many2one ('crm.lead', 'Opportunity', domain="[('type', '=', 'opportunity')]"),
|
||||
'attendee_ids': fields.many2many('calendar.attendee', 'meeting_attendee_rel',\
|
||||
'event_id', 'attendee_id', 'Attendees'),
|
||||
'date_closed': fields.datetime('Closed', readonly=True),
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
id="crm_case_categ_meet_case"
|
||||
name="Schedule a Meeting"
|
||||
res_model="crm.meeting"
|
||||
src_model="crm.case"
|
||||
src_model="mailgate.thread"
|
||||
view_mode="calendar,tree,form,gantt"
|
||||
context="{'default_case_id': active_id, 'default_duration': 4.0}"
|
||||
/>
|
||||
|
|
|
@ -55,78 +55,16 @@ class crm_opportunity(osv.osv):
|
|||
self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')})
|
||||
return res
|
||||
|
||||
def _compute_day(self, cr, uid, ids, fields, args, context={}):
|
||||
"""
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Openday’s IDs
|
||||
@return: difference between current date and log date
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
cal_obj = self.pool.get('resource.calendar')
|
||||
res_obj = self.pool.get('resource.resource')
|
||||
|
||||
res = {}
|
||||
for opportunity in self.browse(cr, uid, ids , context):
|
||||
for field in fields:
|
||||
res[opportunity.id] = {}
|
||||
duration = 0
|
||||
ans = False
|
||||
if field == 'day_open':
|
||||
if opportunity.date_open:
|
||||
date_create = datetime.strptime(opportunity.create_date, "%Y-%m-%d %H:%M:%S")
|
||||
date_open = datetime.strptime(opportunity.date_open, "%Y-%m-%d %H:%M:%S")
|
||||
ans = date_open - date_create
|
||||
date_until = opportunity.date_open
|
||||
elif field == 'day_close':
|
||||
if opportunity.date_closed:
|
||||
date_create = datetime.strptime(opportunity.create_date, "%Y-%m-%d %H:%M:%S")
|
||||
date_close = datetime.strptime(opportunity.date_closed, "%Y-%m-%d %H:%M:%S")
|
||||
date_until = opportunity.date_closed
|
||||
ans = date_close - date_create
|
||||
if ans:
|
||||
resource_id = False
|
||||
if opportunity.user_id:
|
||||
resource_ids = res_obj.search(cr, uid, [('user_id','=',opportunity.user_id.id)])
|
||||
if resource_ids and len(resource_ids):
|
||||
resource_id = resource_ids[0]
|
||||
|
||||
duration = float(ans.days)
|
||||
if opportunity.section_id and opportunity.section_id.resource_calendar_id:
|
||||
duration = float(ans.days) * 24
|
||||
new_dates = cal_obj.interval_get(cr,
|
||||
uid,
|
||||
opportunity.section_id.resource_calendar_id and opportunity.section_id.resource_calendar_id.id or False,
|
||||
mx.DateTime.strptime(opportunity.create_date, '%Y-%m-%d %H:%M:%S'),
|
||||
duration,
|
||||
resource=resource_id
|
||||
)
|
||||
no_days = []
|
||||
date_until = mx.DateTime.strptime(date_until, '%Y-%m-%d %H:%M:%S')
|
||||
for in_time, out_time in new_dates:
|
||||
if in_time.date not in no_days:
|
||||
no_days.append(in_time.date)
|
||||
if out_time > date_until:
|
||||
break
|
||||
duration = len(no_days)
|
||||
res[opportunity.id][field] = abs(int(duration))
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'stage_id': fields.many2one ('crm.case.stage', 'Stage', \
|
||||
domain="[('section_id','=',section_id),\
|
||||
('object_id.model', '=', 'crm.lead')]"),
|
||||
'categ_id': fields.many2one('crm.case.categ', 'Category', \
|
||||
domain="[('section_id','=',section_id), \
|
||||
('object_id.model', '=', 'crm.lead')]"),
|
||||
'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'),
|
||||
'referred': fields.char('Referred By', size=64),
|
||||
# From crm.case
|
||||
'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \
|
||||
domain="[('partner_id','=',partner_id)]"),
|
||||
|
||||
# Opportunity fields
|
||||
'probability': fields.float('Probability (%)'),
|
||||
'planned_revenue': fields.float('Expected Revenue'),
|
||||
'ref': fields.reference('Reference', selection=crm._links_get, size=128),
|
||||
'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128),
|
||||
'date_closed': fields.datetime('Closed', readonly=True),
|
||||
'user_id': fields.many2one('res.users', 'Salesman'),
|
||||
'phone': fields.char("Phone", size=64),
|
||||
'date_deadline': fields.date('Expected Closing'),
|
||||
'date_action': fields.date('Next Action'),
|
||||
|
@ -136,12 +74,44 @@ class crm_opportunity(osv.osv):
|
|||
\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\'.'),
|
||||
|
||||
'date_open': fields.datetime('Opened', readonly=True),
|
||||
'day_open': fields.function(_compute_day, string='Days to Open', \
|
||||
method=True, multi='day_open', type="float", store=True),
|
||||
'day_close': fields.function(_compute_day, string='Days to Close', \
|
||||
method=True, multi='day_close', type="float", store=True),
|
||||
}
|
||||
|
||||
def case_close(self, cr, uid, ids, *args):
|
||||
"""Closes Case
|
||||
@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 *args: Tuple Value for additional Params
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self._history(cr, uid, cases, _('Close'))
|
||||
self.write(cr, uid, ids, {'state': 'done',
|
||||
'date_closed': time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'probability' : 100.0})
|
||||
#
|
||||
# We use the cache of cases to keep the old case state
|
||||
#
|
||||
self._action(cr, uid, cases, 'done')
|
||||
return True
|
||||
|
||||
def case_cancel(self, cr, uid, ids, *args):
|
||||
"""Cancels Case
|
||||
@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 *args: Tuple Value for additional Params
|
||||
"""
|
||||
cases = self.browse(cr, uid, ids)
|
||||
cases[0].state # to fill the browse record cache
|
||||
self._history(cr, uid, cases, _('Cancel'))
|
||||
self.write(cr, uid, ids, {'state': 'cancel',
|
||||
'active': True,
|
||||
'probability' : 0.0})
|
||||
self._action(cr, uid, cases, 'cancel')
|
||||
return True
|
||||
|
||||
def onchange_stage_id(self, cr, uid, ids, stage_id, context={}):
|
||||
|
||||
|
@ -157,35 +127,7 @@ class crm_opportunity(osv.osv):
|
|||
stage = self.pool.get('crm.case.stage').browse(cr, uid, stage_id, context)
|
||||
if not stage.on_change:
|
||||
return {'value':{}}
|
||||
return {'value':{'probability':stage.probability}}
|
||||
|
||||
def stage_next(self, cr, uid, ids, context={}):
|
||||
|
||||
""" @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 stage next’s IDs
|
||||
@param context: A standard dictionary for contextual values """
|
||||
|
||||
res = super(crm_opportunity, self).stage_next(cr, uid, ids, context=context)
|
||||
for case in self.browse(cr, uid, ids, context):
|
||||
if case.stage_id and case.stage_id.on_change:
|
||||
self.write(cr, uid, [case.id], {'probability': case.stage_id.probability})
|
||||
return res
|
||||
|
||||
def stage_previous(self, cr, uid, ids, context={}):
|
||||
|
||||
""" @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 stage previous’s IDs
|
||||
@param context: A standard dictionary for contextual values """
|
||||
|
||||
res = super(crm_opportunity, self).stage_previous(cr, uid, ids, context=context)
|
||||
for case in self.browse(cr, uid, ids, context):
|
||||
if case.stage_id and case.stage_id.on_change:
|
||||
self.write(cr, uid, [case.id], {'probability': case.stage_id.probability})
|
||||
return res
|
||||
return {'value':{'probability': stage.probability}}
|
||||
|
||||
_defaults = {
|
||||
'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.lead', context=c),
|
||||
|
@ -246,3 +188,4 @@ class crm_opportunity(osv.osv):
|
|||
|
||||
crm_opportunity()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -165,7 +165,7 @@
|
|||
<group colspan="4">
|
||||
<field colspan="4" name="email_cc" string="CC"/>
|
||||
</group>
|
||||
<field name="history_line" colspan="4" nolabel="1" mode="form,tree">
|
||||
<field name="message_ids" colspan="4" nolabel="1" mode="form,tree">
|
||||
<form string="Communication history">
|
||||
<group col="7" colspan="4">
|
||||
<field name="date"/>
|
||||
|
|
|
@ -30,9 +30,17 @@ class crm_phonecall(osv.osv):
|
|||
_name = "crm.phonecall"
|
||||
_description = "Phonecall Cases"
|
||||
_order = "id desc"
|
||||
_inherit = 'crm.case'
|
||||
_inherit = 'mailgate.thread'
|
||||
|
||||
_columns = {
|
||||
# From crm.case
|
||||
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
|
||||
select=True, help='Sales team to which Case belongs to.\
|
||||
Define Responsible user and Email account for mail gateway.'),
|
||||
'user_id': fields.many2one('res.users', 'Responsible'),
|
||||
'partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
|
||||
# phonecall fields
|
||||
'duration': fields.float('Duration'),
|
||||
'categ_id': fields.many2one('crm.case.categ', 'Category', \
|
||||
domain="[('section_id','=',section_id),\
|
||||
|
|
|
@ -256,7 +256,7 @@
|
|||
|
||||
<record id="crm_case_calendar-view" model="ir.ui.view">
|
||||
<field name="name">crm.case.calendar</field>
|
||||
<field name="model">crm.case</field>
|
||||
<field name="model">mailgate.thread</field>
|
||||
<field name="type">calendar</field>
|
||||
<field name="arch" type="xml">
|
||||
<calendar color="user_id" date_start="create_date"
|
||||
|
@ -273,7 +273,7 @@
|
|||
|
||||
<record id="crm_case_tree-view" model="ir.ui.view">
|
||||
<field name="name">crm.case.tree</field>
|
||||
<field name="model">crm.case</field>
|
||||
<field name="model">mailgate.thread</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree colors="red:date_deadline<current_date and state=='open';black:state in ('draft', 'cancel','done','pending')" string="Cases">
|
||||
|
@ -311,7 +311,7 @@
|
|||
|
||||
<record id="crm_case-view" model="ir.ui.view">
|
||||
<field name="name">crm.case.form</field>
|
||||
<field name="model">crm.case</field>
|
||||
<field name="model">mailgate.thread</field>
|
||||
<field name="type">form</field>
|
||||
<field name="priority" eval="1"/>
|
||||
<field name="arch" type="xml">
|
||||
|
@ -392,7 +392,8 @@
|
|||
<group colspan="4">
|
||||
<field colspan="4" name="email_cc" string="CC"/>
|
||||
</group>
|
||||
<field name="history_line" colspan="4" nolabel="1" mode="form,tree">
|
||||
<!-- TODO-->
|
||||
<!-- <field name="history_line" colspan="4" nolabel="1" mode="form,tree">
|
||||
<form string="Communication history">
|
||||
<group col="7" colspan="4">
|
||||
<field name="date"/>
|
||||
|
@ -416,7 +417,7 @@
|
|||
<field name="email_to"/>
|
||||
<field name="date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</field> -->
|
||||
<button colspan="4" string="Send New Email"
|
||||
name="%(action_crm_send_mail)d"
|
||||
context="{'mail':'new', 'model': 'crm.case'}"
|
||||
|
@ -431,7 +432,7 @@
|
|||
|
||||
<record id="view_crm_case_filter" model="ir.ui.view">
|
||||
<field name="name">crm.case.select</field>
|
||||
<field name="model">crm.case</field>
|
||||
<field name="model">mailgate.thread</field>
|
||||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Case">
|
||||
|
@ -463,7 +464,7 @@
|
|||
|
||||
<record id="crm_case_categ0-act" model="ir.actions.act_window">
|
||||
<field name="name">Cases</field>
|
||||
<field name="res_model">crm.case</field>
|
||||
<field name="res_model">mailgate.thread</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="crm_case_tree-view"/>
|
||||
<field name="search_view_id" ref="view_crm_case_filter"/>
|
||||
|
@ -471,7 +472,7 @@
|
|||
|
||||
<record id="crm_case_categ0-act_open" model="ir.actions.act_window">
|
||||
<field name="name">Open Cases</field>
|
||||
<field name="res_model">crm.case</field>
|
||||
<field name="res_model">mailgate.thread</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="domain">
|
||||
[('state','<>','done'),('state','<>','cancel'),('state','<>','pending')]
|
||||
|
@ -481,7 +482,7 @@
|
|||
|
||||
<record id="crm_case_section_open_act" model="ir.actions.act_window">
|
||||
<field name="name">Cases</field>
|
||||
<field name="res_model">crm.case</field>
|
||||
<field name="res_model">mailgate.thread</field>
|
||||
<field name="domain">[('section_id','child_of',[active_id])]</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form,calendar</field>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<record id="process_process_contractprocess0" model="process.process">
|
||||
<field eval="1" name="active"/>
|
||||
<field name="model_id" ref="crm.model_crm_case"/>
|
||||
<field name="model_id" ref="mail_gateway.model_mailgate_thread"/>
|
||||
<field eval=""""Contract"""" name="name"/>
|
||||
</record>
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
|||
-->
|
||||
|
||||
<record id="process_node_leads0" model="process.node">
|
||||
<field name="model_id" ref="crm.model_crm_case"/>
|
||||
<field name="model_id" ref="mail_gateway.model_mailgate_thread"/>
|
||||
<field eval=""""state"""" name="kind"/>
|
||||
<field eval=""""Leads"""" name="name"/>
|
||||
<field eval=""""Very first contact with new prospect"""" name="note"/>
|
||||
|
@ -37,7 +37,7 @@
|
|||
</record>
|
||||
|
||||
<record id="process_node_opportunities0" model="process.node">
|
||||
<field name="model_id" ref="crm.model_crm_case"/>
|
||||
<field name="model_id" ref="mail_gateway.model_mailgate_thread"/>
|
||||
<field eval=""""state"""" name="kind"/>
|
||||
<field eval=""""Opportunities"""" name="name"/>
|
||||
<field eval=""""When a real project/opportunity is detected"""" name="note"/>
|
||||
|
@ -47,7 +47,7 @@
|
|||
</record>
|
||||
|
||||
<record id="process_node_meeting0" model="process.node">
|
||||
<field name="model_id" ref="crm.model_crm_case"/>
|
||||
<field name="model_id" ref="mail_gateway.model_mailgate_thread"/>
|
||||
<field eval=""""state"""" name="kind"/>
|
||||
<field eval=""""Meeting"""" name="name"/>
|
||||
<field eval=""""Schedule a normal or phone meeting"""" name="note"/>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
##############################################################################
|
||||
|
||||
#import report_businessopp
|
||||
import crm_report
|
||||
#import crm_report
|
||||
import crm_lead_report
|
||||
import crm_phonecall_report
|
||||
#import crm_opportunity_report
|
||||
|
|
|
@ -34,7 +34,7 @@ class crm_lead_report(osv.osv):
|
|||
""" CRM Lead Report """
|
||||
_name = "crm.lead.report"
|
||||
_auto = False
|
||||
_inherit = "crm.case.report"
|
||||
# _inherit = "crm.case.report"
|
||||
_description = "CRM Lead Report"
|
||||
|
||||
_columns = {
|
||||
|
|
|
@ -28,7 +28,7 @@ class crm_phonecall_report(osv.osv):
|
|||
_name = "crm.phonecall.report"
|
||||
_description = "Phone calls by user and section"
|
||||
_auto = False
|
||||
_inherit = "crm.case.report"
|
||||
# _inherit = "crm.case.report"
|
||||
|
||||
_columns = {
|
||||
'delay_close': fields.float('Delay to close', digits=(16,2),readonly=True, group_operator="avg",help="Number of Days to close the case"),
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
"access_crm_segmentation_line","crm.segmentation.line","model_crm_segmentation_line","crm.group_crm_manager",1,1,1,1
|
||||
"access_crm_case_section","crm.case.section","model_crm_case_section","crm.group_crm_user",1,0,0,0
|
||||
"access_crm_case_categ","crm.case.categ","model_crm_case_categ","crm.group_crm_user",1,0,0,0
|
||||
"access_crm_case_manger","crm.case manager","model_crm_case","crm.group_crm_user",1,1,1,1
|
||||
"access_crm_case","crm.case","model_crm_case","crm.group_crm_manager",1,1,1,1
|
||||
"access_crm_meeting","crm.meeting","model_crm_meeting","crm.group_crm_manager",1,1,1,1
|
||||
"access_crm_lead","crm.lead","model_crm_lead","crm.group_crm_manager",1,1,1,1
|
||||
"access_crm_phonecall","crm.phonecall","model_crm_phonecall","crm.group_crm_manager",1,1,1,1
|
||||
|
|
|
|
@ -84,7 +84,7 @@ class crm_opportunity2phonecall(osv.osv_memory):
|
|||
record_ids = context and context.get('active_ids', []) or []
|
||||
|
||||
phonecall_obj = self.pool.get('crm.phonecall')
|
||||
opp_obj = self.pool.get('crm.opportunity')
|
||||
opp_obj = self.pool.get('crm.lead')
|
||||
mod_obj = self.pool.get('ir.model.data')
|
||||
result = mod_obj._get_id(cr, uid, 'crm', 'view_crm_case_phonecalls_filter')
|
||||
res = mod_obj.read(cr, uid, result, ['res_id'])
|
||||
|
|
|
@ -55,7 +55,7 @@ class crm_send_new_email(osv.osv_memory):
|
|||
""" This sends an email to ALL the addresses of the selected partners.
|
||||
"""
|
||||
|
||||
hist_obj = self.pool.get('crm.case.history')
|
||||
hist_obj = self.pool.get('mailgate.message')
|
||||
smtp_pool = self.pool.get('email.smtpclient')
|
||||
|
||||
if not context:
|
||||
|
@ -76,14 +76,14 @@ class crm_send_new_email(osv.osv_memory):
|
|||
|
||||
case = case_pool.browse(cr, uid, res_id)
|
||||
if context.get('mail', 'new') == 'new':
|
||||
if len(case.history_line):
|
||||
message_id = case.history_line[0].message_id
|
||||
if len(case.message_ids):
|
||||
message_id = case.message_ids[0].message_id
|
||||
else:
|
||||
hist = hist_obj.browse(cr, uid, res_id)
|
||||
message_id = hist.message_id
|
||||
model = hist.log_id.model_id.model
|
||||
model = hist.model_id.model
|
||||
model_pool = self.pool.get(model)
|
||||
case = model_pool.browse(cr, uid, hist.log_id.res_id)
|
||||
case = model_pool.browse(cr, uid, hist.res_id)
|
||||
emails = [data['email_to']] + (data['email_cc'] or '').split(',')
|
||||
emails = filter(None, emails)
|
||||
body = data['text']
|
||||
|
@ -179,15 +179,15 @@ class crm_send_new_email(osv.osv_memory):
|
|||
"""
|
||||
This function gets default values for reply mail
|
||||
"""
|
||||
hist_obj = self.pool.get('crm.case.history')
|
||||
hist_obj = self.pool.get('mailgate.message')
|
||||
res_ids = context and context.get('active_ids', []) or []
|
||||
|
||||
include_original = context and context.get('include_original', False) or False
|
||||
res = {}
|
||||
for hist in hist_obj.browse(cr, uid, res_ids):
|
||||
model = hist.log_id.model_id.model
|
||||
for hist in hist_obj.browse(cr, uid, res_ids, context=context):
|
||||
model = hist.model_id.model
|
||||
model_pool = self.pool.get(model)
|
||||
case = model_pool.browse(cr, uid, hist.log_id.res_id)
|
||||
case = model_pool.browse(cr, uid, hist.res_id)
|
||||
if 'email_to' in fields:
|
||||
res.update({'email_to': case.email_from or hist.email_from or False})
|
||||
if 'email_from' in fields:
|
||||
|
|
|
@ -29,7 +29,7 @@ class crm_claim(osv.osv):
|
|||
_name = "crm.claim"
|
||||
_description = "Claim Cases"
|
||||
_order = "id desc"
|
||||
_inherit = 'crm.case'
|
||||
_inherit = 'mailgate.thread'
|
||||
_columns = {
|
||||
'date_closed': fields.datetime('Closed', readonly=True),
|
||||
'date': fields.datetime('Date'),
|
||||
|
|
|
@ -28,7 +28,7 @@ class crm_fundraising(osv.osv):
|
|||
_name = "crm.fundraising"
|
||||
_description = "Fund Raising Cases"
|
||||
_order = "id desc"
|
||||
_inherit ='crm.case'
|
||||
_inherit ='mailgate.thread'
|
||||
|
||||
_columns = {
|
||||
'date_closed': fields.datetime('Closed', readonly=True),
|
||||
|
|
|
@ -30,7 +30,7 @@ class crm_helpdesk(osv.osv):
|
|||
_name = "crm.helpdesk"
|
||||
_description = "Helpdesk Cases"
|
||||
_order = "id desc"
|
||||
_inherit = 'crm.case'
|
||||
_inherit = 'mailgate.thread'
|
||||
|
||||
_columns = {
|
||||
'date_closed': fields.datetime('Closed', readonly=True),
|
||||
|
|
|
@ -20,13 +20,7 @@
|
|||
##############################################################################
|
||||
|
||||
from osv import osv, fields
|
||||
|
||||
from osv import osv
|
||||
from osv import fields
|
||||
|
||||
|
||||
from osv import osv
|
||||
from osv import fields
|
||||
import time
|
||||
|
||||
|
||||
class mailgate_thread(osv.osv):
|
||||
|
@ -36,10 +30,100 @@ class mailgate_thread(osv.osv):
|
|||
_name = 'mailgate.thread'
|
||||
_description = 'Mailgateway Thread'
|
||||
|
||||
def _get_log_ids(self, cr, uid, ids, field_names, arg, context=None):
|
||||
"""Gets id for case log from history of particular case
|
||||
@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
|
||||
@return:Dictionary of History Ids
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
result = {}
|
||||
domain = []
|
||||
history_obj = False
|
||||
model_obj = self.pool.get('ir.model')
|
||||
history_obj = self.pool.get('mailgate.message')
|
||||
|
||||
if 'message_ids' in field_names:
|
||||
name = 'message_ids'
|
||||
domain += [('email_to', '!=', False)]
|
||||
|
||||
if 'log_ids' in field_names:
|
||||
name = 'log_ids'
|
||||
domain += [('email_to', '=', False)]
|
||||
|
||||
model_ids = model_obj.search(cr, uid, [('model', '=', self._name)])
|
||||
domain += [('model_id', '=', model_ids[0])]
|
||||
for case in self.browse(cr, uid, ids, context):
|
||||
domain1 = domain + [('res_id', '=', case.id)]
|
||||
history_ids = history_obj.search(cr, uid, domain1, context=context)
|
||||
if history_ids:
|
||||
result[case.id] = {name: history_ids}
|
||||
else:
|
||||
result[case.id] = {name: []}
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'name':fields.char('Name', size=64),
|
||||
'message_ids':fields.one2many('mailgate.message', 'thread_id', 'Message'),
|
||||
# 'message_ids':fields.one2many('mailgate.message', 'thread_id', 'Message'),
|
||||
'message_ids': fields.function(_get_log_ids, method=True, type='one2many', \
|
||||
multi="message_ids", relation="mailgate.message", string="Messages"),
|
||||
'log_ids': fields.function(_get_log_ids, method=True, type='one2many', \
|
||||
multi="log_ids", relation="mailgate.message", string="Logs"),
|
||||
}
|
||||
|
||||
def __history(self, cr, uid, cases, keyword, history=False, email=False, details=None, email_from=False, message_id=False, context={}):
|
||||
"""
|
||||
@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 cases: a browse record list
|
||||
@param keyword: Case action keyword e.g.: If case is closed "Close" keyword is used
|
||||
@param history: Value True/False, If True it makes entry in case History otherwise in Case Log
|
||||
@param email: Email address if any
|
||||
@param details: Details of case history if any
|
||||
@param context: A standard dictionary for contextual values"""
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
# The mailgate sends the ids of the cases and not the object list
|
||||
if all(isinstance(case_id, (int, long)) for case_id in cases) and context.get('model'):
|
||||
cases = self.pool.get(context['model']).browse(cr, uid, cases, context=context)
|
||||
|
||||
model_obj = self.pool.get('ir.model')
|
||||
|
||||
obj = self.pool.get('mailgate.message')
|
||||
for case in cases:
|
||||
model_ids = model_obj.search(cr, uid, [('model', '=', case._name)])
|
||||
data = {
|
||||
'name': keyword,
|
||||
'user_id': uid,
|
||||
'date': time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'model_id' : model_ids and model_ids[0] or False,
|
||||
'res_id': case.id,
|
||||
'section_id': case.section_id.id,
|
||||
'message_id':message_id
|
||||
}
|
||||
|
||||
if history:
|
||||
data['description'] = details or case.description
|
||||
data['email_to'] = email or \
|
||||
(case.section_id and case.section_id.reply_to) or \
|
||||
(case.user_id and case.user_id.address_id and \
|
||||
case.user_id.address_id.email) or tools.config.get('email_from', False)
|
||||
data['email_from'] = email_from or \
|
||||
(case.section_id and case.section_id.reply_to) or \
|
||||
(case.user_id and case.user_id.address_id and \
|
||||
case.user_id.address_id.email) or tools.config.get('email_from', False)
|
||||
res = obj.create(cr, uid, data, context)
|
||||
return True
|
||||
|
||||
_history = __history
|
||||
history = __history
|
||||
|
||||
mailgate_thread()
|
||||
|
||||
|
@ -51,7 +135,7 @@ class mailgate_message(osv.osv):
|
|||
_description = 'Mailgateway Message'
|
||||
|
||||
_columns = {
|
||||
'name':fields.char('Message', size=64, required=True),
|
||||
'name':fields.char('Message', size=64),
|
||||
'thread_id':fields.many2one('mailgate.thread', 'Thread'),
|
||||
'date': fields.datetime('Date'),
|
||||
'model_id': fields.many2one('ir.model', "Model"),
|
||||
|
@ -63,6 +147,7 @@ class mailgate_message(osv.osv):
|
|||
'email_cc': fields.char('Email From', size=84),
|
||||
'email_bcc': fields.char('Email From', size=84),
|
||||
'message_id': fields.char('Message Id', size=1024, readonly=True, help="Message Id on Email Server.", select=True),
|
||||
'description': fields.text('Description'),
|
||||
'attachment_ids': fields.many2many('ir.attachment', 'message_attachment_rel', 'message_id', 'attachment_id', 'Attachments'),
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue