From 53d54c80a0f35160ca69127671c512aa6f183333 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Thu, 14 Jun 2012 16:17:32 +0200 Subject: [PATCH 001/146] [IMP] mail: initial model for mail.alias - work-in-progress bzr revid: odo@openerp.com-20120614141732-oa6fhfqgl887c04i --- addons/mail/__init__.py | 1 + addons/mail/mail_alias.py | 82 ++++++++++++++++++++++++++++++++++++++ addons/mail/mail_thread.py | 61 +++++++++++++++------------- 3 files changed, 117 insertions(+), 27 deletions(-) create mode 100644 addons/mail/mail_alias.py diff --git a/addons/mail/__init__.py b/addons/mail/__init__.py index d9835f86fc5..4c313338ceb 100644 --- a/addons/mail/__init__.py +++ b/addons/mail/__init__.py @@ -23,6 +23,7 @@ import mail_message import mail_thread import mail_group import mail_subscription +import mail_alias import res_users import res_partner import report diff --git a/addons/mail/mail_alias.py b/addons/mail/mail_alias.py new file mode 100644 index 00000000000..b5aa6f6d76a --- /dev/null +++ b/addons/mail/mail_alias.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Business Applications +# Copyright (C) 2012 OpenERP S.A. (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.osv import fields, osv + +class mail_alias(osv.Model): + """A Mail Alias is a mapping of an email address with a given OpenERP Document + model. It is used by OpenERP's mail gateway when processing incoming emails + sent to the system. If the recipient address (To) of the message matches + a Mail Alias, the message will be either processed following the rules + of that alias. If the message is a reply it will be attached to the + existing discussion on the corresponding record, otherwise a new + record of the corresponding model will be created. + + This is meant to be used in combination with a catch-all email configuration + on the company's mail server, so that as soon as a new mail.alias is + created, it becomes immediately usable and OpenERP will accept email for it. + """ + _name = 'mail.alias' + _description = "Mail Alias" + _rec_name = 'alias_name' + + _columns = { + 'alias_name': fields.char('Mailbox Alias', required=True, + help="The name of the mailbox alias, e.g. `jobs' " + "if you want to catch emails for ",), + 'alias_model_id': fields.many2one('ir.model', 'Aliased Model', required=True, + help="The model (OpenERP Document Kind) to which this alias " + "corresponds. Any incoming email that does not reply to an " + "existing record will cause the creation of a new record " + "of this model (e.g. a Project Task)", + # only allow selecting mail_thread models! + domain="[('field_ids', 'in', 'message_ids')]"), + 'alias_user_id': fields.many2one('res.users', 'Owner', + help="The owner of records created upon receiving emails on this alias. " + "If this field is kept empty the system will attempt to find the right owner " + "based on the sender (From) address, or will use the Administrator account " + "if no system user is found for that address."), + 'alias_defaults': fields.text('Default Values', required=True, + help="The representation of a Python dictionary that will be evaluated to provide " + "default values when creating new records."), + 'alias_force_thread_id': fields.integer('Record Thread ID', + help="Optional ID of the thread (record) to which all " + "messages will be attached, even if they did not reply to it. " + "If set, this will disable the creation of new records completely.") + } + _defaults = { + 'alias_defaults': '{}', + 'alias_user_id': lambda s,c,u,ctx: u + } + _sql_constraint = [ + ('mailbox_uniq', 'unique (alias_name)', 'Unfortunately this mail alias is already used, please choose a unique one') + ] + + def create_unique_alias(self, cr, uid, values, context=None): + # TODO: call create() with `values` after checking that `alias_name` + # is unique. If not unique, append a sequential number after it until + # a unique one if found. + # E.g if create_unique_alias is called with {'alias_name': 'abc'} + # and 'abc', 'abc1', 'abc2' alias exist, replace alias_name with 'abc3'. + return + + + \ No newline at end of file diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index b1b6c68e4cc..40824ba5427 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -72,6 +72,7 @@ class mail_thread(osv.osv): _columns = { 'message_ids': fields.function(_get_message_ids, method=True, type='one2many', obj='mail.message', string='Temp messages', _fields_id = 'res_id'), + 'message_ids': fields.one2many('mail.message', 'res_id', 'Messages', domain=[('model','=',_name)]), } #------------------------------------------------------ @@ -445,6 +446,13 @@ class mail_thread(osv.osv): msgs = msg_obj.read(cr, uid, msg_ids, context=context) return msgs + + def message_catchall(self, cr, uid, message, context=None): + """TODO proper docstring, inspired by messsage_process()""" + # TODO + pass + + #------------------------------------------------------ # Email specific #------------------------------------------------------ @@ -452,7 +460,7 @@ class mail_thread(osv.osv): def message_process(self, cr, uid, model, message, custom_values=None, save_original=False, strip_attachments=False, - context=None): + thread_id=None, context=None): """Process an incoming RFC2822 email message related to the given thread model, relying on ``mail.message.parse()`` for the parsing operation, and then calling ``message_new`` @@ -472,6 +480,10 @@ class mail_thread(osv.osv): email source attached to the message after it is imported. :param bool strip_attachments: whether to strip all attachments before processing the message, in order to save some space. + :param int thread_id: optional ID of the record/thread from ``model`` + to which this mail should be attached. When provided, this + overrides the automatic detection based on the message + headers. """ # extract message bytes - we are forced to pass the message as binary because # we don't know its encoding until we parse its headers and hence can't @@ -479,13 +491,12 @@ class mail_thread(osv.osv): if isinstance(message, xmlrpclib.Binary): message = str(message.data) - model_pool = self.pool.get(model) - if self._name != model: - if context is None: context = {} - context.update({'thread_model': model}) + if context is None: context = {} mail_message = self.pool.get('mail.message') - res_id = False + model_pool = self.pool.get(model) + if self._name != model: + context.update({'thread_model': model}) # Parse Message # Warning: message_from_string doesn't always work correctly on unicode, @@ -504,8 +515,7 @@ class mail_thread(osv.osv): return model_pool.message_new(cr, uid, msg, custom_values, context=context) - res_id = False - if msg.get('references') or msg.get('in-reply-to'): + if not thread_id and (msg.get('references') or msg.get('in-reply-to')): references = msg.get('references') or msg.get('in-reply-to') if '\r\n' in references: references = references.split('\r\n') @@ -513,26 +523,23 @@ class mail_thread(osv.osv): references = references.split(' ') for ref in references: ref = ref.strip() - res_id = tools.reference_re.search(ref) - if res_id: - res_id = res_id.group(1) - else: - res_id = tools.res_re.search(msg['subject']) - if res_id: - res_id = res_id.group(1) - if res_id: - res_id = int(res_id) - if model_pool.exists(cr, uid, res_id): - if hasattr(model_pool, 'message_update'): - model_pool.message_update(cr, uid, [res_id], msg, {}, context=context) - else: - # referenced thread was not found, we'll have to create a new one - res_id = False - if not res_id: - res_id = create_record(msg) + thread_id = tools.reference_re.search(ref) + if not thread_id: + thread_id = tools.res_re.search(msg['subject']) + if thread_id: + thread_id = int(thread_id.group(1)) + if not model_pool.exists(cr, uid, thread_id) or \ + not hasattr(model_pool, 'message_update'): + # referenced thread not found or not updatable, + # -> create a new one + thread_id = False + if not thread_id: + thread_id = create_record(msg) + else: + model_pool.message_update(cr, uid, [thread_id], msg, {}, context=context) #To forward the email to other followers - self.message_forward(cr, uid, model, [res_id], msg_txt, context=context) - return res_id + self.message_forward(cr, uid, model, [thread_id], msg_txt, context=context) + return thread_id def message_new(self, cr, uid, msg_dict, custom_values=None, context=None): """Called by ``message_process`` when a new message is received From 4fd82385df1e606e84968f1cf545654b1538209e Mon Sep 17 00:00:00 2001 From: "Amit Patel (OpenERP)" Date: Tue, 19 Jun 2012 17:01:07 +0530 Subject: [PATCH 002/146] [FIX]: When we cancel the repair order then status should be "Cancelled" not "Cancel" Product to repair field on repair order should not show service products Move, when create a new move it should take Product to repair by default. bzr revid: apa@tinyerp.com-20120619113107-z9sipz51tb3kv2kx --- addons/mrp_repair/mrp_repair.py | 2 +- addons/mrp_repair/mrp_repair_view.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/mrp_repair/mrp_repair.py b/addons/mrp_repair/mrp_repair.py index 6f14ba22bea..4b48a9fdeb7 100644 --- a/addons/mrp_repair/mrp_repair.py +++ b/addons/mrp_repair/mrp_repair.py @@ -122,7 +122,7 @@ class mrp_repair(osv.osv): 'prodlot_id': fields.many2one('stock.production.lot', 'Lot Number', select=True, domain="[('product_id','=',product_id)]"), 'state': fields.selection([ ('draft','Quotation'), - ('cancel','Cancel'), + ('cancel','Cancelled'), ('confirmed','Confirmed'), ('under_repair','Under Repair'), ('ready','Ready to Repair'), diff --git a/addons/mrp_repair/mrp_repair_view.xml b/addons/mrp_repair/mrp_repair_view.xml index 6e40bb8fd26..80ae7ae919f 100644 --- a/addons/mrp_repair/mrp_repair_view.xml +++ b/addons/mrp_repair/mrp_repair_view.xml @@ -45,7 +45,7 @@