Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[11.0][mig] purchase_order_block] #480

Merged
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 oca_dependencies.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
server-tools
purchase-workflow
100 changes: 100 additions & 0 deletions purchase_order_approval_block/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
.. image:: https://img.shields.io/badge/licence-LGPL--3-blue.svg
:target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License LGPL-3

=============================
Purchase Order Approval Block
=============================

This module allows you to block the approval of an RFQ when an Approval
Block Reason has been provided. Upon confirmation of an RFQ the orders will be
waiting for approval by a Manager.

Configuration
=============

* Go to ‘Purchases / Configuration / Purchase Approval Block Reasons’ and create
the blocking reasons as needed, providing a name and a description. A field
‘Active’ allows you to deactivate the reason if you do not plan to use it
any more.
* Assign the security group 'Release blocked RFQ' to users that should be able
to release the block. Users in group 'Purchase / Managers' are by default
assigned to this group.

Usage
=====

Set the Purchase Approval Block
-------------------------------

#. Go to ‘Purchases / Purchase / Requests for Quotation’
#. Create a new RFQ and indicate the approval block reason (found in the
right hand side of the screen, below the order date).

Search existing RFQ
-------------------

There is a filter ‘Blocked’ to search for orders that are blocked for approval.
It is also possible to search RFQ’s with a specific block reason.

Confirm the RFQ
---------------

#. Press the button ‘Confirm’. If there’s an approval block, the order will
be set to status 'To Approve'. You will then need to request a Purchase
Manager to approve it.

Release the purchase approval block
-----------------------------------

While the RFQ is in draft, members of security group ‘Release blocked RFQ’,
can see a button ‘Release Approval Block’. From this point and on, anyone
seeing that RFQ will be able to validate it.

Notifications to followers
--------------------------

Followers of the RFQ receive notifications when an approval block has been
set or released.

.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/142/11.0

Bug Tracker
===========

Bugs are tracked on `GitHub Issues
<https://github.com/OCA/purchase-workflow/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smashing it by providing a detailed and welcomed feedback.

Credits
=======

Images
------

* Odoo Community Association: `Icon <https://odoo-community.org/logo.png>`_.

Contributors
------------

* Jordi Ballester Alomar <[email protected]>
* Roser Garcia <[email protected]>
* Darshan Patel <[email protected]>

Maintainer
----------

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

This module is maintained by the OCA.

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

To contribute to this module, please visit https://odoo-community.org.
3 changes: 3 additions & 0 deletions purchase_order_approval_block/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

from . import models
from . import wizard
23 changes: 23 additions & 0 deletions purchase_order_approval_block/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

{
"name": "Purchase Order Approval Block",
"author": "Eficent, Odoo Community Association (OCA)",
"version": "11.0.1.0.0",
"category": "Purchase Management",
"website": "https://github.com/OCA/purchase-workflow",
"depends": [
'purchase',
'purchase_exception',
],
"data": [
'data/purchase_exception_data.xml',
'security/ir.model.access.csv',
'security/purchase_order_approval_block_security.xml',
'views/purchase_approval_block_reason_view.xml',
'views/purchase_order_view.xml',
],
"license": 'LGPL-3',
"installable": True
}
16 changes: 16 additions & 0 deletions purchase_order_approval_block/data/purchase_exception_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>

<record id ="po_excep_approval_block" model="exception.rule">
<field name="name">Approval Blocked</field>
<field name="description">The approval has been blocked,
with a Blocking reason.</field>
<field name="sequence">100</field>
<field name="rule_group">purchase</field>
<field name="model">purchase.order</field>
<field name="code">if 'approval_block_id' in purchase._fields and purchase.approval_block_id: failed = True</field>
<field name="next_state">to approve</field>
<field name="active" eval="True"/>
</record>

</odoo>
3 changes: 3 additions & 0 deletions purchase_order_approval_block/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

from . import purchase_approval_block_reason
from . import purchase_order
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class PurchaseApprovalBlockReason(models.Model):
_name = 'purchase.approval.block.reason'

name = fields.Char(required=True)
description = fields.Text()
active = fields.Boolean(default=True)
58 changes: 58 additions & 0 deletions purchase_order_approval_block/models/purchase_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import api, fields, models, _


class PurchaseOrder(models.Model):
_inherit = "purchase.order"

approval_block_id = fields.Many2one(
comodel_name='purchase.approval.block.reason',
string='Approval Block Reason',
)
approval_blocked = fields.Boolean(
'Approval Blocked',
compute='_compute_approval_blocked',
)

@api.multi
def _compute_approval_blocked(self):
for rec in self:
if rec.approval_block_id:
rec.approval_blocked = True

@api.model
def create(self, vals):
po = super(PurchaseOrder, self).create(vals)
if 'approval_block_id' in vals and vals['approval_block_id']:
po.message_post(body=_('Order \"%s\" blocked with reason'
' \"%s\"') % (po.name,
po.approval_block_id.name))
return po

@api.multi
def write(self, vals):
res = super(PurchaseOrder, self).write(vals)
for po in self:
if 'approval_block_id' in vals and vals['approval_block_id']:
po.message_post(
body=_('Order \"%s\" blocked with reason \"%s\"') % (
po.name, po.approval_block_id.name))
elif 'approval_block_id' in vals and not vals['approval_block_id']:
po.message_post(
body=_('Order \"%s\" approval block released.') % po.name)
return res

@api.multi
def button_approve(self, force=False):
for rec in self:
if rec.approval_block_id:
rec.button_release_approval_block()
return super(PurchaseOrder, self).button_approve(force=force)

@api.multi
def button_release_approval_block(self):
for order in self:
order.approval_block_id = False
return True
3 changes: 3 additions & 0 deletions purchase_order_approval_block/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_purchase_order_approval_block_reason,purchase.order.block.reason,model_purchase_approval_block_reason,purchase.group_purchase_user,1,0,0,0
access_purchase_order_approval_block_reason_manager,purchase.order.block.reason,model_purchase_approval_block_reason,purchase.group_purchase_manager,1,1,1,1
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>

<!--
Copyright 2017 Eficent Business and IT Consulting Services S.L.
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
-->

<odoo>
<record id="group_rfq_approval_block" model="res.groups">
<field name="name">Release RFQ with approval block</field>
<field name="category_id" ref="base.module_category_hidden"/>
<field name="users" eval="[(4, ref('base.user_root'))]"/>
<field name="comment">
The user will be able to release an RFQ blocked for approval.
</field>
</record>
<record id="purchase.group_purchase_manager" model="res.groups">
<field name="implied_ids" eval="[(4, ref('group_rfq_approval_block'))]"/>
</record>
</odoo>
3 changes: 3 additions & 0 deletions purchase_order_approval_block/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

from . import test_purchase_order_approval_block
from . import test_po_approval_block_reason
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo.addons.purchase_order_approval_block.tests.\
test_purchase_order_approval_block import TestPurchaseOrderApprovalBlock


class TestPoApprovalBlockReason(TestPurchaseOrderApprovalBlock):

def test_po_approval_block_manual_release(self):
"""Confirming the Blocked PO"""
# Create a PO
purchase = self._create_purchase(
[(self.product1, 1),
(self.product2, 5),
(self.product3, 8)])

purchase.approval_block_id = self.po_approval_block_reason.id

self.assertEqual(purchase.approval_blocked, True)
# The purchase manager unblocks the RFQ with block
purchase.sudo(self.user2_id).button_release_approval_block()
self.assertEqual(purchase.approval_block_id, self.env[
'purchase.approval.block.reason'])
# The purchase user validates the RFQ without block
purchase.sudo(self.user1_id).button_confirm()
# The PO is approved
self.assertEqual(purchase.state, 'purchase')

def test_po_approval_block_to_approve_release_01(self):
# Create a PO
purchase = self._create_purchase(
[(self.product1, 1),
(self.product2, 5),
(self.product3, 8)])

purchase.approval_block_id = self.po_approval_block_reason.id
# The purchase user validates the RFQ with block, and is now to approve
purchase.sudo(self.user2_id).button_confirm()
self.assertEquals(purchase.state, 'to approve')

# Simulation the opening of the wizard purchase_exception_confirm and
# set ignore_exception to True
po_except_confirm = \
self.env['purchase.exception.confirm'].with_context(
{
'active_id': purchase.id,
'active_ids': [purchase.id],
'active_model': purchase._name
}).create({'ignore': True})
po_except_confirm.action_confirm()

self.assertEqual(purchase.state, 'purchase')

def test_po_approval_block_to_approve_release_02(self):
# Create a PO
purchase = self._create_purchase(
[(self.product1, 1),
(self.product2, 5),
(self.product3, 8)])

purchase.approval_block_id = self.po_approval_block_reason.id
# The purchase user validates the RFQ with block, and is now to approve
purchase.sudo(self.user2_id).button_confirm()
self.assertEquals(purchase.state, 'to approve')

purchase.sudo(self.user2_id).button_approve()

self.assertEqual(purchase.state, 'purchase')
Loading