diff --git a/dms_version/README.rst b/dms_version/README.rst new file mode 100644 index 000000000..81abfb282 --- /dev/null +++ b/dms_version/README.rst @@ -0,0 +1,96 @@ +================================== +Document Management System Version +================================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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-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 + :target: https://github.com/OCA/dms/tree/13.0/dms_version + :alt: OCA/dms +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/dms-13-0/dms-13-0-dms_version + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/292/13.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Documents Versioning enables version control for the document management system. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Go to any file form and if the file has an older version its possible to revert it. + +Known issues / Roadmap +====================== + +Creating an addon to compress attachments could be useful. + +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 smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* MuK IT +* Tecnativa +* elego + +Contributors +~~~~~~~~~~~~ + +* Mathias Markl +* `Tecnativa `_: + + * Víctor Martínez + +* `AgentERP `_: + + * Maria Sparenberg + +* `Elego `_: + + * Yu Weng + +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. + +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_version/__init__.py b/dms_version/__init__.py new file mode 100644 index 000000000..c7b0b610d --- /dev/null +++ b/dms_version/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2017-2020 MuK IT GmbH +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models +from . import wizard diff --git a/dms_version/__manifest__.py b/dms_version/__manifest__.py new file mode 100644 index 000000000..53709d1b5 --- /dev/null +++ b/dms_version/__manifest__.py @@ -0,0 +1,27 @@ +# Copyright 2017-2020 MuK IT GmbH +# Copyright 2021 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Document Management System Version", + "summary": """Version Control for Documents""", + "version": "14.0.1.0.0", + "category": "Document Management", + "license": "AGPL-3", + "website": "https://github.com/OCA/dms", + "author": """MuK IT, + Tecnativa, + elego Software Solutions Gmbh, + Odoo Community Association (OCA)""", + "depends": ["dms", "base_revision"], + "data": [ + "security/ir.model.access.csv", + "security/security.xml", + "wizard/restore_old_revision_view.xml", + "views/dms_file_view.xml", + "views/dms_directory_view.xml", + "views/dms_storage_view.xml", + ], + "maintainers": ["victoralmau"], + "application": False, +} diff --git a/dms_version/models/__init__.py b/dms_version/models/__init__.py new file mode 100644 index 000000000..7c3320a18 --- /dev/null +++ b/dms_version/models/__init__.py @@ -0,0 +1,6 @@ +# Copyright 2017-2020 MuK IT GmbH +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import dms_file +from . import dms_directory +from . import dms_storage diff --git a/dms_version/models/dms_directory.py b/dms_version/models/dms_directory.py new file mode 100644 index 000000000..d8bbfccc7 --- /dev/null +++ b/dms_version/models/dms_directory.py @@ -0,0 +1,26 @@ +# Copyright 2017-2020 MuK IT GmbH +# Copyright 2021 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class DmsDirectory(models.Model): + _inherit = "dms.directory" + + has_versioning = fields.Boolean( + default=False, + help="Indicates if files have an active version control.", + ) + + @api.onchange("storage_id") + def _onchange_storage_id(self): + for record in self: + if record.storage_id.save_type != "attachment" and record.is_root_directory: + record.has_versioning = record.storage_id.has_versioning + + @api.onchange("parent_id") + def _onchange_parent_id(self): + for record in self: + if record.parent_id: + record.has_versioning = record.parent_id.has_versioning diff --git a/dms_version/models/dms_file.py b/dms_version/models/dms_file.py new file mode 100644 index 000000000..13e62ae75 --- /dev/null +++ b/dms_version/models/dms_file.py @@ -0,0 +1,283 @@ +# Copyright 2017-2020 MuK IT GmbH +# Copyright 2021 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, exceptions, fields, models + + +class DmsFile(models.Model): + _name = "dms.file" + _inherit = ["dms.file", "base.revision"] + + name = fields.Char( + tracking=True, + ) + directory_id = fields.Many2one( + tracking=True, + ) + storage_id = fields.Many2one( + tracking=True, + ) + extension = fields.Char( + tracking=True, + ) + mimetype = fields.Char( + tracking=True, + ) + category_id = fields.Many2one( + tracking=True, + ) + current_revision_id = fields.Many2one( + comodel_name="dms.file", + readonly=True, + ) + old_revision_ids = fields.One2many( + comodel_name="dms.file", + ) + has_versioning = fields.Boolean( + string="Has Versioning", + tracking=True, + ) + can_edit_has_versioning = fields.Boolean( + compute="_compute_can_edit_has_versioning", + default=True, + ) + origin_id = fields.Many2one( + comodel_name="dms.file", + ) + all_revision_ids = fields.One2many( + comodel_name="dms.file", + inverse_name="origin_id", + readonly=True, + domain=["|", ("active", "=", False), ("active", "=", True)], + context={"active_test": False}, + ) + all_revision_count = fields.Integer( + compute="_compute_all_revision_count", + ) + parent_id = fields.Many2one( + comodel_name="dms.file", + ) + has_current_revision = fields.Boolean( + compute="_compute_has_current_revision", store=True + ) + + # (overwrite) sql_constraints revision_unique from module base_revision + _sql_constraints = [ + ( + "revision_unique", + "Check(1=1)", + "Reference and revision must be unique.", + ) + ] + + @api.constrains("unrevisioned_name", "revision_number", "directory_id") + def check_unique_name_revision_number(self): + for rec in self: + if rec.origin_id: + res = self.search_count( + [ + ("unrevisioned_name", "=", rec.unrevisioned_name), + ("revision_number", "=", rec.revision_number), + ("directory_id", "=", rec.directory_id.id), + "|", + ("active", "=", False), + ("active", "=", True), + ] + ) + if res > 1: + raise exceptions.UserError( + _("Reference and revision must be unique in a directory.") + ) + + @api.constrains("active", "origin_id") + def check_unique_active_file(self): + for rec in self: + if rec.origin_id: + res = self.search_count( + [ + ("origin_id", "=", rec.origin_id.id), + ] + ) + if res > 1: + raise exceptions.UserError( + _( + 'Found more active version of file "%s".' + % rec.origin_id.name + ) + ) + + @api.constrains("revision_number", "origin_id") + def check_unique_origin_revision_number(self): + for rec in self: + if rec.origin_id: + res = self.search_count( + [ + ("origin_id", "=", rec.origin_id.id), + ("revision_number", "=", rec.revision_number), + "|", + ("active", "=", False), + ("active", "=", True), + ] + ) + if res > 1: + raise exceptions.UserError( + _('Revision number "%s" must be unique.' % rec.revision_number) + ) + + def _compute_can_edit_has_versioning(self): + can_edit = self.user_has_groups("dms_version.group_dms_version_user") + for rec in self: + rec.can_edit_has_versioning = can_edit + + @api.depends("current_revision_id", "current_revision_id.active") + def _compute_has_current_revision(self): + for rec in self: + rec.has_current_revision = False + if rec.current_revision_id and rec.current_revision_id.active: + rec.has_current_revision = True + elif not rec.current_revision_id and rec.has_versioning and rec.active: + rec.has_current_revision = True + + @api.depends("all_revision_ids") + def _compute_all_revision_count(self): + for rec in self: + rec.all_revision_count = len(rec.origin_id.all_revision_ids) - 1 + + @api.onchange("directory_id") + def _onchange_directory_id(self): + for rec in self: + if rec.directory_id: + rec.has_versioning = rec.directory_id.has_versioning + + def action_view_revision(self): + self.ensure_one() + action = self.env.ref("dms_version.action_dms_revisions_file") + res = action.read()[0] + res["domain"] = [ + "&", + ("id", "in", self.origin_id.all_revision_ids.ids), + "|", + ("active", "=", False), + ("active", "=", True), + ] + return res + + @api.model + def create(self, values): + res = super().create(values) + if "origin_id" not in values: + res.origin_id = res + return res + + def write(self, vals): + if ( + not self.env.context.get("restore_old_revision", False) + and "active" in vals + and vals["active"] + ): + raise exceptions.UserError( + _("Please use the restore button to activate this revision.") + ) + if vals.get("content"): + versions = self.filtered(lambda x: x.has_versioning) + super(DmsFile, versions).write({"active": False}) + action = versions.with_context(new_vals=vals).create_revision() + res = self.search(action["domain"]) + if versions.ids == self.ids: + return res + else: + return super( + DmsFile, self.filtered(lambda x: not x.has_versioning) + ).write(vals) + res = super().write(vals) + return res + + def _get_new_rev_data(self, new_rev_number): + self.ensure_one() + res = super()._get_new_rev_data(new_rev_number) + new_vals = self.env.context.get("new_vals", False) + if new_vals: + res.update(new_vals) + res["origin_id"] = self.origin_id.id + res["parent_id"] = self.id + res["active"] = True + max_new_rev_number = ( + max(self.origin_id.all_revision_ids.mapped("revision_number")) + 1 + ) + res["revision_number"] = max_new_rev_number + return res + + def action_restore_old_revision(self): + self.ensure_one() + rec_link = self.get_html_link() + msg1 = _("This version is restored.") + if self.current_revision_id.active: + current_version_link = self.current_revision_id.get_html_link() + msg1 += _("\nThe version %s is now archived.") % (current_version_link,) + msg2 = _("The version %s is restored. This version is now archived.") % ( + rec_link, + ) + self.current_revision_id.message_post(body=msg2) + self.message_post(body=msg1) + if self.origin_id.id not in (self.current_revision_id.id, self.id): + msg3 = _("The version %s is restored.") % (rec_link) + if self.current_revision_id.active: + msg3 += _(" The version %s is now archived.") % (current_version_link) + self.origin_id.message_post(body=msg3) + self.current_revision_id.active = False + self.active = True + self.origin_id.all_revision_ids.write({"current_revision_id": self.id}) + self.current_revision_id.write({"current_revision_id": False}) + + def copy_revision_with_context(self): + new_revision = super().copy_revision_with_context() + new_rev_number = new_revision.revision_number + new_revision.write( + { + "name": "%s-%02d" % (self.unrevisioned_name, new_rev_number), + } + ) + return new_revision + + def get_html_link(self): + self.ensure_one() + res = '%s' % ( + self.id, + self.name, + ) + return res + + # (override) function create_revistion() from base_revision + def create_revision(self): + revision_ids = [] + # Looping over records + for rec in self: + # Calling Copy method + copied_rec = rec.copy_revision_with_context() + if hasattr(self, "message_post"): + # (change) add a link for opening the copied record + msg = _("This revision is created from file %s.") % ( + rec.get_html_link() + ) + copied_rec.message_post(body=msg) + msg = _("A new revision %s is created from this file.") % ( + copied_rec.get_html_link() + ) + rec.message_post(body=msg) + if rec.id != rec.origin_id.id: + msg = _("A new revision %s is created from file %s.") % ( + copied_rec.get_html_link(), + rec.get_html_link(), + ) + rec.origin_id.message_post(body=msg) + revision_ids.append(copied_rec.id) + action = { + "type": "ir.actions.act_window", + "view_mode": "tree,form", + "name": _("New Revisions"), + "res_model": self._name, + "domain": [("id", "in", revision_ids)], + "target": "current", + } + return action diff --git a/dms_version/models/dms_storage.py b/dms_version/models/dms_storage.py new file mode 100644 index 000000000..370bbef58 --- /dev/null +++ b/dms_version/models/dms_storage.py @@ -0,0 +1,14 @@ +# Copyright 2017-2020 MuK IT GmbH +# Copyright 2021 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class DmsStorage(models.Model): + _inherit = "dms.storage" + + has_versioning = fields.Boolean( + default=False, + help="Indicates if files have an active version control.", + ) diff --git a/dms_version/readme/CONTRIBUTORS.rst b/dms_version/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..9657f7dc5 --- /dev/null +++ b/dms_version/readme/CONTRIBUTORS.rst @@ -0,0 +1,4 @@ +* Mathias Markl +* `Tecnativa `_:", + + * Víctor Martínez diff --git a/dms_version/readme/DESCRIPTION.rst b/dms_version/readme/DESCRIPTION.rst new file mode 100644 index 000000000..59613e934 --- /dev/null +++ b/dms_version/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +Documents Versioning enables version control for the document management system. diff --git a/dms_version/readme/ROADMAP.rst b/dms_version/readme/ROADMAP.rst new file mode 100644 index 000000000..1403b6a76 --- /dev/null +++ b/dms_version/readme/ROADMAP.rst @@ -0,0 +1 @@ +Creating an addon to compress attachments could be useful. diff --git a/dms_version/readme/USAGE.rst b/dms_version/readme/USAGE.rst new file mode 100644 index 000000000..fd6fa198e --- /dev/null +++ b/dms_version/readme/USAGE.rst @@ -0,0 +1 @@ +Go to any file form and if the file has an older version its possible to revert it. diff --git a/dms_version/security/ir.model.access.csv b/dms_version/security/ir.model.access.csv new file mode 100644 index 000000000..0cc9fbbe4 --- /dev/null +++ b/dms_version/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_restore_old_revision,access_restore_old_revision,model_restore_old_revision,base.group_user,1,1,1,1 diff --git a/dms_version/security/security.xml b/dms_version/security/security.xml new file mode 100644 index 000000000..e1738bb98 --- /dev/null +++ b/dms_version/security/security.xml @@ -0,0 +1,6 @@ + + + + Allow Change Versioning + + diff --git a/dms_version/static/description/icon.png b/dms_version/static/description/icon.png new file mode 100644 index 000000000..ce8ae7f2d Binary files /dev/null and b/dms_version/static/description/icon.png differ diff --git a/dms_version/static/description/icon.svg b/dms_version/static/description/icon.svg new file mode 100644 index 000000000..fd5ad63c0 --- /dev/null +++ b/dms_version/static/description/icon.svg @@ -0,0 +1 @@ + diff --git a/dms_version/static/description/index.html b/dms_version/static/description/index.html new file mode 100644 index 000000000..8aa44b23a --- /dev/null +++ b/dms_version/static/description/index.html @@ -0,0 +1,434 @@ + + + + + + +Document Management System Version + + + +
+

Document Management System Version

+ + +

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

+

Documents Versioning enables version control for the document management system.

+

Table of contents

+ +
+

Usage

+

Go to any file form and if the file has an older version its possible to revert it.

+
+
+

Known issues / Roadmap

+

Creating an addon to compress attachments could be useful.

+
+
+

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 smashing it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • MuK IT
  • +
  • Tecnativa
  • +
+
+
+

Contributors

+ +
+
+

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.

+

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_version/tests/__init__.py b/dms_version/tests/__init__.py new file mode 100644 index 000000000..a2fa51905 --- /dev/null +++ b/dms_version/tests/__init__.py @@ -0,0 +1 @@ +from . import test_dms_file diff --git a/dms_version/tests/test_dms_file.py b/dms_version/tests/test_dms_file.py new file mode 100644 index 000000000..a21566ad7 --- /dev/null +++ b/dms_version/tests/test_dms_file.py @@ -0,0 +1,180 @@ +# Copyright 2017-2020 MuK IT GmbH +# Copyright 2021-2022 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import base64 +import logging + +from odoo.exceptions import UserError +from odoo.tests import Form + +from odoo.addons.dms.tests.common import StorageDatabaseBaseCase + +_logger = logging.getLogger(__name__) + + +class TestFileVersion(StorageDatabaseBaseCase): + def setUp(self): + super().setUp() + self.storage.has_versioning = True + self.my_directory = self.create_directory(storage=self.storage) + + def test_01_onchange_events_of_directory(self): + self.assertTrue(self.my_directory.has_versioning) + self.my_sub1_directory = self.create_directory( + storage=self.storage, directory=self.my_directory + ) + self.assertTrue(self.my_sub1_directory.has_versioning) + self.my_directory.has_versioning = False + self.my_sub2_directory = self.create_directory( + storage=self.storage, directory=self.my_directory + ) + self.assertFalse(self.my_sub2_directory.has_versioning) + + def test_02_file_version(self): + self.assertTrue(self.my_directory.has_versioning) + _logger.info("Step 1: Create file_01 and file_02") + file_01 = self.create_file(directory=self.my_directory) + self.assertFalse(file_01.current_revision_id) + self.assertTrue(file_01.active) + self.assertTrue(file_01.has_versioning) + file_01.write({"content": base64.b64encode(b"\xff new_1")}) + self.assertFalse(file_01.active) + self.assertTrue(file_01.current_revision_id.active) + self.assertEqual(file_01.current_revision_id.revision_number, 1) + self.assertEqual(file_01.origin_id, file_01) + file_02 = file_01.current_revision_id + self.assertEqual(file_02.origin_id, file_01) + self.assertEqual(file_02.parent_id, file_01) + + _logger.info("Step 2: Create file_03 and file_04") + file_02.write({"content": base64.b64encode(b"\xff new_2")}) + file_03 = file_01.current_revision_id + file_03.write({"content": base64.b64encode(b"\xff new_3")}) + file_04 = file_01.current_revision_id + self.assertEqual(file_01.all_revision_count, 3) + self.assertIn(file_02, file_01.all_revision_ids) + self.assertIn(file_03, file_01.all_revision_ids) + self.assertIn(file_04, file_01.all_revision_ids) + + logs = """ + # Check values in following table + # id origin_id parent_id current_revision_id version_number active + # file_01 1 1 False 4 0 False + # file_02 2 1 1 4 1 False + # file_03 3 1 2 4 2 False + # file_04 4 1 3 False 3 True + """ + _logger.info(logs) + self.assertEqual(file_01.origin_id, file_01) + self.assertFalse(file_01.parent_id) + self.assertEqual(file_01.current_revision_id, file_04) + self.assertFalse(file_01.active) + self.assertEqual(file_01.revision_number, 0) + self.assertEqual(file_02.origin_id, file_01) + self.assertEqual(file_02.parent_id, file_01) + self.assertEqual(file_02.current_revision_id, file_04) + self.assertFalse(file_02.active) + self.assertEqual(file_02.revision_number, 1) + self.assertEqual(file_03.origin_id, file_01) + self.assertEqual(file_03.parent_id, file_02) + self.assertEqual(file_03.current_revision_id, file_04) + self.assertFalse(file_03.active) + self.assertEqual(file_03.revision_number, 2) + self.assertEqual(file_04.origin_id, file_01) + self.assertEqual(file_04.parent_id, file_03) + self.assertFalse(file_04.current_revision_id) + self.assertTrue(file_04.active) + self.assertEqual(file_04.revision_number, 3) + + _logger.info("Step 3: Restore file_02") + wizard = Form( + self.env["restore.old.revision"].with_context(active_id=file_02.id) + ).save() + wizard.action_done() + logs = """ + # Check values in following table + # id current_revision_id active + # file_01 1 2 False + # file_02 2 False True + # file_03 3 2 False + # file_04 4 2 False + """ + _logger.info(logs) + self.assertEqual(file_01.current_revision_id, file_02) + self.assertFalse(file_02.current_revision_id) + self.assertEqual(file_03.current_revision_id, file_02) + self.assertEqual(file_04.current_revision_id, file_02) + self.assertFalse(file_01.active) + self.assertTrue(file_02.active) + self.assertFalse(file_03.active) + self.assertFalse(file_04.active) + _logger.info("Step 4: Create file_05") + file_02.write({"content": base64.b64encode(b"\xff new_4")}) + file_05 = file_01.current_revision_id + logs = """ + # Check values in following table + # id origin_id parent_id current_revision_id version_number active + # file_01 1 1 False 5 0 False + # file_02 2 1 1 5 1 False + # file_03 3 1 2 5 2 False + # file_04 4 1 3 5 3 False + # file_05 5 1 2 False 4 True + """ + _logger.info(logs) + self.assertEqual(file_01.origin_id, file_01) + self.assertFalse(file_01.parent_id) + self.assertEqual(file_01.current_revision_id, file_05) + self.assertFalse(file_01.active) + self.assertEqual(file_01.revision_number, 0) + self.assertEqual(file_02.origin_id, file_01) + self.assertEqual(file_02.parent_id, file_01) + self.assertEqual(file_02.current_revision_id, file_05) + self.assertFalse(file_02.active) + self.assertEqual(file_02.revision_number, 1) + self.assertEqual(file_03.origin_id, file_01) + self.assertEqual(file_03.parent_id, file_02) + self.assertEqual(file_03.current_revision_id, file_05) + self.assertFalse(file_03.active) + self.assertEqual(file_03.revision_number, 2) + self.assertEqual(file_04.origin_id, file_01) + self.assertEqual(file_04.parent_id, file_03) + self.assertEqual(file_04.current_revision_id, file_05) + self.assertFalse(file_04.active) + self.assertEqual(file_04.revision_number, 3) + self.assertEqual(file_05.origin_id, file_01) + self.assertEqual(file_05.parent_id, file_02) + self.assertFalse(file_05.current_revision_id) + self.assertTrue(file_05.active) + self.assertEqual(file_05.revision_number, 4) + + _logger.info("check_unique_name_revision_number") + error_message = "Reference and revision must be unique in a directory." + with self.assertRaises(UserError, msg=error_message): + file_04.write({"revision_number": 1}) + + _logger.info("check_unique_origin_revision_number") + error_message = 'Revision number "1" must be unique.' + with self.assertRaises(UserError, msg=error_message): + file_04.write({"revision_number": 1}) + + _logger.info("check_set_file_active_with_function_write") + error_message = "Please use the restore button to activate this revision." + with self.assertRaises(UserError, msg=error_message): + file_04.write({"active": True}) + + _logger.info("check_unique_active_file") + error_message = 'Found more active version of file "%s".' % (file_01.name) + with self.assertRaises(UserError, msg=error_message): + file_04.with_context(restore_old_revision=True).write({"active": True}) + + _logger.info("check_action_view_revision") + expected_domain = [ + "&", + ("id", "in", file_01.all_revision_ids.ids), + "|", + ("active", "=", False), + ("active", "=", True), + ] + action = file_05.action_view_revision() + self.assertEqual(action["domain"], expected_domain) diff --git a/dms_version/views/dms_directory_view.xml b/dms_version/views/dms_directory_view.xml new file mode 100644 index 000000000..4ef36461a --- /dev/null +++ b/dms_version/views/dms_directory_view.xml @@ -0,0 +1,27 @@ + + + + + dms_directory.form + dms.directory + + + + + + + + + dms_directory.form + dms.directory + + + + + + + + diff --git a/dms_version/views/dms_file_view.xml b/dms_version/views/dms_file_view.xml new file mode 100644 index 000000000..c8b1ea08b --- /dev/null +++ b/dms_version/views/dms_file_view.xml @@ -0,0 +1,164 @@ + + + + + Revisions + dms.file + tree,form + + + dms_file.search + dms.file + + + + + + + + + + + + + + dms_file.tree + dms.file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {'readonly': [('active', '=', False)]} + + + + + diff --git a/dms_version/views/dms_storage_view.xml b/dms_version/views/dms_storage_view.xml new file mode 100644 index 000000000..a19ac9679 --- /dev/null +++ b/dms_version/views/dms_storage_view.xml @@ -0,0 +1,27 @@ + + + + + dms_storage.form + dms.storage + + + + + + + + + dms_storage.form + dms.storage + + + + + + + + diff --git a/dms_version/wizard/__init__.py b/dms_version/wizard/__init__.py new file mode 100644 index 000000000..6995a99c3 --- /dev/null +++ b/dms_version/wizard/__init__.py @@ -0,0 +1 @@ +from . import restore_old_revision diff --git a/dms_version/wizard/restore_old_revision.py b/dms_version/wizard/restore_old_revision.py new file mode 100644 index 000000000..57d477cfd --- /dev/null +++ b/dms_version/wizard/restore_old_revision.py @@ -0,0 +1,33 @@ +from odoo import api, fields, models + + +class RestoreOldRevision(models.TransientModel): + _name = "restore.old.revision" + _description = "Restore Old Revision" + + file_id = fields.Many2one( + comodel_name="dms.file", + required=True, + string="Old Version", + ) + current_revision_id = fields.Many2one( + comodel_name="dms.file", + string="Current Version", + related="file_id.current_revision_id", + ) + has_current_revision = fields.Boolean( + related="file_id.has_current_revision", + ) + + @api.model + def default_get(self, fields): + res = super().default_get(fields) + active_id = self.env.context.get("active_id") + res["file_id"] = (active_id,) + return res + + def action_done(self): + self.file_id.with_context( + restore_old_revision=True + ).action_restore_old_revision() + return {"type": "ir.actions.act_window_close"} diff --git a/dms_version/wizard/restore_old_revision_view.xml b/dms_version/wizard/restore_old_revision_view.xml new file mode 100644 index 000000000..751e72191 --- /dev/null +++ b/dms_version/wizard/restore_old_revision_view.xml @@ -0,0 +1,57 @@ + + + + + restore.old.revision.form + restore.old.revision + +
+
+ Do you really want to restore this archived file? + Be aware that the current version will be archived if you continue.! +
+
+ Do you really want to restore this archived file? +
+ + + + + +
+
+
+
+
+ + + Restore Old Revision + ir.actions.act_window + restore.old.revision + form + new + + +
+