mirror of
https://github.com/OCA/knowledge.git
synced 2025-07-17 12:42:56 -06:00
[IMP][10.0][document_page_approval] Change Requests and workflow improvements on documents (#155)
This commit is contained in:
parent
6f8fe0a8cf
commit
ae6e3be82a
@ -58,6 +58,7 @@ Contributors
|
|||||||
* Savoir-faire Linux <support@savoirfairelinux.com>
|
* Savoir-faire Linux <support@savoirfairelinux.com>
|
||||||
* Gervais Naoussi <gervaisnaoussi@gmail.com>
|
* Gervais Naoussi <gervaisnaoussi@gmail.com>
|
||||||
* Maxime Chambreuil <mchambreuil@opensourceintegrators.com>
|
* Maxime Chambreuil <mchambreuil@opensourceintegrators.com>
|
||||||
|
* Iván Todorovich <ivan.todorovich@gmail.com>
|
||||||
|
|
||||||
Maintainer
|
Maintainer
|
||||||
----------
|
----------
|
||||||
|
@ -3,3 +3,4 @@
|
|||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
|
from .hooks import post_init_hook, uninstall_hook
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Document Page Approval',
|
'name': 'Document Page Approval',
|
||||||
'version': '10.0.1.1.0',
|
'version': '10.0.2.0.0',
|
||||||
"author": "Savoir-faire Linux, Odoo Community Association (OCA)",
|
"author": "Savoir-faire Linux, Odoo Community Association (OCA)",
|
||||||
"website": "http://www.savoirfairelinux.com",
|
"website": "http://www.savoirfairelinux.com",
|
||||||
"license": "AGPL-3",
|
"license": "AGPL-3",
|
||||||
@ -25,4 +25,6 @@
|
|||||||
'images/page_history_list.png',
|
'images/page_history_list.png',
|
||||||
'images/page_history.png',
|
'images/page_history.png',
|
||||||
],
|
],
|
||||||
|
'post_init_hook': 'post_init_hook',
|
||||||
|
'uninstall_hook': 'uninstall_hook',
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<odoo noupdate="1">
|
<odoo>
|
||||||
|
|
||||||
<!-- Allow user to make upgrade-proof customizations to email template -->
|
<!-- If user wants to make upgrade-proof customizations to email templates, he should edit ir.model.data and check noupdate himself -->
|
||||||
<record id="email_template_new_draft_need_approval" model="mail.template">
|
<record id="email_template_new_draft_need_approval" model="mail.template">
|
||||||
<field name="name">Automated new draft need approval Notification Mail</field>
|
<field name="name">Automated new draft need approval Notification Mail</field>
|
||||||
<field name="email_from">${object.create_uid.company_id.email or 'noreply@localhost.com'}</field>
|
<field name="email_from">${object.create_uid.company_id.email or 'noreply@localhost.com'}</field>
|
||||||
<field name="subject">New version of "${object.page_id.name}" to approve</field>
|
<field name="subject">New version of ${object.display_name} needs your approval</field>
|
||||||
<field name="email_to">${object.get_approvers_email}</field>
|
|
||||||
<field name="model_id" ref="model_document_page_history"/>
|
<field name="model_id" ref="model_document_page_history"/>
|
||||||
<field name="auto_delete" eval="True"/>
|
<field name="auto_delete" eval="True"/>
|
||||||
<field name="lang">${object.create_uid.partner_id.lang}</field>
|
<field name="lang">${object.create_uid.partner_id.lang}</field>
|
||||||
@ -14,13 +13,30 @@
|
|||||||
<![CDATA[
|
<![CDATA[
|
||||||
<p>Hello,</p>
|
<p>Hello,</p>
|
||||||
|
|
||||||
<p>The page "${object.page_id.name}" has been modified and need your approval.</p>
|
<p>${object.create_uid.name} submited a new Change Request for <b>${object.page_id.name}</b> and it needs your approval.</p>
|
||||||
|
|
||||||
<p>You can review the new version here : <a href="${object.get_page_url}">${object.get_page_url}</a></p>
|
<h1><a href="${object.page_url}">${object.display_name}</a></h1>
|
||||||
|
<p>
|
||||||
|
<b>Modified by:</b> ${object.create_uid.name}<br/>
|
||||||
|
<b>Date:</b> ${object.create_date}<br>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
% if object.summary:
|
||||||
|
<h3>Summary</h3>
|
||||||
|
<p>${object.summary}</p>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
<h3>Diff</h3>
|
||||||
|
<div style="overflow-x:scroll; font-size:0.85em; margin-bottom:2em;">
|
||||||
|
${object.diff|safe}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>Have a great day.</p>
|
||||||
|
|
||||||
<p>Have a great day.<br/>
|
|
||||||
--<br/>
|
--<br/>
|
||||||
Odoo</p>]]>
|
|
||||||
|
<p>Odoo</p>
|
||||||
|
]]>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
22
document_page_approval/hooks.py
Normal file
22
document_page_approval/hooks.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2018 Ivan Todorovich (<ivan.todorovich@gmail.com>)
|
||||||
|
# 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'"
|
||||||
|
)
|
@ -0,0 +1,14 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2018 Ivan Todorovich <ivan.todorovich@gmail.com>
|
||||||
|
# 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
|
||||||
|
""")
|
@ -2,7 +2,9 @@
|
|||||||
# Copyright (C) 2013 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
|
# Copyright (C) 2013 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from openerp import api, fields, models
|
|
||||||
|
from odoo import api, fields, models
|
||||||
|
from ast import literal_eval
|
||||||
|
|
||||||
|
|
||||||
class DocumentPageApproval(models.Model):
|
class DocumentPageApproval(models.Model):
|
||||||
@ -10,104 +12,126 @@ class DocumentPageApproval(models.Model):
|
|||||||
|
|
||||||
_inherit = 'document.page'
|
_inherit = 'document.page'
|
||||||
|
|
||||||
@api.multi
|
history_ids = fields.One2many(
|
||||||
def _get_display_content(self):
|
order='approved_date DESC',
|
||||||
"""Display the content of document."""
|
domain=[('state', '=', 'approved')],
|
||||||
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 requires approval base on his parent."""
|
|
||||||
for page in self:
|
|
||||||
page.is_parent_approval_required = self.is_approval_required(page)
|
|
||||||
|
|
||||||
def is_approval_required(self, page):
|
|
||||||
"""Check if a document requires 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'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
approved_date = fields.Datetime(
|
approved_date = fields.Datetime(
|
||||||
compute=_get_approved_date,
|
'Approved Date',
|
||||||
string="Approved Date"
|
related='history_head.approved_date',
|
||||||
|
store=True,
|
||||||
|
index=True,
|
||||||
|
readonly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
approved_uid = fields.Many2one(
|
approved_uid = fields.Many2one(
|
||||||
'res.users',
|
'res.users',
|
||||||
compute=_get_approved_uid,
|
'Approved by',
|
||||||
string="Approved By",
|
related='history_head.approved_uid',
|
||||||
|
store=True,
|
||||||
|
index=True,
|
||||||
|
readonly=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
approval_required = fields.Boolean("Require approval")
|
approval_required = fields.Boolean(
|
||||||
|
'Require approval',
|
||||||
is_parent_approval_required = fields.Boolean(
|
help='Require approval for changes on this page or its child pages.',
|
||||||
compute=_is_parent_approval_required,
|
|
||||||
string="parent approval"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
approver_gid = fields.Many2one(
|
approver_gid = fields.Many2one(
|
||||||
"res.groups",
|
"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',
|
||||||
|
)
|
||||||
|
|
||||||
|
am_i_approver = fields.Boolean(
|
||||||
|
compute='_compute_am_i_approver'
|
||||||
|
)
|
||||||
|
|
||||||
|
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('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
|
||||||
|
@api.depends('is_approval_required', 'approver_group_ids')
|
||||||
|
def _compute_am_i_approver(self):
|
||||||
|
"""Check if the current user can approve changes to this page."""
|
||||||
|
for rec in self:
|
||||||
|
rec.am_i_approver = rec.can_user_approve_this_page(self.env.user)
|
||||||
|
|
||||||
|
@api.multi
|
||||||
|
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.approver_group_ids:
|
||||||
|
return True
|
||||||
|
return len(user.groups_id & self.approver_group_ids) > 0
|
||||||
|
|
||||||
|
@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
|
||||||
|
@ -11,117 +11,122 @@ from odoo import api, fields, models
|
|||||||
class DocumentPageHistoryWorkflow(models.Model):
|
class DocumentPageHistoryWorkflow(models.Model):
|
||||||
"""Useful to manage edition's workflow on a document."""
|
"""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(
|
||||||
|
related='page_id.am_i_approver'
|
||||||
|
)
|
||||||
|
|
||||||
|
page_url = fields.Text(
|
||||||
|
compute='_compute_page_url',
|
||||||
|
string="URL",
|
||||||
|
)
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def page_approval_draft(self):
|
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'})
|
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(
|
template = self.env.ref(
|
||||||
'document_page_approval.email_template_new_draft_need_approval')
|
'document_page_approval.email_template_new_draft_need_approval')
|
||||||
for page in self:
|
approver_gid = self.env.ref(
|
||||||
if page.is_parent_approval_required:
|
'document_page_approval.group_document_approver_user')
|
||||||
template.send_mail(page.id, force_send=True)
|
for rec in self:
|
||||||
return True
|
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
|
@api.multi
|
||||||
def page_approval_approved(self):
|
def page_approval_approved(self):
|
||||||
"""Set a document state as approve."""
|
"""Set a change request as approved."""
|
||||||
message_obj = self.env['mail.message']
|
|
||||||
self.write({
|
self.write({
|
||||||
'state': 'approved',
|
'state': 'approved',
|
||||||
'approved_date': datetime.now().strftime(
|
'approved_date': datetime.now().strftime(
|
||||||
DEFAULT_SERVER_DATETIME_FORMAT),
|
DEFAULT_SERVER_DATETIME_FORMAT),
|
||||||
'approved_uid': self.env.uid
|
'approved_uid': self.env.uid
|
||||||
})
|
})
|
||||||
# Notify followers a new version is available
|
for rec in self:
|
||||||
for page_history in self:
|
# Trigger computed field update
|
||||||
subtype = self.env.ref('mail.mt_comment')
|
rec.page_id._compute_history_head()
|
||||||
message_obj.create(
|
# Notify state change
|
||||||
{'res_id': page_history.page_id.id,
|
rec.message_post(
|
||||||
'model': 'document.page',
|
subtype='mt_comment',
|
||||||
'subtype_id': subtype.id,
|
body=_(
|
||||||
'body': _('New version of the document %s'
|
'Change request has been approved by %s.'
|
||||||
' approved.') % page_history.page_id.name
|
) % (self.env.user.name)
|
||||||
}
|
|
||||||
)
|
)
|
||||||
return True
|
# Notify followers a new version is available
|
||||||
|
rec.page_id.message_post(
|
||||||
@api.multi
|
subtype='mt_comment',
|
||||||
def _can_user_approve_page(self):
|
body=_(
|
||||||
"""Check if a user cas approve the page."""
|
'New version of the document %s approved.'
|
||||||
user = self.env.user
|
) % (rec.page_id.name)
|
||||||
for page in self:
|
|
||||||
page.can_user_approve_page = page.can_user_approve_this_page(
|
|
||||||
page.page_id,
|
|
||||||
user
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def can_user_approve_this_page(self, page, user):
|
@api.multi
|
||||||
"""Check if a user can approved the page."""
|
def page_approval_cancelled(self):
|
||||||
if page:
|
"""Set a change request as cancelled."""
|
||||||
res = page.approver_gid in user.groups_id
|
self.write({'state': 'cancelled'})
|
||||||
res = res or self.can_user_approve_this_page(page.parent_id, user)
|
for rec in self:
|
||||||
else:
|
rec.message_post(
|
||||||
res = False
|
subtype='mt_comment',
|
||||||
return res
|
body=_(
|
||||||
|
'Change request <b>%s</b> has been cancelled by %s.'
|
||||||
|
) % (rec.display_name, self.env.user.name)
|
||||||
|
)
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def get_approvers_guids(self):
|
def _compute_am_i_owner(self):
|
||||||
"""Return the approvers group."""
|
"""Check if current user is the owner"""
|
||||||
res = {}
|
for rec in self:
|
||||||
for page in self:
|
rec.am_i_owner = (rec.create_uid == self.env.user)
|
||||||
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 = []
|
|
||||||
|
|
||||||
return res
|
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def _get_approvers_email(self):
|
def _compute_page_url(self):
|
||||||
"""Get the approvers email."""
|
"""Compute the page url."""
|
||||||
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]
|
|
||||||
|
|
||||||
@api.multi
|
|
||||||
def _get_page_url(self):
|
|
||||||
"""Get the page url."""
|
|
||||||
for page in self:
|
for page in self:
|
||||||
base_url = self.env['ir.config_parameter'].get_param(
|
base_url = self.env['ir.config_parameter'].get_param(
|
||||||
'web.base.url',
|
'web.base.url',
|
||||||
default='http://localhost:8069'
|
default='http://localhost:8069'
|
||||||
)
|
)
|
||||||
|
|
||||||
page.get_page_url = (
|
page.page_url = (
|
||||||
'{}/web#db={}&id={}&view_type=form&'
|
'{}/web#db={}&id={}&view_type=form&'
|
||||||
'model=document.page.history').format(
|
'model=document.page.history').format(
|
||||||
base_url,
|
base_url,
|
||||||
@ -129,37 +134,18 @@ class DocumentPageHistoryWorkflow(models.Model):
|
|||||||
page.id
|
page.id
|
||||||
)
|
)
|
||||||
|
|
||||||
state = fields.Selection(
|
@api.multi
|
||||||
[('draft', 'Draft'), ('approved', 'Approved')],
|
def _compute_diff(self):
|
||||||
'Status',
|
"""Shows a diff between this version and the previous version"""
|
||||||
readonly=True
|
history = self.env['document.page.history']
|
||||||
)
|
for rec in self:
|
||||||
|
domain = [
|
||||||
approved_date = fields.Datetime("Approved Date")
|
('page_id', '=', rec.page_id.id),
|
||||||
|
('state', '=', 'approved')]
|
||||||
approved_uid = fields.Many2one(
|
if rec.approved_date:
|
||||||
'res.users',
|
domain.append(('approved_date', '<', rec.approved_date))
|
||||||
"Approved By"
|
prev = history.search(domain, limit=1, order='approved_date DESC')
|
||||||
)
|
if prev:
|
||||||
|
rec.diff = self.getDiff(prev.id, rec.id)
|
||||||
is_parent_approval_required = fields.Boolean(
|
else:
|
||||||
related='page_id.is_parent_approval_required',
|
rec.diff = self.getDiff(False, rec.id)
|
||||||
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
|
|
||||||
)
|
|
||||||
|
@ -2,8 +2,13 @@
|
|||||||
<odoo>
|
<odoo>
|
||||||
|
|
||||||
<record id="group_document_approver_user" model="res.groups">
|
<record id="group_document_approver_user" model="res.groups">
|
||||||
<field name="name">Document approver</field>
|
<field name="name">Approver</field>
|
||||||
<field name="users" eval="[(4, ref('base.user_root'))]"/>
|
<field name="category_id" ref="knowledge.module_category_knowledge"/>
|
||||||
|
<field name="implied_ids" eval="[(4, ref('document_page.group_document_editor'))]"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="document_page.group_document_manager" model="res.groups">
|
||||||
|
<field name="implied_ids" eval="[(4, ref('group_document_approver_user'))]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
@ -1,2 +1 @@
|
|||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
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
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from . import test_document_page_approval, test_document_page_history_workflow
|
from . import test_document_page_approval
|
||||||
|
@ -1,37 +1,125 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from openerp.tests import common
|
from odoo.tests import common
|
||||||
|
|
||||||
|
|
||||||
class TestDocumentPageApproval(common.TransactionCase):
|
class TestDocumentPageApproval(common.TransactionCase):
|
||||||
"""Test document page approval model."""
|
|
||||||
|
|
||||||
def test_get_display_content(self):
|
def setUp(self):
|
||||||
"""Test page display content."""
|
super(TestDocumentPageApproval, self).setUp()
|
||||||
# Check content of a category
|
self.page_obj = self.env['document.page']
|
||||||
category = self.env['document.page'].search([
|
self.history_obj = self.env['document.page.history']
|
||||||
('name', '=', 'OpenERP Features')
|
# 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
|
def test_change_request_approve(self):
|
||||||
pages = self.env['document.page'].search([
|
page = self.page2
|
||||||
('parent_id', '=', category.id)
|
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')
|
||||||
|
|
||||||
|
def test_change_request_from_scratch(self):
|
||||||
|
page = self.page2
|
||||||
|
|
||||||
|
# aprove everything
|
||||||
|
self.history_obj.search([
|
||||||
|
('page_id', '=', page.id),
|
||||||
|
('state', '!=', 'approved')
|
||||||
|
]).signal_workflow('page_approval_approve')
|
||||||
|
|
||||||
|
# new change request from scrath
|
||||||
|
chreq = self.history_obj.create({
|
||||||
|
'page_id': page.id,
|
||||||
|
'summary': 'Changed something',
|
||||||
|
'content': 'New content',
|
||||||
|
})
|
||||||
|
|
||||||
|
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_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]
|
page = pages[0]
|
||||||
self.assertIsNotNone(page.display_content, 'Page content')
|
self.assertIsNotNone(page.page_url)
|
||||||
|
|
||||||
# Check if approval is required
|
|
||||||
self.assertTrue(page.is_approval_required(page) ==
|
|
||||||
category.approval_required)
|
|
||||||
|
|
||||||
# Check content of an approval page
|
|
||||||
page.approval_required = True
|
|
||||||
|
|
||||||
self.assertIsNotNone(page.display_content, 'Page content')
|
|
||||||
|
|
||||||
# Check if approval is required
|
|
||||||
self.assertTrue(page.is_approval_required(page))
|
|
||||||
|
|
||||||
# Check if parent approval is required
|
|
||||||
self.assertTrue(page.is_parent_approval_required)
|
|
||||||
|
@ -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)
|
|
@ -1,92 +1,189 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<odoo>
|
<odoo>
|
||||||
|
|
||||||
<record id="wiki_history_form_inherit" model="ir.ui.view">
|
<!-- History Form View -->
|
||||||
<field name="name">document.page.history.form</field>
|
<record id="wiki_history_form_inherit" model="ir.ui.view">
|
||||||
<field name="model">document.page.history</field>
|
<field name="name">document.page.history.form</field>
|
||||||
<field name="inherit_id"
|
<field name="model">document.page.history</field>
|
||||||
ref="document_page.wiki_history_form"/>
|
<field name="inherit_id" ref="document_page.wiki_history_form"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//form/label[@for='page_id']"
|
<sheet position="before">
|
||||||
position="before">
|
<header>
|
||||||
<header attrs="{'invisible':[('is_parent_approval_required','=',False)]}">
|
<!-- draft -> to approve -->
|
||||||
<button name="page_approval_approve"
|
<button name="page_approval_to_approve" string="Send to Review" class="oe_highlight"
|
||||||
string="Approve"
|
attrs="{'invisible':['|','|',('is_approval_required','=',False),('am_i_owner','=',False),('state', 'not in', ['draft'])]}"/>
|
||||||
states="draft"
|
<!-- approve if i am approver -->
|
||||||
class="btn-primary"
|
<button name="page_approval_approve" string="Approve" class="oe_highlight"
|
||||||
attrs="{'invisible':[('can_user_approve_page','=',False)]}"/>
|
attrs="{'invisible':['|','|',('is_approval_required','=',False),('am_i_approver','=',False),('state','not in',['draft','to approve'])]}"/>
|
||||||
<field name="state"
|
<!-- approve if it's not required and i am owner -->
|
||||||
widget="statusbar"
|
<button name="page_approval_approve" string="Approve" class="oe_highlight"
|
||||||
statusbar_visible="draft,approved"/>
|
attrs="{'invisible':['|','|',('is_approval_required','=',True),('am_i_owner','=',False),('state','not in',['draft', 'to approve'])]}"/>
|
||||||
<field name="is_parent_approval_required"
|
<!-- cancel if i am owner or approver -->
|
||||||
invisible="1" />
|
<button name="page_approval_cancel" string="Cancel"
|
||||||
<field name="can_user_approve_page"
|
attrs="{'invisible':['|','&',('am_i_owner','=',False),('am_i_approver','=',False),('state','not in',['draft','to approve'])]}"/>
|
||||||
invisible="1" />
|
<!-- reopen if i am owner or approver -->
|
||||||
</header>
|
<button name="page_approval_reopen" string="Back to draft"
|
||||||
</xpath>
|
attrs="{'invisible':['|','&',('am_i_owner','=',False),('am_i_approver','=',False),('state','not in',['cancelled'])]}"/>
|
||||||
|
<field name="am_i_owner" invisible="1"/>
|
||||||
|
<field name="am_i_approver" invisible="1"/>
|
||||||
|
<field name="is_approval_required" invisible="1"/>
|
||||||
|
<field name="state" widget="statusbar" statusbar_visible="draft,approved" />
|
||||||
|
</header>
|
||||||
|
</sheet>
|
||||||
|
<xpath expr="//field[@name='create_uid']/parent::group" position="after">
|
||||||
|
<group>
|
||||||
|
<field name="approved_uid" readonly="1" attrs="{'invisible':[('state','not in',['approved'])]}"/>
|
||||||
|
<field name="approved_date" readonly="1" attrs="{'invisible':[('state','not in',['approved'])]}"/>
|
||||||
|
</group>
|
||||||
|
</xpath>
|
||||||
|
<field name="content" position="attributes">
|
||||||
|
<attribute name="attrs">{'readonly': [('state', 'not in', ['draft'])]}</attribute>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
<sheet position="after">
|
||||||
|
<div class="oe_chatter">
|
||||||
|
<field name="message_follower_ids" widget="mail_followers"/>
|
||||||
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
|
</div>
|
||||||
|
</sheet>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
<record id="wiki_form_inherit" model="ir.ui.view">
|
<!-- Page Form View -->
|
||||||
<field name="name">document.page.form</field>
|
<record id="wiki_form_inherit" model="ir.ui.view">
|
||||||
<field name="model">document.page</field>
|
<field name="name">document.page.form</field>
|
||||||
<field name="inherit_id"
|
<field name="model">document.page</field>
|
||||||
ref="document_page.view_wiki_form" />
|
<field name="inherit_id" ref="document_page.view_wiki_form" />
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<field name="display_content"
|
|
||||||
position="before">
|
|
||||||
<group class="oe_read_only">
|
|
||||||
<field name="approved_date" />
|
|
||||||
<field name="approved_uid" />
|
|
||||||
</group>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="view_wiki_menu_form_inherit" model="ir.ui.view">
|
<sheet position="before">
|
||||||
<field name="name">document.page.form</field>
|
<div class="alert alert-info" role="alert" style="margin-bottom:0px;"
|
||||||
<field name="model">document.page</field>
|
attrs="{'invisible': [('has_changes_pending_approval','=',False)]}">
|
||||||
<field name="inherit_id"
|
This document has <b>Changes Pending Approval</b>. You are viewing the last approved content.
|
||||||
ref="document_page.view_wiki_menu_form" />
|
</div>
|
||||||
<field name="arch" type="xml">
|
<div class="alert alert-warning oe_edit_only" role="alert" style="margin-bottom:0px;"
|
||||||
<field name="display_content"
|
attrs="{'invisible': [('is_approval_required','=',False)]}">
|
||||||
position="before">
|
This document requires approval. If edited, you will create a new <b>Change Request</b>.
|
||||||
<group class="oe_read_only"
|
</div>
|
||||||
attrs="{'invisible':[('type','!=','content')]}">
|
<field name="is_approval_required" invisible="1"/>
|
||||||
<field name="approved_date" />
|
<field name="has_changes_pending_approval" invisible="1"/>
|
||||||
<field name="approved_uid" />
|
</sheet>
|
||||||
</group>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="view_category_form_inherit" model="ir.ui.view">
|
<field name="type" position="before">
|
||||||
<field name="name">document.page.category.form</field>
|
<div class="oe_button_box" name="button_box">
|
||||||
<field name="model">document.page</field>
|
<button class="oe_stat_button" name="action_changes_pending_approval"
|
||||||
<field name="inherit_id"
|
string="Change Requests" type="object"
|
||||||
ref="document_page.view_category_form" />
|
attrs="{'invisible':[('has_changes_pending_approval','=',False)]}" icon="fa-edit"/>
|
||||||
<field name="arch" type="xml">
|
</div>
|
||||||
<field name="parent_id" position="after">
|
|
||||||
<field name="approval_required"/>
|
|
||||||
<field name="approver_gid"
|
|
||||||
attrs="{'invisible':[('approval_required','!=', True)], 'required':[('approval_required','=', True)]}"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
</field>
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="view_wiki_history_tree_inherit" model="ir.ui.view">
|
<field name="content_uid" position="after">
|
||||||
<field name="name">document.page.history.tree</field>
|
<field name="approved_uid"/>
|
||||||
<field name="model">document.page.history</field>
|
|
||||||
<field name="inherit_id"
|
|
||||||
ref="document_page.view_wiki_history_tree" />
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="page_id" position="after">
|
|
||||||
<field name="state"
|
|
||||||
attrs="{'invisible':[('is_parent_approval_required','=',False)]}"/>
|
|
||||||
<field name="is_parent_approval_required"
|
|
||||||
invisible="1" />
|
|
||||||
</field>
|
|
||||||
</field>
|
</field>
|
||||||
</record>
|
|
||||||
|
<field name="content_date" position="replace">
|
||||||
|
<field name="approved_date"/>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
<field name="history_ids" position="inside">
|
||||||
|
<tree>
|
||||||
|
<field name="id"/>
|
||||||
|
<field name="approved_date"/>
|
||||||
|
<field name="summary"/>
|
||||||
|
<field name="create_uid"/>
|
||||||
|
<field name="approved_uid"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Page Menu Form View -->
|
||||||
|
<record id="view_wiki_menu_form_inherit" model="ir.ui.view">
|
||||||
|
<field name="name">document.page.form</field>
|
||||||
|
<field name="model">document.page</field>
|
||||||
|
<field name="inherit_id" ref="document_page.view_wiki_menu_form" />
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<field name="content" position="before">
|
||||||
|
<group class="oe_read_only" attrs="{'invisible':[('type','!=','content')]}">
|
||||||
|
<field name="approved_date" />
|
||||||
|
<field name="approved_uid" />
|
||||||
|
</group>
|
||||||
|
</field>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Catgory Form View -->
|
||||||
|
<record id="view_category_form_inherit" model="ir.ui.view">
|
||||||
|
<field name="name">document.page.category.form</field>
|
||||||
|
<field name="model">document.page</field>
|
||||||
|
<field name="inherit_id" ref="document_page.view_category_form" />
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<field name="parent_id" position="after">
|
||||||
|
<field name="approval_required"/>
|
||||||
|
<field name="approver_gid"
|
||||||
|
attrs="{'invisible':[('approval_required','!=', True)], 'required':[('approval_required','=', True)]}"/>
|
||||||
|
</field>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- History Tree view -->
|
||||||
|
<record id="view_wiki_history_tree_inherit" model="ir.ui.view">
|
||||||
|
<field name="name">document.page.history.tree</field>
|
||||||
|
<field name="model">document.page.history</field>
|
||||||
|
<field name="inherit_id" ref="document_page.view_wiki_history_tree"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree position="attributes">
|
||||||
|
<attribute name="decoration-info">state=='draft'</attribute>
|
||||||
|
<attribute name="decoration-primary">state=='to approve'</attribute>
|
||||||
|
<attribute name="decoration-muted">state=='cancelled'</attribute>
|
||||||
|
</tree>
|
||||||
|
<tree position="inside">
|
||||||
|
<field name="state"/>
|
||||||
|
<field name="approved_uid"/>
|
||||||
|
<field name="approved_date"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- History Search view -->
|
||||||
|
<record id="view_wiki_history_filter" model="ir.ui.view">
|
||||||
|
<field name="name">document.page.history.search</field>
|
||||||
|
<field name="model">document.page.history</field>
|
||||||
|
<field name="inherit_id" ref="document_page.view_wiki_history_filter"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<field name="page_id" position="before">
|
||||||
|
<field name="state"/>
|
||||||
|
</field>
|
||||||
|
<field name="create_uid" position="after">
|
||||||
|
<filter name="draft" string="Draft" domain="[('state','=','draft')]"/>
|
||||||
|
<filter name="pending" string="Pending Approval" domain="[('state','=','to approve')]"/>
|
||||||
|
<filter name="approved" string="Approved" domain="[('state','=','approved')]"/>
|
||||||
|
<filter name="cancelled" string="Cancelled" domain="[('state','=','cancelled')]"/>
|
||||||
|
</field>
|
||||||
|
<filter name="group_author" position="before">
|
||||||
|
<filter name="group_state" string="State" context="{'group_by':'state'}" />
|
||||||
|
</filter>
|
||||||
|
<filter name="group_author" position="after">
|
||||||
|
<filter name="group_approver" string="Approver" context="{'group_by':'approved_uid'}" />
|
||||||
|
</filter>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Change Requests Action -->
|
||||||
|
<record model="ir.actions.act_window" id="action_change_requests">
|
||||||
|
<field name="name">Change Requests</field>
|
||||||
|
<field name="res_model">document.page.history</field>
|
||||||
|
<field name="view_type">form</field>
|
||||||
|
<field name="view_mode">tree,form</field>
|
||||||
|
<field name="context">{'search_default_state':'to approve'}</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem id="menu_page_change_requests"
|
||||||
|
name="Change Requests"
|
||||||
|
parent="document_page.menu_wiki"
|
||||||
|
action="action_change_requests"
|
||||||
|
sequence="25"
|
||||||
|
groups="document_page.group_document_editor" />
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
@ -1,40 +1,104 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<odoo>
|
<odoo>
|
||||||
|
|
||||||
<record model="workflow" id="wkf_document_page_history_aproval">
|
<record model="workflow" id="wkf_document_page_history_aproval">
|
||||||
<field name="name">document.page.history.aproval.wkf</field>
|
<field name="name">document.page.history.aproval.wkf</field>
|
||||||
<field name="osv">document.page.history</field>
|
<field name="osv">document.page.history</field>
|
||||||
<field name="on_create">True</field>
|
<field name="on_create">True</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="workflow.activity" id="act_approved">
|
<record model="workflow.activity" id="act_draft">
|
||||||
<field name="wkf_id"
|
<field name="wkf_id" ref="wkf_document_page_history_aproval" />
|
||||||
ref="wkf_document_page_history_aproval" />
|
<field name="flow_start">True</field>
|
||||||
<field name="name">approved</field>
|
<field name="name">draft</field>
|
||||||
<field name="kind">function</field>
|
<field name="kind">function</field>
|
||||||
<field name="action">page_approval_approved()</field>
|
<field name="action">page_approval_draft()</field>
|
||||||
<field name="flow_stop">True</field>
|
</record>
|
||||||
</record>
|
|
||||||
|
|
||||||
<record model="workflow.activity" id="act_draft">
|
<record model="workflow.activity" id="act_to_approve">
|
||||||
<field name="wkf_id"
|
<field name="wkf_id" ref="wkf_document_page_history_aproval" />
|
||||||
ref="wkf_document_page_history_aproval" />
|
<field name="name">to approve</field>
|
||||||
<field name="flow_start">True</field>
|
<field name="kind">function</field>
|
||||||
<field name="name">draft</field>
|
<field name="action">page_approval_to_approve()</field>
|
||||||
<field name="kind">function</field>
|
</record>
|
||||||
<field name="action">page_approval_draft()</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record model="workflow.transition" id="tda">
|
<record model="workflow.activity" id="act_approved">
|
||||||
<field name="act_from" ref="act_draft" />
|
<field name="wkf_id" ref="wkf_document_page_history_aproval" />
|
||||||
<field name="act_to" ref="act_approved" />
|
<field name="name">approved</field>
|
||||||
<field name="signal">page_approval_approve</field>
|
<field name="kind">function</field>
|
||||||
</record>
|
<field name="action">page_approval_approved()</field>
|
||||||
|
<field name="flow_stop">True</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
<record model="workflow.transition" id="tad">
|
<record model="workflow.activity" id="act_cancelled">
|
||||||
<field name="act_from" ref="act_approved" />
|
<field name="wkf_id" ref="wkf_document_page_history_aproval" />
|
||||||
<field name="act_to" ref="act_draft" />
|
<field name="name">cancelled</field>
|
||||||
<field name="signal">edit</field>
|
<field name="kind">function</field>
|
||||||
</record>
|
<field name="action">page_approval_cancelled()</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Transitions -->
|
||||||
|
<record model="workflow.transition" id="tdr">
|
||||||
|
<field name="act_from" ref="act_draft"/>
|
||||||
|
<field name="act_to" ref="act_to_approve"/>
|
||||||
|
<field name="condition">am_i_owner</field>
|
||||||
|
<field name="signal">page_approval_to_approve</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="workflow.transition" id="tda">
|
||||||
|
<field name="act_from" ref="act_draft"/>
|
||||||
|
<field name="act_to" ref="act_approved"/>
|
||||||
|
<field name="condition">am_i_approver</field>
|
||||||
|
<field name="signal">page_approval_approve</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="workflow.transition" id="tra">
|
||||||
|
<field name="act_from" ref="act_to_approve"/>
|
||||||
|
<field name="act_to" ref="act_approved"/>
|
||||||
|
<field name="condition">am_i_approver</field>
|
||||||
|
<field name="signal">page_approval_approve</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="workflow.transition" id="tad">
|
||||||
|
<field name="act_from" ref="act_approved"/>
|
||||||
|
<field name="act_to" ref="act_draft"/>
|
||||||
|
<field name="condition">am_i_approver</field>
|
||||||
|
<field name="signal">edit</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="workflow.transition" id="tdc">
|
||||||
|
<field name="act_from" ref="act_draft"/>
|
||||||
|
<field name="act_to" ref="act_cancelled"/>
|
||||||
|
<field name="condition">am_i_owner</field>
|
||||||
|
<field name="signal">page_approval_cancel</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="workflow.transition" id="trc">
|
||||||
|
<field name="act_from" ref="act_to_approve"/>
|
||||||
|
<field name="act_to" ref="act_cancelled"/>
|
||||||
|
<field name="condition">am_i_owner or am_i_approver</field>
|
||||||
|
<field name="signal">page_approval_cancel</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="workflow.transition" id="tcd">
|
||||||
|
<field name="act_from" ref="act_cancelled"/>
|
||||||
|
<field name="act_to" ref="act_draft"/>
|
||||||
|
<field name="condition">am_i_owner or am_i_approver</field>
|
||||||
|
<field name="signal">page_approval_reopen</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!-- Automatic Transitions for change requests created directly from documents -->
|
||||||
|
<record model="workflow.transition" id="tda_auto">
|
||||||
|
<field name="act_from" ref="act_draft"/>
|
||||||
|
<field name="act_to" ref="act_approved"/>
|
||||||
|
<field name="condition">not is_approval_required</field>
|
||||||
|
<field name="signal">document_page_auto_confirm</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="workflow.transition" id="tdr_auto">
|
||||||
|
<field name="act_from" ref="act_draft"/>
|
||||||
|
<field name="act_to" ref="act_to_approve"/>
|
||||||
|
<field name="condition">is_approval_required</field>
|
||||||
|
<field name="signal">document_page_auto_confirm</field>
|
||||||
|
</record>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
Loading…
Reference in New Issue
Block a user