From 1c2af052b2b5b13c030002bb23efbc6e968c9b0b Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Fri, 25 Jun 2010 19:41:41 +0200 Subject: [PATCH] [FIX] crm, mail_gateway: review, cleanup and improvements in mail_gateway and crm bzr revid: odo@openerp.com-20100625174141-an257bdq3yjyagse --- addons/crm/crm_lead.py | 32 ++-- addons/crm/crm_opportunity.py | 2 +- addons/crm/wizard/crm_forward_to_partner.py | 138 ++++++++++-------- .../wizard/crm_forward_to_partner_view.xml | 22 ++- addons/crm/wizard/crm_send_email.py | 38 ++--- addons/crm/wizard/crm_send_email_view.xml | 11 +- addons/mail_gateway/mail_gateway.py | 38 ++--- 7 files changed, 142 insertions(+), 139 deletions(-) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index f6d32573006..0acfed73c3f 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -96,20 +96,20 @@ class crm_lead(osv.osv, crm_case): _columns = { # From crm.case - 'name': fields.char('Name', size=64), - 'active': fields.boolean('Active', required=False), + 'name': fields.char('Name', size=64), + 'active': fields.boolean('Active', required=False), 'date_action_last': fields.datetime('Last Action', readonly=1), 'date_action_next': fields.datetime('Next Action', readonly=1), - 'email_from': fields.char('Email', size=128, help="These people will receive email."), + 'email_from': fields.char('Email', size=128, help="E-mail address of the contact"), '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.'), + select=True, help='Sales team to which this case belongs to.\ + Defines responsible user and e-mail address for the 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"), +addresses will receive a copy of the future e-mail communication between partner \ +and users"), 'description': fields.text('Notes'), - 'write_date': fields.datetime('Update Date' , readonly=True), + 'write_date': fields.datetime('Update Date' , readonly=True), # Lead fields 'categ_id': fields.many2one('crm.case.categ', 'Lead Source', \ @@ -274,8 +274,8 @@ and users by email"), res = mailgate_pool.get_partner(cr, uid, msg.get('from') or msg.get_unixfrom()) if res: vals.update(res) - res = self.create(cr, uid, vals, context) + res = self.create(cr, uid, vals, context) attachents = msg.get('attachments', []) for attactment in attachents or []: @@ -318,14 +318,22 @@ and users by email"), if res and maps.get(res.group(1).lower()): key = maps.get(res.group(1).lower()) vls[key] = res.group(2).lower() - vals.update(vls) - res = self.write(cr, uid, ids, vals) + + # Unfortunately the API is based on lists + # but we want to update the state based on the + # previous state, so we have to loop: + for case in self.browse(cr, uid, ids, context=context): + values = dict(vals) + if case.state == crm.AVAILABLE_STATES[4][0]: #pending + values.update(state=crm.AVAILABLE_STATES[1][0]) #open + res = self.write(cr, uid, [case.id], values, context=context) + return res def emails_get(self, cr, uid, ids, context=None): - """ + """ Get Emails @param self: The object pointer @param cr: the current row, from the database cursor, diff --git a/addons/crm/crm_opportunity.py b/addons/crm/crm_opportunity.py index 0adbf2f2489..4faebe37d91 100644 --- a/addons/crm/crm_opportunity.py +++ b/addons/crm/crm_opportunity.py @@ -109,7 +109,7 @@ class crm_opportunity(osv.osv): _defaults = { 'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.lead', context=c), - 'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0], + 'priority': crm.AVAILABLE_PRIORITIES[2][0], } def action_makeMeeting(self, cr, uid, ids, context=None): diff --git a/addons/crm/wizard/crm_forward_to_partner.py b/addons/crm/wizard/crm_forward_to_partner.py index eaf6978fc2c..700ac5fc5b1 100644 --- a/addons/crm/wizard/crm_forward_to_partner.py +++ b/addons/crm/wizard/crm_forward_to_partner.py @@ -20,10 +20,12 @@ # ############################################################################## -from osv import osv, fields +import base64 +import itertools -from tools.translate import _ +from osv import osv, fields import tools +from tools.translate import _ class crm_lead_forward_to_partner(osv.osv_memory): """Forwards lead history""" @@ -31,20 +33,27 @@ class crm_lead_forward_to_partner(osv.osv_memory): _columns = { 'name': fields.selection([('user', 'User'), ('partner', 'Partner'), \ - ('email', 'Email Address')], 'Send to', required=True), - 'user_id': fields.many2one('res.users', "User"), - 'partner_id' : fields.many2one('res.partner', 'Partner'), - 'address_id' : fields.many2one('res.partner.address', 'Address'), - 'email_from' : fields.char('From', required=True, size=128), - 'email_to' : fields.char('To', required=True, size=128), - 'subject' : fields.char('Subject', required=True, size=128), - 'message' : fields.text('Message', required=True), + ('email', 'Email Address')], 'Send to', required=True), + 'user_id': fields.many2one('res.users', "User"), + 'partner_id' : fields.many2one('res.partner', 'Partner'), + 'address_id' : fields.many2one('res.partner.address', 'Address'), + 'email_from' : fields.char('From', required=True, size=128), + 'email_to' : fields.char('To', required=True, size=128), + 'subject' : fields.char('Subject', required=True, size=128), + 'message' : fields.text('Message', required=True), 'history': fields.selection([('latest', 'Latest email'), ('whole', 'Whole Story'), ('info', 'Case Information')], 'Send history', required=True), - 'add_cc': fields.boolean('Add as CC', required=False, help="Selcect if you want this user to add as cc for this case.This user will receive all future conversations"), + 'add_cc': fields.boolean('Add as CC', required=False, help="Check this box if you want this address to be added in the CC list"\ + " for this case, in order to receive all future conversations"), } - + + _defaults = { + 'history': 'latest', + 'add_cc': True, + 'email_from': lambda self, cr, uid, *a: self.pool.get('res.users')._get_email_from(cr, uid, uid)[uid] + } + def get_whole_history(self, cr, uid, ids, context=None): - """This function gets whole communication history and returns as top posting style + """This function gets whole communication history and returns as top posting style @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -87,13 +96,10 @@ class crm_lead_forward_to_partner(osv.osv_memory): """ if not user: return {'value': {'email_to': False}} - email = False - addr = self.pool.get('res.users').read(cr, uid, user, ['address_id'])['address_id'] - if addr: - email = self.pool.get('res.partner.address').read(cr, uid, addr[0] , ['email'])['email'] + email = self.pool.get('res.users')._get_email_from(cr, uid, [user])[user] return {'value': {'email_to': email}} - def on_change_history(self, cr, uid, ids, history, context=None): + def on_change_history(self, cr, uid, ids, history_type, context=None): """Gives message body according to type of history selected * info: Forward the case information * whole: Send the whole history @@ -106,31 +112,35 @@ class crm_lead_forward_to_partner(osv.osv_memory): """ #TODO: ids and context are not comming res = False - msg_val = '' res_id = context.get('active_id') - model = context.get('active_model') - model_pool = self.pool.get(model) - if not res_id or not model: - return res - if history == 'info': + msg_val = self._get_case_history(cr, uid, history_type, res_id, context=context) + if msg_val: + res = {'value': {'message' : '\n\n' + msg_val}} + return res + + def _get_case_history(self, cr, uid, history_type, res_id, context=None): + if not res_id: + return + + model_pool = self.pool.get('crm.lead') + if history_type == 'info': msg_val = self.get_lead_details(cr, uid, res_id, context=context) - if history == 'whole': + elif history_type == 'whole': log_ids = model_pool.browse(cr, uid, res_id, context=context).message_ids - log_ids = map(lambda x: x.id, log_ids) + log_ids = [x.id for x in log_ids] if not log_ids: raise osv.except_osv('Warning!', 'There is no history to send') msg_val = self.get_whole_history(cr, uid, log_ids, context=context) - if history == 'latest': + elif history_type == 'latest': log_ids = model_pool.browse(cr, uid, res_id, context=context).message_ids if not log_ids: raise osv.except_osv('Warning!', 'There is no history to send') msg_val = self.get_latest_history(cr, uid, log_ids[0].id, context=context) - if msg_val: - res = {'value': {'message' : '\n\n' + msg_val}} - return res + return msg_val + def on_change_partner(self, cr, uid, ids, partner_id): """This function fills address information based on partner/user selected @@ -169,7 +179,7 @@ class crm_lead_forward_to_partner(osv.osv_memory): context = {} res_id = context.get('active_id', False) - + model = context.get('active_model', False) if not res_id or not model: return {} @@ -184,19 +194,35 @@ class crm_lead_forward_to_partner(osv.osv_memory): body = case_pool.format_body(this.message) email_from = this.email_from or False - flag = False - flag = tools.email_send( - email_from, - emails, - this.subject, - body, + # extract attachements from case and emails according to mode + attachments = [] + attach_pool = self.pool.get('ir.attachment') + direct_attachments = attach_pool.search(cr, uid, [('res_model', '=', 'crm.lead'), ('res_id', '=', res_id)], context=context) + attachments += attach_pool.browse(cr, uid, direct_attachments, context=context) + if this.history in ['latest', 'whole'] and case.message_ids: + msgs = case.message_ids + if this.history == 'latest': + msgs = msgs[:1] + attachments.extend(itertools.chain(*[m.attachment_ids for m in msgs])) + + result = tools.email_send( + email_from, + emails, + this.subject, + body, + openobject_id=str(case.id), + attach=[(a.datas_fname or a.name, base64.decodestring(a.datas)) for a in attachments if a.datas], + reply_to=case.section_id.reply_to, ) - if flag: + + if result: case_pool._history(cr, uid, [case], _('Forward'), history=True, email=this.email_to, subject=this.subject, details=body, email_from=email_from) - if not flag: - raise osv.except_osv(_('Error!'), _('Unable to send mail. Please check SMTP is configured properly.')) - if this.add_cc: + else: + raise osv.except_osv(_('Error!'), _('Unable to send mail. Please check SMTP is configured properly.')) + + if this.add_cc and (not case.email_cc or not this.email_to in case.email_cc): case_pool.write(cr, uid, case.id, {'email_cc' : case.email_cc and case.email_cc + ', ' + this.email_to or this.email_to}) + return {} def get_lead_details(self, cr, uid, lead_id, context=None): @@ -209,11 +235,11 @@ class crm_lead_forward_to_partner(osv.osv_memory): 'zip', 'city', 'country_id', 'state_id', 'email_from', 'phone', 'fax', 'mobile' ] - + for field_name in field_names: field_definition = lead_proxy._columns[field_name] value = None - + if field_definition._type == 'selection': if hasattr(field_definition.selection, '__call__'): key = field_definition.selection(lead_proxy, cr, uid, context=context) @@ -225,7 +251,7 @@ class crm_lead_forward_to_partner(osv.osv_memory): value = lead[field_name].name_get()[0][1] else: value = lead[field_name] - + message.append("%s: %s" % (field_definition.string, value or '')) elif lead.type == 'opportunity': pa = lead.partner_address_id @@ -254,29 +280,21 @@ class crm_lead_forward_to_partner(osv.osv_memory): if context is None: context = {} + defaults = super(crm_lead_forward_to_partner, self).default_get(cr, uid, fields, context=context) + active_ids = context.get('active_ids') if not active_ids: - return {} + return defaults lead_proxy = self.pool.get('crm.lead') lead = lead_proxy.browse(cr, uid, active_ids[0], context=context) - message = False - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - email_from = '' - if user.address_id and user.address_id.email: - email_from = "%s <%s>" % (user.name, user.address_id.email) - - message = self.get_lead_details(cr, uid, lead.id, context=context) - - res = { - 'email_from' : email_from, - 'subject' : '%s: ' % (_('Fwd'), lead.name), + message = self._get_case_history(cr, uid, defaults.get('history'), lead.id, context=context) + defaults.update({ + 'subject' : '%s: %s' % (_('Fwd'), lead.name), 'message' : message, - } - if 'history' in fields: - res.update({'history': 'latest'}) - return res + }) + return defaults crm_lead_forward_to_partner() diff --git a/addons/crm/wizard/crm_forward_to_partner_view.xml b/addons/crm/wizard/crm_forward_to_partner_view.xml index b6295cfa3a9..e8a60cea01f 100644 --- a/addons/crm/wizard/crm_forward_to_partner_view.xml +++ b/addons/crm/wizard/crm_forward_to_partner_view.xml @@ -7,28 +7,24 @@ form
- + - + - + - - - - - - - - - + + + + + + - diff --git a/addons/crm/wizard/crm_send_email.py b/addons/crm/wizard/crm_send_email.py index d48f56239e4..1a552ae7d20 100644 --- a/addons/crm/wizard/crm_send_email.py +++ b/addons/crm/wizard/crm_send_email.py @@ -53,7 +53,8 @@ class crm_send_new_email(osv.osv_memory): _columns = { 'email_to' : fields.char('To', size=64, required=True), 'email_from' : fields.char('From', size=64, required=True), - 'email_cc' : fields.char('CC', size=128), + 'email_cc' : fields.char('CC', size=128, help="Carbon Copy: list of recipients that will receive"\ + " a copy of this mail, and future communication related to this case"), 'subject': fields.char('Subject', size=128, required=True), 'text': fields.text('Message', required=True), 'state': fields.selection(crm.AVAILABLE_STATES, string='Set New State To', required=True), @@ -92,7 +93,7 @@ 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.message_ids): + if case.message_ids: message_id = case.message_ids[0].message_id else: hist = hist_obj.browse(cr, uid, res_id) @@ -112,8 +113,6 @@ class crm_send_new_email(osv.osv_memory): if message_id: x_headers['References'] = "%s" % (message_id) - flag = False - flag = tools.email_send( email_from, emails, @@ -121,10 +120,11 @@ class crm_send_new_email(osv.osv_memory): body, email_cc=email_cc, attach=attach, - reply_to=case.section_id and case.section_id.reply_to or email_from, + reply_to=case.section_id and case.section_id.reply_to, openobject_id=str(case.id), x_headers=x_headers ) + if not flag: raise osv.except_osv(_('Error!'), _('Unable to send mail. Please check SMTP is configured properly.')) if flag: @@ -165,23 +165,23 @@ class crm_send_new_email(osv.osv_memory): mod_obj = self.pool.get(model) res_id = context and context.get('active_ids', []) or [] + user_obj = self.pool.get('res.users') + user_mail_from = user_obj._get_email_from(cr, uid, [uid], context=context)[uid] + for case in mod_obj.browse(cr, uid, res_id): if 'email_to' in fields: res.update({'email_to': case.email_from}) if 'email_from' in fields: - res.update({'email_from': (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 and \ - "%s <%s>" % (case.user_id.name, case.user_id.address_id.email)) or \ - tools.config.get('email_from',False)}) + res.update({'email_from': case.section_id and case.section_id.reply_to or user_mail_from}) if 'subject' in fields: - res.update({'subject': '[%s] %s' % (str(case.id), context.get('subject', case.name) or '')}) + res.update({'subject': str(context.get('subject', case.name) or '')}) if 'email_cc' in fields: res.update({'email_cc': case.email_cc or ''}) if 'text' in fields: res.update({'text': '\n\n'+(case.user_id.signature or '')}) if 'state' in fields: res.update({'state': 'pending'}) + return res def get_reply_defaults(self, cr, uid, fields, context=None): @@ -191,6 +191,9 @@ class crm_send_new_email(osv.osv_memory): hist_obj = self.pool.get('mailgate.message') res_ids = context and context.get('active_ids', []) or [] + user_obj = self.pool.get('res.users') + user_mail_from = user_obj._get_email_from(cr, uid, [uid], context=context)[uid] + include_original = context and context.get('include_original', False) or False res = {} for hist in hist_obj.browse(cr, uid, res_ids, context=context): @@ -201,14 +204,12 @@ class crm_send_new_email(osv.osv_memory): return {} model_pool = self.pool.get(model) - res_id = hist.res_id + res_id = hist.res_id case = model_pool.browse(cr, uid, 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: - res.update({'email_from': (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 hist.email_to or tools.config.get('email_from',False)}) + res.update({'email_from': case.section_id and case.section_id.reply_to or user_mail_from}) signature = '\n' + (case.user_id.signature or '') original = [signature] @@ -251,13 +252,6 @@ class crm_send_new_email(osv.osv_memory): return True if tools.config.get('email_from'): return True - - for case in mod_obj.browse(cr, uid, context.get('active_ids', [])): - if not case.user_id: - raise osv.except_osv(_('Error'), _('You must define a responsible user for this case in order to use this action!')) - if not case.user_id.address_id.email: - raise osv.except_osv(_('Warning!'), _("Please specify user's email address !")) - return True crm_send_new_email() diff --git a/addons/crm/wizard/crm_send_email_view.xml b/addons/crm/wizard/crm_send_email_view.xml index c0125014c1a..b5af4004801 100644 --- a/addons/crm/wizard/crm_send_email_view.xml +++ b/addons/crm/wizard/crm_send_email_view.xml @@ -10,12 +10,11 @@ form - - - - - - + + + + + diff --git a/addons/mail_gateway/mail_gateway.py b/addons/mail_gateway/mail_gateway.py index 8c6e2a92afe..2b4ed360589 100644 --- a/addons/mail_gateway/mail_gateway.py +++ b/addons/mail_gateway/mail_gateway.py @@ -152,7 +152,7 @@ class mailgate_tool(osv.osv_memory): _name = 'email.server.tools' _description = "Email Server Tools" - + def _to_decode(self, s, charsets): if not s: return s @@ -168,7 +168,7 @@ class mailgate_tool(osv.osv_memory): if text: text = decode_header(text.replace('\r', '')) return ''.join(map(lambda x:self._to_decode(x[0], [x[1]]), text or [])) - + def to_email(self, text): _email = re.compile(r'.*<.*@.*\..*>', re.UNICODE) def record(path): @@ -179,7 +179,7 @@ class mailgate_tool(osv.osv_memory): bits = _email.sub(record, text) return bits - + def history(self, cr, uid, model, res_ids, msg, attach, context=None): """This function creates history for mails fetched @param self: The object pointer @@ -212,7 +212,7 @@ class mailgate_tool(osv.osv_memory): } msg_id = msg_pool.create(cr, uid, msg_data, context=context) return True - + def email_send(self, cr, uid, model, res_id, msg, from_email=False, email_default=False): """This function Sends return email on submission of Fetched email in OpenERP database @param self: The object pointer @@ -227,10 +227,7 @@ class mailgate_tool(osv.osv_memory): model_pool = self.pool.get(model) from_email = from_email or tools.config.get('email_from', None) message = email.message_from_string(tools.ustr(msg).encode('utf-8')) - subject = "[%s] %s" %(res_id, message['Subject']) - #msg_mails = [] - #mails = [self._decode_header(message['From']), self._decode_header(message['To'])] - #mails += self._decode_header(message.get('Cc', '')).split(',') + subject = message['Subject'] values = {} if hasattr(model_pool, 'emails_get'): @@ -241,11 +238,6 @@ class mailgate_tool(osv.osv_memory): em = emails['user_email'] + emails['email_from'] + emails['email_cc'] msg_mails = map(self.to_email, filter(None, em)) - #mm = [self._decode_header(message['From']), self._decode_header(message['To'])] - #mm += self._decode_header(message.get('Cc', '')).split(',') - - #msg_mails = map(self.to_email, filter(None, mm)) - encoding = message.get_content_charset() message['body'] = message.get_payload(decode=True) if encoding: @@ -258,10 +250,9 @@ Hello %s,""" % (from_mail)) Your Request ID: %s""") % (res_id) body += _(""" - Thanks --------- Original Message -------- +-------- Original Message -------- %s """) % (self._to_decode(message['body'], [encoding])) res = None @@ -284,7 +275,6 @@ Thanks @param message: Email details @param attach: Email attachments @param context: A standard dictionary for contextual values""" - model_pool = self.pool.get(model) if not context: context = {} @@ -441,14 +431,14 @@ Thanks # Store messages context.update({'model' : model}) if hasattr(model_pool, '_history'): - model_pool._history(cr, uid, res_ids, _('Receive'), history=True, - subject = msg.get('subject'), - email = msg.get('to'), - details = msg.get('body'), - email_from = msg.get('from'), - message_id = msg.get('message-id'), + model_pool._history(cr, uid, res_ids, _('Receive'), history=True, + subject = msg.get('subject'), + email = msg.get('to'), + details = msg.get('body'), + email_from = msg.get('from'), + message_id = msg.get('message-id'), references = msg.get('references', False), - attach = msg.get('attachments', {}).items(), + attach = msg.get('attachments', {}).items(), context = context) else: self.history(cr, uid, model, res_ids, msg, att_ids, context=context) @@ -476,5 +466,3 @@ Thanks return res mailgate_tool() - -