Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions document_page_approval/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Contributors
* Savoir-faire Linux <[email protected]>
* Gervais Naoussi <[email protected]>
* Maxime Chambreuil <[email protected]>
* Iván Todorovich <[email protected]>

Maintainer
----------
Expand Down
1 change: 1 addition & 0 deletions document_page_approval/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import models
from .hooks import post_init_hook, uninstall_hook
4 changes: 3 additions & 1 deletion document_page_approval/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

{
'name': 'Document Page Approval',
'version': '10.0.1.1.0',
'version': '10.0.2.0.0',
"author": "Savoir-faire Linux, Odoo Community Association (OCA)",
"website": "http://www.savoirfairelinux.com",
"license": "AGPL-3",
Expand All @@ -25,4 +25,6 @@
'images/page_history_list.png',
'images/page_history.png',
],
'post_init_hook': 'post_init_hook',
'uninstall_hook': 'uninstall_hook',
}
32 changes: 24 additions & 8 deletions document_page_approval/data/email_template.xml
Original file line number Diff line number Diff line change
@@ -1,26 +1,42 @@
<?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">
<field name="name">Automated new draft need approval Notification Mail</field>
<field name="email_from">${object.create_uid.company_id.email or '[email protected]'}</field>
<field name="subject">New version of "${object.page_id.name}" to approve</field>
<field name="email_to">${object.get_approvers_email}</field>
<field name="subject">New version of ${object.display_name} needs your approval</field>
<field name="model_id" ref="model_document_page_history"/>
<field name="auto_delete" eval="True"/>
<field name="lang">${object.create_uid.partner_id.lang}</field>
<field name="body_html">
<![CDATA[
<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/>
Odoo</p>]]>

<p>Odoo</p>
]]>
</field>
</record>

Expand Down
22 changes: 22 additions & 0 deletions document_page_approval/hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Ivan Todorovich (<[email protected]>)
# 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'"
)
14 changes: 14 additions & 0 deletions document_page_approval/migrations/10.0.2.0.0/post-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Ivan Todorovich <[email protected]>
# 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
""")
200 changes: 112 additions & 88 deletions document_page_approval/models/document_page_approval.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,112 +2,136 @@
# Copyright (C) 2013 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
# 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):
"""Useful to know the state of a document."""

_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 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'
history_ids = fields.One2many(
order='approved_date DESC',
domain=[('state', '=', 'approved')],
)

approved_date = fields.Datetime(
compute=_get_approved_date,
string="Approved Date"
'Approved Date',
related='history_head.approved_date',
store=True,
index=True,
readonly=True,
)

approved_uid = fields.Many2one(
'res.users',
compute=_get_approved_uid,
string="Approved By",
'Approved by',
related='history_head.approved_uid',
store=True,
index=True,
readonly=True,
)

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',
)

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
Loading