Add oca-purchase submodule with 96 purchase modules moved from oca-workflow-process

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ernad Husremovic 2025-08-30 18:00:40 +02:00
parent b0628ee8ea
commit 7378b233e9
3994 changed files with 334316 additions and 0 deletions

View file

@ -0,0 +1,46 @@
# Purchase Order Approval Block
Odoo addon: purchase_order_approval_block
## Installation
```bash
pip install odoo-bringout-oca-purchase-workflow-purchase_order_approval_block
```
## Dependencies
This addon depends on:
- purchase_exception
## Manifest Information
- **Name**: Purchase Order Approval Block
- **Version**: 16.0.1.0.0
- **Category**: Purchase Management
- **License**: AGPL-3
- **Installable**: True
## Source
Based on [OCA/purchase-workflow](https://github.com/OCA/purchase-workflow) branch 16.0, addon `purchase_order_approval_block`.
## License
This package maintains the original AGPL-3 license from the upstream Odoo project.
## Documentation
- Overview: doc/OVERVIEW.md
- Architecture: doc/ARCHITECTURE.md
- Models: doc/MODELS.md
- Controllers: doc/CONTROLLERS.md
- Wizards: doc/WIZARDS.md
- Reports: doc/REPORTS.md
- Security: doc/SECURITY.md
- Install: doc/INSTALL.md
- Usage: doc/USAGE.md
- Configuration: doc/CONFIGURATION.md
- Dependencies: doc/DEPENDENCIES.md
- Troubleshooting: doc/TROUBLESHOOTING.md
- FAQ: doc/FAQ.md

View file

@ -0,0 +1,32 @@
# Architecture
```mermaid
flowchart TD
U[Users] -->|HTTP| V[Views and QWeb Templates]
V --> C[Controllers]
V --> W[Wizards Transient Models]
C --> M[Models and ORM]
W --> M
M --> R[Reports]
DX[Data XML] --> M
S[Security ACLs and Groups] -. enforces .-> M
subgraph Purchase_order_approval_block Module - purchase_order_approval_block
direction LR
M:::layer
W:::layer
C:::layer
V:::layer
R:::layer
S:::layer
DX:::layer
end
classDef layer fill:#eef8ff,stroke:#6ea8fe,stroke-width:1px
```
Notes
- Views include tree/form/kanban templates and report templates.
- Controllers provide website/portal routes when present.
- Wizards are UI flows implemented with `models.TransientModel`.
- Data XML loads data/demo records; Security defines groups and access.

View file

@ -0,0 +1,3 @@
# Configuration
Refer to Odoo settings for purchase_order_approval_block. Configure related models, access rights, and options as needed.

View file

@ -0,0 +1,3 @@
# Controllers
This module does not define custom HTTP controllers.

View file

@ -0,0 +1,5 @@
# Dependencies
This addon depends on:
- [purchase_exception](https://github.com/bringout/oca-workflow-process)

View file

@ -0,0 +1,4 @@
# FAQ
- Q: Which Odoo version? A: 16.0 (OCA/OCB packaged).
- Q: How to enable? A: Start server with --addon purchase_order_approval_block or install in UI.

View file

@ -0,0 +1,7 @@
# Install
```bash
pip install odoo-bringout-oca-purchase-workflow-purchase_order_approval_block"
# or
uv pip install odoo-bringout-oca-purchase-workflow-purchase_order_approval_block"
```

View file

@ -0,0 +1,13 @@
# Models
Detected core models and extensions in purchase_order_approval_block.
```mermaid
classDiagram
class purchase_approval_block_reason
class purchase_order
```
Notes
- Classes show model technical names; fields omitted for brevity.
- Items listed under _inherit are extensions of existing models.

View file

@ -0,0 +1,6 @@
# Overview
Packaged Odoo addon: purchase_order_approval_block. Provides features documented in upstream Odoo 16 under this addon.
- Source: OCA/OCB 16.0, addon purchase_order_approval_block
- License: LGPL-3

View file

@ -0,0 +1,3 @@
# Reports
This module does not define custom reports.

View file

@ -0,0 +1,42 @@
# Security
Access control and security definitions in purchase_order_approval_block.
## Access Control Lists (ACLs)
Model access permissions defined in:
- **[ir.model.access.csv](../purchase_order_approval_block/security/ir.model.access.csv)**
- 2 model access rules
## Record Rules
Row-level security rules defined in:
## Security Groups & Configuration
Security groups and permissions defined in:
- **[purchase_order_approval_block_security.xml](../purchase_order_approval_block/security/purchase_order_approval_block_security.xml)**
- 2 security groups defined
```mermaid
graph TB
subgraph "Security Layers"
A[Users] --> B[Groups]
B --> C[Access Control Lists]
C --> D[Models]
B --> E[Record Rules]
E --> F[Individual Records]
end
```
Security files overview:
- **[ir.model.access.csv](../purchase_order_approval_block/security/ir.model.access.csv)**
- Model access permissions (CRUD rights)
- **[purchase_order_approval_block_security.xml](../purchase_order_approval_block/security/purchase_order_approval_block_security.xml)**
- Security groups, categories, and XML-based rules
Notes
- Access Control Lists define which groups can access which models
- Record Rules provide row-level security (filter records by user/group)
- Security groups organize users and define permission sets
- All security is enforced at the ORM level by Odoo

View file

@ -0,0 +1,5 @@
# Troubleshooting
- Ensure Python and Odoo environment matches repo guidance.
- Check database connectivity and logs if startup fails.
- Validate that dependent addons listed in DEPENDENCIES.md are installed.

View file

@ -0,0 +1,7 @@
# Usage
Start Odoo including this addon (from repo root):
```bash
python3 scripts/nix_odoo_web_server.py --db-name mydb --addon purchase_order_approval_block
```

View file

@ -0,0 +1,8 @@
# Wizards
Transient models exposed as UI wizards in purchase_order_approval_block.
```mermaid
classDiagram
class PurchaseExceptionConfirm
```

View file

@ -0,0 +1,127 @@
=============================
Purchase Order Approval Block
=============================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:5a8e994cddf30485f4fedae5e3124314a9afeb1c518fb69816f651e5605c2142
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpurchase--workflow-lightgray.png?logo=github
:target: https://github.com/OCA/purchase-workflow/tree/16.0/purchase_order_approval_block
:alt: OCA/purchase-workflow
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/purchase-workflow-16-0/purchase-workflow-16-0-purchase_order_approval_block
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/purchase-workflow&target_branch=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
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.
**Table of contents**
.. contents::
:local:
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 RFQ with approval block' 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 RFQs with a specific block reason.
Confirm the RFQ
~~~~~~~~~~~~~~~
#. Press the button Confirm. If theres 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 RFQ with approval block,
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.
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 to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/purchase-workflow/issues/new?body=module:%20purchase_order_approval_block%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* ForgeFlow
Contributors
~~~~~~~~~~~~
* Jordi Ballester Alomar <jordi.ballester@forgeflow.com>
* Roser Garcia <roser.garcia@forgeflow.com>
* Darshan Patel <darshan.patel.serpentcs@gmail.com>
Maintainers
~~~~~~~~~~~
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
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.
This module is part of the `OCA/purchase-workflow <https://github.com/OCA/purchase-workflow/tree/16.0/purchase_order_approval_block>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View file

@ -0,0 +1,4 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import models
from . import wizard

View file

@ -0,0 +1,20 @@
# Copyright 2017 ForgeFlow S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "Purchase Order Approval Block",
"author": "ForgeFlow, Odoo Community Association (OCA)",
"version": "16.0.1.0.0",
"category": "Purchase Management",
"website": "https://github.com/OCA/purchase-workflow",
"depends": ["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": "AGPL-3",
"installable": True,
}

View file

@ -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 self._fields and self.approval_block_id: failed = True</field>
<!-- <field name="next_state">to approve</field> -->
<field name="active" eval="True" />
</record>
</odoo>

View file

@ -0,0 +1,141 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * purchase_order_approval_block
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: purchase_order_approval_block
#: model:res.groups,comment:purchase_order_approval_block.group_rfq_approval_block
msgid ""
"\n"
" The user will be able to release an RFQ blocked for approval.\n"
" "
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__active
msgid "Active"
msgstr "Aktivan"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_order__approval_block_id
msgid "Approval Block Reason"
msgstr "Blokada odobrenja Reason"
#. module: purchase_order_approval_block
#: model:exception.rule,name:purchase_order_approval_block.po_excep_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_order__approval_blocked
msgid "Approval Blocked"
msgstr "Blokada odobrenjaed"
#. module: purchase_order_approval_block
#: model_terms:ir.ui.view,arch_db:purchase_order_approval_block.view_purchase_order_filter
msgid "Blocked for Approval"
msgstr "Blocked for Approval"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__create_uid
msgid "Created by"
msgstr "Kreirao"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__create_date
msgid "Created on"
msgstr "Kreirano"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__description
msgid "Description"
msgstr "Opis"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__display_name
msgid "Display Name"
msgstr "Prikazani naziv"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__id
msgid "ID"
msgstr "ID"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason____last_update
msgid "Last Modified on"
msgstr "Zadnje mijenjano"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__write_uid
msgid "Last Updated by"
msgstr "Zadnji ažurirao"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__write_date
msgid "Last Updated on"
msgstr "Zadnje ažurirano"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__name
msgid "Name"
msgstr "Naziv:"
#. module: purchase_order_approval_block
#. odoo-python
#: code:addons/purchase_order_approval_block/models/purchase_order.py:0
#: code:addons/purchase_order_approval_block/models/purchase_order.py:0
#, python-format
msgid "Order \"%(order_name)s\" blocked with reason \"%(block_name)s\""
msgstr "Nalog \"%(order_name)s\" blocked with reason \"%(block_name)s\""
#. module: purchase_order_approval_block
#. odoo-python
#: code:addons/purchase_order_approval_block/models/purchase_order.py:0
#, python-format
msgid "Order \"%s\" approval block released."
msgstr "Nalog \"%s\" approval block released."
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_approval_block_reason
msgid "Purchase Approval Block Reason"
msgstr "Nabavni Blokada odobrenja Reason"
#. module: purchase_order_approval_block
#: model:ir.actions.act_window,name:purchase_order_approval_block.action_purchase_approval_block_reason
#: model:ir.ui.menu,name:purchase_order_approval_block.menu_purchase_approval_block_reason
msgid "Purchase Approval Block Reasons"
msgstr "Nabavni Blokada odobrenja Reasons"
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_order
msgid "Purchase Order"
msgstr "Nalog za nabavu"
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_exception_confirm
msgid "Purchase exception wizard"
msgstr "Čarobnjak izuzetaka nabavke"
#. module: purchase_order_approval_block
#: model_terms:ir.ui.view,arch_db:purchase_order_approval_block.purchase_order_form
msgid "Release Approval Block"
msgstr "Release Blokada odobrenja"
#. module: purchase_order_approval_block
#: model:res.groups,name:purchase_order_approval_block.group_rfq_approval_block
msgid "Release RFQ with approval block"
msgstr "Release RFQ with approval block"
#. module: purchase_order_approval_block
#: model:exception.rule,description:purchase_order_approval_block.po_excep_approval_block
msgid ""
"The approval has been blocked,\n"
" with a Blocking reason."
msgstr ""

View file

@ -0,0 +1,148 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * purchase_order_approval_block
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-02-11 22:35+0000\n"
"Last-Translator: Ivorra78 <informatica@totmaterial.es>\n"
"Language-Team: none\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: purchase_order_approval_block
#: model:res.groups,comment:purchase_order_approval_block.group_rfq_approval_block
msgid ""
"\n"
" The user will be able to release an RFQ blocked for approval.\n"
" "
msgstr ""
"\n"
" El usuario será capaz de liberar una solicitud bloqueada para "
"su aprobación.\n"
" "
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__active
msgid "Active"
msgstr "Activo"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_order__approval_block_id
msgid "Approval Block Reason"
msgstr "Razón del Bloqueo de Aprobación"
#. module: purchase_order_approval_block
#: model:exception.rule,name:purchase_order_approval_block.po_excep_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_order__approval_blocked
msgid "Approval Blocked"
msgstr "Aprobación Bloqueada"
#. module: purchase_order_approval_block
#: model_terms:ir.ui.view,arch_db:purchase_order_approval_block.view_purchase_order_filter
msgid "Blocked for Approval"
msgstr "Bloqueado para Aprobación"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__create_uid
msgid "Created by"
msgstr "Creado por"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__create_date
msgid "Created on"
msgstr "Creado el"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__description
msgid "Description"
msgstr "Descripción"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__display_name
msgid "Display Name"
msgstr "Mostrar Nombre"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__id
msgid "ID"
msgstr "ID"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason____last_update
msgid "Last Modified on"
msgstr "Última Modificación el"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__write_uid
msgid "Last Updated by"
msgstr "Última Actualización por"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__write_date
msgid "Last Updated on"
msgstr "Última Actualización el"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__name
msgid "Name"
msgstr "Nombre"
#. module: purchase_order_approval_block
#: code:addons/purchase_order_approval_block/models/purchase_order.py:0
#: code:addons/purchase_order_approval_block/models/purchase_order.py:0
#, python-format
msgid "Order \"%(order_name)s\" blocked with reason \"%(block_name)s\""
msgstr "Orden \"%(order_name)s\" bloqueada con el motivo \"%(block_name)s\""
#. module: purchase_order_approval_block
#: code:addons/purchase_order_approval_block/models/purchase_order.py:0
#, python-format
msgid "Order \"%s\" approval block released."
msgstr "Liberado bloqueo del pedido \"%s\"."
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_approval_block_reason
msgid "Purchase Approval Block Reason"
msgstr "Motivo del Bloqueo de Aprobación de Compra"
#. module: purchase_order_approval_block
#: model:ir.actions.act_window,name:purchase_order_approval_block.action_purchase_approval_block_reason
#: model:ir.ui.menu,name:purchase_order_approval_block.menu_purchase_approval_block_reason
msgid "Purchase Approval Block Reasons"
msgstr "Motivos del Bloqueo de Aprobación de Compra"
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_order
msgid "Purchase Order"
msgstr "Orden de Compra"
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_exception_confirm
msgid "Purchase exception wizard"
msgstr "Asistente para excepciones de compra"
#. module: purchase_order_approval_block
#: model_terms:ir.ui.view,arch_db:purchase_order_approval_block.purchase_order_form
msgid "Release Approval Block"
msgstr "Liberación de Bloqueo de Aprobación"
#. module: purchase_order_approval_block
#: model:res.groups,name:purchase_order_approval_block.group_rfq_approval_block
msgid "Release RFQ with approval block"
msgstr "Liberar solicitud con bloqueo de aprobación"
#. module: purchase_order_approval_block
#: model:exception.rule,description:purchase_order_approval_block.po_excep_approval_block
msgid ""
"The approval has been blocked,\n"
" with a Blocking reason."
msgstr ""
"La aprobación ha sido bloqueada,\n"
" con una razón de bloqueo."

View file

@ -0,0 +1,157 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * purchase_order_approval_block
#
# Translators:
# Quentin THEURET <odoo@kerpeo.com>, 2018
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 11.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-02-23 17:51+0000\n"
"PO-Revision-Date: 2020-10-06 14:04+0000\n"
"Last-Translator: Yann Papouin <y.papouin@dec-industrie.com>\n"
"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 3.10\n"
#. module: purchase_order_approval_block
#: model:res.groups,comment:purchase_order_approval_block.group_rfq_approval_block
msgid ""
"\n"
" The user will be able to release an RFQ blocked for approval.\n"
" "
msgstr ""
"\n"
" L'utilisateur sera capable de débloquer une demande de prix "
"bloquée pour approbation.\n"
" "
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__active
msgid "Active"
msgstr "Actif"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_order__approval_block_id
msgid "Approval Block Reason"
msgstr "Motif du blocage de l'approbation"
#. module: purchase_order_approval_block
#: model:exception.rule,name:purchase_order_approval_block.po_excep_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_order__approval_blocked
msgid "Approval Blocked"
msgstr "Approbation bloquée"
#. module: purchase_order_approval_block
#: model_terms:ir.ui.view,arch_db:purchase_order_approval_block.view_purchase_order_filter
msgid "Blocked for Approval"
msgstr "Bloquée pour approbation"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__create_uid
msgid "Created by"
msgstr "Créé par"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__create_date
msgid "Created on"
msgstr "Créé le"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__description
msgid "Description"
msgstr "Description"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__display_name
msgid "Display Name"
msgstr "Nom d'affichage"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__id
msgid "ID"
msgstr "ID"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason____last_update
msgid "Last Modified on"
msgstr "Dernière modification le"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__write_uid
msgid "Last Updated by"
msgstr "Dernière modification par"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__write_date
msgid "Last Updated on"
msgstr "Mis à jour le"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__name
msgid "Name"
msgstr "Nom"
#. module: purchase_order_approval_block
#: code:addons/purchase_order_approval_block/models/purchase_order.py:44
#, python-format
msgid "Order \"%s\" approval block released."
msgstr "Suppression du blocage de l'approbation de la commande \"%s\"."
#. module: purchase_order_approval_block
#: code:addons/purchase_order_approval_block/models/purchase_order.py:29
#: code:addons/purchase_order_approval_block/models/purchase_order.py:40
#, python-format
msgid "Order \"%s\" blocked with reason \"%s\""
msgstr "Commande \"%s\" bloquée pour le motif \"%s\""
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_approval_block_reason
msgid "Purchase Approval Block Reason"
msgstr "Motif de blocage d'une approbation d'achat"
#. module: purchase_order_approval_block
#: model:ir.actions.act_window,name:purchase_order_approval_block.action_purchase_approval_block_reason
#: model:ir.ui.menu,name:purchase_order_approval_block.menu_purchase_approval_block_reason
msgid "Purchase Approval Block Reasons"
msgstr "Motifs de blocage d'une approbation d'achat"
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_order
msgid "Purchase Order"
msgstr "Commande fournisseur"
#. module: purchase_order_approval_block
#: model_terms:ir.ui.view,arch_db:purchase_order_approval_block.purchase_approval_block_reason_tree_view
msgid "Purchase Order Approval Block Reasons"
msgstr "Motifs de blocage d'une approbation de commande d'achat"
#. module: purchase_order_approval_block
#: model_terms:ir.ui.view,arch_db:purchase_order_approval_block.purchase_order_form
msgid "Release Approval Block"
msgstr "Supprimer le motif de blocage"
#. module: purchase_order_approval_block
#: model:res.groups,name:purchase_order_approval_block.group_rfq_approval_block
msgid "Release RFQ with approval block"
msgstr "Débloquer les demandes de prix avec un blocage d'approbation"
#. module: purchase_order_approval_block
#: model:exception.rule,description:purchase_order_approval_block.po_excep_approval_block
msgid ""
"The approval has been blocked,\n"
" with a Blocking reason."
msgstr "L'approbation a été bloquée, à cause d'un motif de blocage."
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_exception_confirm
msgid "purchase.exception.confirm"
msgstr "purchase.exception.confirm"
#~ msgid "purchase.approval.block.reason"
#~ msgstr "purchase.approval.block.reason"

View file

@ -0,0 +1,149 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * purchase_order_approval_block
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-02-24 11:06+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\n"
"Language-Team: none\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.6.2\n"
#. module: purchase_order_approval_block
#: model:res.groups,comment:purchase_order_approval_block.group_rfq_approval_block
msgid ""
"\n"
" The user will be able to release an RFQ blocked for approval.\n"
" "
msgstr ""
"\n"
" L'utente potrà rilasciare una RDP bloccata per l'approvazione.\n"
" "
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__active
msgid "Active"
msgstr "Attiva"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_order__approval_block_id
msgid "Approval Block Reason"
msgstr "Motivo blocco approvazione"
#. module: purchase_order_approval_block
#: model:exception.rule,name:purchase_order_approval_block.po_excep_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_order__approval_blocked
msgid "Approval Blocked"
msgstr "Approvazione bloccata"
#. module: purchase_order_approval_block
#: model_terms:ir.ui.view,arch_db:purchase_order_approval_block.view_purchase_order_filter
msgid "Blocked for Approval"
msgstr "Bloccata per approvazione"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__create_uid
msgid "Created by"
msgstr "Creato da"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__create_date
msgid "Created on"
msgstr "Creato il"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__description
msgid "Description"
msgstr "Descrizione"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__display_name
msgid "Display Name"
msgstr "Nome visualizzato"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__id
msgid "ID"
msgstr "ID"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason____last_update
msgid "Last Modified on"
msgstr "Ultima modifica il"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__write_uid
msgid "Last Updated by"
msgstr "Ultimo aggiornamento di"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__write_date
msgid "Last Updated on"
msgstr "Ultimo aggiornamento il"
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__name
msgid "Name"
msgstr "Nome"
#. module: purchase_order_approval_block
#. odoo-python
#: code:addons/purchase_order_approval_block/models/purchase_order.py:0
#: code:addons/purchase_order_approval_block/models/purchase_order.py:0
#, python-format
msgid "Order \"%(order_name)s\" blocked with reason \"%(block_name)s\""
msgstr "Ordine \"%(order_name)s\" bloccato con motivo \"%(block_name)s\""
#. module: purchase_order_approval_block
#. odoo-python
#: code:addons/purchase_order_approval_block/models/purchase_order.py:0
#, python-format
msgid "Order \"%s\" approval block released."
msgstr "Blocco approvazione ordine \"%s\" rilasciato."
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_approval_block_reason
msgid "Purchase Approval Block Reason"
msgstr "Motivo blocco approvazione acquisto"
#. module: purchase_order_approval_block
#: model:ir.actions.act_window,name:purchase_order_approval_block.action_purchase_approval_block_reason
#: model:ir.ui.menu,name:purchase_order_approval_block.menu_purchase_approval_block_reason
msgid "Purchase Approval Block Reasons"
msgstr "Motivi blocco approvazione acquisto"
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_order
msgid "Purchase Order"
msgstr "Ordine di acquisto"
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_exception_confirm
msgid "Purchase exception wizard"
msgstr "Procedura guidata eccezione di acquisto"
#. module: purchase_order_approval_block
#: model_terms:ir.ui.view,arch_db:purchase_order_approval_block.purchase_order_form
msgid "Release Approval Block"
msgstr "Blocco rilascio approvazione"
#. module: purchase_order_approval_block
#: model:res.groups,name:purchase_order_approval_block.group_rfq_approval_block
msgid "Release RFQ with approval block"
msgstr "Rilascio RDP con blocco approvazione"
#. module: purchase_order_approval_block
#: model:exception.rule,description:purchase_order_approval_block.po_excep_approval_block
msgid ""
"The approval has been blocked,\n"
" with a Blocking reason."
msgstr ""
"L'approvazione è stata bloccata,\n"
" con un motivo di blocco."

View file

@ -0,0 +1,141 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * purchase_order_approval_block
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: purchase_order_approval_block
#: model:res.groups,comment:purchase_order_approval_block.group_rfq_approval_block
msgid ""
"\n"
" The user will be able to release an RFQ blocked for approval.\n"
" "
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__active
msgid "Active"
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_order__approval_block_id
msgid "Approval Block Reason"
msgstr ""
#. module: purchase_order_approval_block
#: model:exception.rule,name:purchase_order_approval_block.po_excep_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_order__approval_blocked
msgid "Approval Blocked"
msgstr ""
#. module: purchase_order_approval_block
#: model_terms:ir.ui.view,arch_db:purchase_order_approval_block.view_purchase_order_filter
msgid "Blocked for Approval"
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__create_uid
msgid "Created by"
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__create_date
msgid "Created on"
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__description
msgid "Description"
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__display_name
msgid "Display Name"
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__id
msgid "ID"
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason____last_update
msgid "Last Modified on"
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__write_uid
msgid "Last Updated by"
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__write_date
msgid "Last Updated on"
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model.fields,field_description:purchase_order_approval_block.field_purchase_approval_block_reason__name
msgid "Name"
msgstr ""
#. module: purchase_order_approval_block
#. odoo-python
#: code:addons/purchase_order_approval_block/models/purchase_order.py:0
#: code:addons/purchase_order_approval_block/models/purchase_order.py:0
#, python-format
msgid "Order \"%(order_name)s\" blocked with reason \"%(block_name)s\""
msgstr ""
#. module: purchase_order_approval_block
#. odoo-python
#: code:addons/purchase_order_approval_block/models/purchase_order.py:0
#, python-format
msgid "Order \"%s\" approval block released."
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_approval_block_reason
msgid "Purchase Approval Block Reason"
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.actions.act_window,name:purchase_order_approval_block.action_purchase_approval_block_reason
#: model:ir.ui.menu,name:purchase_order_approval_block.menu_purchase_approval_block_reason
msgid "Purchase Approval Block Reasons"
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_order
msgid "Purchase Order"
msgstr ""
#. module: purchase_order_approval_block
#: model:ir.model,name:purchase_order_approval_block.model_purchase_exception_confirm
msgid "Purchase exception wizard"
msgstr ""
#. module: purchase_order_approval_block
#: model_terms:ir.ui.view,arch_db:purchase_order_approval_block.purchase_order_form
msgid "Release Approval Block"
msgstr ""
#. module: purchase_order_approval_block
#: model:res.groups,name:purchase_order_approval_block.group_rfq_approval_block
msgid "Release RFQ with approval block"
msgstr ""
#. module: purchase_order_approval_block
#: model:exception.rule,description:purchase_order_approval_block.po_excep_approval_block
msgid ""
"The approval has been blocked,\n"
" with a Blocking reason."
msgstr ""

View file

@ -0,0 +1,2 @@
from . import purchase_approval_block_reason
from . import purchase_order

View file

@ -0,0 +1,13 @@
# Copyright 2017 ForgeFlow 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"
_description = "Purchase Approval Block Reason"
name = fields.Char(required=True)
description = fields.Text()
active = fields.Boolean(default=True)

View file

@ -0,0 +1,65 @@
# Copyright 2017 ForgeFlow 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(
compute="_compute_approval_blocked",
)
@api.depends("approval_block_id")
def _compute_approval_blocked(self):
for rec in self:
rec.approval_blocked = rec.approval_block_id
@api.model_create_multi
def create(self, mvals):
records = super(PurchaseOrder, self).create(mvals)
for vals, po in zip(mvals, records):
if "approval_block_id" in vals and vals["approval_block_id"]:
po.message_post(
body=_(
'Order "%(order_name)s" blocked with reason "%(block_name)s"'
)
% {
"order_name": po.name,
"block_name": po.approval_block_id.name,
}
)
return records
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 "%(order_name)s" blocked with reason "%(block_name)s"'
)
% {
"order_name": po.name,
"block_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
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)
def button_release_approval_block(self):
for order in self:
order.approval_block_id = False
return True

View file

@ -0,0 +1,7 @@
* 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 RFQ with approval block' to users that
should be able to release the block. Users in group 'Purchase / Managers'
are by default assigned to this group.

View file

@ -0,0 +1,3 @@
* Jordi Ballester Alomar <jordi.ballester@forgeflow.com>
* Roser Garcia <roser.garcia@forgeflow.com>
* Darshan Patel <darshan.patel.serpentcs@gmail.com>

View file

@ -0,0 +1,3 @@
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.

View file

@ -0,0 +1,32 @@
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 RFQs with a specific block reason.
Confirm the RFQ
~~~~~~~~~~~~~~~
#. Press the button Confirm. If theres 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 RFQ with approval block,
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.

View file

@ -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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_purchase_order_approval_block_reason purchase.order.block.reason model_purchase_approval_block_reason purchase.group_purchase_user 1 0 0 0
3 access_purchase_order_approval_block_reason_manager purchase.order.block.reason model_purchase_approval_block_reason purchase.group_purchase_manager 1 1 1 1

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2017 ForgeFlow S.L.
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<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>

View file

@ -0,0 +1,483 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Purchase Order Approval Block</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="purchase-order-approval-block">
<h1 class="title">Purchase Order Approval Block</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:5a8e994cddf30485f4fedae5e3124314a9afeb1c518fb69816f651e5605c2142
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/purchase-workflow/tree/16.0/purchase_order_approval_block"><img alt="OCA/purchase-workflow" src="https://img.shields.io/badge/github-OCA%2Fpurchase--workflow-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/purchase-workflow-16-0/purchase-workflow-16-0-purchase_order_approval_block"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/purchase-workflow&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>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.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#configuration" id="toc-entry-1">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="toc-entry-2">Usage</a><ul>
<li><a class="reference internal" href="#set-the-purchase-approval-block" id="toc-entry-3">Set the Purchase Approval Block</a></li>
<li><a class="reference internal" href="#search-existing-rfq" id="toc-entry-4">Search existing RFQ</a></li>
<li><a class="reference internal" href="#confirm-the-rfq" id="toc-entry-5">Confirm the RFQ</a></li>
<li><a class="reference internal" href="#release-the-purchase-approval-block" id="toc-entry-6">Release the purchase approval block</a></li>
<li><a class="reference internal" href="#notifications-to-followers" id="toc-entry-7">Notifications to followers</a></li>
</ul>
</li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-8">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-9">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-10">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-11">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-12">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
<ul class="simple">
<li>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.</li>
<li>Assign the security group Release RFQ with approval block to users that
should be able to release the block. Users in group Purchase / Managers
are by default assigned to this group.</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
<div class="section" id="set-the-purchase-approval-block">
<h2><a class="toc-backref" href="#toc-entry-3">Set the Purchase Approval Block</a></h2>
<ol class="arabic simple">
<li>Go to Purchases / Purchase / Requests for Quotation</li>
<li>Create a new RFQ and indicate the approval block reason (found in the
right hand side of the screen, below the order date).</li>
</ol>
</div>
<div class="section" id="search-existing-rfq">
<h2><a class="toc-backref" href="#toc-entry-4">Search existing RFQ</a></h2>
<p>There is a filter Blocked to search for orders that are blocked for approval.
It is also possible to search RFQs with a specific block reason.</p>
</div>
<div class="section" id="confirm-the-rfq">
<h2><a class="toc-backref" href="#toc-entry-5">Confirm the RFQ</a></h2>
<ol class="arabic simple">
<li>Press the button Confirm. If theres an approval block, the order will
be set to status To Approve. You will then need to request a Purchase
Manager to approve it.</li>
</ol>
</div>
<div class="section" id="release-the-purchase-approval-block">
<h2><a class="toc-backref" href="#toc-entry-6">Release the purchase approval block</a></h2>
<p>While the RFQ is in draft, members of security group Release RFQ with approval block,
can see a button Release Approval Block. From this point and on, anyone
seeing that RFQ will be able to validate it.</p>
</div>
<div class="section" id="notifications-to-followers">
<h2><a class="toc-backref" href="#toc-entry-7">Notifications to followers</a></h2>
<p>Followers of the RFQ receive notifications when an approval block has been
set or released.</p>
</div>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-8">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/purchase-workflow/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/purchase-workflow/issues/new?body=module:%20purchase_order_approval_block%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-9">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-10">Authors</a></h2>
<ul class="simple">
<li>ForgeFlow</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-11">Contributors</a></h2>
<ul class="simple">
<li>Jordi Ballester Alomar &lt;<a class="reference external" href="mailto:jordi.ballester&#64;forgeflow.com">jordi.ballester&#64;forgeflow.com</a>&gt;</li>
<li>Roser Garcia &lt;<a class="reference external" href="mailto:roser.garcia&#64;forgeflow.com">roser.garcia&#64;forgeflow.com</a>&gt;</li>
<li>Darshan Patel &lt;<a class="reference external" href="mailto:darshan.patel.serpentcs&#64;gmail.com">darshan.patel.serpentcs&#64;gmail.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-12">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/purchase-workflow/tree/16.0/purchase_order_approval_block">OCA/purchase-workflow</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,4 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import test_purchase_order_approval_block
from . import test_po_approval_block_reason

View file

@ -0,0 +1,70 @@
# Copyright 2017 ForgeFlow S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from .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.with_user(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.with_user(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.with_user(self.user2_id).button_confirm()
purchase.company_id.po_double_validation = False
self.assertEqual(purchase.state, "draft")
# 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.with_user(self.user2_id).button_confirm()
self.assertEqual(purchase.state, "draft")
purchase.with_user(self.user2_id).button_approve()
self.assertEqual(purchase.state, "purchase")

View file

@ -0,0 +1,80 @@
# Copyright 2017 ForgeFlow S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
import time
from odoo.tests.common import TransactionCase
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
class TestPurchaseOrderApprovalBlock(TransactionCase):
def setUp(self):
super(TestPurchaseOrderApprovalBlock, self).setUp()
self.users_obj = self.env["res.users"]
self.po_obj = self.env["purchase.order"]
self.po_block_obj = self.env["purchase.approval.block.reason"]
# company
self.company1 = self.env.ref("base.main_company")
# groups
self.group_purchase_user = self.env.ref("purchase.group_purchase_user")
self.group_purchase_manager = self.env.ref("purchase.group_purchase_manager")
# Partner
self.partner1 = self.env.ref("base.res_partner_1")
# Products
self.product1 = self.env.ref("product.product_product_7")
self.product2 = self.env.ref("product.product_product_9")
self.product3 = self.env.ref("product.product_product_11")
# Create users
self.user1_id = self._create_user(
"user_1", [self.group_purchase_user], self.company1
)
self.user2_id = self._create_user(
"user_2", [self.group_purchase_manager], self.company1
)
# Create a PO Block Reason
self._create_block_reason()
def _create_block_reason(self):
self.po_approval_block_reason = self.po_block_obj.create(
{"name": "Needs Permission", "description": "Permission to validate"}
)
def _create_user(self, login, groups, company):
"""Create a user."""
group_ids = [group.id for group in groups]
user = self.users_obj.with_context(no_reset_password=True).create(
{
"name": "Purchase User",
"login": login,
"password": "test",
"email": "test@yourcompany.com",
"company_id": company.id,
"company_ids": [(4, company.id)],
"groups_id": [(6, 0, group_ids)],
}
)
return user.id
def _create_purchase(self, line_products):
"""Create a purchase order.
``line_products`` is a list of tuple [(product, qty)]
"""
lines = []
for product, qty in line_products:
line_values = {
"name": product.name,
"product_id": product.id,
"product_qty": qty,
"product_uom": product.uom_id.id,
"price_unit": 100,
"date_planned": time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
}
lines.append((0, 0, line_values))
purchase = self.po_obj.create(
{
"partner_id": self.partner1.id,
"order_line": lines,
"company_id": self.company1.id,
}
)
return purchase

View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2017 ForgeFlow S.L.
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="purchase_approval_block_reason_tree_view" model="ir.ui.view">
<field name="name">purchase.approval.block.reason.tree</field>
<field name="model">purchase.approval.block.reason</field>
<field name="arch" type="xml">
<tree>
<field name="name" />
<field name="description" />
</tree>
</field>
</record>
<record id="purchase_approval_block_reason_form_view" model="ir.ui.view">
<field name="name">purchase.approval.block.reason.form</field>
<field name="model">purchase.approval.block.reason</field>
<field name="arch" type="xml">
<form>
<sheet>
<div class="oe_button_box" name="active_button_box">
<button
name="toggle_active"
type="object"
class="oe_stat_button"
icon="fa-archive"
>
<field
name="active"
widget="boolean_button"
options='{"terminology": "archive"}'
/>
</button>
</div>
<group name="top" colspan="2" col="2">
<field name="name" />
<field name="description" />
</group>
</sheet>
</form>
</field>
</record>
<record id="action_purchase_approval_block_reason" model="ir.actions.act_window">
<field name="name">Purchase Approval Block Reasons</field>
<field name="res_model">purchase.approval.block.reason</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem
id="menu_purchase_approval_block_reason"
name="Purchase Approval Block Reasons"
parent="purchase.menu_purchase_config"
action="action_purchase_approval_block_reason"
/>
</odoo>

View file

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2017 ForgeFlow S.L.
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="purchase_order_form" model="ir.ui.view">
<field name="name">purchase.order.form.block.reason</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_form" />
<field name="arch" type="xml">
<button name="button_draft" position="attributes">
<attribute name="states">cancel,to approve</attribute>
</button>
<field name="date_order" position="after">
<field
name="approval_block_id"
force_save="1"
attrs="{'readonly': ['|',('approval_blocked','=', True), ('state', 'not in', 'draft')]}"
/>
<field name="approval_blocked" invisible="True" />
</field>
<xpath expr="//header/button[@name='button_confirm']" position="before">
<button
name="button_release_approval_block"
string="Release Approval Block"
type="object"
class="btn-primary"
groups="purchase_order_approval_block.group_rfq_approval_block"
attrs="{'invisible': ['|',('approval_block_id', '=', False),
('state', 'not in', ['draft', 'sent'])]}"
/>
</xpath>
</field>
</record>
<record id="view_purchase_order_filter" model="ir.ui.view">
<field name="name">request.quotation.select.block.reason</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.view_purchase_order_filter" />
<field name="arch" type="xml">
<field name="product_id" position="after">
<field name="approval_block_id" />
</field>
<filter name="approved" position="after">
<filter
string="Blocked for Approval"
name="blocked_po"
domain="[('approval_block_id', '!=', False)]"
/>
</filter>
</field>
</record>
</odoo>

View file

@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from . import purchase_exception_confirm

View file

@ -0,0 +1,14 @@
# Copyright 2017 ForgeFlow S.L.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import models
class PurchaseExceptionConfirm(models.TransientModel):
_inherit = "purchase.exception.confirm"
def action_confirm(self):
self.ensure_one()
if self.ignore and self.related_model_id.approval_block_id:
self.related_model_id.button_release_approval_block()
return super(PurchaseExceptionConfirm, self).action_confirm()

View file

@ -0,0 +1,42 @@
[project]
name = "odoo-bringout-oca-purchase-workflow-purchase_order_approval_block"
version = "16.0.0"
description = "Purchase Order Approval Block - Odoo addon"
authors = [
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
]
dependencies = [
"odoo-bringout-oca-purchase-workflow-purchase_exception>=16.0.0",
"requests>=2.25.1"
]
readme = "README.md"
requires-python = ">= 3.11"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Office/Business",
]
[project.urls]
homepage = "https://github.com/bringout/0"
repository = "https://github.com/bringout/0"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.build.targets.wheel]
packages = ["purchase_order_approval_block"]
[tool.rye]
managed = true
dev-dependencies = [
"pytest>=8.4.1",
]