diff --git a/dms_field_auto_classification/README.rst b/dms_field_auto_classification/README.rst new file mode 100644 index 000000000..88012d0b8 --- /dev/null +++ b/dms_field_auto_classification/README.rst @@ -0,0 +1,124 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +===================================== +Auto classify files into embedded DMS +===================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:08d9cc488429baf098763c68704aa8516ffc5b2f1ff40c2b7422db0be35d39ff + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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%2Fdms-lightgray.png?logo=github + :target: https://github.com/OCA/dms/tree/18.0/dms_field_auto_classification + :alt: OCA/dms +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/dms-18-0/dms-18-0-dms_field_auto_classification + :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/dms&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Automatically classify files within a .zip file to the corresponding +directory(s) related to an embedded DMS. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +1. Go to Documents / Configuration / Classification Templates and create + or edit a template. +2. You can set a model to which it is linked (res.partner for example). +3. You can define the details to indicate which field is referenced by + the defined filename pattern. + +Full example from res.partner: + +Filename pattern: ([0-9]{8}[A-Z]).\*.pdf Details: VAT (field) and 0 +(index) Directory Pattern example 1: {0} > This will attempt to add the +files to the directory linked to the partner with the VAT name. +Directory Pattern example 2: {0} / Misc > This will attempt to add the +files to the "Misc" subdirectory linked to the partner with the VAT +name. + +Usage +===== + +1. Go to Documents / Auto Classification and select a template and a + .zip file. +2. Press the Analyze button +3. As many lines will be set as the number of files contained in the + .zip file and apply the filename pattern. +4. The record to which they are related (res.partner for example) will + be show on the lines. +5. Press the Classify button +6. The files (dms.file) will be created in the corresponding + directories. + +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 +------- + +* Tecnativa + +Contributors +------------ + +- `Tecnativa `__: + + - Víctor Martínez + - Pedro M. Baeza + +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-victoralmau| image:: https://github.com/victoralmau.png?size=40px + :target: https://github.com/victoralmau + :alt: victoralmau + +Current `maintainer `__: + +|maintainer-victoralmau| + +This module is part of the `OCA/dms `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/dms_field_auto_classification/__init__.py b/dms_field_auto_classification/__init__.py new file mode 100644 index 000000000..e1e144406 --- /dev/null +++ b/dms_field_auto_classification/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import models +from . import wizards diff --git a/dms_field_auto_classification/__manifest__.py b/dms_field_auto_classification/__manifest__.py new file mode 100644 index 000000000..7b9e61324 --- /dev/null +++ b/dms_field_auto_classification/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2024 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Auto classify files into embedded DMS", + "version": "19.0.1.0.0", + "category": "Document Management", + "website": "https://github.com/OCA/dms", + "author": "Tecnativa, Odoo Community Association (OCA)", + "license": "AGPL-3", + "depends": ["dms_auto_classification", "dms_field"], + "installable": True, + "data": [ + "security/ir.model.access.csv", + "views/dms_classification_template_views.xml", + "wizards/wizard_dms_classification_views.xml", + ], + "demo": ["demo/dms_classification_template_demo.xml"], + "maintainers": ["victoralmau"], +} diff --git a/dms_field_auto_classification/demo/dms_classification_template_demo.xml b/dms_field_auto_classification/demo/dms_classification_template_demo.xml new file mode 100644 index 000000000..261edd865 --- /dev/null +++ b/dms_field_auto_classification/demo/dms_classification_template_demo.xml @@ -0,0 +1,20 @@ + + + + Partners template + ([0-9]{8}[A-Z]).*.pdf + + {0} + + + + + 0 + + diff --git a/dms_field_auto_classification/i18n/ar.po b/dms_field_auto_classification/i18n/ar.po new file mode 100644 index 000000000..b1c7b59df --- /dev/null +++ b/dms_field_auto_classification/i18n/ar.po @@ -0,0 +1,107 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * dms_field_auto_classification +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: ar\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " +"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__create_uid +msgid "Created by" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__create_date +msgid "Created on" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__detail_ids +msgid "Details" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__display_name +msgid "Display Name" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_dms_classification_template +msgid "Dms Classification Template" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_dms_classification_template_detail +msgid "Dms Classification Template Detail" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__field_id +msgid "Field" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__id +msgid "ID" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__index +msgid "Index" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__write_date +msgid "Last Updated on" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__model_id +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__model_id +msgid "Model" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__model +msgid "Model name" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__parent_id +msgid "Parent" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_wizard_dms_classification_detail__record_ref +msgid "Record Referenced" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__sequence +msgid "Sequence" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_wizard_dms_classification_detail__template_id +msgid "Template" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_wizard_dms_classification_detail +msgid "Wizard Dms Classification Detail" +msgstr "" diff --git a/dms_field_auto_classification/i18n/dms_field_auto_classification.pot b/dms_field_auto_classification/i18n/dms_field_auto_classification.pot new file mode 100644 index 000000000..8e34de915 --- /dev/null +++ b/dms_field_auto_classification/i18n/dms_field_auto_classification.pot @@ -0,0 +1,105 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * dms_field_auto_classification +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.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: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__create_uid +msgid "Created by" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__create_date +msgid "Created on" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__detail_ids +msgid "Details" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__display_name +msgid "Display Name" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_dms_classification_template +msgid "Dms Classification Template" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_dms_classification_template_detail +msgid "Dms Classification Template Detail" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__field_id +msgid "Field" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__id +msgid "ID" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__index +msgid "Index" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__write_date +msgid "Last Updated on" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__model_id +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__model_id +msgid "Model" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__model +msgid "Model name" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__parent_id +msgid "Parent" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_wizard_dms_classification_detail__record_ref +msgid "Record Referenced" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__sequence +msgid "Sequence" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_wizard_dms_classification_detail__template_id +msgid "Template" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_wizard_dms_classification_detail +msgid "Wizard Dms Classification Detail" +msgstr "" diff --git a/dms_field_auto_classification/i18n/es.po b/dms_field_auto_classification/i18n/es.po new file mode 100644 index 000000000..b2c2b1094 --- /dev/null +++ b/dms_field_auto_classification/i18n/es.po @@ -0,0 +1,114 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * dms_field_auto_classification +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-01-23 12:22+0000\n" +"PO-Revision-Date: 2026-02-19 14:40+0000\n" +"Last-Translator: herminioelx \n" +"Language-Team: \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.15.2\n" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__detail_ids +msgid "Details" +msgstr "Detalles" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__display_name +msgid "Display Name" +msgstr "Nombre a Mostrar" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_dms_classification_template +msgid "Dms Classification Template" +msgstr "Plantilla de clasificación Dms" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_dms_classification_template_detail +msgid "Dms Classification Template Detail" +msgstr "Plantilla de Clasificación Dms Detalle" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__field_id +msgid "Field" +msgstr "Campo" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__id +msgid "ID" +msgstr "ID" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__index +msgid "Index" +msgstr "Índice" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail____last_update +msgid "Last Modified on" +msgstr "Última Modificación el" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__write_uid +msgid "Last Updated by" +msgstr "Actualizado por última vez por" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__write_date +msgid "Last Updated on" +msgstr "Última modificación el" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__model_id +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__model_id +msgid "Model" +msgstr "Modelo" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__model +msgid "Model name" +msgstr "Nombre del modelo" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__parent_id +msgid "Parent" +msgstr "Padre" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_wizard_dms_classification_detail__record_ref +msgid "Record Referenced" +msgstr "Registro referenciado" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__sequence +msgid "Sequence" +msgstr "Secuencia" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_wizard_dms_classification_detail__template_id +msgid "Template" +msgstr "Plantilla" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_wizard_dms_classification_detail +msgid "Wizard Dms Classification Detail" +msgstr "Asistente de Clasificación Dms Detalle" diff --git a/dms_field_auto_classification/i18n/it.po b/dms_field_auto_classification/i18n/it.po new file mode 100644 index 000000000..64ca3fdf4 --- /dev/null +++ b/dms_field_auto_classification/i18n/it.po @@ -0,0 +1,113 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * dms_field_auto_classification +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-10-03 10:06+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.6.2\n" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__detail_ids +msgid "Details" +msgstr "Dettagli" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_dms_classification_template +msgid "Dms Classification Template" +msgstr "Modello classificazione DMS" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_dms_classification_template_detail +msgid "Dms Classification Template Detail" +msgstr "Dettagli modello classificazione DMS" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__field_id +msgid "Field" +msgstr "Campo" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__id +msgid "ID" +msgstr "ID" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__index +msgid "Index" +msgstr "Indice" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail____last_update +msgid "Last Modified on" +msgstr "Ultima modifica il" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__model_id +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__model_id +msgid "Model" +msgstr "Modello" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__model +msgid "Model name" +msgstr "Nome modello" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__parent_id +msgid "Parent" +msgstr "Padre" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_wizard_dms_classification_detail__record_ref +msgid "Record Referenced" +msgstr "Record referenziato" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__sequence +msgid "Sequence" +msgstr "Sequenza" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_wizard_dms_classification_detail__template_id +msgid "Template" +msgstr "Modello" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_wizard_dms_classification_detail +msgid "Wizard Dms Classification Detail" +msgstr "Dettagli procedura guidata classificazione DMS" diff --git a/dms_field_auto_classification/i18n/sl.po b/dms_field_auto_classification/i18n/sl.po new file mode 100644 index 000000000..12ffddd66 --- /dev/null +++ b/dms_field_auto_classification/i18n/sl.po @@ -0,0 +1,109 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * dms_field_auto_classification +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2026-06-22 11:46+0000\n" +"Last-Translator: Matjaz Mozetic \n" +"Language-Team: none\n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || " +"n%100==4 ? 2 : 3;\n" +"X-Generator: Weblate 5.15.2\n" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__create_uid +msgid "Created by" +msgstr "Ustvaril" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__create_date +msgid "Created on" +msgstr "Ustvarjeno" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__detail_ids +msgid "Details" +msgstr "Podrobnosti" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__display_name +msgid "Display Name" +msgstr "Prikazani naziv" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_dms_classification_template +msgid "Dms Classification Template" +msgstr "DMS predloga klasifikacije" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_dms_classification_template_detail +msgid "Dms Classification Template Detail" +msgstr "DMS podrobnosti predloge klasifikacije" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__field_id +msgid "Field" +msgstr "Polje" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__id +msgid "ID" +msgstr "ID" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__index +msgid "Index" +msgstr "Indeks" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__write_uid +msgid "Last Updated by" +msgstr "Zadnji posodobil" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__write_date +msgid "Last Updated on" +msgstr "Zadnjič posodobljeno" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__model_id +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__model_id +msgid "Model" +msgstr "Model" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__model +msgid "Model name" +msgstr "Naziv modela" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__parent_id +msgid "Parent" +msgstr "Nadrejeni" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_wizard_dms_classification_detail__record_ref +msgid "Record Referenced" +msgstr "Sklic na zapis" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__sequence +msgid "Sequence" +msgstr "Zaporedje" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_wizard_dms_classification_detail__template_id +msgid "Template" +msgstr "Predloga" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_wizard_dms_classification_detail +msgid "Wizard Dms Classification Detail" +msgstr "Čarovnik DMS podrobnosti klasifikacije" diff --git a/dms_field_auto_classification/i18n/sv.po b/dms_field_auto_classification/i18n/sv.po new file mode 100644 index 000000000..2a5849f8d --- /dev/null +++ b/dms_field_auto_classification/i18n/sv.po @@ -0,0 +1,106 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * dms_field_auto_classification +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__create_uid +msgid "Created by" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__create_date +msgid "Created on" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__detail_ids +msgid "Details" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__display_name +msgid "Display Name" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_dms_classification_template +msgid "Dms Classification Template" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_dms_classification_template_detail +msgid "Dms Classification Template Detail" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__field_id +msgid "Field" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__id +msgid "ID" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__index +msgid "Index" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__write_date +msgid "Last Updated on" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__model_id +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__model_id +msgid "Model" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template__model +msgid "Model name" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__parent_id +msgid "Parent" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_wizard_dms_classification_detail__record_ref +msgid "Record Referenced" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_dms_classification_template_detail__sequence +msgid "Sequence" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model.fields,field_description:dms_field_auto_classification.field_wizard_dms_classification_detail__template_id +msgid "Template" +msgstr "" + +#. module: dms_field_auto_classification +#: model:ir.model,name:dms_field_auto_classification.model_wizard_dms_classification_detail +msgid "Wizard Dms Classification Detail" +msgstr "" diff --git a/dms_field_auto_classification/models/__init__.py b/dms_field_auto_classification/models/__init__.py new file mode 100644 index 000000000..cb95092bf --- /dev/null +++ b/dms_field_auto_classification/models/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import dms_classification_template diff --git a/dms_field_auto_classification/models/dms_classification_template.py b/dms_field_auto_classification/models/dms_classification_template.py new file mode 100644 index 000000000..77fe1b647 --- /dev/null +++ b/dms_field_auto_classification/models/dms_classification_template.py @@ -0,0 +1,46 @@ +# Copyright 2024 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class DmsClassificationTemplate(models.Model): + _inherit = "dms.classification.template" + + model_id = fields.Many2one( + comodel_name="ir.model", string="Model", domain=[("transient", "=", False)] + ) + model = fields.Char( + compute="_compute_model", string="Model name", compute_sudo=True + ) + detail_ids = fields.One2many( + string="Details", + comodel_name="dms.classification.template.detail", + inverse_name="parent_id", + ) + + @api.depends("model_id") + def _compute_model(self): + for item in self: + item.model = item.model_id.model + + +class DmsClassificationTemplateDetail(models.Model): + _name = "dms.classification.template.detail" + _description = "Dms Classification Template Detail" + _order = "sequence, field_id" + + parent_id = fields.Many2one( + comodel_name="dms.classification.template", + string="Parent", + ) + model_id = fields.Many2one( + related="parent_id.model_id", + ) + field_id = fields.Many2one( + comodel_name="ir.model.fields", + domain="[('model_id', '=', model_id)]", + string="Field", + ) + index = fields.Integer(required=True, default=0) + sequence = fields.Integer(required=True, default=10) diff --git a/dms_field_auto_classification/pyproject.toml b/dms_field_auto_classification/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/dms_field_auto_classification/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/dms_field_auto_classification/readme/CONFIGURE.md b/dms_field_auto_classification/readme/CONFIGURE.md new file mode 100644 index 000000000..7a851d3ab --- /dev/null +++ b/dms_field_auto_classification/readme/CONFIGURE.md @@ -0,0 +1,14 @@ +1. Go to Documents / Configuration / Classification Templates and + create or edit a template. +2. You can set a model to which it is linked (res.partner for example). +3. You can define the details to indicate which field is referenced by + the defined filename pattern. + +Full example from res.partner: + +Filename pattern: (\[0-9\]{8}\[A-Z\]).\*.pdf Details: VAT (field) and 0 +(index) Directory Pattern example 1: {0} \> This will attempt to add the +files to the directory linked to the partner with the VAT name. +Directory Pattern example 2: {0} / Misc \> This will attempt to add the +files to the "Misc" subdirectory linked to the partner with the VAT +name. diff --git a/dms_field_auto_classification/readme/CONTRIBUTORS.md b/dms_field_auto_classification/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..5fee39042 --- /dev/null +++ b/dms_field_auto_classification/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- [Tecnativa](https://www.tecnativa.com): + - Víctor Martínez + - Pedro M. Baeza diff --git a/dms_field_auto_classification/readme/DESCRIPTION.md b/dms_field_auto_classification/readme/DESCRIPTION.md new file mode 100644 index 000000000..9d3d71216 --- /dev/null +++ b/dms_field_auto_classification/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +Automatically classify files within a .zip file to the corresponding +directory(s) related to an embedded DMS. diff --git a/dms_field_auto_classification/readme/USAGE.md b/dms_field_auto_classification/readme/USAGE.md new file mode 100644 index 000000000..c8bf4ea52 --- /dev/null +++ b/dms_field_auto_classification/readme/USAGE.md @@ -0,0 +1,10 @@ +1. Go to Documents / Auto Classification and select a template and a + .zip file. +2. Press the Analyze button +3. As many lines will be set as the number of files contained in the + .zip file and apply the filename pattern. +4. The record to which they are related (res.partner for example) will + be show on the lines. +5. Press the Classify button +6. The files (dms.file) will be created in the corresponding + directories. diff --git a/dms_field_auto_classification/security/ir.model.access.csv b/dms_field_auto_classification/security/ir.model.access.csv new file mode 100644 index 000000000..e16b79fc4 --- /dev/null +++ b/dms_field_auto_classification/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_dms_classification_template_detail_manager,dms_classification_template_detail_manager,model_dms_classification_template_detail,dms.group_dms_manager,1,1,1,1 diff --git a/dms_field_auto_classification/static/description/icon.png b/dms_field_auto_classification/static/description/icon.png new file mode 100644 index 000000000..9fd5b327a Binary files /dev/null and b/dms_field_auto_classification/static/description/icon.png differ diff --git a/dms_field_auto_classification/static/description/icon.svg b/dms_field_auto_classification/static/description/icon.svg new file mode 100644 index 000000000..38e821a45 --- /dev/null +++ b/dms_field_auto_classification/static/description/icon.svg @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dms_field_auto_classification/static/description/index.html b/dms_field_auto_classification/static/description/index.html new file mode 100644 index 000000000..5228543c9 --- /dev/null +++ b/dms_field_auto_classification/static/description/index.html @@ -0,0 +1,470 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Auto classify files into embedded DMS

+ +

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

+

Automatically classify files within a .zip file to the corresponding +directory(s) related to an embedded DMS.

+

Table of contents

+ +
+

Configuration

+
    +
  1. Go to Documents / Configuration / Classification Templates and create +or edit a template.
  2. +
  3. You can set a model to which it is linked (res.partner for example).
  4. +
  5. You can define the details to indicate which field is referenced by +the defined filename pattern.
  6. +
+

Full example from res.partner:

+

Filename pattern: ([0-9]{8}[A-Z]).*.pdf Details: VAT (field) and 0 +(index) Directory Pattern example 1: {0} > This will attempt to add the +files to the directory linked to the partner with the VAT name. +Directory Pattern example 2: {0} / Misc > This will attempt to add the +files to the “Misc” subdirectory linked to the partner with the VAT +name.

+
+
+

Usage

+
    +
  1. Go to Documents / Auto Classification and select a template and a +.zip file.
  2. +
  3. Press the Analyze button
  4. +
  5. As many lines will be set as the number of files contained in the +.zip file and apply the filename pattern.
  6. +
  7. The record to which they are related (res.partner for example) will +be show on the lines.
  8. +
  9. Press the Classify button
  10. +
  11. The files (dms.file) will be created in the corresponding +directories.
  12. +
+
+
+

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

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+
    +
  • Tecnativa:
      +
    • Víctor Martínez
    • +
    • Pedro M. Baeza
    • +
    +
  • +
+
+
+

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 maintainer:

+

victoralmau

+

This module is part of the OCA/dms project on GitHub.

+

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

+
+
+
+
+ + diff --git a/dms_field_auto_classification/tests/__init__.py b/dms_field_auto_classification/tests/__init__.py new file mode 100644 index 000000000..0be859d20 --- /dev/null +++ b/dms_field_auto_classification/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) + +from . import test_dms_field_auto_classification diff --git a/dms_field_auto_classification/tests/data/test.zip b/dms_field_auto_classification/tests/data/test.zip new file mode 100644 index 000000000..155578038 Binary files /dev/null and b/dms_field_auto_classification/tests/data/test.zip differ diff --git a/dms_field_auto_classification/tests/test_dms_field_auto_classification.py b/dms_field_auto_classification/tests/test_dms_field_auto_classification.py new file mode 100644 index 000000000..720047d4f --- /dev/null +++ b/dms_field_auto_classification/tests/test_dms_field_auto_classification.py @@ -0,0 +1,193 @@ +# Copyright 2024 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from base64 import b64encode +from os import path + +from odoo.tests import Form, new_test_user +from odoo.tests.common import users + +from odoo.addons.base.tests.common import BaseCommon + + +class TestDmsFieldAutoClassification(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, test_dms_field=True)) + cls.template = cls.env.ref( + "dms_field_auto_classification.dms_classification_template_partners" + ) + cls.user = new_test_user( + cls.env, login="test_dms_manager_user", groups="dms.group_dms_manager" + ) + access_group = cls.env.ref("dms.access_group_01_demo") + access_group.explicit_user_ids = [(4, cls.user.id)] + cls.env.ref("dms_field.field_template_partner").unlink() + file_template = cls.env["dms.field.template"].create( + { + "name": "Test partner template", + "storage_id": cls.env.ref("dms.storage_demo").id, + "model_id": cls.env.ref("base.model_res_partner").id, + "group_ids": [(4, access_group.id)], + "directory_format_name": "{{object.vat}}", + } + ) + file_template_ctx = file_template.with_context( + res_model=file_template._name, res_id=file_template.id + ) + file_template_ctx.create_dms_directory() + file_template_ctx.invalidate_model() + cls.partner_a = cls.env["res.partner"].create( + { + "name": "Test partner A", + "vat": "82326033V", + } + ) + cls.partner_b = cls.env["res.partner"].create( + { + "name": "Test partner B", + "vat": "58426469Y", + } + ) + cls.wizard = cls._create_wizard_dms_classification(cls.template) + cls.extra_wizard = cls._create_wizard_dms_classification(cls.template) + + @classmethod + def _data_file(cls, filename, encoding=None): + mode = "rt" if encoding else "rb" + with open(path.join(path.dirname(__file__), filename), mode) as file: + data = file.read() + if encoding: + data = data.encode(encoding) + return b64encode(data) + + @classmethod + def _create_wizard_dms_classification(cls, template): + wizard_form = Form(cls.env["wizard.dms.classification"]) + wizard_form.template_id = template + wizard_form.data_file = cls._data_file("data/test.zip") + return wizard_form.save() + + def test_partner_misc(self): + self.assertEqual(self.partner_a.dms_directory_ids.name, "82326033V") + self.assertEqual(self.partner_b.dms_directory_ids.name, "58426469Y") + + @users("test_dms_manager_user") + def test_wizard_dms_clasification_process(self): + self.wizard = self.wizard.with_user(self.env.user) + self.assertEqual(self.wizard.state, "draft") + # Wizard - Analyze process + self.wizard.action_analyze() + self.assertEqual(self.wizard.state, "analyze") + self.assertEqual(len(self.wizard.detail_ids), 2) + file_names = self.wizard.mapped("detail_ids.file_name") + self.assertIn("82326033V.pdf", file_names) + self.assertIn("58426469Y.pdf", file_names) + detail_1 = self.wizard.detail_ids.filtered( + lambda x: x.file_name == "82326033V.pdf" + ) + self.assertEqual(detail_1.state, "to_classify") + self.assertEqual(detail_1.directory_id, self.partner_a.dms_directory_ids) + self.assertEqual(detail_1.record_ref, self.partner_a) + detail_2 = self.wizard.detail_ids.filtered( + lambda x: x.file_name == "58426469Y.pdf" + ) + self.assertEqual(detail_2.state, "to_classify") + self.assertEqual(detail_2.directory_id, self.partner_b.dms_directory_ids) + self.assertEqual(detail_2.record_ref, self.partner_b) + # Wizard - Classify process + res = self.wizard.action_classify() + dms_files = self.env[res["res_model"]].search(res["domain"]) + self.assertEqual(len(dms_files), 2) + self.assertEqual( + detail_1.file_id.directory_id, self.partner_a.dms_directory_ids + ) + self.assertEqual(detail_1.file_id.name, "82326033V.pdf") + self.assertTrue(detail_1.file_id.content) + self.assertEqual(detail_1.file_id.res_model, self.partner_a._name) + self.assertEqual(detail_1.file_id.res_id, self.partner_a.id) + self.assertEqual( + detail_2.file_id.directory_id, self.partner_b.dms_directory_ids + ) + self.assertEqual(detail_2.file_id.name, "58426469Y.pdf") + self.assertTrue(detail_2.file_id.content) + self.assertEqual(detail_2.file_id.res_model, self.partner_b._name) + self.assertEqual(detail_2.file_id.res_id, self.partner_b.id) + # Extra wizard + self.extra_wizard = self.extra_wizard.with_user(self.env.user) + self.assertEqual(self.extra_wizard.state, "draft") + # New Wizard - Analyze process + self.extra_wizard.action_analyze() + self.assertEqual(self.extra_wizard.state, "analyze") + self.assertEqual(len(self.extra_wizard.detail_ids), 2) + file_names = self.extra_wizard.mapped("detail_ids.file_name") + self.assertIn("82326033V.pdf", file_names) + self.assertIn("58426469Y.pdf", file_names) + detail_1 = self.extra_wizard.detail_ids.filtered( + lambda x: x.file_name == "82326033V.pdf" + ) + self.assertEqual(detail_1.directory_id, self.partner_a.dms_directory_ids) + self.assertTrue(detail_1.file_id) + self.assertEqual(detail_1.record_ref, self.partner_a) + self.assertEqual(detail_1.state, "classified") + detail_2 = self.extra_wizard.detail_ids.filtered( + lambda x: x.file_name == "58426469Y.pdf" + ) + self.assertEqual(detail_2.directory_id, self.partner_b.dms_directory_ids) + self.assertTrue(detail_2.file_id) + self.assertEqual(detail_2.record_ref, self.partner_b) + self.assertEqual(detail_1.state, "classified") + # New Wizard - Classify process + res = self.extra_wizard.action_classify() + new_dms_files = self.env[res["res_model"]].search(res["domain"]) - dms_files + self.assertEqual(len(new_dms_files), 0) + + @users("test_dms_manager_user") + def test_wizard_dms_clasification_process_filename_pattern(self): + self.template.filename_pattern = self.template.filename_pattern.replace( + ".pdf", ".txt" + ) + self.assertEqual(self.wizard.state, "draft") + self.wizard = self.wizard.with_user(self.env.user) + self.wizard.action_analyze() + self.assertEqual(self.wizard.state, "analyze") + self.assertEqual(len(self.wizard.detail_ids), 0) + + @users("test_dms_manager_user") + def test_wizard_dms_clasification_process_subdirectory(self): + self.template.directory_pattern = "{0} / Misc" + # Create subdirectory to partner a + directory_misc_a = self.env["dms.directory"].create( + {"name": "Misc", "parent_id": self.partner_a.dms_directory_ids.id} + ) + # Create subdirectory to partner b + directory_misc_b = self.env["dms.directory"].create( + {"name": "Misc", "parent_id": self.partner_b.dms_directory_ids.id} + ) + # Wizard - Analyze process + self.wizard = self.wizard.with_user(self.env.user) + self.wizard.action_analyze() + self.assertEqual(self.wizard.state, "analyze") + self.assertEqual(len(self.wizard.detail_ids), 2) + file_names = self.wizard.mapped("detail_ids.file_name") + self.assertIn("82326033V.pdf", file_names) + self.assertIn("58426469Y.pdf", file_names) + detail_1 = self.wizard.detail_ids.filtered( + lambda x: x.file_name == "82326033V.pdf" + ) + self.assertEqual(detail_1.state, "to_classify") + self.assertEqual(detail_1.directory_id, directory_misc_a) + self.assertEqual(detail_1.record_ref, self.partner_a) + detail_2 = self.wizard.detail_ids.filtered( + lambda x: x.file_name == "58426469Y.pdf" + ) + self.assertEqual(detail_2.state, "to_classify") + self.assertEqual(detail_2.directory_id, directory_misc_b) + self.assertEqual(detail_2.record_ref, self.partner_b) + # Wizard - Classify process + res = self.wizard.action_classify() + dms_files = self.env[res["res_model"]].search(res["domain"]) + self.assertEqual(len(dms_files), 2) + self.assertEqual(detail_1.file_id.directory_id, directory_misc_a) + self.assertEqual(detail_2.file_id.directory_id, directory_misc_b) diff --git a/dms_field_auto_classification/views/dms_classification_template_views.xml b/dms_field_auto_classification/views/dms_classification_template_views.xml new file mode 100644 index 000000000..a91a70347 --- /dev/null +++ b/dms_field_auto_classification/views/dms_classification_template_views.xml @@ -0,0 +1,37 @@ + + + + dms.classification.template tree + dms.classification.template + + + + + + + + + dms.classification.template form + dms.classification.template + + + + + + + + + + + + + + + + diff --git a/dms_field_auto_classification/wizards/__init__.py b/dms_field_auto_classification/wizards/__init__.py new file mode 100644 index 000000000..4ba9cc23a --- /dev/null +++ b/dms_field_auto_classification/wizards/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import wizard_dms_classification diff --git a/dms_field_auto_classification/wizards/wizard_dms_classification.py b/dms_field_auto_classification/wizards/wizard_dms_classification.py new file mode 100644 index 000000000..63567351c --- /dev/null +++ b/dms_field_auto_classification/wizards/wizard_dms_classification.py @@ -0,0 +1,83 @@ +# Copyright 2024-2026 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import re + +from odoo import api, fields, models + + +class WizardDmsClassificationDetail(models.TransientModel): + _inherit = "wizard.dms.classification.detail" + + template_id = fields.Many2one(related="parent_id.template_id") + record_ref = fields.Reference( + string="Record Referenced", + compute="_compute_record_ref", + selection=lambda self: self._get_ref_selection(), + ) + + @api.model + def _get_ref_selection(self): + models = self.env["ir.model"].sudo().search([("transient", "=", False)]) + return [(model.model, model.name) for model in models] + + @api.depends( + "directory_id", + "directory_id.root_directory_id", + "directory_id.res_model", + "directory_id.res_id", + ) + def _compute_record_ref(self): + """Set the linked record according to directory or root directory (to be + correct if we are in a subdirectory).""" + for record in self: + directory = False + if record.directory_id.res_model and record.directory_id.res_id: + directory = record.directory_id + elif ( + record.directory_id.parent_id.res_model + and record.directory_id.parent_id.res_id + ): + directory = record.directory_id.parent_id + elif ( + record.directory_id.root_directory_id.res_model + and record.directory_id.root_directory_id.res_id + ): + directory = record.directory_id.root_directory_id + record.record_ref = ( + f"{directory.res_model},{directory.res_id}" if directory else False + ) + + @api.depends("file_name", "template_id.model_id") + def _compute_directory_id(self): + """Overwrite to redefine the directory if the template has a linked model.""" + self_with_model = self.filtered(lambda x: x.template_id.model_id) + _self = self - self_with_model + res = super(WizardDmsClassificationDetail, _self)._compute_directory_id() + directory_model = self.env["dms.directory"] + for item in self_with_model: + domain = [ + ("company_id", "=", self.parent_id.company_id.id), + ("res_model", "=", item.template_id.model_id.model), + ("res_id", ">", 0), + ] + directories = directory_model.search(domain) + # We also add the subdirectorior because they are necessary and have not + # set res_model and res_id + directories += directories.mapped("child_directory_ids") + if directories: + matches = re.search(item.template_id.filename_pattern, item.file_name) + if matches: + directory_pattern = item.template_id.directory_pattern + for detail in item.template_id.detail_ids: + matches_value = matches.groups()[detail.index] + # Change directory pattern if index in pattern + expected = f"{{{detail.index}}}" + if expected in directory_pattern: + directory_pattern = directory_pattern.replace( + expected, matches_value + ) + # Search directories according to directory_pattern + item.directory_id = self.parent_id._get_directory_from_pattern( + directory_pattern, directories + ) + return res diff --git a/dms_field_auto_classification/wizards/wizard_dms_classification_views.xml b/dms_field_auto_classification/wizards/wizard_dms_classification_views.xml new file mode 100644 index 000000000..a7a91ad61 --- /dev/null +++ b/dms_field_auto_classification/wizards/wizard_dms_classification_views.xml @@ -0,0 +1,19 @@ + + + + wizard.dms.classification form + wizard.dms.classification + + + + + + + +