Initial commit: OCA Technical packages (595 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:03 +02:00
commit 2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions

View file

@ -0,0 +1,47 @@
# Consider the production potential is available to promise
Odoo addon: stock_available_mrp
## Installation
```bash
pip install odoo-bringout-oca-stock-logistics-availability-stock_available_mrp
```
## Dependencies
This addon depends on:
- stock_available
- mrp
## Manifest Information
- **Name**: Consider the production potential is available to promise
- **Version**: 16.0.1.1.0
- **Category**: Hidden
- **License**: AGPL-3
- **Installable**: True
## Source
Based on [OCA/stock-logistics-availability](https://github.com/OCA/stock-logistics-availability) branch 16.0, addon `stock_available_mrp`.
## 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 Stock_available_mrp Module - stock_available_mrp
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 stock_available_mrp. 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,6 @@
# Dependencies
This addon depends on:
- [stock_available](../../odoo-bringout-oca-stock-logistics-availability-stock_available)
- [mrp](../../odoo-bringout-oca-ocb-mrp)

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 stock_available_mrp or install in UI.

View file

@ -0,0 +1,7 @@
# Install
```bash
pip install odoo-bringout-oca-stock-logistics-availability-stock_available_mrp"
# or
uv pip install odoo-bringout-oca-stock-logistics-availability-stock_available_mrp"
```

View file

@ -0,0 +1,12 @@
# Models
Detected core models and extensions in stock_available_mrp.
```mermaid
classDiagram
class product_product
```
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: stock_available_mrp. Provides features documented in upstream Odoo 16 under this addon.
- Source: OCA/OCB 16.0, addon stock_available_mrp
- License: LGPL-3

View file

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

View file

@ -0,0 +1,8 @@
# Security
This module does not define custom security rules or access controls beyond Odoo defaults.
Default Odoo security applies:
- Base user access through standard groups
- Model access inherited from dependencies
- No custom row-level security rules

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 stock_available_mrp
```

View file

@ -0,0 +1,3 @@
# Wizards
This module does not include UI wizards.

View file

@ -0,0 +1,43 @@
[project]
name = "odoo-bringout-oca-stock-logistics-availability-stock_available_mrp"
version = "16.0.0"
description = "Consider the production potential is available to promise - Odoo addon"
authors = [
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
]
dependencies = [
"odoo-bringout-oca-stock-logistics-availability-stock_available>=16.0.0",
"odoo-bringout-oca-ocb-mrp>=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 = ["stock_available_mrp"]
[tool.rye]
managed = true
dev-dependencies = [
"pytest>=8.4.1",
]

View file

@ -0,0 +1,140 @@
=========================================================
Consider the production potential is available to promise
=========================================================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:e6f6a385b0f5ef7f6a95fff8cc68cfe7cb4e6832323c98d873bc806255582515
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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%2Fstock--logistics--availability-lightgray.png?logo=github
:target: https://github.com/OCA/stock-logistics-availability/tree/16.0/stock_available_mrp
:alt: OCA/stock-logistics-availability
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/stock-logistics-availability-16-0/stock-logistics-availability-16-0-stock_available_mrp
: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/stock-logistics-availability&target_branch=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
This module takes the potential quantities available for Products into account in
the quantity available to promise, where the "Potential quantity" is the
quantity that can be manufactured with the components immediately at hand.
By configuration, the "Potential quantity" can be computed based on other product field.
For example, "Potential quantity" can be the quantity that can be manufactured
with the components available to promise.
**Table of contents**
.. contents::
:local:
Known issues / Roadmap
======================
Known issues
~~~~~~~~~~~~
The manufacturing delays are not taken into account : this module assumes that
if you have components in stock goods, you can manufacture finished goods
quickly enough.
As a consequence, and to avoid overestimating, **only the first level** of Bill
of Materials is considered.
However Sets (a.k.a "phantom" BoMs) are taken into account: if a component must
be replaced with a set, it's the stock of the set's product which will decide
the potential.
If a product has several variants, only the variant with the biggest potential
will be taken into account when reporting the production potential. For
example, even if you actually have enough components to make 10 iPads 16Go AND
42 iPads 32Go, we'll consider that you can promise only 42 iPads.
Removed features
~~~~~~~~~~~~~~~~
Previous versions of this module used to let programmers demand to get the
potential quantity in an arbitrary Unit of Measure using the `context`. This
feature was present in the standard computations too until v8.0, but it has
been dropped from the standard from v8.0 on.
For the sake of consistency the potential quantity is now always reported in
the product's main Unit of Measure too.
Roadmap
~~~~~~~
Possible improvements for future versions:
* Take manufacturing delays into account: we should not promise goods to
customers if they want them delivered earlier that we can make them
* Compute the quantity of finished product that can be made directly on each
Bill of Material: this would be useful for production managers, and may make
the computations faster by avoiding to compute the same BoM several times
when several variants share the same BoM.
* Add an option (probably as a sub-module) to consider all raw materials as
available if they can be bought from the suppliers in time for the
manufacturing.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/stock-logistics-availability/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/stock-logistics-availability/issues/new?body=module:%20stock_available_mrp%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
~~~~~~~
* Numérigraphe
Contributors
~~~~~~~~~~~~
* Loïc Bellier (Numérigraphe) <lb@numerigraphe.com>
* Lionel Sausin (Numérigraphe) <ls@numerigraphe.com>
* many thanks to Graeme Gellatly for his advice and code review
* Laurent Mignon <laurent.mignon@acsone.eu>
* Cédric Pigeon <cedric.pigeon@acsone.eu>
* Florian da Costa <florian.dacosta@akretion.com>
* Joan Mateu <joan.mateu@forgeflow.com>
* `Tecnativa <https://www.tecnativa.com>`_:
* Víctor Martínez
* `Trobz <https://trobz.com>`_:
* Khoi Vo <khoivha@trobz.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/stock-logistics-availability <https://github.com/OCA/stock-logistics-availability/tree/16.0/stock_available_mrp>`_ 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 @@
# Copyright 2014 Numérigraphe SARL
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import models

View file

@ -0,0 +1,13 @@
# Copyright 2014 Numérigraphe SARL, Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
"name": "Consider the production potential is available to promise",
"version": "16.0.1.1.0",
"author": "Numérigraphe," "Odoo Community Association (OCA)",
"website": "https://github.com/OCA/stock-logistics-availability",
"category": "Hidden",
"depends": ["stock_available", "mrp"],
"demo": ["demo/mrp_data.xml"],
"license": "AGPL-3",
"installable": True,
}

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">
<record id="product_kit_1a" model="product.product">
<field name="default_code">PCSC234-WHITE</field>
<field
name="product_tmpl_id"
ref="mrp.product_product_table_kit_product_template"
/>
<field
name="product_template_attribute_value_ids"
eval="[(6,0,[ref('product.product_attribute_value_3')])]"
/>
</record>
<record id="mrp.product_product_table_kit" model="product.product">
<field
name="product_template_attribute_value_ids"
eval="[(6,0,[ref('product.product_attribute_value_4')])]"
/>
</record>
<record id="mrp.mrp_bom_kit_line_2" model="mrp.bom.line">
<field
name="bom_product_template_attribute_value_ids"
eval="[(6,0,[ref('product.product_attribute_value_4')])]"
/>
</record>
<record id="product_computer_desk_bolt_white" model="product.product">
<field name="name">Bolt</field>
<field name="categ_id" ref="product.product_category_5" />
<field name="standard_price">1.0</field>
<field name="list_price">5.0</field>
<field name="type">product</field>
<field name="uom_id" ref="uom.product_uom_unit" />
<field name="uom_po_id" ref="uom.product_uom_unit" />
<field name="default_code">BOLT-WHITE</field>
</record>
<record id="mrp_bom_kit_line_3" model="mrp.bom.line">
<field name="product_id" ref="product_computer_desk_bolt_white" />
<field name="product_qty">4</field>
<field name="product_uom_id" ref="uom.product_uom_unit" />
<field name="sequence">5</field>
<field name="bom_id" ref="mrp.mrp_bom_kit" />
<field
name="bom_product_template_attribute_value_ids"
eval="[(6,0,[ref('product.product_attribute_value_3')])]"
/>
</record>
</odoo>

View file

@ -0,0 +1,24 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_available_mrp
#
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: stock_available_mrp
#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template
msgid "Bolt"
msgstr "Matica"
#. module: stock_available_mrp
#: model:ir.model,name:stock_available_mrp.model_product_product
msgid "Product Variant"
msgstr "Varijanta proizvoda"

View file

@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_available_mrp
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2022-08-17 12:07+0000\n"
"Last-Translator: jabelchi <jabelchi@gmail.com>\n"
"Language-Team: none\n"
"Language: ca\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.3.2\n"
#. module: stock_available_mrp
#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template
msgid "Bolt"
msgstr "Cargol"
#. module: stock_available_mrp
#: model:ir.model,name:stock_available_mrp.model_product_product
msgid "Product Variant"
msgstr ""
#~ msgid "Product"
#~ msgstr "Producte"
#~ msgid "Table Kit"
#~ msgstr "Kit de taula"
#~ msgid "Table kit"
#~ msgstr "Kit de taula"
#~ msgid "Units"
#~ msgstr "Unitats"

View file

@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_available_mrp
#
# Translators:
# Rudolf Schnapka <rs@techno-flex.de>, 2016
msgid ""
msgstr ""
"Project-Id-Version: stock-logistics-warehouse (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-01-14 01:38+0000\n"
"PO-Revision-Date: 2016-01-14 09:35+0000\n"
"Last-Translator: Rudolf Schnapka <rs@techno-flex.de>\n"
"Language-Team: German (http://www.transifex.com/oca/OCA-stock-logistics-"
"warehouse-8-0/language/de/)\n"
"Language: de\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"
#. module: stock_available_mrp
#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template
msgid "Bolt"
msgstr ""
#. module: stock_available_mrp
#: model:ir.model,name:stock_available_mrp.model_product_product
msgid "Product Variant"
msgstr ""
#~ msgid "Product"
#~ msgstr "Produkt"
#~ msgid "Product Template"
#~ msgstr "Produktvorlage"
#~ msgid "Thousand"
#~ msgstr "Tausend"

View file

@ -0,0 +1,60 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_available_mrp
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: stock-logistics-warehouse (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-01-14 01:38+0000\n"
"PO-Revision-Date: 2023-10-15 20:37+0000\n"
"Last-Translator: Ivorra78 <informatica@totmaterial.es>\n"
"Language-Team: Spanish (http://www.transifex.com/oca/"
"OCA-stock-logistics-warehouse-8-0/language/es/)\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: stock_available_mrp
#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template
msgid "Bolt"
msgstr "Perno"
#. module: stock_available_mrp
#: model:ir.model,name:stock_available_mrp.model_product_product
msgid "Product Variant"
msgstr "Variante del Producto"
#~ msgid "Display Name"
#~ msgstr "Mostrar Nombre"
#~ msgid "ID"
#~ msgstr "ID (identificación)"
#~ msgid "Last Modified on"
#~ msgstr "Última Modificación el"
#~ msgid "Product"
#~ msgstr "Producto"
#~ msgid "Table Kit"
#~ msgstr "Conjunto de mesa"
#~ msgid "Table kit"
#~ msgstr "Conjunto de mesa"
#~ msgid "Units"
#~ msgstr "Unidades"
#~ msgid "kg"
#~ msgstr "kilogramos"
#~ msgid "m³"
#~ msgstr "metros cúbicos"
#~ msgid "Product Template"
#~ msgstr "Plantilla de producto"

View file

@ -0,0 +1,35 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_available_mrp
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: stock-logistics-warehouse (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-01-14 01:38+0000\n"
"PO-Revision-Date: 2016-01-13 16:35+0000\n"
"Last-Translator: <>\n"
"Language-Team: Finnish (http://www.transifex.com/oca/OCA-stock-logistics-"
"warehouse-8-0/language/fi/)\n"
"Language: fi\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"
#. module: stock_available_mrp
#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template
msgid "Bolt"
msgstr ""
#. module: stock_available_mrp
#: model:ir.model,name:stock_available_mrp.model_product_product
msgid "Product Variant"
msgstr ""
#~ msgid "Product"
#~ msgstr "Tuote"
#~ msgid "Product Template"
#~ msgstr "Tuotteen malli"

View file

@ -0,0 +1,51 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_available_mrp
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: stock-logistics-warehouse (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-01-14 01:38+0000\n"
"PO-Revision-Date: 2020-11-12 12:44+0000\n"
"Last-Translator: Yann Papouin <y.papouin@dec-industrie.com>\n"
"Language-Team: French (http://www.transifex.com/oca/OCA-stock-logistics-"
"warehouse-8-0/language/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: stock_available_mrp
#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template
msgid "Bolt"
msgstr "Boulon"
#. module: stock_available_mrp
#: model:ir.model,name:stock_available_mrp.model_product_product
msgid "Product Variant"
msgstr ""
#~ msgid "Product"
#~ msgstr "Article"
#~ msgid "Table Kit"
#~ msgstr "Table en kit"
#~ msgid "Table kit"
#~ msgstr "Table en kit"
#~ msgid "kg"
#~ msgstr "kg"
#~ msgid "BOM"
#~ msgstr "Nomenclature"
#~ msgid "Unit(s)"
#~ msgstr "Unité(s)"
#~ msgid "Product Template"
#~ msgstr "Modèle de produit"

View file

@ -0,0 +1,66 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_available_mrp
#
# Translators:
# Bole <bole@dajmi5.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: stock-logistics-warehouse (9.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-06-12 19:59+0000\n"
"PO-Revision-Date: 2016-06-14 10:45+0000\n"
"Last-Translator: Bole <bole@dajmi5.com>\n"
"Language-Team: Croatian (Croatia) (http://www.transifex.com/oca/OCA-stock-"
"logistics-warehouse-9-0/language/hr_HR/)\n"
"Language: hr_HR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
#. module: stock_available_mrp
#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template
msgid "Bolt"
msgstr ""
#. module: stock_available_mrp
#: model:ir.model,name:stock_available_mrp.model_product_product
msgid "Product Variant"
msgstr ""
#~ msgid "Product"
#~ msgstr "Proizvod"
#~ msgid "Product Template"
#~ msgstr "Predložak proizvoda"
#~ msgid "<span class=\"o_stat_text\">Potential</span>"
#~ msgstr "<span class=\"o_stat_text\">Potencijal</span>"
#~ msgid "Component ids"
#~ msgstr "ID-ovi komponenata"
#~ msgid "Potential"
#~ msgstr "Potencijal"
#~ msgid ""
#~ "Quantity of this Product that could be produced using the materials "
#~ "already at hand."
#~ msgstr ""
#~ "Količina ovog proizvoda nije mogla biti proizvedena korištenjem trenutno "
#~ "raspoloživih materijala."
#~ msgid ""
#~ "Quantity of this Product that could be produced using the materials "
#~ "already at hand. If the product has several variants, this will be the "
#~ "biggest quantity that can be made for a any single variant."
#~ msgstr ""
#~ "Količina ovog proizvoda koja može biti proizvodedna raspoloživim "
#~ "količinama sirovina. Ako proizvod ima nekoliko varijanti, ovo će biti "
#~ "najveća moguća količina koja se može proizvesti za svaku pojedinu "
#~ "varijantu."
#~ msgid "Thousand"
#~ msgstr "Tisuću"

View file

@ -0,0 +1,33 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_available_mrp
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: stock-logistics-warehouse (9.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-09-04 10:11+0000\n"
"PO-Revision-Date: 2023-11-24 16:35+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\n"
"Language-Team: Italian (http://www.transifex.com/oca/"
"OCA-stock-logistics-warehouse-9-0/language/it/)\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 4.17\n"
#. module: stock_available_mrp
#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template
msgid "Bolt"
msgstr "Bullone"
#. module: stock_available_mrp
#: model:ir.model,name:stock_available_mrp.model_product_product
msgid "Product Variant"
msgstr "Variante prodotto"
#~ msgid "Product"
#~ msgstr "Prodotto"

View file

@ -0,0 +1,66 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_available_mrp
#
# Translators:
# Claudio Araujo Santos <claudioaraujosantos@gmail.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: stock-logistics-warehouse (9.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-07-03 20:56+0000\n"
"PO-Revision-Date: 2024-05-21 00:58+0000\n"
"Last-Translator: Rodrigo Macedo <sottomaiormacedotec@users.noreply."
"translation.odoo-community.org>\n"
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/oca/"
"OCA-stock-logistics-warehouse-9-0/language/pt_BR/)\n"
"Language: pt_BR\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: stock_available_mrp
#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template
msgid "Bolt"
msgstr "Parafuso"
#. module: stock_available_mrp
#: model:ir.model,name:stock_available_mrp.model_product_product
msgid "Product Variant"
msgstr "Variante do Produto"
#~ msgid "Product"
#~ msgstr "Produto"
#~ msgid "Product Template"
#~ msgstr "Modelo Produto"
#~ msgid "<span class=\"o_stat_text\">Potential</span>"
#~ msgstr "<span class=\"o_stat_text\">Potencial</span>"
#~ msgid "Component ids"
#~ msgstr "IDs de componentes"
#~ msgid "Potential"
#~ msgstr "Potencial"
#~ msgid ""
#~ "Quantity of this Product that could be produced using the materials "
#~ "already at hand."
#~ msgstr ""
#~ "Quantidade deste produto que poderia ser produzido usando os materiais já "
#~ "na mão."
#~ msgid ""
#~ "Quantity of this Product that could be produced using the materials "
#~ "already at hand. If the product has several variants, this will be the "
#~ "biggest quantity that can be made for a any single variant."
#~ msgstr ""
#~ "Quantidade deste produto que poderia ser produzido usando os materiais já "
#~ "na mão. Se o produto tiver várias variantes, esta será a maior quantidade "
#~ "que pode ser feito por qualquer uma única variante."
#~ msgid "Thousand"
#~ msgstr "Mil"

View file

@ -0,0 +1,40 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_available_mrp
#
# Translators:
# Matjaž Mozetič <m.mozetic@matmoz.si>, 2016
msgid ""
msgstr ""
"Project-Id-Version: stock-logistics-warehouse (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-01-14 01:38+0000\n"
"PO-Revision-Date: 2016-01-14 05:18+0000\n"
"Last-Translator: Matjaž Mozetič <m.mozetic@matmoz.si>\n"
"Language-Team: Slovenian (http://www.transifex.com/oca/OCA-stock-logistics-"
"warehouse-8-0/language/sl/)\n"
"Language: sl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n"
"%100==4 ? 2 : 3);\n"
#. module: stock_available_mrp
#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template
msgid "Bolt"
msgstr ""
#. module: stock_available_mrp
#: model:ir.model,name:stock_available_mrp.model_product_product
msgid "Product Variant"
msgstr ""
#~ msgid "Product"
#~ msgstr "Proizvod"
#~ msgid "Product Template"
#~ msgstr "Predloga proizvoda"
#~ msgid "Thousand"
#~ msgstr "Tisoč"

View file

@ -0,0 +1,24 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_available_mrp
#
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: stock_available_mrp
#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template
msgid "Bolt"
msgstr ""
#. module: stock_available_mrp
#: model:ir.model,name:stock_available_mrp.model_product_product
msgid "Product Variant"
msgstr ""

View file

@ -0,0 +1,27 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_available_mrp
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-02-19 17:06+0000\n"
"Last-Translator: İsmail Çağan Yılmaz <ismail.cagan.yilmaz@gmail.com>\n"
"Language-Team: none\n"
"Language: tr\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: stock_available_mrp
#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template
msgid "Bolt"
msgstr "Cıvata"
#. module: stock_available_mrp
#: model:ir.model,name:stock_available_mrp.model_product_product
msgid "Product Variant"
msgstr "Ürün Varyantı"

View file

@ -0,0 +1,61 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_available_mrp
#
# Translators:
# Jeffery Chenn <jeffery9@gmail.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: stock-logistics-warehouse (9.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-08-28 10:00+0000\n"
"PO-Revision-Date: 2019-09-26 15:05+0000\n"
"Last-Translator: 黎伟杰 <674416404@qq.com>\n"
"Language-Team: Chinese (China) (http://www.transifex.com/oca/OCA-stock-"
"logistics-warehouse-9-0/language/zh_CN/)\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 3.8\n"
#. module: stock_available_mrp
#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template
msgid "Bolt"
msgstr "螺栓"
#. module: stock_available_mrp
#: model:ir.model,name:stock_available_mrp.model_product_product
msgid "Product Variant"
msgstr ""
#~ msgid "Product"
#~ msgstr "产品"
#~ msgid "Table Kit"
#~ msgstr "桌台套件"
#~ msgid "Table kit"
#~ msgstr "桌台套件"
#~ msgid "kg"
#~ msgstr "公斤"
#~ msgid "BOM"
#~ msgstr "BOM"
#~ msgid "Unit(s)"
#~ msgstr "件"
#~ msgid "Product Template"
#~ msgstr "产品模板"
#~ msgid "<span class=\"o_stat_text\">Potential</span>"
#~ msgstr "<span class=\"o_stat_text\">潜在</span>"
#~ msgid "Potential"
#~ msgstr "潜在"
#~ msgid "Thousand"
#~ msgstr "千"

View file

@ -0,0 +1,4 @@
# Copyright 2014 Numérigraphe SARL
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import product_product

View file

@ -0,0 +1,187 @@
# Copyright 2014 Numérigraphe SARL
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from collections import Counter
from odoo import api, models
from odoo.fields import first
from odoo.tools import float_round
class ProductProduct(models.Model):
_inherit = "product.product"
@api.depends(
"virtual_available",
"bom_ids",
"bom_ids.product_qty",
"variant_bom_ids",
"variant_bom_ids.product_qty",
)
def _compute_available_quantities(self):
res = super()._compute_available_quantities()
return res
def _compute_available_quantities_dict(self):
res, stock_dict = super()._compute_available_quantities_dict()
# compute qty for product with bom
product_with_bom = self.filtered("variant_bom_ids")
product_with_bom |= (self - product_with_bom).filtered(
lambda p: p.bom_ids
and any(not bom.product_id or bom.product_id == p for bom in p.bom_ids)
)
if not product_with_bom:
return res, stock_dict
icp = self.env["ir.config_parameter"]
stock_available_mrp_based_on = icp.sudo().get_param(
"stock_available_mrp_based_on", "qty_available"
)
# explode all boms at once
exploded_boms = product_with_bom._explode_boms()
# extract the list of product used as bom component
component_products = self.env["product.product"].browse()
for exploded_components in exploded_boms.values():
for bom_component in exploded_components:
component_products |= first(bom_component).product_id
# Compute stock for product components.
# {'productid': {field_name: qty}}
if res and stock_available_mrp_based_on in list(res.values())[0]:
# If the qty is computed by the same method use it to avoid
# stressing the cache
component_qties, _ = component_products._compute_available_quantities_dict()
else:
# The qty is a field computed by an other method than the
# current one. Take the value on the record.
component_qties = {
p.id: {stock_available_mrp_based_on: p[stock_available_mrp_based_on]}
for p in component_products
}
for product in product_with_bom:
# Need by product (same product can be in many BOM lines/levels)
bom_id = first(
product.variant_bom_ids
or product.bom_ids.filtered(
lambda b, product=product: not b.product_id
or b.product_id == product
)
)
exploded_components = exploded_boms[product.id]
component_needs = product._get_components_needs(exploded_components)
if not component_needs:
# The BoM has no line we can use
potential_qty = 0.0
else:
# Find the lowest quantity we can make with the stock at hand
components_potential_qty = min(
component_qties[component.id][stock_available_mrp_based_on] / need
for component, need in component_needs.items()
)
potential_qty = bom_id.product_qty * components_potential_qty
potential_qty = potential_qty > 0.0 and potential_qty or 0.0
# We want to respect the rounding factor of the potential_qty
# Rounding down as we want to be pesimistic.
potential_qty = bom_id.product_uom_id._compute_quantity(
potential_qty,
bom_id.product_tmpl_id.uom_id,
rounding_method="DOWN",
)
res[product.id]["potential_qty"] = potential_qty
res[product.id]["immediately_usable_qty"] += potential_qty
return res, stock_dict
def _explode_boms(self):
"""
return a dict by product_id of exploded bom lines
:return:
"""
return self.explode_bom_quantities()
@api.model
def _get_components_needs(self, exploded_components):
"""Return the needed qty of each compoments in the exploded_components
:type exploded_components
:rtype: collections.Counter
"""
needs = Counter()
for bom_line, bom_qty in exploded_components:
component = bom_line.product_id
needs += Counter({component: bom_qty})
return needs
def explode_bom_quantities(self):
"""Explode a bill of material with quantities to consume
It returns a dict with the exploded bom lines and
the quantity they consume. Example::
{
<product-id>: [
(<bom-line-id>, <quantity>)
(<bom-line-id>, <quantity>)
]
}
The 'MrpBom.explode()' method includes the same information, with other
things, but is under-optimized to be used for the purpose of this
module. The killer is particularly the call to `_bom_find()` which can
generate thousands of SELECT for searches.
"""
result = {}
for product in self:
lines_done = []
bom_lines = [
(first(product.bom_ids), bom_line, product, 1.0)
for bom_line in first(product.bom_ids).bom_line_ids
]
while bom_lines:
(current_bom, current_line, current_product, current_qty) = bom_lines[0]
bom_lines = bom_lines[1:]
if current_line._skip_bom_line(current_product):
continue
line_quantity = current_qty * current_line.product_qty
sub_bom = first(current_line.product_id.bom_ids)
if sub_bom.type == "phantom":
product_uom = current_line.product_uom_id
converted_line_quantity = product_uom._compute_quantity(
line_quantity / sub_bom.product_qty,
sub_bom.product_uom_id,
)
bom_lines = [
(
sub_bom,
line,
current_line.product_id,
converted_line_quantity,
)
for line in sub_bom.bom_line_ids
] + bom_lines
else:
# We round up here because the user expects that if he has
# to consume a little more, the whole UOM unit should be
# consumed.
rounding = current_line.product_uom_id.rounding
line_quantity = float_round(
line_quantity,
precision_rounding=rounding,
rounding_method="UP",
)
lines_done.append((current_line, line_quantity))
result[product.id] = lines_done
return result

View file

@ -0,0 +1,15 @@
* Loïc Bellier (Numérigraphe) <lb@numerigraphe.com>
* Lionel Sausin (Numérigraphe) <ls@numerigraphe.com>
* many thanks to Graeme Gellatly for his advice and code review
* Laurent Mignon <laurent.mignon@acsone.eu>
* Cédric Pigeon <cedric.pigeon@acsone.eu>
* Florian da Costa <florian.dacosta@akretion.com>
* Joan Mateu <joan.mateu@forgeflow.com>
* `Tecnativa <https://www.tecnativa.com>`_:
* Víctor Martínez
* `Trobz <https://trobz.com>`_:
* Khoi Vo <khoivha@trobz.com>

View file

@ -0,0 +1,6 @@
This module takes the potential quantities available for Products into account in
the quantity available to promise, where the "Potential quantity" is the
quantity that can be manufactured with the components immediately at hand.
By configuration, the "Potential quantity" can be computed based on other product field.
For example, "Potential quantity" can be the quantity that can be manufactured
with the components available to promise.

View file

@ -0,0 +1,41 @@
Known issues
~~~~~~~~~~~~
The manufacturing delays are not taken into account : this module assumes that
if you have components in stock goods, you can manufacture finished goods
quickly enough.
As a consequence, and to avoid overestimating, **only the first level** of Bill
of Materials is considered.
However Sets (a.k.a "phantom" BoMs) are taken into account: if a component must
be replaced with a set, it's the stock of the set's product which will decide
the potential.
If a product has several variants, only the variant with the biggest potential
will be taken into account when reporting the production potential. For
example, even if you actually have enough components to make 10 iPads 16Go AND
42 iPads 32Go, we'll consider that you can promise only 42 iPads.
Removed features
~~~~~~~~~~~~~~~~
Previous versions of this module used to let programmers demand to get the
potential quantity in an arbitrary Unit of Measure using the `context`. This
feature was present in the standard computations too until v8.0, but it has
been dropped from the standard from v8.0 on.
For the sake of consistency the potential quantity is now always reported in
the product's main Unit of Measure too.
Roadmap
~~~~~~~
Possible improvements for future versions:
* Take manufacturing delays into account: we should not promise goods to
customers if they want them delivered earlier that we can make them
* Compute the quantity of finished product that can be made directly on each
Bill of Material: this would be useful for production managers, and may make
the computations faster by avoiding to compute the same BoM several times
when several variants share the same BoM.
* Add an option (probably as a sub-module) to consider all raw materials as
available if they can be bought from the suppliers in time for the
manufacturing.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View file

@ -0,0 +1,501 @@
<!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>Consider the production potential is available to promise</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="consider-the-production-potential-is-available-to-promise">
<h1 class="title">Consider the production potential is available to promise</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:e6f6a385b0f5ef7f6a95fff8cc68cfe7cb4e6832323c98d873bc806255582515
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<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/stock-logistics-availability/tree/16.0/stock_available_mrp"><img alt="OCA/stock-logistics-availability" src="https://img.shields.io/badge/github-OCA%2Fstock--logistics--availability-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/stock-logistics-availability-16-0/stock-logistics-availability-16-0-stock_available_mrp"><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/stock-logistics-availability&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 takes the potential quantities available for Products into account in
the quantity available to promise, where the “Potential quantity” is the
quantity that can be manufactured with the components immediately at hand.
By configuration, the “Potential quantity” can be computed based on other product field.
For example, “Potential quantity” can be the quantity that can be manufactured
with the components available to promise.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-1">Known issues / Roadmap</a><ul>
<li><a class="reference internal" href="#known-issues" id="toc-entry-2">Known issues</a></li>
<li><a class="reference internal" href="#removed-features" id="toc-entry-3">Removed features</a></li>
<li><a class="reference internal" href="#roadmap" id="toc-entry-4">Roadmap</a></li>
</ul>
</li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-5">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-6">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-7">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-8">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-9">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#toc-entry-1">Known issues / Roadmap</a></h1>
<div class="section" id="known-issues">
<h2><a class="toc-backref" href="#toc-entry-2">Known issues</a></h2>
<p>The manufacturing delays are not taken into account : this module assumes that
if you have components in stock goods, you can manufacture finished goods
quickly enough.</p>
<p>As a consequence, and to avoid overestimating, <strong>only the first level</strong> of Bill
of Materials is considered.</p>
<p>However Sets (a.k.a “phantom” BoMs) are taken into account: if a component must
be replaced with a set, its the stock of the sets product which will decide
the potential.</p>
<p>If a product has several variants, only the variant with the biggest potential
will be taken into account when reporting the production potential. For
example, even if you actually have enough components to make 10 iPads 16Go AND
42 iPads 32Go, well consider that you can promise only 42 iPads.</p>
</div>
<div class="section" id="removed-features">
<h2><a class="toc-backref" href="#toc-entry-3">Removed features</a></h2>
<p>Previous versions of this module used to let programmers demand to get the
potential quantity in an arbitrary Unit of Measure using the <cite>context</cite>. This
feature was present in the standard computations too until v8.0, but it has
been dropped from the standard from v8.0 on.</p>
<p>For the sake of consistency the potential quantity is now always reported in
the products main Unit of Measure too.</p>
</div>
<div class="section" id="roadmap">
<h2><a class="toc-backref" href="#toc-entry-4">Roadmap</a></h2>
<p>Possible improvements for future versions:</p>
<ul class="simple">
<li>Take manufacturing delays into account: we should not promise goods to
customers if they want them delivered earlier that we can make them</li>
<li>Compute the quantity of finished product that can be made directly on each
Bill of Material: this would be useful for production managers, and may make
the computations faster by avoiding to compute the same BoM several times
when several variants share the same BoM.</li>
<li>Add an option (probably as a sub-module) to consider all raw materials as
available if they can be bought from the suppliers in time for the
manufacturing.</li>
</ul>
</div>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-5">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/stock-logistics-availability/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/stock-logistics-availability/issues/new?body=module:%20stock_available_mrp%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-6">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-7">Authors</a></h2>
<ul class="simple">
<li>Numérigraphe</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-8">Contributors</a></h2>
<ul>
<li><p class="first">Loïc Bellier (Numérigraphe) &lt;<a class="reference external" href="mailto:lb&#64;numerigraphe.com">lb&#64;numerigraphe.com</a>&gt;</p>
</li>
<li><p class="first">Lionel Sausin (Numérigraphe) &lt;<a class="reference external" href="mailto:ls&#64;numerigraphe.com">ls&#64;numerigraphe.com</a>&gt;</p>
</li>
<li><p class="first">many thanks to Graeme Gellatly for his advice and code review</p>
</li>
<li><p class="first">Laurent Mignon &lt;<a class="reference external" href="mailto:laurent.mignon&#64;acsone.eu">laurent.mignon&#64;acsone.eu</a>&gt;</p>
</li>
<li><p class="first">Cédric Pigeon &lt;<a class="reference external" href="mailto:cedric.pigeon&#64;acsone.eu">cedric.pigeon&#64;acsone.eu</a>&gt;</p>
</li>
<li><p class="first">Florian da Costa &lt;<a class="reference external" href="mailto:florian.dacosta&#64;akretion.com">florian.dacosta&#64;akretion.com</a>&gt;</p>
</li>
<li><p class="first">Joan Mateu &lt;<a class="reference external" href="mailto:joan.mateu&#64;forgeflow.com">joan.mateu&#64;forgeflow.com</a>&gt;</p>
</li>
<li><p class="first"><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:</p>
<ul class="simple">
<li>Víctor Martínez</li>
</ul>
</li>
<li><p class="first"><a class="reference external" href="https://trobz.com">Trobz</a>:</p>
<blockquote>
<ul class="simple">
<li>Khoi Vo &lt;<a class="reference external" href="mailto:khoivha&#64;trobz.com">khoivha&#64;trobz.com</a>&gt;</li>
</ul>
</blockquote>
</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-9">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/stock-logistics-availability/tree/16.0/stock_available_mrp">OCA/stock-logistics-availability</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 @@
# Copyright 2014 Numérigraphe SARL
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import test_potential_qty

View file

@ -0,0 +1,508 @@
# Copyright 2014 Numérigraphe SARL
# Copyright 2021 Tecnativa - Víctor Martínez
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo.osv.expression import TRUE_LEAF
from odoo.tests.common import TransactionCase
class TestPotentialQty(TransactionCase):
"""Test the potential quantity on a product with a multi-line BoM"""
@classmethod
def setUpClass(cls):
super(TestPotentialQty, cls).setUpClass()
cls.product_model = cls.env["product.product"]
cls.bom_model = cls.env["mrp.bom"]
cls.bom_line_model = cls.env["mrp.bom.line"]
cls.stock_quant_model = cls.env["stock.quant"]
cls.config = cls.env["ir.config_parameter"]
cls.location = cls.env["stock.location"]
cls.main_company = cls.env.ref("base.main_company")
# Get the warehouses
cls.wh_main = cls.env.ref("stock.warehouse0")
cls.wh_ch = cls.env.ref("stock.stock_warehouse_shop0")
# We need to compute parent_left and parent_right of the locations as
# they are used to compute qty_available of the product.
cls.location._parent_store_compute()
cls.setup_demo_data()
@classmethod
def setup_demo_data(cls):
#  An interesting product (multi-line BoM, variants)
cls.tmpl = cls.env.ref("mrp.product_product_table_kit_product_template")
#  First variant
cls.var1 = cls.env.ref("mrp.product_product_table_kit")
cls.var1.type = "product"
#  Second variant
cls.var2 = cls.env.ref("stock_available_mrp.product_kit_1a")
cls.var2.type = "product"
# Make bolt a stockable product to be able to change its stock
# we need to unreserve the existing move before being able to do it.
bolt = cls.env.ref("mrp.product_product_computer_desk_bolt")
bolt.stock_move_ids._do_unreserve()
bolt.type = "product"
# Components that can be used to make the product
components = [
# Bolt
bolt,
# Wood Panel
cls.env.ref("mrp.product_product_wood_panel"),
]
# Zero-out the inventory of all variants and components
for component in components + [v for v in cls.tmpl.product_variant_ids]:
moves = component.stock_move_ids.filtered(
lambda mo: mo.state not in ("done", "cancel")
)
moves._action_cancel()
component.stock_quant_ids.unlink()
# A product without a BoM
cls.product_wo_bom = cls.env.ref("product.product_product_11")
def create_inventory(self, product, qty, location=None, company_id=None):
if location is None:
location = self.wh_main.lot_stock_id
if company_id:
self.env["stock.quant"].with_company(company_id)._update_available_quantity(
product, location, qty
)
else:
self.env["stock.quant"]._update_available_quantity(product, location, qty)
def create_simple_bom(self, product, sub_product, product_qty=1, sub_product_qty=1):
bom = self.bom_model.create(
{
"product_tmpl_id": product.product_tmpl_id.id,
"product_id": product.id,
"product_qty": product_qty,
}
)
self.bom_line_model.create(
{
"bom_id": bom.id,
"product_id": sub_product.id,
"product_qty": sub_product_qty,
}
)
return bom
def assertPotentialQty(self, record, qty, msg):
record.invalidate_model()
# Check the potential
self.assertEqual(record.potential_qty, qty, msg)
def test_01_potential_qty_no_bom(self):
#  Check the potential when there's no BoM
self.assertPotentialQty(
self.product_wo_bom, 0.0, "The potential without a BoM should be 0"
)
def test_02_potential_qty_no_bom_for_company(self):
chicago_id = self.ref("stock.res_company_1")
# Receive 1000x Wood Panel owned by Chicago
self.create_inventory(
product=self.env.ref("mrp.product_product_wood_panel"),
qty=1000.0,
location=self.wh_ch.lot_stock_id,
company_id=chicago_id,
)
# Put Bolt owned by Chicago for 1000x the 1st variant in main WH
self.create_inventory(
product=self.env.ref("mrp.product_product_computer_desk_bolt"),
qty=1000.0,
location=self.wh_ch.lot_stock_id,
company_id=chicago_id,
)
self.assertPotentialQty(
self.tmpl, 250.0, "Wrong template potential after receiving components"
)
test_user = self.env["res.users"].create(
{
"name": "test_demo",
"login": "test_demo",
"company_id": self.main_company.id,
"company_ids": [(4, self.main_company.id), (4, chicago_id)],
"groups_id": [
(4, self.ref("stock.group_stock_user")),
(4, self.ref("mrp.group_mrp_user")),
],
}
)
bom = self.env["mrp.bom"].search([("product_tmpl_id", "=", self.tmpl.id)])
test_user_tmpl = self.tmpl.with_user(test_user)
self.assertPotentialQty(
test_user_tmpl, 250.0, "Simple user can access to the potential_qty"
)
# Set the bom on the main company (visible to members of main company)
# and all products without company (visible to all)
# and the demo user on Chicago (child of main company)
self.env["product.product"].search([TRUE_LEAF]).write({"company_id": False})
test_user.write({"company_ids": [(6, 0, self.main_company.ids)]})
bom.company_id = self.main_company
self.assertPotentialQty(
test_user_tmpl,
0,
"The bom should not be visible to non members of the bom's "
"company or company child of the bom's company",
)
bom.company_id = chicago_id
test_user.write({"company_ids": [(4, chicago_id)]})
self.assertPotentialQty(test_user_tmpl, 250.0, "")
def test_03_potential_qty(self):
for i in [self.tmpl, self.var1, self.var2]:
self.assertPotentialQty(i, 0.0, "The potential quantity should start at 0")
# Receive 1000x Wood Panel
self.create_inventory(
product=self.env.ref("mrp.product_product_wood_panel"),
qty=1000.0,
location=self.wh_main.lot_stock_id,
)
for i in [self.tmpl, self.var1, self.var2]:
self.assertPotentialQty(
i,
0.0,
"Receiving a single component should not change the "
"potential of %s" % i,
)
# Receive enough bolt to make 1000x the 1st variant in main WH
self.create_inventory(
product=self.env.ref("mrp.product_product_computer_desk_bolt"),
qty=1000.0,
location=self.wh_main.lot_stock_id,
)
self.assertPotentialQty(
self.tmpl, 250.0, "Wrong template potential after receiving components"
)
self.assertPotentialQty(
self.var1, 250.0, "Wrong variant 1 potential after receiving components"
)
self.assertPotentialQty(
self.var2,
0.0,
"Receiving variant 1's component should not change "
"variant 2's potential",
)
# Receive enough components to make 213 the 2nd variant at Chicago
self.create_inventory(
self.env.ref("mrp.product_product_wood_panel"),
1000.0,
self.wh_ch.lot_stock_id,
self.ref("stock.res_company_1"),
)
self.create_inventory(
self.env.ref("stock_available_mrp.product_computer_desk_bolt_white"),
852.0,
self.wh_ch.lot_stock_id,
self.ref("stock.res_company_1"),
)
self.assertPotentialQty(
self.tmpl.with_context(test=True),
250.0,
"Wrong template potential after receiving components",
)
self.assertPotentialQty(
self.var1,
250.0,
"Receiving variant 2's component should not change "
"variant 1's potential",
)
self.assertPotentialQty(
self.var2, 213.0, "Wrong variant 2 potential after receiving components"
)
# Check by warehouse
self.assertPotentialQty(
self.tmpl.with_context(warehouse=self.wh_main.id),
250.0,
"Wrong potential quantity in main WH",
)
self.assertPotentialQty(
self.tmpl.with_context(warehouse=self.wh_ch.id),
213.0,
"Wrong potential quantity in Chicago WH",
)
# Check by location
self.assertPotentialQty(
self.tmpl.with_context(location=self.wh_main.lot_stock_id.id),
250.0,
"Wrong potential quantity in main WH location",
)
self.assertPotentialQty(
self.tmpl.with_context(location=self.wh_ch.lot_stock_id.id),
213.0,
"Wrong potential quantity in Chicago WH location",
)
def test_04_multi_unit_recursive_bom(self):
# Test multi-level and multi-units BOM
uom_unit = self.env.ref("uom.product_uom_unit")
uom_unit.rounding = 1.0
p1 = self.product_model.create(
{
"name": "Test product with BOM",
"type": "product",
"uom_id": self.env.ref("uom.product_uom_unit").id,
}
)
p2 = self.product_model.create(
{
"name": "Test sub product with BOM",
"type": "consu",
"uom_id": self.env.ref("uom.product_uom_unit").id,
}
)
p3 = self.product_model.create(
{
"name": "Test component",
"type": "product",
"uom_id": self.env.ref("uom.product_uom_unit").id,
}
)
bom_p1 = self.bom_model.create(
{"product_tmpl_id": p1.product_tmpl_id.id, "product_id": p1.id}
)
self.bom_line_model.create(
{
"bom_id": bom_p1.id,
"product_id": p3.id,
"product_qty": 1,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
}
)
# Two p2 which have a bom
self.bom_line_model.create(
{
"bom_id": bom_p1.id,
"product_id": p2.id,
"product_qty": 2,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
}
)
bom_p2 = self.bom_model.create(
{
"product_tmpl_id": p2.product_tmpl_id.id,
"product_id": p2.id,
"type": "phantom",
}
)
# p2 need 2 unit of component
self.bom_line_model.create(
{
"bom_id": bom_p2.id,
"product_id": p3.id,
"product_qty": 2,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
}
)
p1.invalidate_model()
# Need a least 5 units for one P1
self.assertEqual(0, p1.potential_qty)
self.create_inventory(p3, 1)
p1.invalidate_model()
self.assertEqual(0, p1.potential_qty)
self.create_inventory(p3, 3)
p1.invalidate_model()
self.assertEqual(0, p1.potential_qty)
self.create_inventory(p3, 5)
p1.invalidate_model()
self.assertEqual(1.0, p1.potential_qty)
self.create_inventory(p3, 6)
p1.invalidate_model()
self.assertEqual(3.0, p1.potential_qty)
self.create_inventory(p3, 10)
p1.invalidate_model()
self.assertEqual(5.0, p1.potential_qty)
def test_05_potential_qty_list(self):
# Try to highlight a bug when _get_potential_qty is called on
# a recordset with multiple products
# Recursive compute is not working
p1 = self.product_model.create({"name": "Test P1"})
p2 = self.product_model.create({"name": "Test P2"})
p3 = self.product_model.create({"name": "Test P3", "type": "product"})
self.config.set_param("stock_available_mrp_based_on", "immediately_usable_qty")
# P1 need one P2
self.create_simple_bom(p1, p2)
# P2 need one P3
self.create_simple_bom(p2, p3)
self.create_inventory(p3, 3)
self.product_model.invalidate_model()
products = self.product_model.search([("id", "in", [p1.id, p2.id, p3.id])])
self.assertEqual(
{p1.id: 3.0, p2.id: 3.0, p3.id: 0.0},
{p.id: p.potential_qty for p in products},
)
def test_product_phantom(self):
# Create a BOM product with 2 components
# Set stock quantity for the first one == 0.0
# Set stock quantity for the second one == 1.0
# Create an incoming movement for the first component
# The immediately available quantity should stay == 0.0
uom_unit = self.env.ref("uom.product_uom_unit")
uom_unit.rounding = 1.0
product = self.product_model.create(
{
"name": "Test product with BOM",
"type": "product",
"uom_id": self.env.ref("uom.product_uom_unit").id,
}
)
bom = self.bom_model.create(
{
"product_tmpl_id": product.product_tmpl_id.id,
"product_id": product.id,
"type": "phantom",
}
)
bom_product = self.product_model.create(
{
"name": "BOM product",
"type": "product",
"uom_id": self.env.ref("uom.product_uom_unit").id,
}
)
self.bom_line_model.create(
{
"bom_id": bom.id,
"product_id": bom_product.id,
"product_qty": 3,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
}
)
bom_product_2 = self.product_model.create(
{
"name": "BOM product 2",
"type": "product",
"uom_id": self.env.ref("uom.product_uom_unit").id,
}
)
self.bom_line_model.create(
{
"bom_id": bom.id,
"product_id": bom_product_2.id,
"product_qty": 1,
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
}
)
self.create_inventory(bom_product_2, 1)
move_in = self.env["stock.move"].create(
{
"name": bom_product.name,
"location_id": self.env.ref("stock.stock_location_suppliers").id,
"location_dest_id": self.env.ref("stock.stock_location_stock").id,
"product_id": bom_product.id,
"product_uom_qty": 1.0,
"product_uom": self.env.ref("uom.product_uom_unit").id,
}
)
move_in._action_confirm()
product.invalidate_model()
self.assertEqual(product.immediately_usable_qty, 0.0)
def test_06_potential_qty(self):
# BoM only applies to white variant.
bom = self.env["mrp.bom"].search([("product_tmpl_id", "=", self.tmpl.id)])
bom.bom_line_ids.write({"bom_product_template_attribute_value_ids": False})
bom.product_id = self.var2.id
for i in [self.tmpl, self.var1, self.var2]:
self.assertPotentialQty(i, 0.0, "The potential quantity should start at 0")
# Receive 1000x Wood Panel
self.create_inventory(
product=self.env.ref("mrp.product_product_wood_panel"),
qty=1000.0,
location=self.wh_main.lot_stock_id,
)
for i in [self.tmpl, self.var1, self.var2]:
self.assertPotentialQty(
i,
0.0,
"Receiving a single component should not change the "
"potential of %s" % i,
)
# Receive second component
self.create_inventory(
product=self.env.ref("mrp.product_product_computer_desk_bolt"),
qty=1000.0,
location=self.wh_main.lot_stock_id,
)
self.assertPotentialQty(
self.tmpl,
0,
"Template potential changed after receiving partial variant 2 components",
)
self.assertPotentialQty(
self.var1,
0,
"Variant 1 potential changed after receiving partial variant 2 components",
)
self.assertPotentialQty(
self.var2,
0.0,
"Variant 2 potential changed after receiving partial components",
)
# Receive enough components to make 250 the 1st variant
self.create_inventory(
product=self.env.ref(
"stock_available_mrp.product_computer_desk_bolt_white"
),
qty=1000.0,
location=self.wh_main.lot_stock_id,
)
self.var1.invalidate_model()
self.assertPotentialQty(
self.tmpl,
250.0,
"Wrong template potential after receiving variant 2 components",
)
self.assertPotentialQty(
self.var1,
0,
"Wrong variant 1 potential after receiving variant 2 components",
)
self.assertPotentialQty(
self.var2, 250.0, "Wrong variant 2 potential after receiving its components"
)