diff --git a/__init__.py b/__init__.py
index 296d16d..0ecc117 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,16 +1,17 @@
# The COPYRIGHT file at the top level of this repository contains the full
# copyright notices and license terms.
from trytond.pool import Pool
-from .activity import *
-from .imap import *
-from .user import *
+from . import activity
+from . import configuration
+from . import user
def register():
Pool.register(
- Activity,
- IMAPServer,
- User,
+ activity.Activity,
+ activity.Cron,
+ user.User,
+ configuration.Configuration,
module='electronic_mail_activity', type_='model')
Pool.register(
- ActivityReplyMail,
+ activity.ActivityReplyMail,
module='electronic_mail_activity', type_='wizard')
diff --git a/activity.py b/activity.py
index 71dcb68..cf6d678 100644
--- a/activity.py
+++ b/activity.py
@@ -4,6 +4,7 @@ from trytond.pool import Pool, PoolMeta
from trytond.model import fields, ModelView
from trytond.transaction import Transaction
from trytond.wizard import Wizard, StateAction
+from trytond.pyson import Eval, Bool
from email.utils import parseaddr, formataddr, formatdate, make_msgid
from email import encoders, message_from_bytes
from email.mime.multipart import MIMEMultipart
@@ -26,6 +27,16 @@ except ImportError:
__all__ = ['Activity', 'ActivityReplyMail']
+class Cron(metaclass=PoolMeta):
+ __name__ = 'ir.cron'
+
+ @classmethod
+ def __setup__(cls):
+ super().__setup__()
+ cls.method.selection.extend([
+ ('activity.activity|create_activity', "Create Activity")])
+
+
class Activity(metaclass=PoolMeta):
__name__ = 'activity.activity'
@@ -40,12 +51,17 @@ class Activity(metaclass=PoolMeta):
def __setup__(cls):
super(Activity, cls).__setup__()
cls._buttons.update({
- 'new': {
- 'icon': 'tryton-email',
- },
- 'reply': {
- 'icon': 'tryton-forward'
- },
+ 'new': {
+ 'icon': 'tryton-email',
+ },
+ 'reply': {
+ 'icon': 'tryton-forward',
+ },
+ 'guess': {
+ 'icon': 'tryton-forward',
+ 'invisible': Bool(Eval('resource', -1)),
+ 'depends': ['resource'],
+ },
})
@property
@@ -58,6 +74,10 @@ class Activity(metaclass=PoolMeta):
and self.related_activity.mail and
self.related_activity.mail.message_id or "")
+ @classmethod
+ def _get_origin(cls):
+ return super()._get_origin() + ['electronic.mail']
+
@property
def reference(self):
result = ""
@@ -95,6 +115,17 @@ class Activity(metaclass=PoolMeta):
def reply(cls, activities):
cls.check_activity_user_info()
+ @classmethod
+ @ModelView.button
+ def guess(cls, activities):
+ activities = cls.browse(sorted(activities, key=lambda x: x.id))
+ for activity in activities:
+ activity = cls(activity)
+ activity.guess_resource()
+ # Each activity is saved because in this list there
+ # could be a resource of another of the same list
+ activity.save()
+
@classmethod
def check_activity_user_info(cls):
"Check if user have deffined the a server and a mailbox"
@@ -265,158 +296,59 @@ class Activity(metaclass=PoolMeta):
return None
@classmethod
- def create_activity(cls, received_mails):
- IMAPServer = Pool().get('imap.server')
- CompanyEmployee = Pool().get('company.employee')
+ def create_activity(cls):
+ pool = Pool()
+ ModelData = pool.get('ir.model.data')
+ Employee = pool.get('company.employee')
+ ElectronicMail = pool.get('electronic.mail')
+ Mailbox = pool.get('electronic.mail.mailbox')
+ Activity = pool.get('activity.activity')
+ ActivityType = pool.get('activity.type')
+ ActivityConfiguration = pool.get('activity.configuration')
+ mails = ElectronicMail.search([
+ ('mailbox', '=', ActivityConfiguration(0).pending_mailbox)
+ ], order=[('date', 'ASC'), ('id', 'ASC')])
+ activity_type = ActivityType(ModelData.get_id('activity',
+ 'incoming_email_type'))
+ employee = ActivityConfiguration(0).employee
+ processed_mailbox = ActivityConfiguration(0).processed_mailbox
+ activities = []
+ for mail in mails:
+ activity = Activity()
+ activity.subject = mail.subject
+ activity.activity_type = activity_type
+ activity.employee = employee
+ activity.dtstart = mail.date
+ activity.description = html2text(mail.body_plain).replace('\r', '')
+ activity.mail = mail
+ activity.state = 'planned'
+ activity.resource = None
+ activity.origin = mail
+ activities.append(activity)
+ mail.mailbox = processed_mailbox
+ cls.save(activities)
+ ElectronicMail.save(mails)
+ cls.guess(activities)
+
+ def get_previous_activity(self):
ElectronicMail = Pool().get('electronic.mail')
- Attachment = Pool().get('ir.attachment')
- ActivityType = Pool().get('activity.type')
+ if not isinstance(self.origin, ElectronicMail):
+ return
+ parent = self.origin.parent
+ if not parent:
+ return
+ activities = self.search([
+ ('origin', '=', parent)
+ ], limit=1)
+ if activities:
+ return activities[0]
- values = []
- attachs = {}
- for server_id, mails in list(received_mails.items()):
- servers = IMAPServer.browse([server_id])
- server = servers and servers[0] or None
- for mail in mails:
- # Control if the mail recevied is send by us, searching if
- # there are any activity with that mail attached
- activity_exist = cls.search([
- ('mail', '=', mail.id)
- ])
- if activity_exist:
- continue
- # Take the possible employee, if not the default.
- deliveredtos = mail.deliveredto and [mail.deliveredto] or []
- deliveredtos.extend([m[1] for m in mail.all_to])
- deliveredtos.extend([m[1] for m in mail.all_cc])
- deliveredtos = ElectronicMail.validate_emails(deliveredtos)
- contact = None
- if deliveredtos:
- employees = CompanyEmployee.search([])
- parties = [p.party.id for p in employees]
- contacts = []
- for deliveredto in deliveredtos:
- cm = cls.get_contact_mechanism(deliveredto, parties)
- if cm:
- contacts.append(cm)
- contact = contacts and contacts[0] or None
- employee = None
- if contact:
- emails_employee = [c.value
- for c in contact.party.contact_mechanisms
- if c.type == 'email']
- employee = CompanyEmployee.search([
- ('party', '=', contact.party.id)
- ])
- if not employee:
- employee = server and server.employee or None
- emails_employee = (server and server.employee and
- [server.employee.party.email] or [])
- else:
- employee = employee[0]
-
- # Search for the parties with that mails, to attach in the
- # contacts and main contact
- mail_from = ElectronicMail.validate_emails(
- parseaddr(mail.from_.replace(',', ' '))[1])
- contact = cls.get_contact_mechanism(mail_from)
- main_contact = contact and contact.party or False
-
- email_to = []
- for to in mail.all_to:
- if to[1] not in emails_employee:
- email_to.append(to[1])
- email_cc = email_to + [m[1] for m in mail.all_cc]
- emails_cc = ElectronicMail.validate_emails(email_cc)
- contacts = []
- for email_cc in emails_cc:
- contact = cls.get_contact_mechanism(email_cc)
- if contact:
- contacts.append(contact.party.id)
-
- # Search for the possible activity referenced to add in the
- # same resource.
- referenced_mail = []
- if mail.in_reply_to:
- referenced_mail = ElectronicMail.search([
- ('message_id', '=', mail.in_reply_to)
- ])
- if not referenced_mail and mail.reference:
- referenced_mail = ElectronicMail.search([
- ('message_id', 'in', mail.reference)
- ])
-
- # Fill the fields, in case the activity don't have enought
- # information
- resource = None
- party = (main_contact and
- [r.to for r in main_contact.relations] or [])
- party = party and party[0] or None
- if referenced_mail:
- # Search if the activity have resource to use for activity
- # that create now.
- referenced_mails = [r.id for r in referenced_mail]
- activities = cls.search([
- ('mail', 'in', referenced_mails)
- ])
- if activities:
- resource = activities[0].resource
- party = resource and resource.party or party
-
- # TODO: Search for a better default.
- # By the moment search the first activity type with the 0 in
- # sequence
- activity_types = ActivityType.search([
- ('sequence', '=', 0)
- ])
- activity_type = activity_types and activity_types[0] or None
-
- # Create the activity
- base_values = {
- 'subject': mail.subject or "NONE",
- 'activity_type': activity_type,
- 'employee': employee.id,
- 'dtstart': datetime.datetime.now(),
- 'description': (mail.body_plain
- or html2text(mail.body_html)),
- 'mail': mail.id,
- 'state': 'planned',
- 'resource': None,
- }
- values = base_values.copy()
- if resource:
- values['resource'] = str(resource)
- if party:
- values['party'] = party.id
- if main_contact:
- values['main_contact'] = main_contact.id
- if contacts:
- values['contacts'] = [('add', contacts)]
- try:
- activity = cls.create([values])
- except:
- activity = cls.create([base_values])
-
- # Add all the possible attachments from the mil to the activity
- msg = message_from_bytes(mail.mail_file)
- attachs = ElectronicMail.get_attachments(msg)
- if attachs:
- values = []
- for attach in attachs:
- values.append({
- 'name': attach.get('filename', mail.subject),
- 'type': 'data',
- 'data': attach.get('data'),
- 'resource': str(activity[0])
- })
- try:
- Attachment.create(values)
- except Exception as e:
- logging.getLogger('Activity Mail').info(
- 'The mail (%s) has attachments but they are not '
- 'possible to attach to the activity (%s).\n\n%s' %
- (mail.id, activity.id, e))
- return mails
+ def guess_resource(self):
+ previous_activity = self.get_previous_activity()
+ if previous_activity:
+ if previous_activity.resource:
+ self.resource = previous_activity.resource
+ self.party = previous_activity.resource.party
class ActivityReplyMail(Wizard, metaclass=PoolMeta):
diff --git a/activity.xml b/activity.xml
index b1eb6db..03fe44f 100644
--- a/activity.xml
+++ b/activity.xml
@@ -3,6 +3,13 @@
copyright notices and license terms. -->
+
+ activity.activity|create_activity
+
+
+ days
+
+
Reply Mail
activity.activity.replymail
@@ -42,5 +49,15 @@
+
+ guess
+ Guess Resource
+
+
+
+
+
+
diff --git a/configuration.py b/configuration.py
new file mode 100644
index 0000000..fd12c08
--- /dev/null
+++ b/configuration.py
@@ -0,0 +1,16 @@
+from trytond.pool import Pool, PoolMeta
+from trytond.model import fields, ModelView
+
+
+__all__ = ['Configuration']
+
+
+class Configuration(metaclass=PoolMeta):
+ 'Activity Configuration'
+ __name__ = 'activity.configuration'
+
+ employee = fields.Many2One('company.employee', 'Employee', required=True)
+ pending_mailbox = fields.Many2One('electronic.mail.mailbox', 'Pending Mailbox',
+ required=True)
+ processed_mailbox = fields.Many2One('electronic.mail.mailbox', 'Processed Mailbox',
+ required=True)
\ No newline at end of file
diff --git a/configuration.xml b/configuration.xml
new file mode 100644
index 0000000..5ab0e21
--- /dev/null
+++ b/configuration.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+ activity.configuration
+
+ configuration_form
+
+
+
diff --git a/imap.py b/imap.py
deleted file mode 100644
index f583096..0000000
--- a/imap.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# The COPYRIGHT file at the top level of this repository contains the full
-# copyright notices and license terms.
-from trytond.pool import Pool, PoolMeta
-from trytond.model import fields
-
-__all__ = ['IMAPServer']
-
-
-class IMAPServer(metaclass=PoolMeta):
- __name__ = 'imap.server'
-
- employee = fields.Many2One('company.employee', 'Default Employee')
-
- @classmethod
- def fetch_mails(cls, servers):
- Activity = Pool().get('activity.activity')
- activity_servers = []
- other_servers = []
- for server in servers:
- if server.model and server.model.model == 'activity.activity':
- activity_servers.append(server)
- else:
- other_servers.append(server)
- mails = {}
- if activity_servers:
- mails.update(super(IMAPServer, cls).fetch_mails(activity_servers))
- Activity.create_activity(mails)
- if other_servers:
- mails.update(super(IMAPServer, cls).fetch_mails(other_servers))
- return mails
diff --git a/imap.xml b/imap.xml
deleted file mode 100644
index 9678774..0000000
--- a/imap.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
- imap.server
-
- imap_server_form
-
-
-
diff --git a/locale/ca.po b/locale/ca.po
index 1dabda1..8e66ffc 100644
--- a/locale/ca.po
+++ b/locale/ca.po
@@ -14,6 +14,14 @@ msgctxt "field:activity.activity,related_activity:"
msgid "Related activity"
msgstr "Activitat relacionada"
+msgctxt "field:activity.configuration,pending_mailbox:"
+msgid "Pending Mailbox"
+msgstr "Bústia de correu Pendents"
+
+msgctxt "field:activity.configuration,processed_mailbox:"
+msgid "Processed Mailbox"
+msgstr "Bústia de correu Processats"
+
msgctxt "field:imap.server,employee:"
msgid "Default Employee"
msgstr "Empleat per defecte"
@@ -26,6 +34,10 @@ msgctxt "field:res.user,mailbox:"
msgid "Mailbox"
msgstr "Bústia de correu"
+msgctxt "field:res.user,signature_html:"
+msgid "Signature"
+msgstr "Signatura"
+
msgctxt "field:res.user,smtp_server:"
msgid "SMTP Server"
msgstr "Servidor SMTP"
@@ -63,6 +75,10 @@ msgctxt "model:ir.message,text:no_valid_mail"
msgid "The \"%(mail)s\" of the party \"%(party)s\" it is not correct."
msgstr "El \"%(mail)s\" del tercer \"%(party)s\" no es correcte."
+msgctxt "model:ir.model.button,string:electronic_mail_guess_button"
+msgid "Guess Resource"
+msgstr "Troba recurs"
+
msgctxt "model:ir.model.button,string:electronic_mail_new_button"
msgid "Send Mail"
msgstr "Envia correu"
@@ -71,6 +87,10 @@ msgctxt "model:ir.model.button,string:electronic_mail_reply_button"
msgid "Reply Mail"
msgstr "Respon correu"
+msgctxt "selection:ir.cron,method:"
+msgid "Create Activity"
+msgstr "Crear Activitat"
+
msgctxt "view:activity.activity:"
msgid "Reply Mail"
msgstr "Respon correu"
diff --git a/locale/es.po b/locale/es.po
index 4035963..bd8c194 100644
--- a/locale/es.po
+++ b/locale/es.po
@@ -14,6 +14,14 @@ msgctxt "field:activity.activity,related_activity:"
msgid "Related activity"
msgstr "Actividad relacionada"
+msgctxt "field:activity.configuration,pending_mailbox:"
+msgid "Pending Mailbox"
+msgstr "Buzón Pendientes"
+
+msgctxt "field:activity.configuration,processed_mailbox:"
+msgid "Processed Mailbox"
+msgstr "Buzón Procesados"
+
msgctxt "field:imap.server,employee:"
msgid "Default Employee"
msgstr "Empleado por defecto"
@@ -26,6 +34,10 @@ msgctxt "field:res.user,mailbox:"
msgid "Mailbox"
msgstr "Buzón de correo"
+msgctxt "field:res.user,signature_html:"
+msgid "Signature"
+msgstr "Firma"
+
msgctxt "field:res.user,smtp_server:"
msgid "SMTP Server"
msgstr "Servidor SMTP"
@@ -65,6 +77,10 @@ msgctxt "model:ir.message,text:no_valid_mail"
msgid "The \"%(mail)s\" of the party \"%(party)s\" it is not correct."
msgstr "El \"%(mail)s\" del tercero \"%(party)s\" no es correcto."
+msgctxt "model:ir.model.button,string:electronic_mail_guess_button"
+msgid "Guess Resource"
+msgstr "Encuentra el Recurso"
+
msgctxt "model:ir.model.button,string:electronic_mail_new_button"
msgid "Send Mail"
msgstr "Envio correo"
@@ -73,6 +89,10 @@ msgctxt "model:ir.model.button,string:electronic_mail_reply_button"
msgid "Reply Mail"
msgstr "Responder correo"
+msgctxt "selection:ir.cron,method:"
+msgid "Create Activity"
+msgstr "Crear Actividad"
+
msgctxt "view:activity.activity:"
msgid "Reply Mail"
msgstr "Responder correo"
diff --git a/tryton.cfg b/tryton.cfg
index e17a30a..3398c8d 100644
--- a/tryton.cfg
+++ b/tryton.cfg
@@ -2,11 +2,10 @@
version=5.5.0
depends:
electronic_mail
- electronic_mail_model
electronic_mail_wizard
activity_contact
xml:
activity.xml
- imap.xml
user.xml
message.xml
+ configuration.xml
diff --git a/view/activity_activity_form.xml b/view/activity_activity_form.xml
index 2901033..90da862 100644
--- a/view/activity_activity_form.xml
+++ b/view/activity_activity_form.xml
@@ -2,6 +2,9 @@
+
+
+
diff --git a/view/activity_activity_tree.xml b/view/activity_activity_tree.xml
index 1a05481..12d1664 100644
--- a/view/activity_activity_tree.xml
+++ b/view/activity_activity_tree.xml
@@ -5,6 +5,7 @@
+
diff --git a/view/configuration_form.xml b/view/configuration_form.xml
new file mode 100644
index 0000000..c6ae68e
--- /dev/null
+++ b/view/configuration_form.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/view/imap_server_form.xml b/view/imap_server_form.xml
deleted file mode 100644
index 37a6b41..0000000
--- a/view/imap_server_form.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-