From 661556f582cc4139fc01c5a3997f4c1770f21e81 Mon Sep 17 00:00:00 2001 From: miquelrosell99 <38435442+miquelrosell99@users.noreply.github.com> Date: Fri, 31 Jul 2026 14:16:04 +0200 Subject: [PATCH] [FIX] document_page_reference: avoid duplicate reference on copy and enforce uniqueness --- document_page_reference/README.rst | 6 +--- document_page_reference/__manifest__.py | 2 +- .../migrations/18.0.2.1.4/pre-migrate.py | 29 +++++++++++++++++++ .../models/document_page.py | 11 ++++++- .../static/description/index.html | 26 +++++++---------- .../tests/test_document_reference.py | 7 +++++ 6 files changed, 58 insertions(+), 23 deletions(-) create mode 100644 document_page_reference/migrations/18.0.2.1.4/pre-migrate.py diff --git a/document_page_reference/README.rst b/document_page_reference/README.rst index 39071b1c8bb..287d467deb2 100644 --- a/document_page_reference/README.rst +++ b/document_page_reference/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 Page Reference ======================= @@ -17,7 +13,7 @@ Document Page Reference .. |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 +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fknowledge-lightgray.png?logo=github diff --git a/document_page_reference/__manifest__.py b/document_page_reference/__manifest__.py index 7c370726841..e4de14a6467 100644 --- a/document_page_reference/__manifest__.py +++ b/document_page_reference/__manifest__.py @@ -5,7 +5,7 @@ "name": "Document Page Reference", "summary": """ Include references on document pages""", - "version": "18.0.2.1.3", + "version": "18.0.2.1.4", "license": "AGPL-3", "author": "Creu Blanca,Odoo Community Association (OCA)", "website": "https://github.com/OCA/knowledge", diff --git a/document_page_reference/migrations/18.0.2.1.4/pre-migrate.py b/document_page_reference/migrations/18.0.2.1.4/pre-migrate.py new file mode 100644 index 00000000000..fcdfa9acfb8 --- /dev/null +++ b/document_page_reference/migrations/18.0.2.1.4/pre-migrate.py @@ -0,0 +1,29 @@ +# Copyright 2026 GMI Fabrica +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openupgradelib import openupgrade + + +@openupgrade.migrate() +def migrate(env, version): + """Clear duplicate references before adding the DB unique constraint. + + The oldest record of each duplicated reference keeps its value; the rest + are left without a reference. + """ + openupgrade.logged_query( + env.cr, + """ + WITH duplicates AS ( + SELECT id, + ROW_NUMBER() OVER ( + PARTITION BY reference ORDER BY id + ) AS rn + FROM document_page + WHERE reference IS NOT NULL + ) + UPDATE document_page dp + SET reference = NULL + WHERE id IN (SELECT id FROM duplicates WHERE rn > 1) + """, + ) diff --git a/document_page_reference/models/document_page.py b/document_page_reference/models/document_page.py index 081e2486677..74fe33723a9 100644 --- a/document_page_reference/models/document_page.py +++ b/document_page_reference/models/document_page.py @@ -16,12 +16,21 @@ class DocumentPage(models.Model): _description = "Document Page" reference = fields.Char( - help="Used to find the document, it can contain letters, numbers and _" + copy=False, + help="Used to find the document, it can contain letters, numbers and _", ) content_parsed = fields.Html( "Parsed Content", compute="_compute_content_parsed", sanitize=False, store=True ) + _sql_constraints = [ + ( + "document_page_reference_unique", + "UNIQUE(reference)", + "The reference must be unique.", + ) + ] + def get_formview_action(self, access_uid=None): res = super().get_formview_action(access_uid) view_id = self.env.ref("document_page.view_wiki_form").id diff --git a/document_page_reference/static/description/index.html b/document_page_reference/static/description/index.html index adf3bc02c3d..90b1bf4e9ca 100644 --- a/document_page_reference/static/description/index.html +++ b/document_page_reference/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Document Page Reference -
+
+

Document Page Reference

- - -Odoo Community Association - -
-

Document Page Reference

-

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

+

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

This module allows to add a reference name on documents and simplifies the link between document pages.

Table of contents

@@ -391,13 +386,13 @@

Document Page Reference

-

Usage

+

Usage

When editing a document page add elements like {{XXX}} where XXX is the reference of another page. Now, when viewing the document, it will link directly to the page. Also, the name will be parsed as the display name.

-

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 @@ -405,21 +400,21 @@

Bug Tracker

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

-
diff --git a/document_page_reference/tests/test_document_reference.py b/document_page_reference/tests/test_document_reference.py index 5f75e3b75e2..5db88a5f4b3 100644 --- a/document_page_reference/tests/test_document_reference.py +++ b/document_page_reference/tests/test_document_reference.py @@ -59,6 +59,13 @@ def test_auto_reference(self): ) self.assertFalse(new_page_duplicated_name.reference) + def test_duplicate_page_clears_reference(self): + """Duplicating a page must not reuse the original reference.""" + new_page = self.page1.copy() + self.assertNotEqual(new_page.reference, self.page1.reference) + self.assertTrue(new_page.reference) + self.assertIn("copy", new_page.reference) + def test_get_formview_action(self): res = self.page1.get_formview_action() view_id = self.env.ref("document_page.view_wiki_form").id