diff --git a/cmis_mail/__init__.py b/cmis_mail/__init__.py new file mode 100644 index 00000000..5cb1c491 --- /dev/null +++ b/cmis_mail/__init__.py @@ -0,0 +1 @@ +from . import wizards diff --git a/cmis_mail/__manifest__.py b/cmis_mail/__manifest__.py new file mode 100644 index 00000000..61fd9deb --- /dev/null +++ b/cmis_mail/__manifest__.py @@ -0,0 +1,29 @@ +# Copyright 2022 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Cmis Mail", + "description": """ + This module allows to store attachments with CMIS from the mail + composer if the source model has at least one CMIS folder. + When attachments are added on the mail composer, a checkbox allows to + enable the CMIS storage. If the source model has more than one CMIS + folder, it is possible to specify in which one the attachments must be + stored.""", + 'category': 'Document Management', + "version": "13.0.1.0.0", + "license": "AGPL-3", + "author": "ACSONE SA/NV", + 'website': 'http://alfodoo.org/', + "depends": [ + "mail", + "cmis_field", + ], + "data": [ + "wizards/mail_compose_message.xml", + ], + 'installable': True, + 'images': [ + 'static/description/main_icon.png', + ], +} diff --git a/cmis_mail/i18n/cmis_mail.pot b/cmis_mail/i18n/cmis_mail.pot new file mode 100644 index 00000000..b87d55b8 --- /dev/null +++ b/cmis_mail/i18n/cmis_mail.pot @@ -0,0 +1,84 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * cmis_mail +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-13 09:21+0000\n" +"PO-Revision-Date: 2024-08-13 09:21+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: cmis_mail +#: model:ir.model.fields,field_description:cmis_mail.field_mail_compose_message__allowed_cmis_folder_field_ids +msgid "Allowed Cmis Folder Field" +msgstr "" + +#. module: cmis_mail +#: model:ir.model.fields,field_description:cmis_mail.field_mail_compose_message__cmis_folder_field_id +msgid "CMIS Folder" +msgstr "" + +#. module: cmis_mail +#: model:ir.model.fields.selection,name:cmis_mail.selection__mail_compose_message__cmis_duplicate_handler__new_version +msgid "Create a new version" +msgstr "" + +#. module: cmis_mail +#: code:addons/cmis_mail/wizards/mail_compose_message.py:0 +#, python-format +msgid "Document \"%s\" already exists in CMIS" +msgstr "" + +#. module: cmis_mail +#: model:ir.model,name:cmis_mail.model_mail_compose_message +msgid "Email composition wizard" +msgstr "" + +#. module: cmis_mail +#: model_terms:ir.ui.view,arch_db:cmis_mail.mail_compose_message_form_view +msgid "Enable" +msgstr "" + +#. module: cmis_mail +#: model:ir.model.fields,field_description:cmis_mail.field_mail_compose_message__is_multiple_cmis_fields +msgid "Is Multiple Cmis Fields" +msgstr "" + +#. module: cmis_mail +#: model:ir.model.fields.selection,name:cmis_mail.selection__mail_compose_message__cmis_duplicate_handler__error +msgid "Raise exception" +msgstr "" + +#. module: cmis_mail +#: model:ir.model.fields.selection,name:cmis_mail.selection__mail_compose_message__cmis_duplicate_handler__increment +msgid "Rename as file(X).pdf" +msgstr "" + +#. module: cmis_mail +#: model:ir.model.fields,field_description:cmis_mail.field_mail_compose_message__is_save_in_cmis_enabled +#: model_terms:ir.ui.view,arch_db:cmis_mail.mail_compose_message_form_view +msgid "Save attachments in CMIS" +msgstr "" + +#. module: cmis_mail +#: code:addons/cmis_mail/wizards/mail_compose_message.py:0 +#, python-format +msgid "Saved from Odoo mail composer" +msgstr "" + +#. module: cmis_mail +#: model:ir.model.fields,field_description:cmis_mail.field_mail_compose_message__cmis_duplicate_handler +msgid "Strategy in case of duplicate" +msgstr "" + +#. module: cmis_mail +#: model:ir.model.fields.selection,name:cmis_mail.selection__mail_compose_message__cmis_duplicate_handler__use_existing +msgid "Use existing" +msgstr "" diff --git a/cmis_mail/i18n/fr.po b/cmis_mail/i18n/fr.po new file mode 100644 index 00000000..9c49eabd --- /dev/null +++ b/cmis_mail/i18n/fr.po @@ -0,0 +1,84 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * cmis_mail +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-08-13 09:21+0000\n" +"PO-Revision-Date: 2024-08-13 09:21+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: cmis_mail +#: model:ir.model.fields,field_description:cmis_mail.field_mail_compose_message__allowed_cmis_folder_field_ids +msgid "Allowed Cmis Folder Field" +msgstr "Dossiers CMIS autorisés" + +#. module: cmis_mail +#: model:ir.model.fields,field_description:cmis_mail.field_mail_compose_message__cmis_folder_field_id +msgid "CMIS Folder" +msgstr "Dossier CMIS" + +#. module: cmis_mail +#: model:ir.model.fields.selection,name:cmis_mail.selection__mail_compose_message__cmis_duplicate_handler__new_version +msgid "Create a new version" +msgstr "Créer une nouvelle version" + +#. module: cmis_mail +#: code:addons/cmis_mail/wizards/mail_compose_message.py:0 +#, python-format +msgid "Document \"%s\" already exists in CMIS" +msgstr "Le document \"%s\" existe déjà dans CMIS" + +#. module: cmis_mail +#: model:ir.model,name:cmis_mail.model_mail_compose_message +msgid "Email composition wizard" +msgstr "" + +#. module: cmis_mail +#: model_terms:ir.ui.view,arch_db:cmis_mail.mail_compose_message_form_view +msgid "Enable" +msgstr "Activer" + +#. module: cmis_mail +#: model:ir.model.fields,field_description:cmis_mail.field_mail_compose_message__is_multiple_cmis_fields +msgid "Is Multiple Cmis Fields" +msgstr "Multiples dossier CMIS" + +#. module: cmis_mail +#: model:ir.model.fields.selection,name:cmis_mail.selection__mail_compose_message__cmis_duplicate_handler__error +msgid "Raise exception" +msgstr "Afficher une erreur" + +#. module: cmis_mail +#: model:ir.model.fields.selection,name:cmis_mail.selection__mail_compose_message__cmis_duplicate_handler__increment +msgid "Rename as file(X).pdf" +msgstr "Renommer en tant que fichier(X).pdf" + +#. module: cmis_mail +#: model:ir.model.fields,field_description:cmis_mail.field_mail_compose_message__is_save_in_cmis_enabled +#: model_terms:ir.ui.view,arch_db:cmis_mail.mail_compose_message_form_view +msgid "Save attachments in CMIS" +msgstr "Enregistrer les pièces jointes dans CMIS" + +#. module: cmis_mail +#: code:addons/cmis_mail/wizards/mail_compose_message.py:0 +#, python-format +msgid "Saved from Odoo mail composer" +msgstr "Enregistré depuis le compositeur de courrier Odoo" + +#. module: cmis_mail +#: model:ir.model.fields,field_description:cmis_mail.field_mail_compose_message__cmis_duplicate_handler +msgid "Strategy in case of duplicate" +msgstr "Stratégie en cas de doublon" + +#. module: cmis_mail +#: model:ir.model.fields.selection,name:cmis_mail.selection__mail_compose_message__cmis_duplicate_handler__use_existing +msgid "Use existing" +msgstr "Utiliser l'existant" diff --git a/cmis_mail/static/description/icon.png b/cmis_mail/static/description/icon.png new file mode 100644 index 00000000..12cfdb74 Binary files /dev/null and b/cmis_mail/static/description/icon.png differ diff --git a/cmis_mail/static/description/index.html b/cmis_mail/static/description/index.html new file mode 100644 index 00000000..0030826d --- /dev/null +++ b/cmis_mail/static/description/index.html @@ -0,0 +1,38 @@ +
+
+

Alfodoo, the Odoo-Alfresco connector

+

+ Streamline your business processes by managing your documents in their context within any Odoo apps. +

+
+
+

+
+

+

+ Alfodoo provides a unique solution to seamlessly integrate the open-source ECM Alfresco with Odoo and let the user manages his documents in Alfresco without leaving his Odoo work environment. +

+

+
+ Benefits from the Alfodoo connector: +

+
    +
  • +

    Manage your content/documents linked to your Odoo processes;

    +
  • +
  • +

    Make classification and indexing of content/documents easier and more qualitative;

    +
  • +
  • +

    Enrich documents with Odoo business record information to exploit the powerful Alfresco document management capabilities.

    +
  • +
+

+ This module allows to store attachments with CMIS from the mail composer if the source model has at least one CMIS folder. + When attachments are added on the mail composer, a checkbox allows to enable the CMIS storage. If the source model has more than one CMIS folder, + it is possible to specify in which one the attachments must be stored. +

+
+
+
+
diff --git a/cmis_mail/static/description/main_icon.png b/cmis_mail/static/description/main_icon.png new file mode 100644 index 00000000..2ea088f4 Binary files /dev/null and b/cmis_mail/static/description/main_icon.png differ diff --git a/cmis_mail/wizards/__init__.py b/cmis_mail/wizards/__init__.py new file mode 100644 index 00000000..b528d997 --- /dev/null +++ b/cmis_mail/wizards/__init__.py @@ -0,0 +1 @@ +from . import mail_compose_message diff --git a/cmis_mail/wizards/mail_compose_message.py b/cmis_mail/wizards/mail_compose_message.py new file mode 100644 index 00000000..f113c7c4 --- /dev/null +++ b/cmis_mail/wizards/mail_compose_message.py @@ -0,0 +1,167 @@ +# Copyright 2022 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import base64 +import os +import logging +import mimetypes +from io import BytesIO + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + +_logger = logging.getLogger(__name__) + + +class MailComposeMessage(models.TransientModel): + _inherit = "mail.compose.message" + + is_save_in_cmis_enabled = fields.Boolean( + string="Save attachments in CMIS", + default=False, + ) + allowed_cmis_folder_field_ids = fields.Many2many( + comodel_name="ir.model.fields", + readonly=True, + ) + is_multiple_cmis_fields = fields.Boolean( + readonly=True, + ) + cmis_folder_field_id = fields.Many2one( + string="CMIS Folder", + comodel_name="ir.model.fields", + domain="[('id', 'in', allowed_cmis_folder_field_ids.ids)]", + ) + cmis_duplicate_handler = fields.Selection( + selection=[ + ("use_existing", "Use existing"), + ("error", "Raise exception"), + ("new_version", "Create a new version"), + ("increment", "Rename as file(X).pdf"), + ], + string="Duplicate strategy", + default="increment", + ) + + @api.model + def default_get(self, fields): # pylint:disable=redefined-outer-name + res = super().default_get(fields) + related_model = res.get("model") + if not related_model: + return res + cmis_fields = self.env["ir.model.fields"].search( + [("model", "=", related_model), ("ttype", "=", "cmis_folder")] + ) + if cmis_fields: + res.update( + { + "allowed_cmis_folder_field_ids": [(6, 0, cmis_fields.ids)], + "cmis_folder_field_id": cmis_fields[0].id, + "is_multiple_cmis_fields": len(cmis_fields) > 1, + } + ) + return res + + def _get_cmis_parent_folder(self): + self.ensure_one() + field_name = self.cmis_folder_field_id.name + related_record = self.env[self.model].browse(self.res_id) + field = related_record._fields[field_name] + cmis_backend = field.get_backend(self.env) + root_objectId = related_record[field_name] + if not root_objectId: + field.create_value(related_record) + root_objectId = related_record[field_name] + return cmis_backend.get_cmis_repository().getObject(root_objectId) + + @api.model + def get_mimetype(self, file_name): + return mimetypes.guess_type(file_name)[0] + + @api.model + def _sanitize_query_arg(self, arg): + return arg.replace("'", r"\'") + + def _cmis_document_exists(self, cmis_parent_folder, file_name): + qfile_name = self._sanitize_query_arg(file_name) + cmis_qry = ( + "SELECT cmis:objectId FROM cmis:document WHERE " + "IN_FOLDER('%s') AND cmis:name='%s'" + % (cmis_parent_folder.getObjectId(), qfile_name) + ) + _logger.debug("Query CMIS with %s", cmis_qry) + rs = cmis_parent_folder.repository.query(cmis_qry) + num_found_items = rs.getNumItems() + return num_found_items > 0, rs + + def _save_attachments_in_cmis(self): + self.ensure_one() + if not self.model or not self.res_id: + return + cmis_parent_folder = self._get_cmis_parent_folder() + for attachment in self.attachment_ids: + file_name = attachment.name + buffer = BytesIO(base64.b64decode(attachment.datas)) + cmis_document_exists, rs = self._cmis_document_exists( + cmis_parent_folder, file_name + ) + if not cmis_document_exists or self.cmis_duplicate_handler == "increment": + if cmis_document_exists: + name, ext = os.path.splitext(file_name) + testname = name + "(*)" + ext + rs = cmis_parent_folder.getChildren( + filter="cmis:name=%s" % testname + ) + file_name = name + "(%d)" % rs.getNumItems() + ext + self._create_cmis_document( + buffer, + file_name, + cmis_parent_folder, + ) + if ( + cmis_document_exists + and self.cmis_duplicate_handler == "new_version" + ): + doc = cmis_parent_folder.repository.getObject( + rs.getResults()[0].getObjectId() + ) + self._update_cmis_document(buffer, file_name, doc) + if self.cmis_duplicate_handler == "error": + raise UserError( + _('Document "%s" already exists in CMIS') % (file_name) + ) + + def _create_cmis_document(self, buffer, file_name, cmis_parent_folder): + self.ensure_one() + props = { + "cmis:name": file_name, + } + mimetype = self.get_mimetype(file_name) + return cmis_parent_folder.createDocument( + file_name, + properties=props, + contentFile=buffer, + contentType=mimetype, + ) + + def _update_cmis_document(self, buffer, file_name, cmis_doc): + self.ensure_one() + props = { + "cmis:name": file_name, + } + mimetype = self.get_mimetype(file_name) + cmis_doc = cmis_doc.checkout() + return cmis_doc.checkin( + checkinComment=_("Saved from Odoo mail composer"), + contentFile=buffer, + contentType=mimetype, + major=False, + properties=props, + ) + + def send_mail(self, auto_commit=False): + res = super().send_mail(auto_commit=auto_commit) + for rec in self: + if rec.is_save_in_cmis_enabled: + rec._save_attachments_in_cmis() + return res diff --git a/cmis_mail/wizards/mail_compose_message.xml b/cmis_mail/wizards/mail_compose_message.xml new file mode 100644 index 00000000..4c518e56 --- /dev/null +++ b/cmis_mail/wizards/mail_compose_message.xml @@ -0,0 +1,29 @@ + + + + + mail.compose.message.form (in cmis_mail) + mail.compose.message + + + + + + + + + + + + + + + + + + + + diff --git a/setup/cmis_mail/odoo/addons/cmis_mail b/setup/cmis_mail/odoo/addons/cmis_mail new file mode 120000 index 00000000..497a559d --- /dev/null +++ b/setup/cmis_mail/odoo/addons/cmis_mail @@ -0,0 +1 @@ +../../../../cmis_mail \ No newline at end of file diff --git a/setup/cmis_mail/setup.py b/setup/cmis_mail/setup.py new file mode 100644 index 00000000..28c57bb6 --- /dev/null +++ b/setup/cmis_mail/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)