From 7352bc51a90f28133774de2599305bb60f310511 Mon Sep 17 00:00:00 2001 From: miquelrosell99 <38435442+miquelrosell99@users.noreply.github.com> Date: Fri, 31 Jul 2026 11:25:27 +0200 Subject: [PATCH] [FIX] document_page: do not copy history on page duplicate When duplicating a document.page, the One2many history_ids field was being copied by default, so the new page inherited all past revisions including their current state. Add copy=False on document.page.history_ids so duplicates start with a clean history. Add copy=False on the approval-specific fields of document.page.history (state, approved_date, approved_uid) so a duplicated change request resets to draft and does not inherit approval metadata. In document_page_approval, override copy() so the duplicated page starts with a single draft change request containing the original content, rather than reusing copied histories or auto-advancing to 'to approve'. Add tests covering both behaviors. --- document_page/models/document_page.py | 1 + document_page/tests/test_document_page.py | 1 + .../models/document_page.py | 18 ++++++++++++ .../models/document_page_history.py | 5 ++-- .../tests/test_document_page_approval.py | 28 +++++++++++++++++++ 5 files changed, 51 insertions(+), 2 deletions(-) diff --git a/document_page/models/document_page.py b/document_page/models/document_page.py index a85c863dbe2..a37c0047ecc 100644 --- a/document_page/models/document_page.py +++ b/document_page/models/document_page.py @@ -63,6 +63,7 @@ class DocumentPage(models.Model): "page_id", "History", readonly=True, + copy=False, ) menu_id = fields.Many2one("ir.ui.menu", "Menu", readonly=True) content_date = fields.Datetime( diff --git a/document_page/tests/test_document_page.py b/document_page/tests/test_document_page.py index e9b2fd7d151..62587933f5b 100644 --- a/document_page/tests/test_document_page.py +++ b/document_page/tests/test_document_page.py @@ -61,3 +61,4 @@ def test_page_copy(self): self.assertEqual(page_copy.content, page.content) self.assertEqual(page_copy.draft_name, "1.0") self.assertEqual(page_copy.draft_summary, "summary") + self.assertFalse(page_copy.history_ids & page.history_ids) diff --git a/document_page_approval/models/document_page.py b/document_page_approval/models/document_page.py index d57cb9e3073..63c123881b5 100644 --- a/document_page_approval/models/document_page.py +++ b/document_page_approval/models/document_page.py @@ -135,6 +135,24 @@ def _create_history(self, vals): res.action_to_approve() return res + def copy(self, default=None): + self.ensure_one() + # Do not trigger _inverse_content during copy; otherwise _create_history + # would move the new record straight to "to approve". Create the initial + # change request as draft so the duplicated page starts in the approval + # workflow. + default = dict(default or {}, content=False) + new_page = super().copy(default=default) + self.env["document.page.history"].create( + { + "page_id": new_page.id, + "name": new_page.draft_name, + "summary": new_page.draft_summary, + "content": self.content, + } + ) + return new_page + def action_changes_pending_approval(self): self.ensure_one() action = self.env["ir.actions.act_window"]._for_xml_id( diff --git a/document_page_approval/models/document_page_history.py b/document_page_approval/models/document_page_history.py index 62499fe1152..107d3bd90d8 100644 --- a/document_page_approval/models/document_page_history.py +++ b/document_page_approval/models/document_page_history.py @@ -25,11 +25,12 @@ class DocumentPageHistory(models.Model): "Status", default="draft", readonly=True, + copy=False, ) - approved_date = fields.Datetime() + approved_date = fields.Datetime(copy=False) - approved_uid = fields.Many2one("res.users", "Approved by") + approved_uid = fields.Many2one("res.users", "Approved by", copy=False) is_approval_required = fields.Boolean( related="page_id.is_approval_required", string="Approval required" diff --git a/document_page_approval/tests/test_document_page_approval.py b/document_page_approval/tests/test_document_page_approval.py index 27cac61b06c..a36dbaba196 100644 --- a/document_page_approval/tests/test_document_page_approval.py +++ b/document_page_approval/tests/test_document_page_approval.py @@ -342,3 +342,31 @@ def test_cache_has_changes_pending_approval(self): # Approver user evaluates it. self.assertTrue(page.with_user(self.user2).has_changes_pending_approval) + + def test_history_copy(self): + """Duplicating a page must not copy history or approval metadata.""" + page = self.page2 + chreq = self.history_obj.with_user(self.user2).create( + { + "page_id": page.id, + "content": "
Version 1
", + "state": "approved", + "approved_date": "2026-07-31 10:00:00", + "approved_uid": self.user2.id, + } + ) + original_history = page.history_ids + page_copy = page.copy() + self.assertFalse(page_copy.history_ids & original_history) + # The duplicated page starts with a single draft change request that + # carries the original content but no approval metadata. + all_copy_hist = self.history_obj.search([("page_id", "=", page_copy.id)]) + self.assertEqual(len(all_copy_hist), 1) + self.assertEqual(all_copy_hist.state, "draft") + self.assertEqual(all_copy_hist.content, page.content) + self.assertFalse(all_copy_hist.approved_date) + self.assertFalse(all_copy_hist.approved_uid) + chreq_copy = chreq.copy() + self.assertEqual(chreq_copy.state, "draft") + self.assertFalse(chreq_copy.approved_date) + self.assertFalse(chreq_copy.approved_uid)