From ec5ec36161f29ac69cbe75cee54155b7520c113d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20Todorovich?=
Date: Thu, 22 Feb 2018 14:17:30 -0300
Subject: [PATCH 1/5] [IMP] Refactor document_page_approval to always use
states, and a few code improvements
---
document_page/__openerp__.py | 3 +-
document_page/data/document_page.xml | 41 ----
document_page/demo/document_page.xml | 2 +-
.../migrations/9.0.2.0.0/post-migration.py | 12 +
document_page/models/document_page.py | 114 +++++----
document_page/models/document_page_history.py | 51 ++--
.../security/document_page_security.xml | 16 ++
document_page/security/ir.model.access.csv | 9 +-
.../static/src/css/document_page.css | 35 ++-
document_page/tests/__init__.py | 2 +-
document_page/tests/test_document_page.py | 55 +++--
.../tests/test_document_page_history.py | 21 --
.../tests/test_document_page_show_diff.py | 4 +-
document_page/views/document_page.xml | 132 +++++-----
document_page/views/document_page_assets.xml | 10 +
.../wizard/document_page_show_diff.py | 23 +-
.../wizard/document_page_show_diff.xml | 8 +-
document_page_approval/__init__.py | 1 +
document_page_approval/__openerp__.py | 5 +-
.../data/email_template.xml | 32 ++-
document_page_approval/hooks.py | 22 ++
.../migrations/9.0.2.0.0/post-migration.py | 14 ++
.../models/document_page_approval.py | 168 +++++++------
.../models/document_page_history_workflow.py | 228 +++++++++---------
.../security/document_page_security.xml | 11 +-
.../security/ir.model.access.csv | 1 -
document_page_approval/tests/__init__.py | 2 +-
.../tests/test_document_page_approval.py | 136 +++++++++--
.../test_document_page_history_workflow.py | 67 -----
.../views/document_page_approval.xml | 161 +++++++++----
.../workflows/document_page_approval.xml | 89 ++++++-
31 files changed, 865 insertions(+), 610 deletions(-)
delete mode 100644 document_page/data/document_page.xml
create mode 100644 document_page/migrations/9.0.2.0.0/post-migration.py
delete mode 100644 document_page/tests/test_document_page_history.py
create mode 100644 document_page/views/document_page_assets.xml
create mode 100644 document_page_approval/hooks.py
create mode 100644 document_page_approval/migrations/9.0.2.0.0/post-migration.py
delete mode 100644 document_page_approval/tests/test_document_page_history_workflow.py
diff --git a/document_page/__openerp__.py b/document_page/__openerp__.py
index 8c129f3e68a..e445d881785 100644
--- a/document_page/__openerp__.py
+++ b/document_page/__openerp__.py
@@ -21,7 +21,7 @@
{
'name': 'Document Page',
- 'version': '9.0.1.0.1',
+ 'version': '9.0.2.0.0',
'category': 'Knowledge Management',
'author': 'OpenERP SA, Odoo Community Association (OCA)',
'images': ['images/category_list.png', 'images/create_category.png',
@@ -37,6 +37,7 @@
'wizard/document_page_create_menu.xml',
'wizard/document_page_show_diff.xml',
'views/document_page.xml',
+ 'views/document_page_assets.xml',
'security/document_page_security.xml',
'security/ir.model.access.csv',
],
diff --git a/document_page/data/document_page.xml b/document_page/data/document_page.xml
deleted file mode 100644
index 9cd3c0dd5d0..00000000000
--- a/document_page/data/document_page.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
- The Odoo wiki
- help, quick start, wiki, formatting
- 0
- 1
- Initial Page
- == The Odoo wiki ==
-
-[[File:https://www.odoo.com/openerp_website/static/src/img/logo_transparent_198px.png Odoo]]
-
-The Odoo wiki allows you to manage your enterprise's contents using wiki
-restructured texts. This module provides a collaborative way to manage internal
-FAQs, quality manuals, technical references, etc.
-
-==Keypoints==
-* Same formating style than MediaWiki,
-* Any number of wiki group for different purposes,
-* Detailed history on all pages,
-* Integrated with the document management system.
-
-==Why you should use the OpenERP integrated wiki than a separate wiki system ?==
-* Allows links to any document of the system,
-* Uses the access controls of OpenERP for uniq access rights management,
-* Use it to describe projects, tasks, products,
-* Integrated with customer portal to provide restricted external accesses,
-* Linked to users processes for quality manuals.
-
-==To get more information==
-* [[Basic Wiki Editing]]
-* [[Wiki Documentation]]
-* [http://openerp.com The OpenERP website]
-
-
-
-
-
-
-
diff --git a/document_page/demo/document_page.xml b/document_page/demo/document_page.xml
index 8e6d2eca882..c9e0a042131 100644
--- a/document_page/demo/document_page.xml
+++ b/document_page/demo/document_page.xml
@@ -8,7 +8,7 @@
OpenERP Features
category
-
+
Summary of the feature
Long explanation
diff --git a/document_page/migrations/9.0.2.0.0/post-migration.py b/document_page/migrations/9.0.2.0.0/post-migration.py
new file mode 100644
index 00000000000..f590bbaa6da
--- /dev/null
+++ b/document_page/migrations/9.0.2.0.0/post-migration.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+# Copyright 2018 Ivan Todorovich
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+
+
+def migrate(cr, version): # pragma: no cover
+ # Set all pre-existing categories template to its content
+ cr.execute("""
+ UPDATE document_page
+ SET template = content
+ WHERE type = 'category'
+ """)
diff --git a/document_page/models/document_page.py b/document_page/models/document_page.py
index ed7fc35cfd9..94db69d51b2 100644
--- a/document_page/models/document_page.py
+++ b/document_page/models/document_page.py
@@ -18,10 +18,8 @@
# along with this program. If not, see .
#
##############################################################################
-import logging
-from openerp import models, fields, api
-_logger = logging.getLogger(__name__)
+from openerp import models, fields, api
class DocumentPage(models.Model):
@@ -54,18 +52,38 @@ class DocumentPage(models.Model):
)
content = fields.Text(
- "Content"
+ "Content",
+ compute='_compute_content',
+ inverse='_inverse_content',
+ required=True,
)
+ # no-op computed field
+ summary = fields.Char(
+ help='Describe the changes made',
+ compute=lambda x: x,
+ inverse=lambda x: x,
+ )
+
+ template = fields.Html(
+ "Template",
+ help="Template that will be used as a content template "
+ "for all new page of this category.",
+ )
+
+ # deprecated - should be removed on 10.0
+ # left here because some modules might still need it
display_content = fields.Text(
string='Displayed Content',
- compute='_get_display_content'
+ compute='_compute_display_content'
)
history_ids = fields.One2many(
'document.page.history',
'page_id',
- 'History'
+ 'History',
+ order='create_date DESC',
+ readonly=True
)
menu_id = fields.Many2one(
@@ -99,60 +117,58 @@ class DocumentPage(models.Model):
readonly=True
)
- def _get_page_index(self, page, link=True):
+ @api.multi
+ def _get_page_index(self, link=True):
"""Return the index of a document."""
+ self.ensure_one()
index = []
- for subpage in page.child_ids:
- index += ["" + self._get_page_index(subpage) +
- " "]
+ for subpage in self.child_ids:
+ index += ["" + subpage._get_page_index() + " "]
r = ''
if link:
- r = '%s ' % (page.id, page.name)
+ r = '%s ' % (self.id, self.name)
if index:
r += ""
return r
- def _get_display_content(self):
- """Return the content of a document."""
- for page in self:
- if page.type == "category":
- display_content = self._get_page_index(page, link=False)
+ @api.multi
+ def _compute_display_content(self):
+ # @deprecated, simply use content
+ for rec in self:
+ rec.display_content = rec.content
+
+ @api.multi
+ def _compute_content(self):
+ for rec in self:
+ if rec.type == 'category':
+ rec.content = rec._get_page_index(link=False)
else:
- display_content = page.content
- page.display_content = display_content
+ if rec.history_ids:
+ rec.content = rec.history_ids[0].content
+ else:
+ # html widget's default, so it doesn't trigger ghost save
+ rec.content = '
'
- @api.onchange("parent_id")
- def do_set_content(self):
- """We Set it the right content to the new parent."""
- if self.parent_id and not self.content:
- if self.parent_id.type == "category":
- self.content = self.parent_id.content
+ @api.multi
+ def _inverse_content(self):
+ for rec in self:
+ if rec.content:
+ rec._create_history({
+ 'content': rec.content,
+ 'summary': rec.summary
+ })
- def create_history(self, page_id, content):
- """Create the first history of a newly created document."""
+ @api.multi
+ def _create_history(self, vals):
+ self.ensure_one()
history = self.env['document.page.history']
- return history.create({
- "content": content,
- "page_id": page_id
- })
+ vals['page_id'] = self.id
+ return history.create(vals)
- @api.multi
- def write(self, vals):
- """Write the content and set the history."""
- result = super(DocumentPage, self).write(vals)
- content = vals.get('content')
- if content:
- for page in self:
- self.create_history(page.id, content)
- return result
-
- @api.model
- @api.returns('self', lambda value: value.id)
- def create(self, vals):
- """Create the first history of a document."""
- page_id = super(DocumentPage, self).create(vals)
- content = vals.get('content')
- if content:
- self.create_history(page_id.id, content)
- return page_id
+ @api.onchange("parent_id")
+ def _onchange_parent_id(self):
+ """We Set it the right content to the new parent."""
+ if not self.content or self.content == '
':
+ if self.parent_id and self.parent_id.type == "category":
+ self.content = self.parent_id.template
diff --git a/document_page/models/document_page_history.py b/document_page/models/document_page_history.py
index f296c0947d6..30fc861d721 100644
--- a/document_page/models/document_page_history.py
+++ b/document_page/models/document_page_history.py
@@ -18,11 +18,8 @@
# along with this program. If not, see .
#
##############################################################################
-import logging
import difflib
-from openerp import models, fields, _
-
-_logger = logging.getLogger(__name__)
+from openerp import models, fields, api, _
class DocumentPageHistory(models.Model):
@@ -33,22 +30,38 @@ class DocumentPageHistory(models.Model):
_order = 'id DESC'
_rec_name = "create_date"
- page_id = fields.Many2one('document.page', 'Page')
+ page_id = fields.Many2one('document.page', 'Page', ondelete='cascade')
summary = fields.Char('Summary', index=True)
content = fields.Text("Content")
- create_date = fields.Datetime("Date")
- create_uid = fields.Many2one('res.users', "Modified By")
+ diff = fields.Text(compute='_compute_diff')
+
+ @api.multi
+ def _compute_diff(self):
+ """Shows a diff between this version and the previous version"""
+ history = self.env['document.page.history']
+ for rec in self:
+ prev = history.search([
+ ('page_id', '=', rec.page_id.id),
+ ('create_date', '<', rec.create_date)],
+ limit=1,
+ order='create_date DESC')
+ if prev:
+ rec.diff = self.getDiff(prev.id, rec.id)
+ else:
+ rec.diff = self.getDiff(False, rec.id)
+ @api.model
def getDiff(self, v1, v2):
"""Return the difference between two version of document version."""
- text1 = self.browse(v1).content
- text2 = self.browse(v2).content
- line1 = line2 = ''
- if text1:
- line1 = text1.splitlines(1)
- if text2:
- line2 = text2.splitlines(1)
- if (not line1 and not line2) or (line1 == line2):
+ text1 = v1 and self.browse(v1).content or ''
+ text2 = v2 and self.browse(v2).content or ''
+ # Include line breaks to make it more readable
+ # TODO: consider using a beautify library directly on the content
+ text1 = text1.replace('
', '
\r\n')
+ text2 = text2.replace('
', '
\r\n')
+ line1 = text1.splitlines(1)
+ line2 = text2.splitlines(1)
+ if line1 == line2:
return _('There are no changes in revisions.')
else:
diff = difflib.HtmlDiff()
@@ -58,3 +71,11 @@ def getDiff(self, v1, v2):
"Revision-{}".format(v2),
context=True
)
+
+ @api.multi
+ def name_get(self):
+ result = []
+ for rec in self:
+ name = "%s #%i" % (rec.page_id.name, rec.id)
+ result.append((rec.id, name))
+ return result
diff --git a/document_page/security/document_page_security.xml b/document_page/security/document_page_security.xml
index 6834b69ba89..0771636587f 100644
--- a/document_page/security/document_page_security.xml
+++ b/document_page/security/document_page_security.xml
@@ -1,8 +1,24 @@
+
+
+ User (Read only)
+
+
+
+ Editor
+
+
+
+
+
+ Manager
+
+
+
diff --git a/document_page/security/ir.model.access.csv b/document_page/security/ir.model.access.csv
index 13f0479ff53..61f5869db68 100644
--- a/document_page/security/ir.model.access.csv
+++ b/document_page/security/ir.model.access.csv
@@ -1,4 +1,7 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-document_page_all,document.page,model_document_page,,1,0,0,0
-document_page,document.page,model_document_page,base.group_user,1,1,1,1
-document_page_history,document.page.history,model_document_page_history,base.group_user,1,0,1,0
+document_page_user,document.page user,model_document_page,base.group_document_user,1,0,0,0
+document_page_history_user,document.page.history user,model_document_page_history,base.group_document_user,1,0,0,0
+document_page_editor,document.page editor,model_document_page,group_document_editor,1,1,1,0
+document_page_history_editor,document.page.history editor,model_document_page_history,group_document_editor,1,1,1,0
+document_page_manager,document.page manager,model_document_page,group_document_manager,1,1,1,1
+document_page_history_manager,document.page.history manager,model_document_page_history,group_document_manager,1,1,1,0
diff --git a/document_page/static/src/css/document_page.css b/document_page/static/src/css/document_page.css
index ddbbcffd45b..00a6336c226 100644
--- a/document_page/static/src/css/document_page.css
+++ b/document_page/static/src/css/document_page.css
@@ -1,12 +1,29 @@
-.oe_form_editable .oe_document_page {
- display: none;
+table.diff {
+ font-family: Courier;
+ border: medium;
}
-table.diff {font-family:Courier; border:medium;}
-.diff_header {background-color:#e0e0e0}
-td.diff_header {text-align:right}
-.diff_next {background-color:#c0c0c0}
-.diff_add {background-color:#aaffaa}
-.diff_chg {background-color:#ffff77}
-.diff_sub {background-color:#ffaaaa}
+table.diff .diff_header {
+ background-color: #e0e0e0
+}
+
+table.diff td.diff_header {
+ text-align: right
+}
+
+table.diff .diff_next {
+ background-color:#c0c0c0
+}
+
+table.diff .diff_add {
+ background-color:#aaffaa
+}
+
+table.diff .diff_chg {
+ background-color:#ffff77
+}
+
+table.diff .diff_sub {
+ background-color:#ffaaaa
+}
diff --git a/document_page/tests/__init__.py b/document_page/tests/__init__.py
index 4c507a03227..14e2fa0bef0 100644
--- a/document_page/tests/__init__.py
+++ b/document_page/tests/__init__.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-from . import test_document_page, test_document_page_history
+from . import test_document_page
from . import test_document_page_create_menu
from . import test_document_page_show_diff
diff --git a/document_page/tests/test_document_page.py b/document_page/tests/test_document_page.py
index 9c3b4d72bbd..0b627cbaa47 100644
--- a/document_page/tests/test_document_page.py
+++ b/document_page/tests/test_document_page.py
@@ -4,34 +4,37 @@
class TestDocumentPage(common.TransactionCase):
- """document_page test class."""
- def test_page_creation(self):
- """Test page creation."""
- parent_page = self.env.ref('document_page.demo_category1')
-
- self.assertEqual(parent_page.name, 'OpenERP Features')
+ def setUp(self):
+ super(TestDocumentPage, self).setUp()
+ self.page_obj = self.env['document.page']
+ self.history_obj = self.env['document.page.history']
+ self.category1 = self.env.ref('document_page.demo_category1')
+ self.page1 = self.env.ref('document_page.demo_page1')
- record = self.env['document.page'].create({
- 'name': 'Test Page1',
- 'parent_id': parent_page.id,
+ def test_page_creation(self):
+ page = self.page_obj.create({
+ 'name': 'Test Page 1',
+ 'parent_id': self.category1.id,
'content': 'Test content'
})
- self.assertEqual(record.name, 'Test Page1')
-
- def test_category_display_content(self):
- """Test category display content."""
- page = self.env.ref('document_page.demo_category1')
- self.assertTrue(page.display_content.find('Demo') > 1)
-
- def test_page_display_content(self):
- """Test page display content."""
- page = self.env.ref('document_page.demo_page1')
- self.assertTrue(page.display_content.find('Demo') > 1)
+ self.assertEqual(page.content, 'Test content')
+ self.assertEqual(len(page.history_ids), 1)
+ page.content = 'New content for Demo Page'
+ self.assertEqual(len(page.history_ids), 2)
+
+ def test_category_template(self):
+ page = self.page_obj.create({
+ 'name': 'Test Page 2',
+ 'parent_id': self.category1.id,
+ })
+ page._onchange_parent_id()
+ self.assertEqual(page.content, self.category1.template)
- def test_page_do_set_content(self):
- """Test page set content."""
- page = self.env.ref('document_page.demo_page1')
- page.content = None
- page.do_set_content()
- self.assertTrue(page.display_content.find('Summary') == 1)
+ def test_page_history_diff(self):
+ page = self.page_obj.create({
+ 'name': 'Test Page 3',
+ 'content': 'Test content'
+ })
+ page.content = 'New content'
+ self.assertIsNotNone(page.history_ids[0].diff)
diff --git a/document_page/tests/test_document_page_history.py b/document_page/tests/test_document_page_history.py
deleted file mode 100644
index ced210c1ae5..00000000000
--- a/document_page/tests/test_document_page_history.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from openerp.tests import common
-
-
-class TestDocumentPageHistory(common.TransactionCase):
- """document_page_history test class."""
-
- def test_page_history_demo_page1(self):
- """Test page history demo page1."""
- page = self.env.ref('document_page.demo_page1')
- page.content = 'Test content updated'
- history_document = self.env['document.page.history']
- history_pages = history_document.search([('page_id', '=', page.id)])
- active_ids = [i.id for i in history_pages]
-
- result = history_document.getDiff(active_ids[0], active_ids[0])
- self.assertEqual(result, 'There are no changes in revisions.')
-
- result = history_document.getDiff(active_ids[0], active_ids[1])
- self.assertNotEqual(result, 'There are no changes in revisions.')
diff --git a/document_page/tests/test_document_page_show_diff.py b/document_page/tests/test_document_page_show_diff.py
index a43f7bc1bbd..9498a951c49 100644
--- a/document_page/tests/test_document_page_show_diff.py
+++ b/document_page/tests/test_document_page_show_diff.py
@@ -19,7 +19,7 @@ def test_show_demo_page1_diff(self):
self.assertTrue(
show_diff_object.with_context(
active_ids=[i.id for i in history_pages]
- ).get_diff()
+ )._get_diff()
)
page.write({'content': 'Text content updated'})
@@ -30,7 +30,7 @@ def test_show_demo_page1_diff(self):
with self.assertRaises(Exception) as context:
show_diff_object.with_context(
active_ids=[i.id for i in history_pages]
- ).get_diff()
+ )._get_diff()
self.assertTrue(_("Select one or maximum two history revisions!")
in context.exception)
diff --git a/document_page/views/document_page.xml b/document_page/views/document_page.xml
index 06e4f19aa50..22fbfe2e527 100644
--- a/document_page/views/document_page.xml
+++ b/document_page/views/document_page.xml
@@ -47,31 +47,32 @@
-
+
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -88,12 +89,7 @@
@@ -104,21 +100,14 @@
document.page
-
-
-
-
+
+
+
@@ -149,21 +138,10 @@
-
-
-
-
+
-
-
-
+
@@ -257,25 +235,57 @@
document.page.history
-
-
+
+
+
+
+
+
+
+ document.page.history.search
+ document.page.history
+
+
+
+
+
+
+
+
+
+
+
+
document.page.history.form
document.page.history
-
diff --git a/document_page/views/document_page_assets.xml b/document_page/views/document_page_assets.xml
new file mode 100644
index 00000000000..1be8446786a
--- /dev/null
+++ b/document_page/views/document_page_assets.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/document_page/wizard/document_page_show_diff.py b/document_page/wizard/document_page_show_diff.py
index db42214d6fb..84900e969b6 100644
--- a/document_page/wizard/document_page_show_diff.py
+++ b/document_page/wizard/document_page_show_diff.py
@@ -19,7 +19,7 @@
#
##############################################################################
from openerp import models, fields, _
-from openerp import exceptions
+from openerp.exceptions import UserError
class DocumentPageShowDiff(models.TransientModel):
@@ -27,33 +27,24 @@ class DocumentPageShowDiff(models.TransientModel):
_name = 'wizard.document.page.history.show_diff'
- def get_diff(self):
+ def _get_diff(self):
"""Return the Difference between two document."""
history = self.env["document.page.history"]
ids = self.env.context.get('active_ids', [])
-
- diff = ""
+ diff = False
if len(ids) == 2:
if ids[0] > ids[1]:
diff = history.getDiff(ids[1], ids[0])
else:
diff = history.getDiff(ids[0], ids[1])
elif len(ids) == 1:
- old = history.browse(ids[0])
- nids = history.search(
- [('page_id', '=', old.page_id.id)],
- order='id DESC',
- limit=1
- )
- diff = history.getDiff(ids[0], nids.id)
+ diff = history.browse(ids[0]).diff
else:
- raise exceptions.Warning(
- _("Select one or maximum two history revisions!")
- )
+ raise UserError(
+ _("Select one or maximum two history revisions!"))
return diff
diff = fields.Text(
- 'Diff',
readonly=True,
- default=get_diff
+ default=_get_diff,
)
diff --git a/document_page/wizard/document_page_show_diff.xml b/document_page/wizard/document_page_show_diff.xml
index 4499769fdb1..8214be66102 100644
--- a/document_page/wizard/document_page_show_diff.xml
+++ b/document_page/wizard/document_page_show_diff.xml
@@ -8,13 +8,9 @@
wizard.document.page.history.show_diff
diff --git a/document_page_approval/__init__.py b/document_page_approval/__init__.py
index 7f626589644..de09c2f09ab 100644
--- a/document_page_approval/__init__.py
+++ b/document_page_approval/__init__.py
@@ -19,3 +19,4 @@
#
##############################################################################
from . import models
+from .hooks import post_init_hook, uninstall_hook
diff --git a/document_page_approval/__openerp__.py b/document_page_approval/__openerp__.py
index 1e95feb30df..114a9fd56fa 100644
--- a/document_page_approval/__openerp__.py
+++ b/document_page_approval/__openerp__.py
@@ -21,13 +21,12 @@
{
'name': 'Document Page Approval',
- 'version': '9.0.1.0.0',
+ 'version': '9.0.2.0.0',
"author": "Savoir-faire Linux,Odoo Community Association (OCA)",
"website": "http://www.savoirfairelinux.com",
"license": "AGPL-3",
'category': 'Knowledge Management',
'depends': [
- 'knowledge',
'document_page',
'mail',
],
@@ -40,6 +39,8 @@
],
'installable': True,
'auto_install': False,
+ 'post_init_hook': 'post_init_hook',
+ 'uninstall_hook': 'uninstall_hook',
'images': [
'images/category.png',
'images/page_history_list.png',
diff --git a/document_page_approval/data/email_template.xml b/document_page_approval/data/email_template.xml
index e31c8bcb6b1..08bb782e402 100644
--- a/document_page_approval/data/email_template.xml
+++ b/document_page_approval/data/email_template.xml
@@ -1,15 +1,13 @@
-
-
-
+
+
Automated new draft need approval Notification Mail
${object.create_uid.company_id.email or 'noreply@localhost.com'}
- New version of "${object.page_id.name}" to approve
- ${object.get_approvers_email}
+ New version of ${object.display_name} needs your approval
${object.create_uid.partner_id.lang}
@@ -17,13 +15,29 @@
Hello,
-The page "${object.page_id.name}" has been modified and need your approval.
+${object.create_uid.name} submited a new Change Request for ${object.page_id.name} and it needs your approval.
+
+
+
+ Modified by: ${object.create_uid.name}
+ Date: ${object.create_date}
+
+
+% if object.summary:
+Summary
+${object.summary}
+% endif
+
+Diff
+
+${object.diff|safe}
+
-You can review the new version here : ${object.get_page_url}
+Have a great day.
-Have a great day.
--
-Odoo
]]>
+Odoo
+ ]]>
diff --git a/document_page_approval/hooks.py b/document_page_approval/hooks.py
new file mode 100644
index 00000000000..7cd62e97c53
--- /dev/null
+++ b/document_page_approval/hooks.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Copyright 2018 Ivan Todorovich ()
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
+
+
+def post_init_hook(cr, registry): # pragma: no cover
+ # Set all pre-existing pages history to approved
+ cr.execute("""
+ UPDATE document_page_history
+ SET state='approved',
+ approved_uid=create_uid,
+ approved_date=create_date
+ WHERE state IS NULL
+ """)
+
+
+def uninstall_hook(cr, registry): # pragma: no cover
+ # Remove unapproved pages
+ cr.execute(
+ "DELETE FROM document_page_history "
+ "WHERE state != 'approved'"
+ )
diff --git a/document_page_approval/migrations/9.0.2.0.0/post-migration.py b/document_page_approval/migrations/9.0.2.0.0/post-migration.py
new file mode 100644
index 00000000000..9c04167ce16
--- /dev/null
+++ b/document_page_approval/migrations/9.0.2.0.0/post-migration.py
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+# Copyright 2018 Ivan Todorovich
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
+
+
+def migrate(cr, version): # pragma: no cover
+ # Set all pre-existing pages history to approved
+ cr.execute("""
+ UPDATE document_page_history
+ SET state='approved',
+ approved_uid=create_uid,
+ approved_date=create_date
+ WHERE state IS NULL
+ """)
diff --git a/document_page_approval/models/document_page_approval.py b/document_page_approval/models/document_page_approval.py
index 278f52273c4..2c9e57afaeb 100644
--- a/document_page_approval/models/document_page_approval.py
+++ b/document_page_approval/models/document_page_approval.py
@@ -20,6 +20,7 @@
##############################################################################
from openerp import models, fields, api
+from ast import literal_eval
class DocumentPageApproval(models.Model):
@@ -27,104 +28,101 @@ class DocumentPageApproval(models.Model):
_inherit = 'document.page'
- @api.multi
- def _get_display_content(self):
- """Display the content of document."""
- for page in self:
- content = ""
- if page.type == "category":
- content = self._get_page_index(page, link=False)
- else:
- history = self.env['document.page.history']
- if self.is_approval_required(page):
- history_ids = history.search(
- [
- ('page_id', '=', page.id),
- ('state', '=', 'approved')
- ],
- limit=1,
- order='create_date DESC'
- )
- content = history_ids.content
- else:
- content = page.content
- page.display_content = content
-
- @api.multi
- def _get_approved_date(self):
- """Return the approved date of a document."""
- for page in self:
- approved_date = False
- if self.is_approval_required(page):
- history = self.env['document.page.history']
- history_ids = history.search(
- [
- ('page_id', '=', page.id),
- ('state', '=', 'approved')
- ],
- limit=1,
- order='create_date DESC'
- )
- approved_date = history_ids.approved_date
- page.approved_date = approved_date
-
- @api.multi
- def _get_approved_uid(self):
- """Return the user's id of the approved user."""
- for page in self:
- approved_uid = False
- if self.is_approval_required(page):
- history = self.env['document.page.history']
- history_ids = history.search(
- [
- ('page_id', '=', page.id),
- ('state', '=', 'approved')
- ],
- limit=1,
- order='create_date DESC'
- )
- approved_uid = history_ids.approved_uid.id
- page.approved_uid = approved_uid
-
- @api.multi
- def _is_parent_approval_required(self):
- """Check if the document required approval base on his parrent."""
- for page in self:
- page.is_parent_approval_required = self.is_approval_required(page)
-
- def is_approval_required(self, page):
- """Check if a document required approval."""
- if page:
- res = page.approval_required
- res = res or self.is_approval_required(page.parent_id)
- else:
- res = False
- return res
-
- display_content = fields.Text(
- compute=_get_display_content,
- string='Displayed Content'
+ history_ids = fields.One2many(
+ order='approved_date DESC',
+ domain=[('state', '=', 'approved')],
)
approved_date = fields.Datetime(
- compute=_get_approved_date,
+ compute='_compute_approved_info',
string="Approved Date"
)
approved_uid = fields.Many2one(
'res.users',
- compute=_get_approved_uid,
+ compute='_compute_approved_info',
string="Approved By",
)
- approval_required = fields.Boolean("Require approval")
-
- is_parent_approval_required = fields.Boolean(
- compute=_is_parent_approval_required,
- string="parent approval"
+ approval_required = fields.Boolean(
+ 'Require approval',
+ help='Require approval for changes on this page or its child pages.',
)
approver_gid = fields.Many2one(
"res.groups",
- "Approver group"
+ "Approver group",
+ help='Users must also belong to the Approvers group',
+ )
+
+ is_approval_required = fields.Boolean(
+ 'Approval required',
+ help='If true, changes of this page require approval',
+ compute='_compute_is_approval_required',
+ )
+
+ approver_group_ids = fields.Many2many(
+ 'res.groups',
+ string='Approver groups',
+ help='Groups that can approve changes to this document',
+ compute='_compute_approver_group_ids',
)
+
+ has_changes_pending_approval = fields.Boolean(
+ compute='_compute_has_changes_pending_approval',
+ string='Has changes pending approval'
+ )
+
+ @api.multi
+ @api.depends('history_ids')
+ def _compute_approved_info(self):
+ """Return the approved date of a document."""
+ for page in self:
+ if page.history_ids:
+ page.approved_date = page.history_ids[0].approved_date
+ page.approved_uid = page.history_ids[0].approved_uid
+
+ @api.multi
+ @api.depends('approval_required', 'parent_id.is_approval_required')
+ def _compute_is_approval_required(self):
+ """Check if the document required approval based on his parents."""
+ for page in self:
+ res = page.approval_required
+ if page.parent_id:
+ res = res or page.parent_id.is_approval_required
+ page.is_approval_required = res
+
+ @api.multi
+ @api.depends('approver_gid', 'parent_id.approver_group_ids')
+ def _compute_approver_group_ids(self):
+ """Compute the approver groups based on his parents."""
+ for page in self:
+ res = page.approver_gid
+ if page.parent_id:
+ res = res | page.parent_id.approver_group_ids
+ page.approver_group_ids = res
+
+ @api.multi
+ def _compute_has_changes_pending_approval(self):
+ history = self.env['document.page.history']
+ for rec in self:
+ changes = history.search_count([
+ ('page_id', '=', rec.id),
+ ('state', '=', 'to approve')])
+ rec.has_changes_pending_approval = (changes > 0)
+
+ @api.multi
+ def _create_history(self, vals):
+ res = super(DocumentPageApproval, self)._create_history(vals)
+ res.signal_workflow('document_page_auto_confirm')
+
+ @api.multi
+ def action_changes_pending_approval(self):
+ self.ensure_one()
+ action = self.env.ref('document_page_approval.action_change_requests')
+ action = action.read()[0]
+ context = literal_eval(action['context'])
+ context['search_default_page_id'] = self.id
+ context['default_page_id'] = self.id
+ action['context'] = context
+ return action
diff --git a/document_page_approval/models/document_page_history_workflow.py b/document_page_approval/models/document_page_history_workflow.py
index 2eeb7e91331..fd03f4d2d2c 100644
--- a/document_page_approval/models/document_page_history_workflow.py
+++ b/document_page_approval/models/document_page_history_workflow.py
@@ -28,117 +28,136 @@
class DocumentPageHistoryWorkflow(models.Model):
"""Useful to manage edition's workflow on a document."""
- _inherit = 'document.page.history'
+ _name = 'document.page.history'
+ _inherit = ['document.page.history', 'mail.thread']
+
+ state = fields.Selection([
+ ('draft', 'Draft'),
+ ('to approve', 'Pending Approval'),
+ ('approved', 'Approved'),
+ ('cancelled', 'Cancelled')],
+ 'Status',
+ readonly=True,
+ )
+
+ approved_date = fields.Datetime("Approved Date")
+
+ approved_uid = fields.Many2one(
+ 'res.users',
+ "Approved By"
+ )
+
+ is_approval_required = fields.Boolean(
+ related='page_id.is_approval_required',
+ string="Approval required",
+ )
+
+ am_i_owner = fields.Boolean(compute='_compute_am_i_owner')
+ am_i_approver = fields.Boolean(compute='_compute_am_i_approver')
+
+ page_url = fields.Text(
+ compute='_compute_page_url',
+ string="URL",
+ )
@api.multi
def page_approval_draft(self):
- """Set a document state as draft and notified the reviewers."""
+ """Set a change request as draft"""
self.write({'state': 'draft'})
+
+ @api.multi
+ def page_approval_to_approve(self):
+ """Set a change request as to approve"""
+ self.write({'state': 'to approve'})
template = self.env.ref(
'document_page_approval.email_template_new_draft_need_approval')
- for page in self:
- if page.is_parent_approval_required:
- template.send_mail(page.id, force_send=True)
- return True
+ approver_gid = self.env.ref(
+ 'document_page_approval.group_document_approver_user')
+ for rec in self:
+ if rec.is_approval_required:
+ guids = [g.id for g in rec.page_id.approver_group_ids]
+ users = self.env['res.users'].search([
+ ('groups_id', 'in', guids),
+ ('groups_id', 'in', approver_gid.id)])
+ rec.message_subscribe_users([u.id for u in users])
+ rec.message_post_with_template(template.id)
@api.multi
def page_approval_approved(self):
- """Set a document state as approve."""
- message_obj = self.env['mail.message']
+ """Set a change request as approved."""
self.write({
'state': 'approved',
'approved_date': datetime.now().strftime(
DEFAULT_SERVER_DATETIME_FORMAT),
'approved_uid': self.env.uid
})
- # Notify followers a new version is available
- for page_history in self:
- subtype = self.env.ref('mail.mt_comment')
- message_obj.create(
- {'res_id': page_history.page_id.id,
- 'model': 'document.page',
- 'subtype_id': subtype.id,
- 'body': _('New version of the document %s'
- ' approved.') % page_history.page_id.name
- }
+ for rec in self:
+ # Notify state change
+ rec.message_post(
+ subtype='mt_comment',
+ body=_(
+ 'Change request has been approved by %s.'
+ ) % (self.env.user.name)
)
- return True
-
- @api.multi
- def _can_user_approve_page(self):
- """Check if a user cas approve the page."""
- user = self.env.user
- for page in self:
- page.can_user_approve_page = page.can_user_approve_this_page(
- page.page_id,
- user
+ # Notify followers a new version is available
+ rec.page_id.message_post(
+ subtype='mt_comment',
+ body=_(
+ 'New version of the document %s approved.'
+ ) % (rec.page_id.name)
)
- def can_user_approve_this_page(self, page, user):
- """Check if a user can approved the page."""
- if page:
- res = page.approver_gid in user.groups_id
- res = res or self.can_user_approve_this_page(page.parent_id, user)
- else:
- res = False
- return res
+ @api.multi
+ def page_approval_cancelled(self):
+ """Set a change request as cancelled."""
+ self.write({'state': 'cancelled'})
+ for rec in self:
+ rec.message_post(
+ subtype='mt_comment',
+ body=_(
+ 'Change request %s has been cancelled by %s.'
+ ) % (rec.display_name, self.env.user.name)
+ )
@api.multi
- def get_approvers_guids(self):
- """Return the approvers group."""
- res = {}
- for page in self:
- res[page.id] = self.get_approvers_guids_for_page(page.page_id)
- return res
-
- def get_approvers_guids_for_page(self, page):
- """Return the approvers group for a page."""
- if page:
- if page.approver_gid:
- res = [page.approver_gid.id]
- else:
- res = []
- res.extend(self.get_approvers_guids_for_page(page.parent_id))
- else:
- res = []
+ def _compute_am_i_owner(self):
+ """Check if current user is the owner"""
+ for rec in self:
+ rec.am_i_owner = (rec.create_uid == self.env.user)
- return res
+ @api.multi
+ def _compute_am_i_approver(self):
+ """Check if the current user can approve the page."""
+ for rec in self:
+ rec.am_i_approver = rec.can_user_approve_this_page(self.env.user)
@api.multi
- def _get_approvers_email(self):
- """Get the approvers email."""
- for page in self:
- emails = ''
- guids = self.get_approvers_guids()
- uids = [i.id for i in self.env['res.users'].search([
- ('groups_id', 'in', guids[page.id])
- ])]
- users = self.env['res.users'].browse(uids)
-
- for user in users:
- if user.email:
- emails += user.email
- emails += ','
- else:
- empl = self.env['hr.employee'].search([
- ('login', '=', user.login)
- ])
- if empl.work_email:
- emails += empl.work_email
- emails += ','
-
- page.get_approvers_email = emails[:-1]
+ def can_user_approve_this_page(self, user):
+ """Check if a user can approve this page."""
+ self.ensure_one()
+ # if it's not required, anyone can approve
+ if not self.is_approval_required:
+ return True
+ # to approve, you must have approver rights
+ approver_group_id = self.env.ref(
+ 'document_page_approval.group_document_approver_user')
+ if approver_group_id not in user.groups_id:
+ return False
+ # and belong to at least one of the approver_groups (if any is set)
+ if not self.page_id.approver_group_ids:
+ return True
+ return len(user.groups_id & self.page_id.approver_group_ids) > 0
@api.multi
- def _get_page_url(self):
- """Get the page url."""
+ def _compute_page_url(self):
+ """Compute the page url."""
for page in self:
base_url = self.env['ir.config_parameter'].get_param(
'web.base.url',
default='http://localhost:8069'
)
- page.get_page_url = (
+ page.page_url = (
'{}/web#db={}&id={}&view_type=form&'
'model=document.page.history').format(
base_url,
@@ -146,37 +165,18 @@ def _get_page_url(self):
page.id
)
- state = fields.Selection(
- [('draft', 'Draft'), ('approved', 'Approved')],
- 'Status',
- readonly=True
- )
-
- approved_date = fields.Datetime("Approved Date")
-
- approved_uid = fields.Many2one(
- 'res.users',
- "Approved By"
- )
-
- is_parent_approval_required = fields.Boolean(
- related='page_id.is_parent_approval_required',
- string="parent approval",
- store=False
- )
-
- can_user_approve_page = fields.Boolean(
- compute=_can_user_approve_page,
- string="can user approve this page",
- store=False
- )
- get_approvers_email = fields.Text(
- compute=_get_approvers_email,
- string="get all approvers email",
- store=False
- )
- get_page_url = fields.Text(
- compute=_get_page_url,
- string="URL",
- store=False
- )
+ @api.multi
+ def _compute_diff(self):
+ """Shows a diff between this version and the previous version"""
+ history = self.env['document.page.history']
+ for rec in self:
+ domain = [
+ ('page_id', '=', rec.page_id.id),
+ ('state', '=', 'approved')]
+ if rec.approved_date:
+ domain.append(('approved_date', '<', rec.approved_date))
+ prev = history.search(domain, limit=1, order='approved_date DESC')
+ if prev:
+ rec.diff = self.getDiff(prev.id, rec.id)
+ else:
+ rec.diff = self.getDiff(False, rec.id)
diff --git a/document_page_approval/security/document_page_security.xml b/document_page_approval/security/document_page_security.xml
index d41d96f8204..3618a677650 100644
--- a/document_page_approval/security/document_page_security.xml
+++ b/document_page_approval/security/document_page_security.xml
@@ -1,9 +1,16 @@
+
- Document approver
-
+ Approver
+
+
+
+
+
+
+
diff --git a/document_page_approval/security/ir.model.access.csv b/document_page_approval/security/ir.model.access.csv
index f8e75f150da..97dd8b917b8 100644
--- a/document_page_approval/security/ir.model.access.csv
+++ b/document_page_approval/security/ir.model.access.csv
@@ -1,2 +1 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
-document_page_history,document.page.history,model_document_page_history,group_document_approver_user,1,1,1,0
diff --git a/document_page_approval/tests/__init__.py b/document_page_approval/tests/__init__.py
index 2413da8115f..30782b8b608 100644
--- a/document_page_approval/tests/__init__.py
+++ b/document_page_approval/tests/__init__.py
@@ -1,2 +1,2 @@
# -*- coding: utf-8 -*-
-from . import test_document_page_approval, test_document_page_history_workflow
+from . import test_document_page_approval
diff --git a/document_page_approval/tests/test_document_page_approval.py b/document_page_approval/tests/test_document_page_approval.py
index 4c0e8457209..f418fd5d8a6 100644
--- a/document_page_approval/tests/test_document_page_approval.py
+++ b/document_page_approval/tests/test_document_page_approval.py
@@ -3,35 +3,123 @@
class TestDocumentPageApproval(common.TransactionCase):
- """Test document page approval model."""
- def test_get_display_content(self):
- """Test page display content."""
- # Check content of a category
- category = self.env['document.page'].search([
- ('name', '=', 'OpenERP Features')
- ])
+ def setUp(self):
+ super(TestDocumentPageApproval, self).setUp()
+ self.page_obj = self.env['document.page']
+ self.history_obj = self.env['document.page.history']
+ # demo
+ self.category1 = self.env.ref('document_page.demo_category1')
+ self.page1 = self.env.ref('document_page.demo_page1')
+ self.approver_gid = self.env.ref(
+ 'document_page_approval.group_document_approver_user')
+ # demo_approval
+ self.category2 = self.page_obj.create({
+ 'name': 'This category requires approval',
+ 'type': 'category',
+ 'approval_required': True,
+ 'approver_gid': self.approver_gid.id,
+ })
+ self.page2 = self.page_obj.create({
+ 'name': 'This page requires approval',
+ 'parent_id': self.category2.id,
+ 'content': 'This content will require approval'
+ })
- self.assertIsNotNone(category.display_content, 'a category')
+ def test_approval_required(self):
+ page = self.page2
+ self.assertTrue(page.is_approval_required)
+ self.assertTrue(page.has_changes_pending_approval)
+ self.assertEqual(len(page.history_ids), 0)
- # Check content of a page
- pages = self.env['document.page'].search([
- ('parent_id', '=', category.id)
- ])
- page = pages[0]
- self.assertIsNotNone(page.display_content, 'Page content')
+ def test_change_request_approve(self):
+ page = self.page2
+ chreq = self.history_obj.search([
+ ('page_id', '=', page.id),
+ ('state', '!=', 'approved')
+ ])[0]
+
+ # It should automatically be in 'to approve' state
+ self.assertEqual(chreq.state, 'to approve')
+ self.assertNotEqual(chreq.content, page.content)
+
+ # who_am_i
+ self.assertTrue(chreq.am_i_owner)
+ self.assertTrue(chreq.am_i_approver)
+
+ # approve
+ chreq.signal_workflow('page_approval_approve')
+ self.assertEqual(chreq.state, 'approved')
+ self.assertEqual(chreq.content, page.content)
+
+ # new changes should create change requests
+ page.write({'content': 'New content'})
+ self.assertNotEqual(page.content, 'New content')
+ chreq = self.history_obj.search([
+ ('page_id', '=', page.id),
+ ('state', '!=', 'approved')
+ ])[0]
+ chreq.signal_workflow('page_approval_approve')
+ self.assertEqual(page.content, 'New content')
+
+ def test_change_request_auto_approve(self):
+ page = self.page1
+ self.assertFalse(page.is_approval_required)
+ page.write({'content': 'New content'})
+ self.assertEqual(page.content, 'New content')
- # Check if approval is required
- self.assertTrue(page.is_approval_required(page) ==
- category.approval_required)
+ def test_change_request_from_scratch(self):
+ page = self.page2
- # Check content of an approval page
- page.approval_required = True
+ # aprove everything
+ self.history_obj.search([
+ ('page_id', '=', page.id),
+ ('state', '!=', 'approved')
+ ]).signal_workflow('page_approval_approve')
- self.assertIsNotNone(page.display_content, 'Page content')
+ # new change request from scrath
+ chreq = self.history_obj.create({
+ 'page_id': page.id,
+ 'summary': 'Changed something',
+ 'content': 'New content',
+ })
- # Check if approval is required
- self.assertTrue(page.is_approval_required(page))
+ self.assertEqual(chreq.state, 'draft')
+ self.assertNotEqual(page.content, chreq.content)
+ self.assertNotEqual(page.approved_date, chreq.approved_date)
+ self.assertNotEqual(page.approved_uid, chreq.approved_uid)
- # Check if parent approval is required
- self.assertTrue(page.is_parent_approval_required)
+ chreq.signal_workflow('page_approval_to_approve')
+ self.assertEqual(chreq.state, 'to approve')
+ self.assertNotEqual(page.content, chreq.content)
+ self.assertNotEqual(page.approved_date, chreq.approved_date)
+ self.assertNotEqual(page.approved_uid, chreq.approved_uid)
+
+ chreq.signal_workflow('page_approval_cancel')
+ self.assertEqual(chreq.state, 'cancelled')
+ self.assertNotEqual(page.content, chreq.content)
+ self.assertNotEqual(page.approved_date, chreq.approved_date)
+ self.assertNotEqual(page.approved_uid, chreq.approved_uid)
+
+ chreq.signal_workflow('page_approval_reopen')
+ self.assertEqual(chreq.state, 'draft')
+ self.assertNotEqual(page.content, chreq.content)
+ self.assertNotEqual(page.approved_date, chreq.approved_date)
+ self.assertNotEqual(page.approved_uid, chreq.approved_uid)
+
+ chreq.signal_workflow('page_approval_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):
+ """Get approver guids."""
+ page = self.page2
+ self.assertTrue(len(page.approver_group_ids) > 0)
+
+ def test_get_page_url(self):
+ """Test if page url exist."""
+ pages = self.env['document.page.history'].search([])
+ page = pages[0]
+ self.assertIsNotNone(page.page_url)
diff --git a/document_page_approval/tests/test_document_page_history_workflow.py b/document_page_approval/tests/test_document_page_history_workflow.py
deleted file mode 100644
index 508aff80073..00000000000
--- a/document_page_approval/tests/test_document_page_history_workflow.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# -*- coding: utf-8 -*-
-from openerp.tests import common
-# Import logger
-import logging
-
-# Get the logger
-_logger = logging.getLogger(__name__)
-
-
-class TestDocumentPageHistoryWorkflow(common.TransactionCase):
- """Test document page history workflow."""
-
- def test_can_user_approve_this_page(self):
- """Test if a user can approve this page."""
- category = self.env.ref('document_page.demo_category1')
- category.approval_required = True
- category.approver_gid = self.env.ref(
- 'document_page_approval.group_document_approver_user')
-
- page = self.env['document.page'].create({
- 'name': 'Test Page10',
- 'content': 'A difficult test',
- 'parent_id': category.id
- })
-
- history = self.env['document.page.history'].search(
- [
- ('page_id', '=', page.id)
- ],
- limit=1,
- order='create_date DESC'
- )
-
- self.assertTrue(history.can_user_approve_page)
-
- def test_get_approvers_guids(self):
- """Get approver guids."""
- category = self.env.ref('document_page.demo_category1')
- category.approval_required = True
- pages = self.env['document.page.history'].search([
- ('page_id', '=', category.id)
- ])
- page = pages[0]
- approvers_guid = page.get_approvers_guids()
- self.assertTrue(len(approvers_guid) > 0)
-
- def test_get_approvers_email(self):
- """Get approver email."""
- category = self.env.ref('document_page.demo_category1')
- category.approval_required = True
- pages = self.env['document.page.history'].search([
- ('page_id', '=', category.id)
- ])
- page = pages[0]
- _logger.info("Email: " + str(page.get_approvers_email))
- self.assertIsNotNone(page.get_approvers_email)
-
- def test_get_page_url(self):
- """Test if page url exist."""
- category = self.env.ref('document_page.demo_category1')
- category.approval_required = True
- pages = self.env['document.page.history'].search([
- ('page_id', '=', category.id)
- ])
- page = pages[0]
- _logger.info("Page: " + str(page.get_page_url))
- self.assertIsNotNone(page.get_page_url)
diff --git a/document_page_approval/views/document_page_approval.xml b/document_page_approval/views/document_page_approval.xml
index 6b0e5c91151..a1ec792d046 100644
--- a/document_page_approval/views/document_page_approval.xml
+++ b/document_page_approval/views/document_page_approval.xml
@@ -3,56 +3,104 @@
document.page.history.form
document.page.history
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {'readonly': [('state', 'not in', ['draft'])]}
+
+
+
+
+
+
+
document.page.form
document.page
-
+
-
-
-
-
-
+
+
+
+ This document has Changes Pending Approval . You are viewing the last approved content.
+
+
+ This document requires approval. If edited, you will create a new Change Request .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/document_page_approval/workflows/document_page_approval.xml b/document_page_approval/workflows/document_page_approval.xml
index ea8a254b5b9..81a5ba85d3d 100644
--- a/document_page_approval/workflows/document_page_approval.xml
+++ b/document_page_approval/workflows/document_page_approval.xml
@@ -6,33 +6,98 @@
True
+
+
+ True
+ draft
+ function
+ page_approval_draft()
+
+
+
+
+ to approve
+ function
+ page_approval_to_approve()
+
+
-
+
approved
function
page_approval_approved()
True
-
-
- True
- draft
+
+
+ cancelled
function
- page_approval_draft()
+ page_approval_cancelled()
+
+
+
+
+
+
+ am_i_owner
+ page_approval_to_approve
-
-
+
+
+ am_i_approver
+ page_approval_approve
+
+
+
+
+
+ am_i_approver
page_approval_approve
-
-
+
+
+ am_i_approver
edit
+
+
+
+
+ am_i_owner
+ page_approval_cancel
+
+
+
+
+
+ am_i_owner or am_i_approver
+ page_approval_cancel
+
+
+
+
+
+ am_i_owner or am_i_approver
+ page_approval_reopen
+
+
+
+
+
+
+ not is_approval_required
+ document_page_auto_confirm
+
+
+
+
+
+ is_approval_required
+ document_page_auto_confirm
+
From 6da6d85ad7e56f11f70dba9d5c87c1ecabb452a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20Todorovich?=
Date: Mon, 19 Feb 2018 15:54:48 -0300
Subject: [PATCH 2/5] [IMP] Add QWeb report to print document pages
---
document_page/__openerp__.py | 1 +
document_page/views/report_document_page.xml | 34 ++++++++++++++++++++
2 files changed, 35 insertions(+)
create mode 100755 document_page/views/report_document_page.xml
diff --git a/document_page/__openerp__.py b/document_page/__openerp__.py
index e445d881785..2b5323b70e2 100644
--- a/document_page/__openerp__.py
+++ b/document_page/__openerp__.py
@@ -38,6 +38,7 @@
'wizard/document_page_show_diff.xml',
'views/document_page.xml',
'views/document_page_assets.xml',
+ 'views/report_document_page.xml',
'security/document_page_security.xml',
'security/ir.model.access.csv',
],
diff --git a/document_page/views/report_document_page.xml b/document_page/views/report_document_page.xml
new file mode 100755
index 00000000000..6882e7deb28
--- /dev/null
+++ b/document_page/views/report_document_page.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 2b4327751ff9d5290d97d4ac61db678578768e92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20Todorovich?=
Date: Thu, 1 Mar 2018 00:08:24 -0300
Subject: [PATCH 3/5] Categories don't save content
---
document_page/models/document_page.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/document_page/models/document_page.py b/document_page/models/document_page.py
index 94db69d51b2..9b2a6ad5b95 100644
--- a/document_page/models/document_page.py
+++ b/document_page/models/document_page.py
@@ -153,10 +153,10 @@ def _compute_content(self):
@api.multi
def _inverse_content(self):
for rec in self:
- if rec.content:
+ if rec.type == 'content':
rec._create_history({
'content': rec.content,
- 'summary': rec.summary
+ 'summary': rec.summary,
})
@api.multi
From dbeec6ef0f76f629bdf2d96c469c2fa4d25f20c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20Todorovich?=
Date: Thu, 1 Mar 2018 11:45:45 -0300
Subject: [PATCH 4/5] FIX Last Contributor (uid and date). Use related fields
instead of computed where possible.
Fix search views, store some fields to make them searchable, added filters
---
document_page/__openerp__.py | 2 +
document_page/models/document_page.py | 56 +++--
document_page/models/document_page_history.py | 1 -
document_page/views/document_page.xml | 208 +++---------------
.../views/document_page_category.xml | 90 ++++++++
document_page/views/document_page_history.xml | 90 ++++++++
.../models/document_page_approval.py | 51 +++--
.../models/document_page_history_workflow.py | 40 ++--
.../views/document_page_approval.xml | 32 ++-
9 files changed, 319 insertions(+), 251 deletions(-)
create mode 100755 document_page/views/document_page_category.xml
create mode 100755 document_page/views/document_page_history.xml
diff --git a/document_page/__openerp__.py b/document_page/__openerp__.py
index 2b5323b70e2..a358f00a910 100644
--- a/document_page/__openerp__.py
+++ b/document_page/__openerp__.py
@@ -37,6 +37,8 @@
'wizard/document_page_create_menu.xml',
'wizard/document_page_show_diff.xml',
'views/document_page.xml',
+ 'views/document_page_category.xml',
+ 'views/document_page_history.xml',
'views/document_page_assets.xml',
'views/report_document_page.xml',
'security/document_page_security.xml',
diff --git a/document_page/models/document_page.py b/document_page/models/document_page.py
index 9b2a6ad5b95..1d8d63fe670 100644
--- a/document_page/models/document_page.py
+++ b/document_page/models/document_page.py
@@ -55,6 +55,7 @@ class DocumentPage(models.Model):
"Content",
compute='_compute_content',
inverse='_inverse_content',
+ search='_search_content',
required=True,
)
@@ -78,12 +79,20 @@ class DocumentPage(models.Model):
compute='_compute_display_content'
)
+ history_head = fields.Many2one(
+ 'document.page.history',
+ 'HEAD',
+ compute='_compute_history_head',
+ store=True,
+ auto_join=True,
+ )
+
history_ids = fields.One2many(
'document.page.history',
'page_id',
'History',
order='create_date DESC',
- readonly=True
+ readonly=True,
)
menu_id = fields.Many2one(
@@ -92,29 +101,21 @@ class DocumentPage(models.Model):
readonly=True
)
- create_date = fields.Datetime(
- "Created on",
- index=True,
- readonly=True
- )
-
- create_uid = fields.Many2one(
- 'res.users',
- 'Author',
+ content_date = fields.Datetime(
+ 'Last Contribution Date',
+ related='history_head.create_date',
+ store=True,
index=True,
- readonly=True
+ readonly=True,
)
- write_date = fields.Datetime(
- "Modification Date",
- index=True,
- readonly=True)
-
- write_uid = fields.Many2one(
+ content_uid = fields.Many2one(
'res.users',
- "Last Contributor",
+ 'Last Contributor',
+ related='history_head.create_uid',
+ store=True,
index=True,
- readonly=True
+ readonly=True,
)
@api.multi
@@ -133,19 +134,21 @@ def _get_page_index(self, link=True):
return r
@api.multi
+ @api.depends('content')
def _compute_display_content(self):
# @deprecated, simply use content
for rec in self:
rec.display_content = rec.content
@api.multi
+ @api.depends('history_head', 'history_ids')
def _compute_content(self):
for rec in self:
if rec.type == 'category':
rec.content = rec._get_page_index(link=False)
else:
- if rec.history_ids:
- rec.content = rec.history_ids[0].content
+ if rec.history_head:
+ rec.content = rec.history_head.content
else:
# html widget's default, so it doesn't trigger ghost save
rec.content = '
'
@@ -159,6 +162,17 @@ def _inverse_content(self):
'summary': rec.summary,
})
+ @api.multi
+ def _search_content(self, operator, value):
+ return [('history_head.content', operator, value)]
+
+ @api.multi
+ @api.depends('history_ids')
+ def _compute_history_head(self):
+ for rec in self:
+ if rec.history_ids:
+ rec.history_head = rec.history_ids[0]
+
@api.multi
def _create_history(self, vals):
self.ensure_one()
diff --git a/document_page/models/document_page_history.py b/document_page/models/document_page_history.py
index 30fc861d721..5ce1dd49645 100644
--- a/document_page/models/document_page_history.py
+++ b/document_page/models/document_page_history.py
@@ -28,7 +28,6 @@ class DocumentPageHistory(models.Model):
_name = "document.page.history"
_description = "Document Page History"
_order = 'id DESC'
- _rec_name = "create_date"
page_id = fields.Many2one('document.page', 'Page', ondelete='cascade')
summary = fields.Char('Summary', index=True)
diff --git a/document_page/views/document_page.xml b/document_page/views/document_page.xml
index 22fbfe2e527..deb2810e2db 100644
--- a/document_page/views/document_page.xml
+++ b/document_page/views/document_page.xml
@@ -1,10 +1,7 @@
-
+
@@ -15,8 +12,8 @@
-
-
+
+
@@ -30,8 +27,8 @@
-
-
+
+
@@ -50,8 +47,8 @@
-
-
+
+
@@ -59,8 +56,8 @@
-
-
+
+
@@ -89,7 +86,7 @@
@@ -100,72 +97,19 @@
document.page
-
-
+
+
+
-
+
-
+
-
-
- document.page.category.form
- document.page
-
-
-
-
-
-
- document.page.category.tree
- document.page
-
-
-
-
-
-
-
-
-
-
@@ -183,135 +127,35 @@
+
tree
+
form
-
-
-
- Category
- document.page
- [('type','=','category')]
- {'default_type': 'category'}
- form
- tree,form
-
-
-
-
-
- tree
-
-
-
-
-
- form
-
-
-
-
-
-
- document.page.history.tree
- document.page.history
-
-
-
-
-
-
-
-
-
-
-
-
- document.page.history.search
- document.page.history
-
-
-
-
-
-
-
-
-
-
-
-
-
- document.page.history.form
- document.page.history
-
-
-
-
+
-
-
- Page history
- document.page.history
- form
- tree,form
-
-
+
-
-
+
-
+
@@ -94,6 +97,7 @@
+
+
document.page.category.form
document.page
@@ -121,6 +126,7 @@
+
document.page.history.tree
document.page.history
@@ -149,6 +155,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -162,9 +180,9 @@
+ name="Change Requests"
+ parent="document_page.menu_wiki"
+ action="action_change_requests"
+ sequence="25"
+ groups="document_page.group_document_editor" />
From a125c0bf5d2729269baae5d515bfb49afba9bc92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Iv=C3=A1n=20Todorovich?=
Date: Thu, 12 Apr 2018 19:05:49 -0300
Subject: [PATCH 5/5] Add api.depends on computed diff
---
document_page/models/document_page_history.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/document_page/models/document_page_history.py b/document_page/models/document_page_history.py
index 5ce1dd49645..71535701e3d 100644
--- a/document_page/models/document_page_history.py
+++ b/document_page/models/document_page_history.py
@@ -35,6 +35,7 @@ class DocumentPageHistory(models.Model):
diff = fields.Text(compute='_compute_diff')
@api.multi
+ @api.depends('content', 'page_id.history_ids')
def _compute_diff(self):
"""Shows a diff between this version and the previous version"""
history = self.env['document.page.history']