Skip to content
Open
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
287 changes: 287 additions & 0 deletions product_state_restriction/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

=========================
Product State Restriction
=========================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:3e30c523236f2069b7cb586a19012b9471aeac0ec7f240181c8941df6bd00e38
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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/license-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%2Fproduct--attribute-lightgray.png?logo=github
:target: https://github.com/OCA/product-attribute/tree/19.0/product_state_restriction
:alt: OCA/product-attribute
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/product-attribute-19-0/product-attribute-19-0-product_state_restriction
: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/product-attribute&target_branch=19.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

Product State Restrictions
==========================

This module extends the OCA **Product State** lifecycle with
configurable operational restrictions.

It builds on the standard product states. On each state you can define
whether products in that state are allowed to be sold, manufactured, or
moved out of the warehouse. When a product is assigned to a restricted
state (or when the restriction flags on a state are changed), the system
enforces the rules automatically.

Features
--------

- **Restrict Sales**: products cannot be sold; ``sale_ok`` is kept in
sync and sales order confirmation is blocked.
- **Restrict Manufacturing**: finished products and components cannot be
used in manufacturing (blocked on MO confirm and on Produce / Mark as
Done).
- **Restrict Outgoing Moves**: products cannot leave the warehouse
(customer deliveries and other outgoing stock moves are blocked).

Why this module
---------------

``product_state`` only provides the lifecycle field. It does not lock
sales, manufacturing, or inventory flows. This module adds the missing
operational control in a modular, upgrade-safe way, using official
extension points (for example the ``_inverse_product_state_id`` hook)
instead of patching core code.

Dependencies
------------

- ``product_state`` (OCA)
- ``sale`` (for sales restrictions)
- ``mrp`` (for manufacturing restrictions)
- ``stock`` (for outgoing move restrictions)

Technical notes
---------------

- Restriction flags live on ``product.state``.
- Changing a product’s state updates ``sale_ok`` via the inverse method
on ``product.template``.
- Changing ``restrict_sale`` on a state updates ``sale_ok`` on all
products currently in that state.
- Hard checks run on:

- ``sale.order`` → ``action_confirm``
- ``mrp.production`` → ``action_confirm`` and ``button_mark_done``
- ``stock.move`` → ``_action_done`` (outgoing destinations)

This keeps behaviour consistent whether the user works from the UI,
imports, or automated flows.

**Table of contents**

.. contents::
:local:

Usage
=====

Usage
=====

1. Install
----------

1. Install **Product State** (``product_state``) if it is not already
installed.
2. Install this module (**Product State Restrictions**).
3. Optional: install ``product_state_sale`` if you want the Product
States menu under **Sales → Configuration → Products**.

2. Configure product states
---------------------------

1. | Go to **Sales → Configuration → Products → Product States**
| (or the equivalent menu under Inventory / Product, depending on
installed modules).

2. Open an existing state (for example *Obsolete* or *End of Lifecycle*)
or create a new one (for example *On Hold* / *Issue*).

3. In the **Restrictions** section, enable the rules you need:

+-----------------------------+----------------------------------------+
| Flag | Effect |
+=============================+========================================+
| **Restrict Sales** | Products in this state cannot be sold. |
| | ``sale_ok`` is set to ``False`` and |
| | confirming a sales order that contains |
| | the product is blocked. |
+-----------------------------+----------------------------------------+
| **Restrict Manufacturing** | Products cannot be manufactured as |
| | finished goods and cannot be consumed |
| | as components. Blocked when confirming |
| | an MO and when clicking **Produce** / |
| | **Mark as Done**. |
+-----------------------------+----------------------------------------+
| **Restrict Outgoing Moves** | Products cannot leave the warehouse |
| | (e.g. customer deliveries). Validation |
| | of the corresponding stock move is |
| | blocked. |
+-----------------------------+----------------------------------------+

4. Save the state.

Typical setup examples:

- **sellable (Normal)**: all restrictions off
- **draft (In Development)**: Restrict Sales (+ optionally Restrict
Outgoing)
- **end / obsolete**: Restrict Sales, Restrict Manufacturing, Restrict
Outgoing
- **custom “Issue / On Hold”**: all three restrictions on until the
problem is resolved

3. Assign a state to a product
------------------------------

1. Open a product template.
2. Set the **State** field (status bar / many2one provided by
``product_state``).
3. Save.

Effects:

- If the state has **Restrict Sales**, ``Can be Sold`` (``sale_ok``) is
turned off automatically.
- Moving the product back to a non-restricted state turns ``sale_ok``
back on (unless you changed it manually for other reasons).

You can also change restriction flags on a state that already has
products assigned: all those products are updated in batch (for
``sale_ok``).

4. What users will see
----------------------

+----------------------------------+----------------------------------+
| Action | When restricted |
+==================================+==================================+
| Confirm sales order | Error: product is in a |
| | restricted state and cannot be |
| | sold. |
+----------------------------------+----------------------------------+
| Confirm manufacturing order | Error: finished product or a |
| | component is restricted for |
| | manufacturing. |
+----------------------------------+----------------------------------+
| Produce / Mark as Done on MO | Same manufacturing restriction |
| | check (so production cannot |
| | bypass planning). |
+----------------------------------+----------------------------------+
| Validate outgoing transfer / | Error: product cannot leave the |
| delivery | warehouse in this state. |
+----------------------------------+----------------------------------+

Messages include the product name and the state name so warehouse and
sales users can react quickly (change state, remove the line, or
escalate).

5. Recommended process
----------------------

1. Define which lifecycle states should block which operations.
2. Train users to move products to *On Hold* / *Issue* (or *Obsolete*)
when there is a quality or master-data problem.
3. After the issue is resolved, move the product back to *sellable* (or
the appropriate open state).
4. Restrictions are lifted automatically according to the flags on the
new state.

6. Notes
--------

- Restrictions are **product-level** (via the product’s state), not
lot/serial-level. For lot holds, use Quality or a dedicated
lot-blocking module.
- ``sale_ok = False`` hides the product from normal sales selection; the
confirm check is an extra safety net.
- Manufacturing is checked both at confirm and at produce time, so users
cannot skip the rule by producing without a prior confirm step in
atypical flows.

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

Bugs are tracked on `GitHub Issues <https://github.com/OCA/product-attribute/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/product-attribute/issues/new?body=module:%20product_state_restriction%0Aversion:%2019.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
-------

* AGF Vector GmbH

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

- Florian Gruber <florian.gruber@agfvector.at>

Other credits
-------------

Credits
~~~~~~~

Authors
^^^^^^^

- Florian Gruber
- AGF Vector GmbH

Other credits
^^^^^^^^^^^^^

The development of this module was supported by AGF Vector GmbH.

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.

.. |maintainer-flogruber| image:: https://github.com/flogruber.png?size=40px
:target: https://github.com/flogruber
:alt: flogruber

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-flogruber|

This module is part of the `OCA/product-attribute <https://github.com/OCA/product-attribute/tree/19.0/product_state_restriction>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
4 changes: 4 additions & 0 deletions product_state_restriction/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright 2026 AGF Vector GmbH (<https://agfvector.at>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from . import models
24 changes: 24 additions & 0 deletions product_state_restriction/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2026 AGF Vector GmbH (<https://agfvector.at>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "Product State Restriction",
"summary": """
""",
"author": "AGF Vector GmbH, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/product-attribute",
"version": "19.0.1.0.0",
"category": "Product",
"depends": [
"product_state",
"product_state_sale",
"sale",
"mrp",
"stock",
],
"data": [
"views/product_state_views.xml",
],
"application": False,
"maintainers": ["flogruber"],
"license": "AGPL-3",
}
Loading
Loading