diff --git a/README.md b/README.md index c3182bb7ca0..05eae590fd7 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Available addons addon | version | maintainers | summary --- | --- | --- | --- [attachment_queue](attachment_queue/) | 16.0.1.1.0 | [![florian-dacosta](https://github.com/florian-dacosta.png?size=30px)](https://github.com/florian-dacosta) [![sebastienbeau](https://github.com/sebastienbeau.png?size=30px)](https://github.com/sebastienbeau) | Base module adding the concept of queue for processing files +[attachment_synchronize](attachment_synchronize/) | 16.0.1.0.0 | [![florian-dacosta](https://github.com/florian-dacosta.png?size=30px)](https://github.com/florian-dacosta) [![sebastienbeau](https://github.com/sebastienbeau.png?size=30px)](https://github.com/sebastienbeau) [![GSLabIt](https://github.com/GSLabIt.png?size=30px)](https://github.com/GSLabIt) [![bealdav](https://github.com/bealdav.png?size=30px)](https://github.com/bealdav) | Attachment Synchronize [attachment_unindex_content](attachment_unindex_content/) | 16.0.1.0.0 | [![moylop260](https://github.com/moylop260.png?size=30px)](https://github.com/moylop260) [![ebirbe](https://github.com/ebirbe.png?size=30px)](https://github.com/ebirbe) [![luisg123v](https://github.com/luisg123v.png?size=30px)](https://github.com/luisg123v) | Disable indexing of attachments [auditlog](auditlog/) | 16.0.2.0.2 | | Audit Log [auto_backup](auto_backup/) | 16.0.1.0.0 | | Backups database diff --git a/attachment_synchronize/README.rst b/attachment_synchronize/README.rst new file mode 100644 index 00000000000..c050f77e309 --- /dev/null +++ b/attachment_synchronize/README.rst @@ -0,0 +1,129 @@ +====================== +Attachment Synchronize +====================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:df01bd9b8a51738a68feed9421bed8ce9d5a23d4c5e8db7a8f230218cb95a611 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github + :target: https://github.com/OCA/server-tools/tree/16.0/attachment_synchronize + :alt: OCA/server-tools +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/server-tools-16-0/server-tools-16-0-attachment_synchronize + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/server-tools&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to **import/export files** from/to backend servers. + +A backend server is defined by the basic `fs_storage `_ OCA module, while it can be configured (amazon S3, sftp,...) with additional modules fs python libraries + +The imported files (and the files to be exported) are stored in Odoo as ``attachment.queue`` objects, defined by the `attachment_queue `_ module while the importation itself (resp. exportation) is realized by **"Attachments Import Tasks"** (resp. "Attachments Export Tasks") defined by this current module. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +As importation and exportation are different processes, they are triggered in different ways : + +**To import files**, you need to create an *"Attachment Import Task"* (menu *Settings > Technical > Attachments Import Tasks*) which defines : + +- where to find the files to import from the backend server (path to the files, selection pattern) +- what to do with the source files in the backend server (avoid duplicates, delete/rename after import...) +- how the files will be processed once imported (through the **File Type** field). + +.. image:: https://raw.githubusercontent.com/OCA/server-tools/16.0/attachment_synchronize/static/description/import_task.png + +.. epigraph:: + + 🔎 The **File Type** options are defined by other modules built to process the Attachments Queues with the same "File Type". + +**To export files**, you need first to register them as *"Attachments Queues"* objects linked to an *"Attachment Export Task"* (which set automatically their **File Type** to *"Export File (External Location)"*). + +Then, you can export one file at a time from the *Attachment Queue*'s form view, or export all the *Attachments Queues* in a pending state related to the same *Export Task* from the given *Export Task* form view (menu *Settings > Technical > Attachments Export Tasks*) : + +.. image:: https://raw.githubusercontent.com/OCA/server-tools/16.0/attachment_synchronize/static/description/export_task.png + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Akretion + +Contributors +~~~~~~~~~~~~ + +`Akretion `_ : + +- Valentin CHEMIERE +- Mourad EL HADJ MIMOUNE +- Florian DA COSTA +- Clément MOMBEREAU + +GS Lab: + +- Giovanni SERRA + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +.. |maintainer-florian-dacosta| image:: https://github.com/florian-dacosta.png?size=40px + :target: https://github.com/florian-dacosta + :alt: florian-dacosta +.. |maintainer-sebastienbeau| image:: https://github.com/sebastienbeau.png?size=40px + :target: https://github.com/sebastienbeau + :alt: sebastienbeau +.. |maintainer-GSLabIt| image:: https://github.com/GSLabIt.png?size=40px + :target: https://github.com/GSLabIt + :alt: GSLabIt +.. |maintainer-bealdav| image:: https://github.com/bealdav.png?size=40px + :target: https://github.com/bealdav + :alt: bealdav + +Current `maintainers `__: + +|maintainer-florian-dacosta| |maintainer-sebastienbeau| |maintainer-GSLabIt| |maintainer-bealdav| + +This module is part of the `OCA/server-tools `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/attachment_synchronize/__init__.py b/attachment_synchronize/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/attachment_synchronize/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/attachment_synchronize/__manifest__.py b/attachment_synchronize/__manifest__.py new file mode 100644 index 00000000000..bcf60d65ad9 --- /dev/null +++ b/attachment_synchronize/__manifest__.py @@ -0,0 +1,28 @@ +# @ 2016 florian DA COSTA @ Akretion +# © 2016 @author Mourad EL HADJ MIMOUNE +# @ 2020 Giovanni Serra @ GSlab.it +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Attachment Synchronize", + "version": "16.0.1.0.0", + "author": "Akretion,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/server-tools", + "maintainers": ["florian-dacosta", "sebastienbeau", "GSLabIt", "bealdav"], + "license": "AGPL-3", + "category": "Generic Modules", + "depends": [ + "attachment_queue", + "fs_storage", # https://github.com/OCA/storage + ], + "data": [ + "views/attachment_queue_views.xml", + "views/attachment_synchronize_task_views.xml", + "views/storage_backend_views.xml", + "data/cron.xml", + "security/ir.model.access.csv", + ], + "demo": ["demo/attachment_synchronize_task_demo.xml"], + "installable": True, + "development_status": "Beta", +} diff --git a/attachment_synchronize/data/cron.xml b/attachment_synchronize/data/cron.xml new file mode 100644 index 00000000000..f43a65a981b --- /dev/null +++ b/attachment_synchronize/data/cron.xml @@ -0,0 +1,16 @@ + + + + + Run attachment tasks import + 30 + minutes + -1 + False + + + code + model.run_task_import_scheduler() + + + diff --git a/attachment_synchronize/demo/attachment_synchronize_task_demo.xml b/attachment_synchronize/demo/attachment_synchronize_task_demo.xml new file mode 100644 index 00000000000..99534417802 --- /dev/null +++ b/attachment_synchronize/demo/attachment_synchronize_task_demo.xml @@ -0,0 +1,24 @@ + + + + TEST Import + + import + delete + test_import + + + + TEST Export + + export + test_export + + + + bWlncmF0aW9uIHRlc3Q= + attachment_queue_imported_demo.doc + + + + diff --git a/attachment_synchronize/i18n/attachment_synchronize.pot b/attachment_synchronize/i18n/attachment_synchronize.pot new file mode 100644 index 00000000000..b301af3e132 --- /dev/null +++ b/attachment_synchronize/i18n/attachment_synchronize.pot @@ -0,0 +1,370 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * attachment_synchronize +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \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: attachment_synchronize +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_form +msgid "Fail" +msgstr "" + +#. module: attachment_synchronize +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_form +msgid "Pending" +msgstr "" + +#. module: attachment_synchronize +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_form +msgid "Success" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,help:attachment_synchronize.field_attachment_synchronize_task__after_import +msgid "Action after import a file" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__after_import +msgid "After Import" +msgstr "" + +#. module: attachment_synchronize +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_form +msgid "Archived" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__attachment_ids +msgid "Attachment" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model,name:attachment_synchronize.model_attachment_queue +msgid "Attachment Queue" +msgstr "" + +#. module: attachment_synchronize +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_search +msgid "Attachment Task" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model,name:attachment_synchronize.model_attachment_synchronize_task +msgid "Attachment synchronize task" +msgstr "" + +#. module: attachment_synchronize +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_search +msgid "Attachments" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.actions.act_window,name:attachment_synchronize.action_attachment_export_task +#: model:ir.ui.menu,name:attachment_synchronize.menu_attachment_export_task +msgid "Attachments Export Tasks" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.actions.act_window,name:attachment_synchronize.action_attachment_import_task +#: model:ir.ui.menu,name:attachment_synchronize.menu_attachment_import_task +msgid "Attachments Import Tasks" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.actions.act_window,name:attachment_synchronize.action_attachment_queue_related +msgid "Attachments Queue" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__avoid_duplicated_files +msgid "Avoid importing duplicated files" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__backend_id +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_search +msgid "Backend" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__count_attachment_done +msgid "Count Attachment Done" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__count_attachment_failed +msgid "Count Attachment Failed" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__count_attachment_pending +msgid "Count Attachment Pending" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__create_uid +msgid "Created by" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__create_date +msgid "Created on" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields.selection,name:attachment_synchronize.selection__attachment_synchronize_task__after_import__delete +msgid "Delete" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__display_name +msgid "Display Name" +msgstr "" + +#. module: attachment_synchronize +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_form +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_tree +msgid "Done attachments" +msgstr "" + +#. module: attachment_synchronize +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_tree +msgid "Duplicate" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__active +msgid "Enabled" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields.selection,name:attachment_synchronize.selection__attachment_queue__file_type__export +msgid "Export File (External location)" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields.selection,name:attachment_synchronize.selection__attachment_synchronize_task__method_type__export +msgid "Export Task" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_fs_storage__export_task_count +msgid "Export Tasks" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model,name:attachment_synchronize.model_fs_storage +msgid "FS Storage" +msgstr "" + +#. module: attachment_synchronize +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_form +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_tree +msgid "Failed attachments" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__failure_emails +msgid "Failure Emails" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__filepath +msgid "File Path" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_queue__file_type +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__file_type +msgid "File Type" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_queue__fs_storage_id +msgid "Filestore Storage" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__id +msgid "ID" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,help:attachment_synchronize.field_attachment_synchronize_task__avoid_duplicated_files +msgid "" +"If checked, a file will not be imported if an Attachment Queue with the same" +" name already exists." +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields.selection,name:attachment_synchronize.selection__attachment_synchronize_task__method_type__import +msgid "Import Task" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_fs_storage__import_task_count +msgid "Import Tasks" +msgstr "" + +#. module: attachment_synchronize +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_form +msgid "Importation" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,help:attachment_synchronize.field_attachment_synchronize_task__move_path +msgid "Imported File will be moved to this path" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,help:attachment_synchronize.field_attachment_synchronize_task__new_name +msgid "" +"Imported File will be renamed to this name.\n" +"New Name can use 'mako' template where 'obj' is the original file's name.\n" +"For instance : ${obj.name}-${obj.create_date}.csv" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task____last_update +msgid "Last Modified on" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__write_date +msgid "Last Updated on" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_queue__method_type +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__method_type +msgid "Method Type" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields.selection,name:attachment_synchronize.selection__attachment_synchronize_task__after_import__move +msgid "Move" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields.selection,name:attachment_synchronize.selection__attachment_synchronize_task__after_import__move_rename +msgid "Move & Rename" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__move_path +msgid "Move Path" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__name +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_form +msgid "Name" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__new_name +msgid "New Name" +msgstr "" + +#. module: attachment_synchronize +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_form +msgid "Notification" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,help:attachment_synchronize.field_attachment_synchronize_task__filepath +msgid "Path to imported/exported files in the Backend" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,help:attachment_synchronize.field_attachment_synchronize_task__pattern +msgid "" +"Pattern used to select the files to be imported following the 'fnmatch' special characters (e.g. '*.txt' to catch all the text files).\n" +"If empty, import all the files found in 'File Path'." +msgstr "" + +#. module: attachment_synchronize +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_form +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_tree +msgid "Pending attachments" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields.selection,name:attachment_synchronize.selection__attachment_synchronize_task__after_import__rename +msgid "Rename" +msgstr "" + +#. module: attachment_synchronize +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_form +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_tree +msgid "Run" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.actions.server,name:attachment_synchronize.cronjob_run_attachment_synchronize_task_import_ir_actions_server +#: model:ir.cron,cron_name:attachment_synchronize.cronjob_run_attachment_synchronize_task_import +msgid "Run attachment tasks import" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__pattern +msgid "Selection Pattern" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_queue__smart_search +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_synchronize_task__smart_search +#: model:ir.model.fields,field_description:attachment_synchronize.field_fs_storage__smart_search +msgid "Smart Search" +msgstr "" + +#. module: attachment_synchronize +#: model_terms:ir.ui.view,arch_db:attachment_synchronize.view_attachment_task_form +msgid "Storage Location" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_attachment_queue__task_id +msgid "Task" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,field_description:attachment_synchronize.field_fs_storage__synchronize_task_ids +msgid "Tasks" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,help:attachment_synchronize.field_attachment_queue__file_type +msgid "" +"The file type determines an import method to be used to parse and transform " +"data before their import in ERP or an export" +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,help:attachment_synchronize.field_attachment_synchronize_task__failure_emails +msgid "" +"Used to fill the 'Failure Emails' field in the 'Attachments Queues' related to this task.\n" +"An alert will be sent to these emails if any operation on these Attachment Queue's file type fails." +msgstr "" + +#. module: attachment_synchronize +#: model:ir.model.fields,help:attachment_synchronize.field_attachment_synchronize_task__file_type +msgid "" +"Used to fill the 'File Type' field in the imported 'Attachments Queues'.\n" +"Further operations will be realized on these Attachments Queues depending on their 'File Type' value." +msgstr "" diff --git a/attachment_synchronize/models/__init__.py b/attachment_synchronize/models/__init__.py new file mode 100644 index 00000000000..afcda8bde86 --- /dev/null +++ b/attachment_synchronize/models/__init__.py @@ -0,0 +1 @@ +from . import attachment_queue, attachment_synchronize_task, storage_backend diff --git a/attachment_synchronize/models/attachment_queue.py b/attachment_synchronize/models/attachment_queue.py new file mode 100644 index 00000000000..9f9861e5305 --- /dev/null +++ b/attachment_synchronize/models/attachment_queue.py @@ -0,0 +1,50 @@ +# @ 2016 Florian DA COSTA @ Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import base64 + +from odoo import api, fields, models + + +class AttachmentQueue(models.Model): + _inherit = "attachment.queue" + + task_id = fields.Many2one("attachment.synchronize.task", string="Task") + method_type = fields.Selection(related="task_id.method_type") + fs_storage_id = fields.Many2one( + "fs.storage", + string="Filestore Storage", + related="task_id.backend_id", + store=True, + ) + file_type = fields.Selection( + selection_add=[("export", "Export File (External location)")] + ) + + def _run(self): + res = super()._run() + if self.file_type == "export": + fs = self.fs_storage_id.fs + folder_path = self.task_id.filepath + full_path = ( + folder_path and fs.sep.join([folder_path, self.name]) or self.name + ) + # create missing folders if necessary : + if folder_path and not fs.exists(folder_path): + fs.makedirs(folder_path) + data = base64.b64decode(self.datas) + with fs.open(full_path, "wb") as f: + f.write(data) + return res + + def _get_failure_emails(self): + res = super()._get_failure_emails() + if self.task_id.failure_emails: + res = self.task_id.failure_emails + return res + + @api.onchange("task_id") + def onchange_task_id(self): + for attachment in self: + if attachment.task_id.method_type == "export": + attachment.file_type = "export" diff --git a/attachment_synchronize/models/attachment_synchronize_task.py b/attachment_synchronize/models/attachment_synchronize_task.py new file mode 100644 index 00000000000..039d35e6b02 --- /dev/null +++ b/attachment_synchronize/models/attachment_synchronize_task.py @@ -0,0 +1,246 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import base64 +import datetime +import logging + +from odoo import api, fields, models, tools +from odoo.osv import expression + +_logger = logging.getLogger(__name__) + + +try: + # We use a jinja2 sandboxed environment to render mako templates. + # Note that the rendering does not cover all the mako syntax, in particular + # arbitrary Python statements are not accepted, and not all expressions are + # allowed: only "public" attributes (not starting with '_') of objects may + # be accessed. + # This is done on purpose: it prevents incidental or malicious execution of + # Python code that may break the security of the server. + from jinja2.sandbox import SandboxedEnvironment + + mako_template_env = SandboxedEnvironment( + variable_start_string="${", + variable_end_string="}", + line_statement_prefix="%", + trim_blocks=True, # do not output newline after blocks + ) + mako_template_env.globals.update( + { + "str": str, + "datetime": datetime, + "len": len, + "abs": abs, + "min": min, + "max": max, + "sum": sum, + "filter": filter, + "map": map, + "round": round, + } + ) +except ImportError: + _logger.warning("jinja2 not available, templating features will not work!") + + +class AttachmentSynchronizeTask(models.Model): + _name = "attachment.synchronize.task" + _description = "Attachment synchronize task" + + name = fields.Char(required=True) + method_type = fields.Selection( + [("import", "Import Task"), ("export", "Export Task")], required=True + ) + pattern = fields.Char( + string="Selection Pattern", + help="Pattern used to select the files to be imported following the 'fnmatch' " + "special characters (e.g. '*.txt' to catch all the text files).\n" + "If empty, import all the files found in 'File Path'.", + ) + filepath = fields.Char( + string="File Path", help="Path to imported/exported files in the Backend" + ) + backend_id = fields.Many2one("fs.storage", string="Backend") + attachment_ids = fields.One2many("attachment.queue", "task_id", string="Attachment") + move_path = fields.Char(help="Imported File will be moved to this path") + new_name = fields.Char( + help="Imported File will be renamed to this name.\n" + "New Name can use 'mako' template where 'obj' is the original file's name.\n" + "For instance : ${obj.name}-${obj.create_date}.csv", + ) + after_import = fields.Selection( + selection=[ + ("rename", "Rename"), + ("move", "Move"), + ("move_rename", "Move & Rename"), + ("delete", "Delete"), + ], + help="Action after import a file", + ) + file_type = fields.Selection( + selection=[], + help="Used to fill the 'File Type' field in the imported 'Attachments Queues'." + "\nFurther operations will be realized on these Attachments Queues depending " + "on their 'File Type' value.", + ) + active = fields.Boolean("Enabled", default=True) + avoid_duplicated_files = fields.Boolean( + string="Avoid importing duplicated files", + help="If checked, a file will not be imported if an Attachment Queue with the " + "same name already exists.", + ) + failure_emails = fields.Char( + help="Used to fill the 'Failure Emails' field in the 'Attachments Queues' " + "related to this task.\nAn alert will be sent to these emails if any operation " + "on these Attachment Queue's file type fails.", + ) + count_attachment_failed = fields.Integer(compute="_compute_count_state") + count_attachment_pending = fields.Integer(compute="_compute_count_state") + count_attachment_done = fields.Integer(compute="_compute_count_state") + + def _compute_count_state(self): + for record in self: + for state in ["failed", "pending", "done"]: + record["count_attachment_{}".format(state)] = len( + record.attachment_ids.filtered(lambda r: r.state == state) + ) + + def _prepare_attachment_vals(self, data, filename): + self.ensure_one() + vals = { + "name": filename, + "datas": data, + "task_id": self.id, + "file_type": self.file_type or False, + } + return vals + + @api.model + def _template_render(self, template, record): + try: + template = mako_template_env.from_string(tools.ustr(template)) + except Exception: + _logger.exception("Failed to load template '{}'".format(template)) + + variables = {"obj": record} + try: + render_result = template.render(variables) + except Exception: + _logger.exception( + "Failed to render template '{}'' using values '{}'".format( + template, variables + ) + ) + render_result = "" + if render_result == "False": + render_result = "" + return render_result + + @api.model + def run_task_import_scheduler(self, domain=None): + if domain is None: + domain = [] + domain = expression.AND([domain, [("method_type", "=", "import")]]) + for task in self.search(domain): + task.run_import() + + def run(self): + for record in self: + method = "run_{}".format(record.method_type) + if not hasattr(self, method): + raise NotImplementedError + else: + getattr(record, method)() + + def _get_files(self): + self.ensure_one() + fs = self.backend_id.fs + filepath = self.filepath or "" + filepath = filepath.rstrip(fs.sep) + if filepath and not fs.exists(filepath): + return [] + if self.pattern: + path = filepath and fs.sep.join([filepath, self.pattern]) or self.pattern + file_path_names = fs.glob(path) + else: + file_path_names = fs.ls(filepath, detail=False) + if self.avoid_duplicated_files: + file_path_names = self._filter_duplicates(file_path_names) + return file_path_names + + def _manage_file_after_import(self, file_name, fullpath, attachment): + self.ensure_one() + fs = self.backend_id.fs + new_name = False + if self.after_import == "rename": + new_name = self._template_render(self.new_name, attachment) + path = self.filepath or "" + elif self.after_import == "move": + new_name = file_name + path = self.move_path or "" + elif self.after_import == "move_rename": + new_name = self._template_render(self.new_name, attachment) + path = self.move_path or "" + if new_name: + new_full_path = fs.sep.join([path.rstrip(fs.sep), new_name]) + fs.move(fullpath, new_full_path) + if self.after_import == "delete": + fs.rm(fullpath) + + def run_import(self): + self.ensure_one() + attach_obj = self.env["attachment.queue"] + file_path_names = self._get_files() + total_import = 0 + fs = self.backend_id.fs + for file_path in file_path_names: + if fs.isdir(file_path): + continue + with self.env.cr.savepoint(): + file_name = file_path.split(fs.sep)[-1] + # avoid use of cat_file because it may not be implemeted in async + # implementation like sshfs + with fs.open(file_path, "rb") as fs_file: + data = fs_file.read() + data = base64.b64encode(data) + attach_vals = self._prepare_attachment_vals(data, file_name) + attachment = attach_obj.create(attach_vals) + self._manage_file_after_import(file_name, file_path, attachment) + total_import += 1 + _logger.info("Run import complete! Imported {} files".format(total_import)) + + def _filter_duplicates(self, file_path_names): + fs = self.backend_id.fs + self.ensure_one() + if self.filepath: + filenames = [x.split(fs.sep)[-1] for x in file_path_names] + else: + filenames = file_path_names + imported = ( + self.env["attachment.queue"] + .search([("name", "in", filenames)]) + .mapped("name") + ) + file_path_names_no_duplicate = [ + x for x in file_path_names if x.split(fs.sep)[-1] not in imported + ] + return file_path_names_no_duplicate + + def run_export(self): + for task in self: + for att in task.attachment_ids.filtered(lambda a: a.state == "pending"): + att.run_as_job() + + def button_duplicate_record(self): + # due to orm limitation method call from ui should not have params + # so we need to define this method to be able to copy + # if we do not do this the context will be injected in default params + self.copy() + + def copy(self, default=None): + if default is None: + default = {} + if "active" not in default: + default["active"] = False + return super().copy(default=default) diff --git a/attachment_synchronize/models/storage_backend.py b/attachment_synchronize/models/storage_backend.py new file mode 100644 index 00000000000..15aabe14840 --- /dev/null +++ b/attachment_synchronize/models/storage_backend.py @@ -0,0 +1,67 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class FsStorage(models.Model): + _inherit = "fs.storage" + + synchronize_task_ids = fields.One2many( + "attachment.synchronize.task", "backend_id", string="Tasks" + ) + import_task_count = fields.Integer( + "Import Tasks", compute="_compute_import_task_count" + ) + export_task_count = fields.Integer( + "Export Tasks", compute="_compute_export_task_count" + ) + + def _compute_import_task_count(self): + for rec in self: + rec.import_task_count = len( + rec.synchronize_task_ids.filtered(lambda t: t.method_type == "import") + ) + + def _compute_export_task_count(self): + for rec in self: + rec.export_task_count = len( + rec.synchronize_task_ids.filtered(lambda t: t.method_type == "export") + ) + + def action_related_import_task(self): + self.ensure_one() + + act_window_xml_id = "attachment_synchronize.action_attachment_import_task" + act_window = self.env["ir.actions.act_window"]._for_xml_id(act_window_xml_id) + domain = [ + ("id", "in", self.synchronize_task_ids.ids), + ("method_type", "=", "import"), + ] + act_window["domain"] = domain + if self.import_task_count == 1: + form = self.env.ref("attachment_synchronize.view_attachment_task_form") + act_window["views"] = [(form.id, "form")] + act_window["res_id"] = ( + self.env["attachment.synchronize.task"].search(domain).id + ) + + return act_window + + def action_related_export_task(self): + self.ensure_one() + + act_window_xml_id = "attachment_synchronize.action_attachment_export_task" + act_window = self.env["ir.actions.act_window"]._for_xml_id(act_window_xml_id) + domain = [ + ("id", "in", self.synchronize_task_ids.ids), + ("method_type", "=", "export"), + ] + act_window["domain"] = domain + if self.export_task_count == 1: + form = self.env.ref("attachment_synchronize.view_attachment_task_form") + act_window["views"] = [(form.id, "form")] + act_window["res_id"] = ( + self.env["attachment.synchronize.task"].search(domain).id + ) + + return act_window diff --git a/attachment_synchronize/readme/CONTRIBUTORS.rst b/attachment_synchronize/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..f48f581a3cc --- /dev/null +++ b/attachment_synchronize/readme/CONTRIBUTORS.rst @@ -0,0 +1,10 @@ +`Akretion `_ : + +- Valentin CHEMIERE +- Mourad EL HADJ MIMOUNE +- Florian DA COSTA +- Clément MOMBEREAU + +GS Lab: + +- Giovanni SERRA diff --git a/attachment_synchronize/readme/DESCRIPTION.rst b/attachment_synchronize/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..fb181967b0b --- /dev/null +++ b/attachment_synchronize/readme/DESCRIPTION.rst @@ -0,0 +1,5 @@ +This module allows to **import/export files** from/to backend servers. + +A backend server is defined by the basic `fs_storage `_ OCA module, while it can be configured (amazon S3, sftp,...) with additional modules fs python libraries + +The imported files (and the files to be exported) are stored in Odoo as ``attachment.queue`` objects, defined by the `attachment_queue `_ module while the importation itself (resp. exportation) is realized by **"Attachments Import Tasks"** (resp. "Attachments Export Tasks") defined by this current module. diff --git a/attachment_synchronize/readme/USAGE.rst b/attachment_synchronize/readme/USAGE.rst new file mode 100644 index 00000000000..f4714693dd1 --- /dev/null +++ b/attachment_synchronize/readme/USAGE.rst @@ -0,0 +1,19 @@ +As importation and exportation are different processes, they are triggered in different ways : + +**To import files**, you need to create an *"Attachment Import Task"* (menu *Settings > Technical > Attachments Import Tasks*) which defines : + +- where to find the files to import from the backend server (path to the files, selection pattern) +- what to do with the source files in the backend server (avoid duplicates, delete/rename after import...) +- how the files will be processed once imported (through the **File Type** field). + +.. image:: ../static/description/import_task.png + +.. epigraph:: + + 🔎 The **File Type** options are defined by other modules built to process the Attachments Queues with the same "File Type". + +**To export files**, you need first to register them as *"Attachments Queues"* objects linked to an *"Attachment Export Task"* (which set automatically their **File Type** to *"Export File (External Location)"*). + +Then, you can export one file at a time from the *Attachment Queue*'s form view, or export all the *Attachments Queues* in a pending state related to the same *Export Task* from the given *Export Task* form view (menu *Settings > Technical > Attachments Export Tasks*) : + +.. image:: ../static/description/export_task.png diff --git a/attachment_synchronize/security/ir.model.access.csv b/attachment_synchronize/security/ir.model.access.csv new file mode 100644 index 00000000000..742f94e2f4e --- /dev/null +++ b/attachment_synchronize/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_attachment_synchronize_task_manager,attachment.synchronize.task.manager,model_attachment_synchronize_task,base.group_system,1,1,1,1 diff --git a/attachment_synchronize/static/description/export_task.png b/attachment_synchronize/static/description/export_task.png new file mode 100644 index 00000000000..8e8bc883444 Binary files /dev/null and b/attachment_synchronize/static/description/export_task.png differ diff --git a/attachment_synchronize/static/description/icon.png b/attachment_synchronize/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/attachment_synchronize/static/description/icon.png differ diff --git a/attachment_synchronize/static/description/import_task.png b/attachment_synchronize/static/description/import_task.png new file mode 100644 index 00000000000..9aee76f5745 Binary files /dev/null and b/attachment_synchronize/static/description/import_task.png differ diff --git a/attachment_synchronize/static/description/index.html b/attachment_synchronize/static/description/index.html new file mode 100644 index 00000000000..23c63d40d28 --- /dev/null +++ b/attachment_synchronize/static/description/index.html @@ -0,0 +1,449 @@ + + + + + +Attachment Synchronize + + + +
+

Attachment Synchronize

+ + +

Beta License: AGPL-3 OCA/server-tools Translate me on Weblate Try me on Runboat

+

This module allows to import/export files from/to backend servers.

+

A backend server is defined by the basic fs_storage OCA module, while it can be configured (amazon S3, sftp,…) with additional modules fs python libraries

+

The imported files (and the files to be exported) are stored in Odoo as attachment.queue objects, defined by the attachment_queue module while the importation itself (resp. exportation) is realized by “Attachments Import Tasks” (resp. “Attachments Export Tasks”) defined by this current module.

+

Table of contents

+ +
+

Usage

+

As importation and exportation are different processes, they are triggered in different ways :

+

To import files, you need to create an “Attachment Import Task” (menu Settings > Technical > Attachments Import Tasks) which defines :

+
    +
  • where to find the files to import from the backend server (path to the files, selection pattern)
  • +
  • what to do with the source files in the backend server (avoid duplicates, delete/rename after import…)
  • +
  • how the files will be processed once imported (through the File Type field).
  • +
+https://raw.githubusercontent.com/OCA/server-tools/16.0/attachment_synchronize/static/description/import_task.png +
+🔎 The File Type options are defined by other modules built to process the Attachments Queues with the same “File Type”.
+

To export files, you need first to register them as “Attachments Queues” objects linked to an “Attachment Export Task” (which set automatically their File Type to “Export File (External Location)”).

+

Then, you can export one file at a time from the Attachment Queue’s form view, or export all the Attachments Queues in a pending state related to the same Export Task from the given Export Task form view (menu Settings > Technical > Attachments Export Tasks) :

+https://raw.githubusercontent.com/OCA/server-tools/16.0/attachment_synchronize/static/description/export_task.png +
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Akretion
  • +
+
+
+

Contributors

+

Akretion :

+ +

GS Lab:

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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.

+

Current maintainers:

+

florian-dacosta sebastienbeau GSLabIt bealdav

+

This module is part of the OCA/server-tools project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/attachment_synchronize/tests/__init__.py b/attachment_synchronize/tests/__init__.py new file mode 100644 index 00000000000..3845a51aec1 --- /dev/null +++ b/attachment_synchronize/tests/__init__.py @@ -0,0 +1,2 @@ +from . import test_import +from . import test_export diff --git a/attachment_synchronize/tests/common.py b/attachment_synchronize/tests/common.py new file mode 100644 index 00000000000..c4d6aa1d6af --- /dev/null +++ b/attachment_synchronize/tests/common.py @@ -0,0 +1,42 @@ +# Copyright 2020 Akretion (http://www.akretion.com). +# @author SĂ©bastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import base64 + +from odoo.tests.common import TransactionCase + + +class SyncCommon(TransactionCase): + def _clean_testing_directory(self): + for test_dir in [ + self.directory_input, + self.directory_output, + self.directory_archived, + ]: + fs = self.backend.fs + if not fs.exists(test_dir): + fs.makedirs(test_dir) + for filename in fs.ls(test_dir, detail=False): + fs.rm(filename) + + def _create_test_file(self): + fs = self.backend.fs + path = fs.sep.join([self.directory_input, "bar.txt"]) + with fs.open(path, "wb") as f: + f.write(self.filedata) + + def setUp(self): + super().setUp() + self.backend = self.env.ref("fs_storage.default_fs_storage") + self.filedata = base64.b64encode(b"This is a simple file") + self.directory_input = "test_import" + self.directory_output = "test_export" + self.directory_archived = "test_archived" + self._clean_testing_directory() + self._create_test_file() + self.task = self.env.ref("attachment_synchronize.import_from_filestore") + + def tearDown(self): + self._clean_testing_directory() + super().tearDown() diff --git a/attachment_synchronize/tests/test_export.py b/attachment_synchronize/tests/test_export.py new file mode 100644 index 00000000000..696b4e67a06 --- /dev/null +++ b/attachment_synchronize/tests/test_export.py @@ -0,0 +1,43 @@ +# Copyright 2020 Akretion (http://www.akretion.com). +# @author SĂ©bastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from unittest import mock + +from odoo.tools import mute_logger + +from .common import SyncCommon + + +def raising_side_effect(*args, **kwargs): + raise Exception("Boom") + + +class TestExport(SyncCommon): + def setUp(self): + super().setUp() + self.task = self.env.ref("attachment_synchronize.export_to_filestore") + self.attachment = self.env["attachment.queue"].create( + { + "name": "foo.txt", + "task_id": self.task.id, + "file_type": "export", + "datas": self.filedata, + } + ) + + def test_export(self): + self.attachment.run() + result = self.backend.fs.ls("test_export", detail=False) + self.assertEqual(result, ["test_export/foo.txt"]) + + @mute_logger("odoo.addons.attachment_queue.models.attachment_queue") + def test_failing_export(self): + with mock.patch.object( + type(self.backend.fs), + "open", + side_effect=raising_side_effect, + ): + self.attachment.with_context(queue_job__no_delay=True).run_as_job() + self.assertEqual(self.attachment.state, "failed") + self.assertEqual(self.attachment.state_message, "Boom") diff --git a/attachment_synchronize/tests/test_import.py b/attachment_synchronize/tests/test_import.py new file mode 100644 index 00000000000..cd20c283ec0 --- /dev/null +++ b/attachment_synchronize/tests/test_import.py @@ -0,0 +1,81 @@ +# Copyright 2020 Akretion (http://www.akretion.com). +# @author SĂ©bastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from .common import SyncCommon + + +class TestImport(SyncCommon): + @property + def archived_files(self): + return self.backend.fs.ls(self.directory_archived, detail=False) + + @property + def input_files(self): + return self.backend.fs.ls(self.directory_input, detail=False) + + def _check_attachment_created(self, count=1): + attachment = self.env["attachment.queue"].search([("name", "=", "bar.txt")]) + self.assertEqual(len(attachment), count) + + def test_import_with_rename(self): + self.task.write({"after_import": "rename", "new_name": "test-${obj.name}"}) + self.task.run_import() + self._check_attachment_created() + self.assertEqual(self.input_files, ["test_import/test-bar.txt"]) + self.assertEqual(self.archived_files, []) + + def test_import_with_move(self): + self.task.write({"after_import": "move", "move_path": self.directory_archived}) + self.task.run_import() + self._check_attachment_created() + self.assertEqual(self.input_files, []) + self.assertEqual(self.archived_files, ["test_archived/bar.txt"]) + + def test_import_with_move_and_rename(self): + self.task.write( + { + "after_import": "move_rename", + "new_name": "foo.txt", + "move_path": self.directory_archived, + } + ) + self.task.run_import() + self._check_attachment_created() + self.assertEqual(self.input_files, []) + self.assertEqual(self.archived_files, ["test_archived/foo.txt"]) + + def test_import_with_delete(self): + self.task.write({"after_import": "delete"}) + self.task.run_import() + self._check_attachment_created() + self.assertEqual(self.input_files, []) + self.assertEqual(self.archived_files, []) + + def test_import_twice(self): + self.task.write({"after_import": "delete"}) + self.task.run_import() + self._check_attachment_created(count=1) + + self._create_test_file() + self.task.run_import() + self._check_attachment_created(count=2) + + def test_import_twice_no_duplicate(self): + self.task.write({"after_import": "delete", "avoid_duplicated_files": True}) + self.task.run_import() + self._check_attachment_created(count=1) + + self._create_test_file() + self.task.run_import() + self._check_attachment_created(count=1) + + def test_running_cron(self): + self.task.write({"after_import": "delete"}) + self.env["attachment.synchronize.task"].run_task_import_scheduler() + self._check_attachment_created(count=1) + + def test_running_cron_disable_task(self): + self.task.write({"after_import": "delete", "active": False}) + self.env["attachment.synchronize.task"].run_task_import_scheduler() + self._check_attachment_created(count=0) diff --git a/attachment_synchronize/views/attachment_queue_views.xml b/attachment_synchronize/views/attachment_queue_views.xml new file mode 100644 index 00000000000..23a6e9c09f6 --- /dev/null +++ b/attachment_synchronize/views/attachment_queue_views.xml @@ -0,0 +1,58 @@ + + + + + attachment.queue + + + + + + + + + + + + + attachment.queue + + + + state == 'done' + + + + + + + + + + attachment.queue + + + + + + + + + + Attachments Queue + ir.actions.act_window + attachment.queue + tree,form + + [('task_id', '=', active_id)] + + + + diff --git a/attachment_synchronize/views/attachment_synchronize_task_views.xml b/attachment_synchronize/views/attachment_synchronize_task_views.xml new file mode 100644 index 00000000000..cc1279213c0 --- /dev/null +++ b/attachment_synchronize/views/attachment_synchronize_task_views.xml @@ -0,0 +1,236 @@ + + + + attachment.synchronize.task + +
+
+
+ + + +
+ + + +
+
+
+ + + + + + + + + + + + + + + +
+
+
+
+ + + attachment.synchronize.task + + + + + + + + + + + + +
diff --git a/base_name_search_improved/i18n/base_name_search_improved.pot b/base_name_search_improved/i18n/base_name_search_improved.pot index 6201a654373..9f2583cdeda 100644 --- a/base_name_search_improved/i18n/base_name_search_improved.pot +++ b/base_name_search_improved/i18n/base_name_search_improved.pot @@ -274,6 +274,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -480,6 +481,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/ca.po b/base_name_search_improved/i18n/ca.po index 1a3065363a0..2536ab03fc4 100644 --- a/base_name_search_improved/i18n/ca.po +++ b/base_name_search_improved/i18n/ca.po @@ -289,6 +289,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -495,6 +496,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/de.po b/base_name_search_improved/i18n/de.po index c334e78a251..5d0a89a3674 100644 --- a/base_name_search_improved/i18n/de.po +++ b/base_name_search_improved/i18n/de.po @@ -289,6 +289,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -495,6 +496,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/es.po b/base_name_search_improved/i18n/es.po index d435084658d..7454bcb710c 100644 --- a/base_name_search_improved/i18n/es.po +++ b/base_name_search_improved/i18n/es.po @@ -315,6 +315,7 @@ msgstr "¿Búsqueda inteligente por nombre activada?" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -521,6 +522,9 @@ msgstr "¿Búsqueda inteligente por nombre activada?" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/es_ES.po b/base_name_search_improved/i18n/es_ES.po index 9573beae365..819450be4a7 100644 --- a/base_name_search_improved/i18n/es_ES.po +++ b/base_name_search_improved/i18n/es_ES.po @@ -289,6 +289,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -495,6 +496,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/eu.po b/base_name_search_improved/i18n/eu.po index 2ddc363505a..f2537e008a4 100644 --- a/base_name_search_improved/i18n/eu.po +++ b/base_name_search_improved/i18n/eu.po @@ -287,6 +287,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -493,6 +494,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/fi.po b/base_name_search_improved/i18n/fi.po index 68503e79b99..ebfa4982fab 100644 --- a/base_name_search_improved/i18n/fi.po +++ b/base_name_search_improved/i18n/fi.po @@ -287,6 +287,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -493,6 +494,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/fr.po b/base_name_search_improved/i18n/fr.po index afb99b1f71b..525289b6c66 100644 --- a/base_name_search_improved/i18n/fr.po +++ b/base_name_search_improved/i18n/fr.po @@ -287,6 +287,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -493,6 +494,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/hr.po b/base_name_search_improved/i18n/hr.po index 4f25f41eae9..003dada4bc7 100644 --- a/base_name_search_improved/i18n/hr.po +++ b/base_name_search_improved/i18n/hr.po @@ -288,6 +288,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -494,6 +495,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/hr_HR.po b/base_name_search_improved/i18n/hr_HR.po index 27747947319..228a825d910 100644 --- a/base_name_search_improved/i18n/hr_HR.po +++ b/base_name_search_improved/i18n/hr_HR.po @@ -289,6 +289,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -495,6 +496,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/it.po b/base_name_search_improved/i18n/it.po index aaafd645ea7..8a330b4f935 100644 --- a/base_name_search_improved/i18n/it.po +++ b/base_name_search_improved/i18n/it.po @@ -120,8 +120,8 @@ msgstr "" "comportamento più \"rilassato\". Odoo cerca nativamente record che includono " "le frasi inserite così come sono inserite. Attivando questa opzioneverranno " "cercati record che contengono le parole inserite indipendentemente " -"dall'ordine in cui sono inserite. Per esempio se cerchiamo un contatto \"Fred" -" Flinstone\", Odoo restituirà in modo predefinito solo i record che " +"dall'ordine in cui sono inserite. Per esempio se cerchiamo un contatto " +"\"Fred Flinstone\", Odoo restituirà in modo predefinito solo i record che " "contengono la frase esatta. Con la ricerca intelligente attiva verrà " "restituito ogni record che contiene le parole \"Fred\" e \"Flinstone\".\n" "
\n" @@ -313,6 +313,7 @@ msgstr "Ricerca nome intelligente abilitata?" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -519,6 +520,9 @@ msgstr "Ricerca nome intelligente abilitata?" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/nb_NO.po b/base_name_search_improved/i18n/nb_NO.po index 3ab9646ecb2..62676997f63 100644 --- a/base_name_search_improved/i18n/nb_NO.po +++ b/base_name_search_improved/i18n/nb_NO.po @@ -288,6 +288,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -494,6 +495,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/nl.po b/base_name_search_improved/i18n/nl.po index c5189da5438..f9a819c8139 100644 --- a/base_name_search_improved/i18n/nl.po +++ b/base_name_search_improved/i18n/nl.po @@ -287,6 +287,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -493,6 +494,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/pt_BR.po b/base_name_search_improved/i18n/pt_BR.po index 325eda59d01..ab4425ef27a 100644 --- a/base_name_search_improved/i18n/pt_BR.po +++ b/base_name_search_improved/i18n/pt_BR.po @@ -290,6 +290,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -496,6 +497,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/sl.po b/base_name_search_improved/i18n/sl.po index 7311d0aa34d..4edaf50d904 100644 --- a/base_name_search_improved/i18n/sl.po +++ b/base_name_search_improved/i18n/sl.po @@ -289,6 +289,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -495,6 +496,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/tr.po b/base_name_search_improved/i18n/tr.po index 3d1b5f0ea62..55d7c44625a 100644 --- a/base_name_search_improved/i18n/tr.po +++ b/base_name_search_improved/i18n/tr.po @@ -289,6 +289,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -495,6 +496,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/tr_TR.po b/base_name_search_improved/i18n/tr_TR.po index 021bccdeff6..f940c0bd4b8 100644 --- a/base_name_search_improved/i18n/tr_TR.po +++ b/base_name_search_improved/i18n/tr_TR.po @@ -288,6 +288,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -494,6 +495,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/base_name_search_improved/i18n/zh_CN.po b/base_name_search_improved/i18n/zh_CN.po index e7bc32d80ef..71216055fe4 100644 --- a/base_name_search_improved/i18n/zh_CN.po +++ b/base_name_search_improved/i18n/zh_CN.po @@ -288,6 +288,7 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_digest_tip__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_fetchmail_server__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_format_address_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_fs_storage__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_google_gmail_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_account__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_iap_autocomplete_api__smart_search @@ -494,6 +495,9 @@ msgstr "" #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_payment_provider_onboarding_wizard__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sale_report__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sequence_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_config__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_mixin__smart_search +#: model:ir.model.fields,field_description:base_name_search_improved.field_server_env_techname_mixin__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_api__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_composer__smart_search #: model:ir.model.fields,field_description:base_name_search_improved.field_sms_resend__smart_search diff --git a/setup/_metapackage/VERSION.txt b/setup/_metapackage/VERSION.txt index 5e7be1c7012..780e05cbc7b 100644 --- a/setup/_metapackage/VERSION.txt +++ b/setup/_metapackage/VERSION.txt @@ -1 +1 @@ -16.0.20240129.0 \ No newline at end of file +16.0.20240130.0 \ No newline at end of file diff --git a/setup/_metapackage/setup.py b/setup/_metapackage/setup.py index e3c8b25eda3..7987e0d5b4d 100644 --- a/setup/_metapackage/setup.py +++ b/setup/_metapackage/setup.py @@ -9,6 +9,7 @@ version=version, install_requires=[ 'odoo-addon-attachment_queue>=16.0dev,<16.1dev', + 'odoo-addon-attachment_synchronize>=16.0dev,<16.1dev', 'odoo-addon-attachment_unindex_content>=16.0dev,<16.1dev', 'odoo-addon-auditlog>=16.0dev,<16.1dev', 'odoo-addon-auto_backup>=16.0dev,<16.1dev', diff --git a/setup/attachment_synchronize/odoo/addons/attachment_synchronize b/setup/attachment_synchronize/odoo/addons/attachment_synchronize new file mode 120000 index 00000000000..771cca7f5b1 --- /dev/null +++ b/setup/attachment_synchronize/odoo/addons/attachment_synchronize @@ -0,0 +1 @@ +../../../../attachment_synchronize \ No newline at end of file diff --git a/setup/attachment_synchronize/setup.py b/setup/attachment_synchronize/setup.py new file mode 100644 index 00000000000..28c57bb6403 --- /dev/null +++ b/setup/attachment_synchronize/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)