mirror of
https://github.com/OCA/knowledge.git
synced 2025-07-13 15:34:49 -06:00
261 lines
8.9 KiB
Python
261 lines
8.9 KiB
Python
from odoo import Command
|
|
from odoo.exceptions import UserError
|
|
from odoo.tests import new_test_user
|
|
|
|
from odoo.addons.base.tests.common import BaseCommon
|
|
|
|
|
|
class TestDocumentPageApproval(BaseCommon):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.page_obj = cls.env["document.page"]
|
|
cls.history_obj = cls.env["document.page.history"]
|
|
|
|
# Demo Data
|
|
cls.category1 = cls.env.ref("document_page.demo_category1")
|
|
cls.page1 = cls.env.ref("document_page.demo_page1")
|
|
|
|
# Create test user without groups first
|
|
cls.user2 = new_test_user(
|
|
cls.env,
|
|
login="test-user2",
|
|
groups="document_page_approval.group_document_approver_user",
|
|
)
|
|
|
|
# Ensure user2 has the approver group
|
|
cls.approver_gid = cls.env.ref(
|
|
"document_page_approval.group_document_approver_user"
|
|
)
|
|
cls.user2.write({"groups_id": [Command.link(cls.approver_gid.id)]})
|
|
|
|
# Create category and page that require approval
|
|
cls.category2 = cls.page_obj.create(
|
|
{
|
|
"name": "This category requires approval",
|
|
"type": "category",
|
|
"approval_required": True,
|
|
"approver_gid": cls.approver_gid.id,
|
|
}
|
|
)
|
|
cls.page2 = cls.page_obj.create(
|
|
{
|
|
"name": "This page requires approval",
|
|
"parent_id": cls.category2.id,
|
|
"content": "This content will require approval",
|
|
}
|
|
)
|
|
|
|
def test_approval_required(self):
|
|
"""Test that the page requires approval."""
|
|
page = self.page2
|
|
self.assertTrue(page.is_approval_required)
|
|
self.assertTrue(page.has_changes_pending_approval)
|
|
self.assertEqual(len(page.history_ids), 0)
|
|
|
|
def test_change_request_approve(self):
|
|
"""Test that an approver can approve a change request."""
|
|
page = self.page2
|
|
|
|
# Get the change request for this page
|
|
chreq = self.history_obj.search(
|
|
[("page_id", "=", page.id), ("state", "!=", "approved")], limit=1
|
|
)
|
|
|
|
self.assertEqual(chreq.state, "to approve")
|
|
|
|
# Ensure user2 is listed as an approver
|
|
self.assertTrue(chreq.with_user(self.user2).am_i_approver)
|
|
|
|
# Approve the request as user2 (approver)
|
|
chreq.with_user(self.user2).action_approve()
|
|
self.assertEqual(chreq.state, "approved")
|
|
self.assertEqual(chreq.content, page.content)
|
|
|
|
# Create new change request
|
|
page.write({"content": "New content"})
|
|
page.invalidate_model() # Recompute fields
|
|
chreq = self.history_obj.search(
|
|
[("page_id", "=", page.id), ("state", "!=", "approved")], limit=1
|
|
)
|
|
|
|
# Approve new changes
|
|
chreq.with_user(self.user2).action_approve()
|
|
self.assertEqual(page.content, "New content")
|
|
|
|
def test_change_request_auto_approve(self):
|
|
"""Test that a page without approval required auto-approves changes."""
|
|
page = self.page1
|
|
self.assertFalse(page.is_approval_required)
|
|
page.write({"content": "New content"})
|
|
self.assertEqual(page.content, "New content")
|
|
|
|
def test_change_request_from_scratch(self):
|
|
"""Test a full change request lifecycle from draft to approval."""
|
|
page = self.page2
|
|
|
|
# Approve all pending change requests
|
|
self.history_obj.search(
|
|
[("page_id", "=", page.id), ("state", "!=", "approved")]
|
|
).with_user(self.user2).action_approve()
|
|
|
|
# Create new change request
|
|
chreq = self.history_obj.create(
|
|
{
|
|
"page_id": page.id,
|
|
"summary": "Changed something",
|
|
"content": "New content",
|
|
}
|
|
)
|
|
|
|
self.assertEqual(chreq.state, "draft")
|
|
chreq.action_to_approve()
|
|
self.assertEqual(chreq.state, "to approve")
|
|
|
|
# Cancel and return to draft
|
|
chreq.with_user(self.user2).action_cancel()
|
|
self.assertEqual(chreq.state, "cancelled")
|
|
|
|
chreq.with_user(self.user2).action_draft()
|
|
self.assertEqual(chreq.state, "draft")
|
|
|
|
chreq.action_to_approve()
|
|
self.assertEqual(chreq.state, "to approve")
|
|
chreq.with_user(self.user2).action_approve()
|
|
self.assertEqual(chreq.state, "approved")
|
|
self.assertEqual(page.content, chreq.content)
|
|
self.assertEqual(page.approved_date, chreq.approved_date)
|
|
self.assertEqual(page.approved_uid, chreq.approved_uid)
|
|
|
|
def test_get_approvers_guids(self):
|
|
"""Test that approver groups are properly assigned."""
|
|
page = self.page2
|
|
self.assertTrue(len(page.approver_group_ids) > 0)
|
|
|
|
def test_get_page_url(self):
|
|
"""Test that the page URL exists."""
|
|
pages = self.env["document.page.history"].search([])
|
|
page = pages[0]
|
|
self.assertIsNotNone(page.page_url)
|
|
|
|
def test_compute_is_approval_required(self):
|
|
"""Ensure approval rules are inherited correctly"""
|
|
self.assertTrue(self.page2.is_approval_required)
|
|
self.page2.parent_id.approval_required = False
|
|
self.page2.invalidate_model()
|
|
self.assertFalse(self.page2.is_approval_required)
|
|
|
|
def test_compute_approver_group_ids(self):
|
|
"""Ensure approver groups are inherited correctly"""
|
|
self.assertIn(self.approver_gid, self.page2.approver_group_ids)
|
|
self.page2.parent_id.approver_gid = False
|
|
self.page2.invalidate_model()
|
|
self.assertFalse(self.page2.approver_group_ids)
|
|
|
|
def test_can_user_approve_this_page(self):
|
|
"""Check different approval conditions"""
|
|
self.assertTrue(
|
|
self.page2.with_user(self.user2).can_user_approve_this_page(self.user2)
|
|
)
|
|
|
|
# Remove approval group from user2
|
|
self.user2.write({"groups_id": [(3, self.approver_gid.id)]})
|
|
self.assertFalse(
|
|
self.page2.with_user(self.user2).can_user_approve_this_page(self.user2)
|
|
)
|
|
|
|
def test_pending_approval_detection(self):
|
|
"""Ensure the system detects pending approval changes"""
|
|
# Reset page2 by removing previous history
|
|
self.history_obj.search([("page_id", "=", self.page2.id)]).unlink()
|
|
|
|
self.page2.invalidate_model()
|
|
self.assertFalse(self.page2.has_changes_pending_approval)
|
|
|
|
# Create a new change request
|
|
self.history_obj.create(
|
|
{
|
|
"page_id": self.page2.id,
|
|
"state": "to approve",
|
|
}
|
|
)
|
|
|
|
self.page2.invalidate_model()
|
|
self.assertTrue(self.page2.has_changes_pending_approval)
|
|
|
|
def test_user_has_drafts(self):
|
|
"""Ensure the system detects drafts correctly"""
|
|
self.page2.invalidate_model()
|
|
self.assertFalse(self.page2.user_has_drafts)
|
|
|
|
self.history_obj.create(
|
|
{
|
|
"page_id": self.page2.id,
|
|
"state": "draft",
|
|
}
|
|
)
|
|
self.page2.invalidate_model()
|
|
self.assertTrue(self.page2.user_has_drafts)
|
|
|
|
def test_action_draft_requires_cancellation(self):
|
|
"""Ensure a change request must be cancelled before setting to draft"""
|
|
chreq = self.history_obj.create(
|
|
{
|
|
"page_id": self.page2.id,
|
|
"state": "to approve",
|
|
}
|
|
)
|
|
with self.assertRaises(UserError):
|
|
chreq.action_draft()
|
|
|
|
def test_action_to_approve_only_from_draft(self):
|
|
"""Ensure only draft requests can be sent for approval"""
|
|
chreq = self.history_obj.create(
|
|
{
|
|
"page_id": self.page2.id,
|
|
"state": "approved",
|
|
}
|
|
)
|
|
with self.assertRaises(UserError):
|
|
chreq.action_to_approve()
|
|
|
|
def test_approval_permission_check(self):
|
|
"""Ensure approval is restricted to approvers"""
|
|
chreq = self.history_obj.create(
|
|
{
|
|
"page_id": self.page2.id,
|
|
"state": "to approve",
|
|
}
|
|
)
|
|
|
|
with self.assertRaises(UserError):
|
|
chreq.with_user(self.env.ref("base.user_demo")).action_approve()
|
|
|
|
# Grant approval rights
|
|
chreq.with_user(self.user2).action_approve()
|
|
self.assertEqual(chreq.state, "approved")
|
|
|
|
def test_page_url_computation(self):
|
|
"""Ensure page URLs are generated correctly"""
|
|
chreq = self.history_obj.create({"page_id": self.page2.id})
|
|
self.assertIn("web#db=", chreq.page_url)
|
|
|
|
def test_diff_computation(self):
|
|
"""Ensure document diff is calculated properly"""
|
|
self.history_obj.create(
|
|
{
|
|
"page_id": self.page2.id,
|
|
"content": "Version 1",
|
|
"state": "approved",
|
|
}
|
|
)
|
|
|
|
chreq2 = self.history_obj.create(
|
|
{
|
|
"page_id": self.page2.id,
|
|
"content": "Version 2",
|
|
}
|
|
)
|
|
chreq2._compute_diff()
|
|
self.assertIsNotNone(chreq2.diff)
|