Merge pull request #121 from hbrunn/8.0-fetchmail_attach_from_folder
[ADD] port fetchmail_attach_from_folderpull/126/head
commit
f7e88259c8
|
@ -1,131 +0,0 @@
|
||||||
# -*- encoding: utf-8 -*-
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# OpenERP, Open Source Management Solution
|
|
||||||
# This module copyright (C) 2013 Therp BV (<http://therp.nl>)
|
|
||||||
# All Rights Reserved
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
########################################################################
|
|
||||||
|
|
||||||
from openerp.osv import fields
|
|
||||||
from openerp.osv.orm import Model
|
|
||||||
from .. import match_algorithm
|
|
||||||
|
|
||||||
|
|
||||||
class fetchmail_server_folder(Model):
|
|
||||||
_name = 'fetchmail.server.folder'
|
|
||||||
_rec_name = 'path'
|
|
||||||
|
|
||||||
def _get_match_algorithms(self):
|
|
||||||
def get_all_subclasses(cls):
|
|
||||||
return cls.__subclasses__() + [subsub
|
|
||||||
for sub in cls.__subclasses__()
|
|
||||||
for subsub in get_all_subclasses(sub)]
|
|
||||||
return dict([(cls.__name__, cls) for cls in get_all_subclasses(
|
|
||||||
match_algorithm.base.base)])
|
|
||||||
|
|
||||||
def _get_match_algorithms_sel(self, cr, uid, context=None):
|
|
||||||
algorithms = []
|
|
||||||
for cls in self._get_match_algorithms().itervalues():
|
|
||||||
algorithms.append((cls.__name__, cls.name))
|
|
||||||
algorithms.sort()
|
|
||||||
return algorithms
|
|
||||||
|
|
||||||
_columns = {
|
|
||||||
'sequence': fields.integer('Sequence'),
|
|
||||||
'path': fields.char(
|
|
||||||
'Path', size=256, help='The path to your mail '
|
|
||||||
"folder. Typically would be something like 'INBOX.myfolder'",
|
|
||||||
required=True
|
|
||||||
),
|
|
||||||
'model_id': fields.many2one(
|
|
||||||
'ir.model', 'Model', required=True,
|
|
||||||
help='The model to attach emails to'
|
|
||||||
),
|
|
||||||
'model_field': fields.char(
|
|
||||||
'Field (model)', size=128,
|
|
||||||
help='The field in your model that contains the field to match '
|
|
||||||
'against.\n'
|
|
||||||
'Examples:\n'
|
|
||||||
"'email' if your model is res.partner, or "
|
|
||||||
"'partner_id.email' if you're matching sale orders"
|
|
||||||
),
|
|
||||||
'model_order': fields.char(
|
|
||||||
'Order (model)', size=128,
|
|
||||||
help='Fields to order by, this mostly useful in conjunction '
|
|
||||||
"with 'Use 1st match'"
|
|
||||||
),
|
|
||||||
'match_algorithm': fields.selection(
|
|
||||||
_get_match_algorithms_sel,
|
|
||||||
'Match algorithm', required=True, translate=True,
|
|
||||||
help='The algorithm used to determine which object an email '
|
|
||||||
'matches.'
|
|
||||||
),
|
|
||||||
'mail_field': fields.char(
|
|
||||||
'Field (email)', size=128,
|
|
||||||
help='The field in the email used for matching. Typically '
|
|
||||||
"this is 'to' or 'from'"
|
|
||||||
),
|
|
||||||
'server_id': fields.many2one('fetchmail.server', 'Server'),
|
|
||||||
'delete_matching': fields.boolean(
|
|
||||||
'Delete matches',
|
|
||||||
help='Delete matched emails from server'
|
|
||||||
),
|
|
||||||
'flag_nonmatching': fields.boolean(
|
|
||||||
'Flag nonmatching',
|
|
||||||
help="Flag emails in the server that don't match any object "
|
|
||||||
'in OpenERP'
|
|
||||||
),
|
|
||||||
'match_first': fields.boolean(
|
|
||||||
'Use 1st match',
|
|
||||||
help='If there are multiple matches, use the first one. If '
|
|
||||||
'not checked, multiple matches count as no match at all'
|
|
||||||
),
|
|
||||||
'domain': fields.char(
|
|
||||||
'Domain', size=128, help='Fill in a search '
|
|
||||||
'filter to narrow down objects to match'
|
|
||||||
),
|
|
||||||
'msg_state': fields.selection(
|
|
||||||
[
|
|
||||||
('sent', 'Sent'),
|
|
||||||
('received', 'Received'),
|
|
||||||
],
|
|
||||||
'Message state',
|
|
||||||
help='The state messages fetched from this folder should be '
|
|
||||||
'assigned in OpenERP'
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
_defaults = {
|
|
||||||
'flag_nonmatching': True,
|
|
||||||
'msg_state': 'received',
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_algorithm(self, cr, uid, ids, context=None):
|
|
||||||
for this in self.browse(cr, uid, ids, context):
|
|
||||||
return self._get_match_algorithms()[this.match_algorithm]()
|
|
||||||
|
|
||||||
def button_attach_mail_manually(self, cr, uid, ids, context=None):
|
|
||||||
for this in self.browse(cr, uid, ids, context):
|
|
||||||
context.update({'default_folder_id': this.id})
|
|
||||||
return {
|
|
||||||
'type': 'ir.actions.act_window',
|
|
||||||
'res_model': 'fetchmail.attach.mail.manually',
|
|
||||||
'target': 'new',
|
|
||||||
'context': context,
|
|
||||||
'view_type': 'form',
|
|
||||||
'view_mode': 'form',
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<openerp>
|
|
||||||
<data>
|
|
||||||
<record model="ir.ui.view" id="view_attach_mail_manually">
|
|
||||||
<field name="name">fetchmail.attach.mail.manually</field>
|
|
||||||
<field name="model">fetchmail.attach.mail.manually</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form col="4" version="7.0" string="Attach mail manually">
|
|
||||||
<sheet>
|
|
||||||
<group>
|
|
||||||
<field name="folder_id" />
|
|
||||||
<field name="mail_ids" nolabel="1" colspan="4">
|
|
||||||
<tree editable="top" create="0">
|
|
||||||
<field name="subject" />
|
|
||||||
<field name="date" />
|
|
||||||
<field name="object_id" />
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</group>
|
|
||||||
</sheet>
|
|
||||||
<footer>
|
|
||||||
<button string="Save" type="object" name="attach_mails" icon="gtk-ok" />
|
|
||||||
<button special="cancel" string="Cancel" icon="gtk-cancel" />
|
|
||||||
</footer>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
</data>
|
|
||||||
</openerp>
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
Email gateway - folders
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Adds the possibility to attach emails from a certain IMAP folder to objects,
|
||||||
|
ie partners. Matching is done via several algorithms, ie email address, email
|
||||||
|
address's domain or the original Odoo algorithm.
|
||||||
|
|
||||||
|
This gives a simple possibility to archive emails in Odoo without a mail
|
||||||
|
client integration.
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
=============
|
||||||
|
|
||||||
|
In your fetchmail configuration, you'll find a new list field `Folders to
|
||||||
|
monitor`. Add your folders here in IMAP notation (usually something like
|
||||||
|
`INBOX.your_folder_name.your_subfolder_name`), choose a model to attach mails
|
||||||
|
to and a matching algorithm to use.
|
||||||
|
|
||||||
|
Exact mailaddress
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Fill in a field to search for the email address in `Field (model)`. For
|
||||||
|
partners, this would be `email`. Also fill in the header field from the email
|
||||||
|
to look at in `Field (email)`. If you want to match incoming mails from your
|
||||||
|
customers, this would be `from`. You can also list header fields, so to match
|
||||||
|
partners receiving this email, you might fill in `to,cc,bcc`.
|
||||||
|
|
||||||
|
Domain of email addresses
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Match the domain of the email address(es) found in `Field (email)`. This would
|
||||||
|
attach a mail to `test1@example.com` to a record with `Field (model)` set to
|
||||||
|
`test2@example.com`. Given that this is a fuzzy match, you probably want to
|
||||||
|
check `Use 1st match`, because otherwise nothing happens if multiple possible
|
||||||
|
matches are found.
|
||||||
|
|
||||||
|
Odoo standard
|
||||||
|
-------------
|
||||||
|
|
||||||
|
This is stricly speaking no matching algorithm, but calls the model's standard
|
||||||
|
action on new incoming mail, which is usually creating a new record.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
A widespread configuration is to have a shared mailbox with several folders,
|
||||||
|
i.e. one where users drop mails they want to attach to partners. Let this
|
||||||
|
folder be called `From partners`. Then create a folder configuration for your
|
||||||
|
server with path `"INBOX.From partners"` (note the quotes because of the space,
|
||||||
|
this is server dependent). Choose model `Partners`, set `Field (model)` to
|
||||||
|
`email` and `Field (email)` to `from`. In `Domain`, you could fill in
|
||||||
|
`[('customer', '=', True)]` to be sure to only match customer records.
|
||||||
|
|
||||||
|
Now when your users drop mails into this folder, they will be fetched by Odoo
|
||||||
|
and attached to the partner in question. After some testing, you might want to
|
||||||
|
check `Delete matches` in your folder configuration so that this folder doesn't
|
||||||
|
grow indefinitely.
|
||||||
|
|
||||||
|
Credits
|
||||||
|
=======
|
||||||
|
|
||||||
|
Contributors
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Holger Brunn <hbrunn@therp.nl>
|
||||||
|
|
||||||
|
Icon
|
||||||
|
----
|
||||||
|
|
||||||
|
http://commons.wikimedia.org/wiki/File:Crystal_Clear_filesystem_folder_favorites.png
|
||||||
|
|
||||||
|
Maintainer
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. image:: http://odoo-community.org/logo.png
|
||||||
|
:alt: Odoo Community Association
|
||||||
|
:target: http://odoo-community.org
|
||||||
|
|
||||||
|
This module is maintained by the OCA.
|
||||||
|
|
||||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.
|
||||||
|
|
||||||
|
To contribute to this module, please visit http://odoo-community.org.
|
|
@ -20,5 +20,6 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
import fetchmail_server
|
from . import match_algorithm
|
||||||
import fetchmail_server_folder
|
from . import model
|
||||||
|
from . import wizard
|
|
@ -21,15 +21,9 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Attach mails in an IMAP folder to existing objects',
|
'name': 'Email gateway - folders',
|
||||||
|
'summary': 'Attach mails in an IMAP folder to existing objects',
|
||||||
'version': '1.0',
|
'version': '1.0',
|
||||||
'description': """
|
|
||||||
Adds the possibility to attach emails from a certain IMAP folder to objects,
|
|
||||||
ie partners. Matching is done via several algorithms, ie email address.
|
|
||||||
|
|
||||||
This gives a simple possibility to archive emails in OpenERP without a mail
|
|
||||||
client integration.
|
|
||||||
""",
|
|
||||||
'author': 'Therp BV',
|
'author': 'Therp BV',
|
||||||
'website': 'http://www.therp.nl',
|
'website': 'http://www.therp.nl',
|
||||||
"category": "Tools",
|
"category": "Tools",
|
||||||
|
@ -38,9 +32,7 @@ client integration.
|
||||||
'view/fetchmail_server.xml',
|
'view/fetchmail_server.xml',
|
||||||
'wizard/attach_mail_manually.xml',
|
'wizard/attach_mail_manually.xml',
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
],
|
],
|
||||||
'js': [],
|
'installable': True,
|
||||||
'installable': False,
|
'active': True,
|
||||||
'active': False,
|
|
||||||
'certificate': '',
|
|
||||||
}
|
}
|
|
@ -20,7 +20,7 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
import base
|
from . import base
|
||||||
import email_exact
|
from . import email_exact
|
||||||
import email_domain
|
from . import email_domain
|
||||||
import openerp_standard
|
from . import openerp_standard
|
|
@ -26,10 +26,10 @@ class base(object):
|
||||||
'''Name shown to the user'''
|
'''Name shown to the user'''
|
||||||
|
|
||||||
required_fields = []
|
required_fields = []
|
||||||
'''Fields on fetchmail_server folder that are required for this algorithm'''
|
'''Fields on fetchmail_server folder required for this algorithm'''
|
||||||
|
|
||||||
readonly_fields = []
|
readonly_fields = []
|
||||||
'''Fields on fetchmail_server folder that are readonly for this algorithm'''
|
'''Fields on fetchmail_server folder readonly for this algorithm'''
|
||||||
|
|
||||||
def search_matches(self, cr, uid, conf, mail_message, mail_message_org):
|
def search_matches(self, cr, uid, conf, mail_message, mail_message_org):
|
||||||
'''Returns ids found for model with mail_message'''
|
'''Returns ids found for model with mail_message'''
|
|
@ -20,7 +20,7 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from email_exact import email_exact
|
from .email_exact import email_exact
|
||||||
|
|
||||||
|
|
||||||
class email_domain(email_exact):
|
class email_domain(email_exact):
|
||||||
|
@ -40,6 +40,6 @@ class email_domain(email_exact):
|
||||||
self._get_mailaddress_search_domain(
|
self._get_mailaddress_search_domain(
|
||||||
conf, mail_message,
|
conf, mail_message,
|
||||||
operator='like',
|
operator='like',
|
||||||
values=['%@'+domain for domain in set(domains)]),
|
values=['%@' + domain for domain in set(domains)]),
|
||||||
order=conf.model_order)
|
order=conf.model_order)
|
||||||
return ids
|
return ids
|
|
@ -20,7 +20,7 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from base import base
|
from .base import base
|
||||||
from openerp.tools.safe_eval import safe_eval
|
from openerp.tools.safe_eval import safe_eval
|
||||||
from openerp.tools.mail import email_split
|
from openerp.tools.mail import email_split
|
||||||
|
|
|
@ -20,14 +20,14 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from base import base
|
from .base import base
|
||||||
|
|
||||||
|
|
||||||
class openerp_standard(base):
|
class openerp_standard(base):
|
||||||
'''No search at all. Use OpenERP's standard mechanism to attach mails to
|
'''No search at all. Use OpenERP's standard mechanism to attach mails to
|
||||||
mail.thread objects. Note that this algorithm always matches.'''
|
mail.thread objects. Note that this algorithm always matches.'''
|
||||||
|
|
||||||
name = 'OpenERP standard'
|
name = 'Odoo standard'
|
||||||
readonly_fields = [
|
readonly_fields = [
|
||||||
'model_field',
|
'model_field',
|
||||||
'mail_field',
|
'mail_field',
|
|
@ -20,6 +20,5 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
import match_algorithm
|
from . import fetchmail_server
|
||||||
import model
|
from . import fetchmail_server_folder
|
||||||
import wizard
|
|
|
@ -19,33 +19,27 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
import logging
|
||||||
import base64
|
import base64
|
||||||
import simplejson
|
import simplejson
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from openerp.osv.orm import Model, except_orm
|
from openerp import models, fields, api, exceptions
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
from openerp.osv import fields
|
|
||||||
from openerp.addons.fetchmail.fetchmail import _logger as logger
|
|
||||||
from openerp.tools.misc import UnquoteEvalContext
|
from openerp.tools.misc import UnquoteEvalContext
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class fetchmail_server(Model):
|
class fetchmail_server(models.Model):
|
||||||
_inherit = 'fetchmail.server'
|
_inherit = 'fetchmail.server'
|
||||||
|
|
||||||
_columns = {
|
folder_ids = fields.One2many(
|
||||||
'folder_ids': fields.one2many(
|
'fetchmail.server.folder', 'server_id', 'Folders')
|
||||||
'fetchmail.server.folder', 'server_id', 'Folders'),
|
object_id = fields.Many2one(required=False)
|
||||||
}
|
|
||||||
|
|
||||||
_defaults = {
|
_defaults = {
|
||||||
'type': 'imap',
|
'type': 'imap',
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, pool, cr):
|
|
||||||
self._columns['object_id'].required = False
|
|
||||||
return super(fetchmail_server, self).__init__(pool, cr)
|
|
||||||
|
|
||||||
def onchange_server_type(
|
def onchange_server_type(
|
||||||
self, cr, uid, ids, server_type=False, ssl=False,
|
self, cr, uid, ids, server_type=False, ssl=False,
|
||||||
object_id=False):
|
object_id=False):
|
||||||
|
@ -75,111 +69,109 @@ class fetchmail_server(Model):
|
||||||
connection = this.connect()
|
connection = this.connect()
|
||||||
for folder in this.folder_ids:
|
for folder in this.folder_ids:
|
||||||
this.handle_folder(connection, folder)
|
this.handle_folder(connection, folder)
|
||||||
|
|
||||||
connection.close()
|
connection.close()
|
||||||
|
|
||||||
return super(fetchmail_server, self).fetch_mail(
|
return super(fetchmail_server, self).fetch_mail(
|
||||||
cr, uid, check_original, context)
|
cr, uid, check_original, context)
|
||||||
|
|
||||||
def handle_folder(self, cr, uid, ids, connection, folder, context=None):
|
@api.multi
|
||||||
|
def handle_folder(self, connection, folder):
|
||||||
'''Return ids of objects matched'''
|
'''Return ids of objects matched'''
|
||||||
|
|
||||||
matched_object_ids = []
|
matched_object_ids = []
|
||||||
|
|
||||||
for this in self.browse(cr, uid, ids, context=context):
|
for this in self:
|
||||||
logger.info('start checking for emails in %s server %s',
|
_logger.info(
|
||||||
folder.path, this.name)
|
'start checking for emails in %s server %s',
|
||||||
|
folder.path, this.name)
|
||||||
|
|
||||||
match_algorithm = folder.get_algorithm()
|
match_algorithm = folder.get_algorithm()
|
||||||
|
|
||||||
if connection.select(folder.path)[0] != 'OK':
|
if connection.select(folder.path)[0] != 'OK':
|
||||||
logger.error(
|
_logger.error(
|
||||||
'Could not open mailbox %s on %s' % (folder.path, this.server))
|
'Could not open mailbox %s on %s',
|
||||||
|
folder.path, this.server)
|
||||||
connection.select()
|
connection.select()
|
||||||
continue
|
continue
|
||||||
result, msgids = this.get_msgids(connection)
|
result, msgids = this.get_msgids(connection)
|
||||||
if result != 'OK':
|
if result != 'OK':
|
||||||
logger.error(
|
_logger.error(
|
||||||
'Could not search mailbox %s on %s' % (
|
'Could not search mailbox %s on %s',
|
||||||
folder.path, this.server))
|
folder.path, this.server)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for msgid in msgids[0].split():
|
for msgid in msgids[0].split():
|
||||||
matched_object_ids += this.apply_matching(
|
matched_object_ids += this.apply_matching(
|
||||||
connection, folder, msgid, match_algorithm)
|
connection, folder, msgid, match_algorithm)
|
||||||
|
|
||||||
logger.info('finished checking for emails in %s server %s',
|
_logger.info(
|
||||||
folder.path, this.name)
|
'finished checking for emails in %s server %s',
|
||||||
|
folder.path, this.name)
|
||||||
|
|
||||||
return matched_object_ids
|
return matched_object_ids
|
||||||
|
|
||||||
def get_msgids(self, cr, uid, ids, connection, context=None):
|
@api.multi
|
||||||
|
def get_msgids(self, connection):
|
||||||
'''Return imap ids of messages to process'''
|
'''Return imap ids of messages to process'''
|
||||||
return connection.search(None, 'UNDELETED')
|
return connection.search(None, 'UNDELETED')
|
||||||
|
|
||||||
def apply_matching(self, cr, uid, ids, connection, folder, msgid,
|
@api.multi
|
||||||
match_algorithm, context=None):
|
def apply_matching(self, connection, folder, msgid, match_algorithm):
|
||||||
'''Return ids of objects matched'''
|
'''Return ids of objects matched'''
|
||||||
|
|
||||||
matched_object_ids = []
|
matched_object_ids = []
|
||||||
|
|
||||||
for this in self.browse(cr, uid, ids, context=context):
|
for this in self:
|
||||||
result, msgdata = connection.fetch(msgid, '(RFC822)')
|
result, msgdata = connection.fetch(msgid, '(RFC822)')
|
||||||
|
|
||||||
if result != 'OK':
|
if result != 'OK':
|
||||||
logger.error(
|
_logger.error(
|
||||||
'Could not fetch %s in %s on %s' % (msgid, folder.path, this.server))
|
'Could not fetch %s in %s on %s',
|
||||||
|
msgid, folder.path, this.server)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
mail_message = self.pool.get('mail.thread').message_parse(
|
mail_message = self.env['mail.thread'].message_parse(
|
||||||
cr, uid, msgdata[0][1], save_original=this.original,
|
msgdata[0][1], save_original=this.original)
|
||||||
context=context)
|
|
||||||
|
|
||||||
if self.pool.get('mail.message').search(
|
if self.env['mail.message'].search(
|
||||||
cr, uid, [
|
[('message_id', '=', mail_message['message_id'])]):
|
||||||
('message_id', '=', mail_message['message_id'])]):
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
found_ids = match_algorithm.search_matches(
|
found_ids = match_algorithm.search_matches(
|
||||||
cr, uid, folder,
|
self.env.cr, self.env.uid, folder, mail_message, msgdata[0][1])
|
||||||
mail_message, msgdata[0][1])
|
|
||||||
|
|
||||||
if found_ids and (len(found_ids) == 1 or
|
if found_ids and (len(found_ids) == 1 or
|
||||||
folder.match_first):
|
folder.match_first):
|
||||||
try:
|
try:
|
||||||
cr.execute('savepoint apply_matching')
|
self.env.cr.execute('savepoint apply_matching')
|
||||||
match_algorithm.handle_match(
|
match_algorithm.handle_match(
|
||||||
cr, uid, connection,
|
self.env.cr, self.env.uid, connection,
|
||||||
found_ids[0], folder, mail_message,
|
found_ids[0], folder, mail_message,
|
||||||
msgdata[0][1], msgid, context)
|
msgdata[0][1], msgid, self.env.context)
|
||||||
cr.execute('release savepoint apply_matching')
|
self.env.cr.execute('release savepoint apply_matching')
|
||||||
matched_object_ids += found_ids[:1]
|
matched_object_ids += found_ids[:1]
|
||||||
except Exception:
|
except Exception:
|
||||||
cr.execute('rollback to savepoint apply_matching')
|
self.env.cr.execute('rollback to savepoint apply_matching')
|
||||||
logger.exception(
|
_logger.exception(
|
||||||
"Failed to fetch mail %s from %s",
|
"Failed to fetch mail %s from %s", msgid, this.name)
|
||||||
msgid, this.name)
|
|
||||||
elif folder.flag_nonmatching:
|
elif folder.flag_nonmatching:
|
||||||
connection.store(msgid, '+FLAGS', '\\FLAGGED')
|
connection.store(msgid, '+FLAGS', '\\FLAGGED')
|
||||||
|
|
||||||
return matched_object_ids
|
return matched_object_ids
|
||||||
|
|
||||||
def attach_mail(
|
@api.multi
|
||||||
self, cr, uid, ids, connection, object_id, folder,
|
def attach_mail(self, connection, object_id, folder, mail_message, msgid):
|
||||||
mail_message, msgid, context=None):
|
|
||||||
'''Return ids of messages created'''
|
'''Return ids of messages created'''
|
||||||
|
|
||||||
mail_message_ids = []
|
mail_message_ids = []
|
||||||
|
|
||||||
for this in self.browse(cr, uid, ids, context):
|
for this in self:
|
||||||
partner_id = None
|
partner_id = None
|
||||||
if folder.model_id.model == 'res.partner':
|
if folder.model_id.model == 'res.partner':
|
||||||
partner_id = object_id
|
partner_id = object_id
|
||||||
if 'partner_id' in self.pool.get(folder.model_id.model)._columns:
|
if 'partner_id' in self.env[folder.model_id.model]._columns:
|
||||||
partner_id = self.pool.get(
|
partner_id = self.env[folder.model_id.model].browse(object_id)\
|
||||||
folder.model_id.model).browse(
|
.partner_id.id
|
||||||
cr, uid, object_id, context
|
|
||||||
).partner_id.id
|
|
||||||
|
|
||||||
attachments = []
|
attachments = []
|
||||||
if this.attach and mail_message.get('attachments'):
|
if this.attach and mail_message.get('attachments'):
|
||||||
|
@ -196,34 +188,29 @@ class fetchmail_server(Model):
|
||||||
'res_id': object_id,
|
'res_id': object_id,
|
||||||
}
|
}
|
||||||
attachments.append(
|
attachments.append(
|
||||||
self.pool.get('ir.attachment').create(
|
self.env['ir.attachment'].create(data_attach))
|
||||||
cr, uid, data_attach, context=context))
|
|
||||||
|
|
||||||
mail_message_ids.append(
|
mail_message_ids.append(
|
||||||
self.pool.get('mail.message').create(
|
self.env['mail.message'].create({
|
||||||
cr, uid,
|
'author_id': partner_id,
|
||||||
{
|
'model': folder.model_id.model,
|
||||||
'author_id': partner_id,
|
'res_id': object_id,
|
||||||
'model': folder.model_id.model,
|
'type': 'email',
|
||||||
'res_id': object_id,
|
'body': mail_message.get('body'),
|
||||||
'type': 'email',
|
'subject': mail_message.get('subject'),
|
||||||
'body': mail_message.get('body'),
|
'email_from': mail_message.get('from'),
|
||||||
'subject': mail_message.get('subject'),
|
'date': mail_message.get('date'),
|
||||||
'email_from': mail_message.get('from'),
|
'message_id': mail_message.get('message_id'),
|
||||||
'date': mail_message.get('date'),
|
'attachment_ids': [(6, 0, [a.id for a in attachments])],
|
||||||
'message_id': mail_message.get('message_id'),
|
}))
|
||||||
'attachment_ids': [(6, 0, attachments)],
|
|
||||||
},
|
|
||||||
context))
|
|
||||||
|
|
||||||
if folder.delete_matching:
|
if folder.delete_matching:
|
||||||
connection.store(msgid, '+FLAGS', '\\DELETED')
|
connection.store(msgid, '+FLAGS', '\\DELETED')
|
||||||
return mail_message_ids
|
return mail_message_ids
|
||||||
|
|
||||||
def button_confirm_login(self, cr, uid, ids, context=None):
|
def button_confirm_login(self, cr, uid, ids, context=None):
|
||||||
retval = super(fetchmail_server, self).button_confirm_login(cr, uid,
|
retval = super(fetchmail_server, self).button_confirm_login(
|
||||||
ids,
|
cr, uid, ids, context)
|
||||||
context)
|
|
||||||
|
|
||||||
for this in self.browse(cr, uid, ids, context):
|
for this in self.browse(cr, uid, ids, context):
|
||||||
this.write({'state': 'draft'})
|
this.write({'state': 'draft'})
|
||||||
|
@ -231,9 +218,8 @@ class fetchmail_server(Model):
|
||||||
connection.select()
|
connection.select()
|
||||||
for folder in this.folder_ids:
|
for folder in this.folder_ids:
|
||||||
if connection.select(folder.path)[0] != 'OK':
|
if connection.select(folder.path)[0] != 'OK':
|
||||||
raise except_orm(
|
raise exceptions.ValidationError(
|
||||||
_('Error'), _('Mailbox %s not found!') %
|
_('Mailbox %s not found!') % folder.path)
|
||||||
folder.path)
|
|
||||||
connection.close()
|
connection.close()
|
||||||
this.write({'state': 'done'})
|
this.write({'state': 'done'})
|
||||||
|
|
||||||
|
@ -249,7 +235,7 @@ class fetchmail_server(Model):
|
||||||
result['fields']['folder_ids']['views']['form']['arch'])
|
result['fields']['folder_ids']['views']['form']['arch'])
|
||||||
modifiers = {}
|
modifiers = {}
|
||||||
docstr = ''
|
docstr = ''
|
||||||
for algorithm in self.pool.get('fetchmail.server.folder')\
|
for algorithm in self.pool['fetchmail.server.folder']\
|
||||||
._get_match_algorithms().itervalues():
|
._get_match_algorithms().itervalues():
|
||||||
for modifier in ['required', 'readonly']:
|
for modifier in ['required', 'readonly']:
|
||||||
for field in getattr(algorithm, modifier + '_fields'):
|
for field in getattr(algorithm, modifier + '_fields'):
|
||||||
|
@ -262,7 +248,7 @@ class fetchmail_server(Model):
|
||||||
docstr += _(algorithm.name) + '\n' + _(algorithm.__doc__) + \
|
docstr += _(algorithm.name) + '\n' + _(algorithm.__doc__) + \
|
||||||
'\n\n'
|
'\n\n'
|
||||||
|
|
||||||
for field in view:
|
for field in view.xpath('//field'):
|
||||||
if field.tag == 'field' and field.get('name') in modifiers:
|
if field.tag == 'field' and field.get('name') in modifiers:
|
||||||
field.set('modifiers', simplejson.dumps(
|
field.set('modifiers', simplejson.dumps(
|
||||||
dict(
|
dict(
|
|
@ -0,0 +1,115 @@
|
||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# OpenERP, Open Source Management Solution
|
||||||
|
# This module copyright (C) 2013 Therp BV (<http://therp.nl>)
|
||||||
|
# All Rights Reserved
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
########################################################################
|
||||||
|
from openerp import api, models, fields
|
||||||
|
from .. import match_algorithm
|
||||||
|
|
||||||
|
|
||||||
|
class fetchmail_server_folder(models.Model):
|
||||||
|
_name = 'fetchmail.server.folder'
|
||||||
|
_rec_name = 'path'
|
||||||
|
|
||||||
|
def _get_match_algorithms(self):
|
||||||
|
def get_all_subclasses(cls):
|
||||||
|
return (cls.__subclasses__() +
|
||||||
|
[subsub
|
||||||
|
for sub in cls.__subclasses__()
|
||||||
|
for subsub in get_all_subclasses(sub)])
|
||||||
|
return dict([(cls.__name__, cls)
|
||||||
|
for cls in get_all_subclasses(
|
||||||
|
match_algorithm.base.base)])
|
||||||
|
|
||||||
|
def _get_match_algorithms_sel(self):
|
||||||
|
algorithms = []
|
||||||
|
for cls in self._get_match_algorithms().itervalues():
|
||||||
|
algorithms.append((cls.__name__, cls.name))
|
||||||
|
algorithms.sort()
|
||||||
|
return algorithms
|
||||||
|
|
||||||
|
sequence = fields.Integer('Sequence')
|
||||||
|
path = fields.Char(
|
||||||
|
'Path',
|
||||||
|
help="The path to your mail folder. Typically would be something like "
|
||||||
|
"'INBOX.myfolder'", required=True)
|
||||||
|
model_id = fields.Many2one(
|
||||||
|
'ir.model', 'Model', required=True,
|
||||||
|
help='The model to attach emails to')
|
||||||
|
model_field = fields.Char(
|
||||||
|
'Field (model)',
|
||||||
|
help='The field in your model that contains the field to match '
|
||||||
|
'against.\n'
|
||||||
|
'Examples:\n'
|
||||||
|
"'email' if your model is res.partner, or "
|
||||||
|
"'partner_id.email' if you're matching sale orders")
|
||||||
|
model_order = fields.Char(
|
||||||
|
'Order (model)',
|
||||||
|
help='Field(s) to order by, this mostly useful in conjunction '
|
||||||
|
"with 'Use 1st match'")
|
||||||
|
match_algorithm = fields.Selection(
|
||||||
|
_get_match_algorithms_sel,
|
||||||
|
'Match algorithm', required=True,
|
||||||
|
help='The algorithm used to determine which object an email matches.')
|
||||||
|
mail_field = fields.Char(
|
||||||
|
'Field (email)',
|
||||||
|
help='The field in the email used for matching. Typically '
|
||||||
|
"this is 'to' or 'from'")
|
||||||
|
server_id = fields.Many2one('fetchmail.server', 'Server')
|
||||||
|
delete_matching = fields.Boolean(
|
||||||
|
'Delete matches',
|
||||||
|
help='Delete matched emails from server')
|
||||||
|
flag_nonmatching = fields.Boolean(
|
||||||
|
'Flag nonmatching',
|
||||||
|
help="Flag emails in the server that don't match any object in Odoo")
|
||||||
|
match_first = fields.Boolean(
|
||||||
|
'Use 1st match',
|
||||||
|
help='If there are multiple matches, use the first one. If '
|
||||||
|
'not checked, multiple matches count as no match at all')
|
||||||
|
domain = fields.Char(
|
||||||
|
'Domain',
|
||||||
|
help='Fill in a search filter to narrow down objects to match')
|
||||||
|
msg_state = fields.Selection(
|
||||||
|
[
|
||||||
|
('sent', 'Sent'),
|
||||||
|
('received', 'Received'),
|
||||||
|
],
|
||||||
|
'Message state',
|
||||||
|
help='The state messages fetched from this folder should be '
|
||||||
|
'assigned in Odoo')
|
||||||
|
|
||||||
|
_defaults = {
|
||||||
|
'flag_nonmatching': True,
|
||||||
|
'msg_state': 'received',
|
||||||
|
}
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def get_algorithm(self):
|
||||||
|
return self._get_match_algorithms()[self.match_algorithm]()
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
def button_attach_mail_manually(self):
|
||||||
|
return {
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
'res_model': 'fetchmail.attach.mail.manually',
|
||||||
|
'target': 'new',
|
||||||
|
'context': dict(self.env.context, default_folder_id=self.id),
|
||||||
|
'view_type': 'form',
|
||||||
|
'view_mode': 'form',
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,21 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# OpenERP, Open Source Management Solution
|
||||||
|
# This module copyright (C) 2015 Therp BV (<http://therp.nl>).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
from . import test_match_algorithms
|
|
@ -0,0 +1,103 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# OpenERP, Open Source Management Solution
|
||||||
|
# This module copyright (C) 2015 Therp BV (<http://therp.nl>).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
from openerp import models
|
||||||
|
from openerp.tests.common import TransactionCase
|
||||||
|
from openerp.addons.fetchmail_attach_from_folder.match_algorithm import (
|
||||||
|
email_exact, email_domain, openerp_standard)
|
||||||
|
|
||||||
|
|
||||||
|
class TestMatchAlgorithms(TransactionCase):
|
||||||
|
def do_matching(self, match_algorithm, expected_xmlid, conf, mail_message,
|
||||||
|
mail_message_org=None):
|
||||||
|
matcher = match_algorithm()
|
||||||
|
matches = matcher.search_matches(
|
||||||
|
self.env.cr, self.env.uid, conf, mail_message, mail_message_org)
|
||||||
|
self.assertEqual(len(matches), 1)
|
||||||
|
self.assertEqual(
|
||||||
|
matches[0], self.env.ref(expected_xmlid).id)
|
||||||
|
matcher.handle_match(
|
||||||
|
self.env.cr, self.env.uid, None, matches[0], conf, mail_message,
|
||||||
|
mail_message_org, None)
|
||||||
|
|
||||||
|
def test_email_exact(self):
|
||||||
|
mail_message = {
|
||||||
|
'subject': 'Testsubject',
|
||||||
|
'to': 'demo@yourcompany.example.com',
|
||||||
|
'from': 'someone@else.com',
|
||||||
|
}
|
||||||
|
conf = self.env['fetchmail.server.folder'].browse([models.NewId()])
|
||||||
|
conf.model_id = self.env.ref('base.model_res_partner').id
|
||||||
|
conf.model_field = 'email'
|
||||||
|
conf.match_algorithm = 'email_exact'
|
||||||
|
conf.mail_field = 'to,from'
|
||||||
|
conf.server_id = self.env['fetchmail.server'].browse([models.NewId()])
|
||||||
|
self.do_matching(
|
||||||
|
email_exact.email_exact, 'base.user_demo_res_partner',
|
||||||
|
conf, mail_message)
|
||||||
|
self.assertEqual(
|
||||||
|
self.env.ref('base.user_demo_res_partner').message_ids.subject,
|
||||||
|
mail_message['subject'])
|
||||||
|
|
||||||
|
def test_email_domain(self):
|
||||||
|
mail_message = {
|
||||||
|
'subject': 'Testsubject',
|
||||||
|
'to': 'test@seagate.com',
|
||||||
|
'from': 'someone@else.com',
|
||||||
|
}
|
||||||
|
conf = self.env['fetchmail.server.folder'].browse([models.NewId()])
|
||||||
|
conf.model_id = self.env.ref('base.model_res_partner').id
|
||||||
|
conf.model_field = 'email'
|
||||||
|
conf.match_algorithm = 'email_domain'
|
||||||
|
conf.mail_field = 'to,from'
|
||||||
|
conf.use_first_match = True
|
||||||
|
conf.server_id = self.env['fetchmail.server'].browse([models.NewId()])
|
||||||
|
self.do_matching(
|
||||||
|
email_domain.email_domain, 'base.res_partner_address_31',
|
||||||
|
conf, mail_message)
|
||||||
|
self.assertEqual(
|
||||||
|
self.env.ref('base.res_partner_address_31').message_ids.subject,
|
||||||
|
mail_message['subject'])
|
||||||
|
|
||||||
|
def test_openerp_standard(self):
|
||||||
|
mail_message_org = (
|
||||||
|
"To: demo@yourcompany.example.com\n"
|
||||||
|
"From: someone@else.com\n"
|
||||||
|
"Subject: testsubject\n"
|
||||||
|
"Message-Id: 42\n"
|
||||||
|
"Hello world"
|
||||||
|
)
|
||||||
|
conf = self.env['fetchmail.server.folder'].browse([models.NewId()])
|
||||||
|
conf.model_id = self.env.ref('base.model_res_partner').id
|
||||||
|
conf.model_field = 'email'
|
||||||
|
conf.match_algorithm = 'openerp_standard'
|
||||||
|
conf.mail_field = 'to,from'
|
||||||
|
conf.server_id = self.env['fetchmail.server'].browse([models.NewId()])
|
||||||
|
matcher = openerp_standard.openerp_standard()
|
||||||
|
matches = matcher.search_matches(
|
||||||
|
self.env.cr, self.env.uid, conf, None, mail_message_org)
|
||||||
|
self.assertEqual(len(matches), 1)
|
||||||
|
matcher.handle_match(
|
||||||
|
self.env.cr, self.env.uid, None, matches[0], conf, None,
|
||||||
|
mail_message_org, None, None)
|
||||||
|
self.assertIn(
|
||||||
|
'Hello world',
|
||||||
|
self.env['mail.message']
|
||||||
|
.search([('subject', '=', 'testsubject')]).body)
|
|
@ -30,19 +30,19 @@
|
||||||
</header>
|
</header>
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="path" />
|
<field name="path" placeholder="INBOX.subfolder1" />
|
||||||
<field name="model_id" />
|
<field name="model_id" />
|
||||||
<field name="model_field" />
|
<field name="model_field" placeholder="email" />
|
||||||
<field name="match_algorithm" />
|
<field name="match_algorithm" />
|
||||||
<field name="mail_field" />
|
<field name="mail_field" placeholder="to,from" />
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="delete_matching" />
|
<field name="delete_matching" />
|
||||||
<field name="flag_nonmatching" />
|
<field name="flag_nonmatching" />
|
||||||
<field name="match_first" />
|
<field name="match_first" />
|
||||||
<field name="msg_state" />
|
<field name="msg_state" />
|
||||||
<field name="model_order" attrs="{'readonly': [('match_first','==',False)], 'required': [('match_first','==',True)]}" />
|
<field name="model_order" attrs="{'readonly': [('match_first','==',False)], 'required': [('match_first','==',True)]}" placeholder="name asc,type desc" />
|
||||||
<field name="domain" />
|
<field name="domain" placeholder="[('state', '=', 'open')]" />
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
</form>
|
</form>
|
|
@ -20,4 +20,4 @@
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
import attach_mail_manually
|
from . import attach_mail_manually
|
|
@ -19,22 +19,18 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
from openerp import fields, models
|
||||||
from openerp.osv import fields
|
|
||||||
from openerp.osv.orm import TransientModel
|
|
||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class attach_mail_manually(TransientModel):
|
class attach_mail_manually(models.TransientModel):
|
||||||
_name = 'fetchmail.attach.mail.manually'
|
_name = 'fetchmail.attach.mail.manually'
|
||||||
|
|
||||||
_columns = {
|
folder_id = fields.Many2one(
|
||||||
'folder_id': fields.many2one('fetchmail.server.folder', 'Folder',
|
'fetchmail.server.folder', 'Folder', readonly=True)
|
||||||
readonly=True),
|
mail_ids = fields.One2many(
|
||||||
'mail_ids': fields.one2many(
|
'fetchmail.attach.mail.manually.mail', 'wizard_id', 'Emails')
|
||||||
'fetchmail.attach.mail.manually.mail', 'wizard_id', 'Emails'),
|
|
||||||
}
|
|
||||||
|
|
||||||
def default_get(self, cr, uid, fields_list, context=None):
|
def default_get(self, cr, uid, fields_list, context=None):
|
||||||
if context is None:
|
if context is None:
|
||||||
|
@ -54,16 +50,14 @@ class attach_mail_manually(TransientModel):
|
||||||
None,
|
None,
|
||||||
'FLAGGED' if folder.flag_nonmatching else 'UNDELETED')
|
'FLAGGED' if folder.flag_nonmatching else 'UNDELETED')
|
||||||
if result != 'OK':
|
if result != 'OK':
|
||||||
logger.error('Could not search mailbox %s on %s' % (
|
_logger.error('Could not search mailbox %s on %s',
|
||||||
folder.path, folder.server_id.name))
|
folder.path, folder.server_id.name)
|
||||||
continue
|
continue
|
||||||
attach_mail_manually_mail._columns['object_id'].selection = [
|
|
||||||
(folder.model_id.model, folder.model_id.name)]
|
|
||||||
for msgid in msgids[0].split():
|
for msgid in msgids[0].split():
|
||||||
result, msgdata = connection.fetch(msgid, '(RFC822)')
|
result, msgdata = connection.fetch(msgid, '(RFC822)')
|
||||||
if result != 'OK':
|
if result != 'OK':
|
||||||
logger.error('Could not fetch %s in %s on %s' % (
|
_logger.error('Could not fetch %s in %s on %s',
|
||||||
msgid, folder.path, folder.server_id.name))
|
msgid, folder.path, folder.server_id.name)
|
||||||
continue
|
continue
|
||||||
mail_message = self.pool.get('mail.thread').message_parse(
|
mail_message = self.pool.get('mail.thread').message_parse(
|
||||||
cr, uid, msgdata[0][1],
|
cr, uid, msgdata[0][1],
|
||||||
|
@ -74,8 +68,8 @@ class attach_mail_manually(TransientModel):
|
||||||
'msgid': msgid,
|
'msgid': msgid,
|
||||||
'subject': mail_message.get('subject', ''),
|
'subject': mail_message.get('subject', ''),
|
||||||
'date': mail_message.get('date', ''),
|
'date': mail_message.get('date', ''),
|
||||||
'object_id': folder.model_id.model+',False'
|
'object_id': '%s,-1' % folder.model_id.model,
|
||||||
}))
|
}))
|
||||||
connection.close()
|
connection.close()
|
||||||
|
|
||||||
return defaults
|
return defaults
|
||||||
|
@ -87,8 +81,8 @@ class attach_mail_manually(TransientModel):
|
||||||
connection.select(this.folder_id.path)
|
connection.select(this.folder_id.path)
|
||||||
result, msgdata = connection.fetch(mail.msgid, '(RFC822)')
|
result, msgdata = connection.fetch(mail.msgid, '(RFC822)')
|
||||||
if result != 'OK':
|
if result != 'OK':
|
||||||
logger.error('Could not fetch %s in %s on %s' % (
|
_logger.error('Could not fetch %s in %s on %s',
|
||||||
mail.msgid, this.folder_id.path, this.server))
|
mail.msgid, this.folder_id.path, this.server)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
mail_message = self.pool.get('mail.thread').message_parse(
|
mail_message = self.pool.get('mail.thread').message_parse(
|
||||||
|
@ -104,26 +98,32 @@ class attach_mail_manually(TransientModel):
|
||||||
connection.close()
|
connection.close()
|
||||||
return {'type': 'ir.actions.act_window_close'}
|
return {'type': 'ir.actions.act_window_close'}
|
||||||
|
|
||||||
|
def fields_view_get(self, cr, user, view_id=None, view_type='form',
|
||||||
|
context=None, toolbar=False, submenu=False):
|
||||||
|
result = super(attach_mail_manually, self).fields_view_get(
|
||||||
|
cr, user, view_id, view_type, context, toolbar, submenu)
|
||||||
|
|
||||||
class attach_mail_manually_mail(TransientModel):
|
tree = result['fields']['mail_ids']['views']['tree']
|
||||||
|
for folder in self.pool['fetchmail.server.folder'].browse(
|
||||||
|
cr, user, [context.get('default_folder_id')], context):
|
||||||
|
tree['fields']['object_id']['selection'] = [
|
||||||
|
(folder.model_id.model, folder.model_id.name)
|
||||||
|
]
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class attach_mail_manually_mail(models.TransientModel):
|
||||||
_name = 'fetchmail.attach.mail.manually.mail'
|
_name = 'fetchmail.attach.mail.manually.mail'
|
||||||
|
|
||||||
_columns = {
|
wizard_id = fields.Many2one(
|
||||||
'wizard_id': fields.many2one('fetchmail.attach.mail.manually',
|
'fetchmail.attach.mail.manually', readonly=True)
|
||||||
readonly=True),
|
msgid = fields.Char('Message id', readonly=True)
|
||||||
'msgid': fields.char('Message id', size=16, readonly=True),
|
subject = fields.Char('Subject', readonly=True)
|
||||||
'subject': fields.char('Subject', size=128, readonly=True),
|
date = fields.Datetime('Date', readonly=True)
|
||||||
'date': fields.datetime('Date', readonly=True),
|
object_id = fields.Reference(
|
||||||
'object_id': fields.reference(
|
lambda self: [
|
||||||
'Object',
|
(m.model, m.name)
|
||||||
selection=lambda self, cr, uid, context: [
|
for m in self.env['ir.model'].search([])
|
||||||
(m.model, m.name)
|
],
|
||||||
for m in self.pool.get('ir.model').browse(
|
string='Object')
|
||||||
cr, uid,
|
|
||||||
self.pool.get('ir.model').search(cr, uid, []),
|
|
||||||
context
|
|
||||||
)
|
|
||||||
],
|
|
||||||
size=128,
|
|
||||||
),
|
|
||||||
}
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<openerp>
|
||||||
|
<data>
|
||||||
|
<record model="ir.ui.view" id="view_attach_mail_manually">
|
||||||
|
<field name="name">fetchmail.attach.mail.manually</field>
|
||||||
|
<field name="model">fetchmail.attach.mail.manually</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form col="4" string="Attach mail manually">
|
||||||
|
<group>
|
||||||
|
<field name="folder_id" />
|
||||||
|
<field name="mail_ids" nolabel="1" colspan="4">
|
||||||
|
<tree editable="top" create="0">
|
||||||
|
<field name="subject" />
|
||||||
|
<field name="date" />
|
||||||
|
<field name="object_id" />
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</group>
|
||||||
|
<footer>
|
||||||
|
<button string="Save" type="object" name="attach_mails" class="oe_highlight" />
|
||||||
|
or
|
||||||
|
<button special="cancel" string="Cancel" class="oe_link" />
|
||||||
|
</footer>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</openerp>
|
Loading…
Reference in New Issue