From ee4052bc1adbc7d65075b79001880f6857392724 Mon Sep 17 00:00:00 2001 From: "rpa (Open ERP)" Date: Mon, 3 May 2010 18:00:48 +0530 Subject: [PATCH] [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 --- addons/crm/__init__.py | 2 +- addons/crm/__openerp__.py | 10 +- addons/crm/crm.py | 497 ------------------ addons/crm/crm_action_rule.py | 26 +- addons/crm/crm_lead.py | 190 ++++++- addons/crm/crm_lead_view.xml | 10 +- addons/crm/crm_mailgate.py | 4 +- addons/crm/crm_meeting.py | 14 +- addons/crm/crm_meeting_menu.xml | 2 +- addons/crm/crm_opportunity.py | 145 ++--- addons/crm/crm_opportunity_view.xml | 2 +- addons/crm/crm_phonecall.py | 10 +- addons/crm/crm_view.xml | 19 +- .../crm/process/crm_configuration_process.xml | 8 +- addons/crm/report/__init__.py | 2 +- addons/crm/report/crm_lead_report.py | 2 +- addons/crm/report/crm_phonecall_report.py | 2 +- addons/crm/security/ir.model.access.csv | 2 - .../wizard/crm_opportunity_to_phonecall.py | 2 +- addons/crm/wizard/crm_send_email.py | 18 +- addons/crm_claim/crm_claim.py | 2 +- addons/crm_fundraising/crm_fundraising.py | 2 +- addons/crm_helpdesk/crm_helpdesk.py | 2 +- addons/mail_gateway/mail_gateway.py | 103 +++- 24 files changed, 402 insertions(+), 674 deletions(-) diff --git a/addons/crm/__init__.py b/addons/crm/__init__.py index de0fac56e29..2d340e7bfc5 100644 --- a/addons/crm/__init__.py +++ b/addons/crm/__init__.py @@ -30,7 +30,7 @@ import crm_opportunity import crm_phonecall import crm_installer -import report +#import report import wizard diff --git a/addons/crm/__openerp__.py b/addons/crm/__openerp__.py index 733ba91f356..2b4f827b6df 100644 --- a/addons/crm/__openerp__.py +++ b/addons/crm/__openerp__.py @@ -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' diff --git a/addons/crm/crm.py b/addons/crm/crm.py index 9d0473c1f1e..2e95ffff8ec 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -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 """ diff --git a/addons/crm/crm_action_rule.py b/addons/crm/crm_action_rule.py index 78fc7e3bd8c..47e02b9308f 100644 --- a/addons/crm/crm_action_rule.py +++ b/addons/crm/crm_action_rule.py @@ -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 diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 730f668567e..db01e94ccc6 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -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() diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index 00cd31820b5..d29460915c0 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -40,7 +40,7 @@
- +