diff --git a/dms/README.rst b/dms/README.rst index 0903e9586..441b57c00 100644 --- a/dms/README.rst +++ b/dms/README.rst @@ -1,7 +1,3 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - ========================== Document Management System ========================== @@ -17,7 +13,7 @@ Document Management System .. |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-LGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html :alt: License: LGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fdms-lightgray.png?logo=github @@ -209,6 +205,7 @@ Contributors - Víctor Martínez - Pedro M. Baeza - Jairo Llopis + - Adasat Torres - `Elego `__: diff --git a/dms/__init__.py b/dms/__init__.py index ada0b87be..fa1be7ea5 100644 --- a/dms/__init__.py +++ b/dms/__init__.py @@ -1,3 +1,4 @@ from . import controllers from . import models from . import wizards +from .hooks import post_init_hook diff --git a/dms/__manifest__.py b/dms/__manifest__.py index baea903cc..72e1262ef 100644 --- a/dms/__manifest__.py +++ b/dms/__manifest__.py @@ -75,4 +75,5 @@ ], "icon": "/dms/static/description/icon.png", "application": True, + "post_init_hook": "post_init_hook", } diff --git a/dms/hooks.py b/dms/hooks.py new file mode 100644 index 000000000..e2d0acc6b --- /dev/null +++ b/dms/hooks.py @@ -0,0 +1,168 @@ +# Copyright 2026 Tecnativa - Adasat Torres +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from odoo import Command + + +def _create_default_storage(env, company): + return env["dms.storage"].create( + { + "name": f"EE storage - {company.name}", + "save_type": "file", + "company_id": company.id, + } + ) + + +def _search_or_create(env, model, domain, vals): + Model = env[model] + res = Model.search(domain) + if not res: + res = Model.create(vals) + return res + + +def _prepare_dms_tags_vals(ee_tag, category_id): + return {"name": ee_tag.name, "category_id": category_id} + + +def _prepare_category_vals(ee_category): + return {"name": ee_category.name} + + +def _prepare_directory_vals(ee_folder, **kwargs): + return {"name": ee_folder.name, **kwargs} + + +def _prepare_file_vals(ee_document, directory_id, tag_ids): + return { + "name": ee_document.name, + "extension": ee_document.file_extension, + "content": ee_document.datas, + "directory_id": directory_id.id, + "tag_ids": [Command.set(tag_ids.ids if tag_ids else [])], + } + + +def _search_create_category(env, ee_facet): + return _search_or_create( + env, + "dms.category", + [("name", "ilike", ee_facet.name)], + _prepare_category_vals(ee_facet), + ) + + +def _search_create_tag(env, ee_tags, category=False): + tags = env["dms.tag"] + for ee_tag in ee_tags: + tags += _search_or_create( + env, + "dms.tag", + [("name", "ilike", ee_tag.name)], + _prepare_dms_tags_vals(ee_tag, category.id if category else False), + ) + return tags + + +def _create_categories_and_tags(env, ee_facets): + for ee_facet in ee_facets: + categ = _search_create_category(env, ee_facet) + _search_create_tag(env, ee_facet.tag_ids, categ) + + +def _search_create_directory(env, folder, **kwargs): + return _search_or_create( + env, + "dms.directory", + [("name", "=", folder.name)], + _prepare_directory_vals(folder, **kwargs), + ) + + +def _search_create_admin_dms_access_group(env): + return _search_create_dms_access_group( + env, + **{ + "name": "Admin", + "group_ids": [Command.link(env.ref("base.group_system").id)], + "perm_create": True, + "perm_write": True, + "perm_unlink": True, + }, + ) + + +def _search_create_dms_access_group(env, **kwargs): + return _search_or_create( + env, "dms.access.group", [("name", "ilike", kwargs.get("name", False))], kwargs + ) + + +def _create_file(env, ee_document, directory): + tags = _search_create_tag(env, ee_document.tag_ids) + _search_or_create( + env, + "dms.file", + [("name", "=", ee_document.name), ("directory_id", "=", directory.id)], + _prepare_file_vals(ee_document, directory, tags), + ) + + +def _create_directory_and_files(env, ee_folder, storage): + admin_access_group = _search_create_admin_dms_access_group(env) + vals = { + "is_root_directory": True, + "storage_id": storage.id, + "group_ids": [Command.link(admin_access_group.id)], + } + if ee_folder.read_group_ids: + read_access_group = _search_create_dms_access_group( + env, + **{ + "name": f"{ee_folder.name} - Read", + "group_ids": [Command.set(ee_folder.read_group_ids.ids)], + "perm_create": False, + "perm_write": False, + "perm_unlink": False, + }, + ) + vals["group_ids"].append(Command.link(read_access_group.id)) + if ee_folder.group_ids: + write_access_group = _search_create_dms_access_group( + env, + **{ + "name": f"{ee_folder.name} - Write", + "group_ids": [Command.set(ee_folder.group_ids.ids)], + "perm_create": True, + "perm_write": True, + "perm_unlink": False, + }, + ) + vals["group_ids"].append(Command.link(write_access_group.id)) + if ee_folder.parent_folder_id: + vals["parent_id"] = _search_create_directory( + env, ee_folder.parent_folder_id, **vals + ).id + vals["is_root_directory"] = False + vals.pop("storage_id") + if ee_folder.facet_ids: + vals["category_id"] = _search_create_category(env, ee_folder.facet_ids[0]).id + directory = _search_create_directory(env, ee_folder, **vals) + for document in ee_folder.document_ids.filtered(lambda d: d.type == "binary"): + _create_file(env, document, directory) + + +def post_init_hook(env): + if not env["ir.module.module"].search( + [("name", "=", "documents"), ("state", "=", "installed")] + ): + return + DocumentsFolder = env["documents.folder"] + for company in env["res.company"].search([]): + if not DocumentsFolder.search([], limit=1): + continue + storage = _create_default_storage(env, company) + for folder in DocumentsFolder.search([]): + _create_categories_and_tags(env, folder.mapped("facet_ids")) + _create_directory_and_files(env, folder, storage) diff --git a/dms/readme/CONTRIBUTORS.md b/dms/readme/CONTRIBUTORS.md index 050b564a7..d535b4553 100644 --- a/dms/readme/CONTRIBUTORS.md +++ b/dms/readme/CONTRIBUTORS.md @@ -6,6 +6,7 @@ - Víctor Martínez - Pedro M. Baeza - Jairo Llopis + - Adasat Torres - [Elego](https://www.elegosoft.com): - Yu Weng \<\> - Philip Witte \<\> diff --git a/dms/static/description/index.html b/dms/static/description/index.html index b7e70c57d..fc7e183ef 100644 --- a/dms/static/description/index.html +++ b/dms/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Document Management System -
+
+

Document Management System

- - -Odoo Community Association - -
-

Document Management System

-

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

+

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

DMS is a module for creating, managing and viewing document files directly within Odoo. This module is only the basis for an entire ecosystem of apps that extend and seamlessly integrate with the document @@ -415,21 +410,21 @@

Document Management System

-

Installation

+

Installation

-

Preview

+

Preview

python-magic library is recommended to be installed for having whole support to get proper file types and file preview.

-

Configuration

+

Configuration

To configure this module, you need to:

-

1. Create a storage

+

1. Create a storage

  1. Go to Documents -> Configuration -> Storages.
  2. Create a new document storage. You can choose between three options @@ -442,7 +437,7 @@

    1. Create a storage

-

2. Create an access group

+

2. Create an access group

  1. Next, create an administrative access group. Go to Configuration -> Access Groups.
-

3. Create a directory

+

3. Create a directory

  1. Afterward, go to Documents -> Directories.
  2. Create a new directory, mark it as root and select the previously @@ -481,7 +476,7 @@

    3. Create a directory

-

Migration

+

Migration

If you need to modify the storage Save Type you might want to migrate the file data. To achieve it, you need to:

    @@ -497,19 +492,19 @@

    Migration

    Migration

-

File Wizard Selection

+

File Wizard Selection

There is an action called action_dms_file_wizard_selector to open a wizard to list files in kanban view. This can be used (example dms_attachment_link module) to add a button in kanban view with the action we need.

-

Usage

+

Usage

The best way to manage the documents is to switch to the Documents view. Existing documents can be managed there and new documents can be created.

-

Portal functionality

+

Portal functionality

You can add any portal user to DMS access groups, and then allow that group in directories, so they will see in the portal such directories and their files. Another possibility is to click on “Share” button @@ -518,7 +513,7 @@

Portal functionality

-

Known issues / Roadmap

+

Known issues / Roadmap

  • Files preview in portal
  • Allow to download folder in portal and create zip file with all @@ -545,7 +540,7 @@

    Known issues / Roadmap

-

Bug Tracker

+

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 @@ -553,16 +548,16 @@

Bug Tracker

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

-

Credits

+

Credits

-

Authors

+

Authors

  • MuK IT
  • Tecnativa
-

Contributors

+

Contributors

  • Elego:
  • -

    Other credits

    +

    Other credits

    Some pictures are based on or inspired by:

    -

    Maintainers

    +

    Maintainers

    This module is maintained by the OCA.

    Odoo Community Association @@ -611,6 +607,5 @@

    Maintainers

    -