Initial commit: OCA Mrp packages (117 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:05 +02:00
commit 277e84fd7a
4403 changed files with 395154 additions and 0 deletions

View file

@ -0,0 +1,44 @@
# MRP Serial Number Propagation
Odoo addon: mrp_lot_number_propagation
## Installation
```bash
pip install odoo-bringout-oca-manufacture-mrp_lot_number_propagation
```
## Dependencies
This addon depends on:
- mrp
## Manifest Information
- **Name**: MRP Serial Number Propagation
- **Version**: 16.0.1.0.1
- **Category**: Manufacturing
- **License**: AGPL-3
- **Installable**: True
## Source
Based on [OCA/manufacture](https://github.com/OCA/manufacture) branch 16.0, addon `mrp_lot_number_propagation`.
## 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
- 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 Mrp_lot_number_propagation Module - mrp_lot_number_propagation
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 mrp_lot_number_propagation. 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:
- [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 mrp_lot_number_propagation or install in UI.

View file

@ -0,0 +1,7 @@
# Install
```bash
pip install odoo-bringout-oca-manufacture-mrp_lot_number_propagation"
# or
uv pip install odoo-bringout-oca-manufacture-mrp_lot_number_propagation"
```

View file

@ -0,0 +1,17 @@
# Models
Detected core models and extensions in mrp_lot_number_propagation.
```mermaid
classDiagram
class mrp_bom
class mrp_bom_line
class mrp_production
class product_product
class product_template
class stock_move
```
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: mrp_lot_number_propagation. Provides features documented in upstream Odoo 16 under this addon.
- Source: OCA/OCB 16.0, addon mrp_lot_number_propagation
- 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 mrp_lot_number_propagation
```

View file

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

View file

@ -0,0 +1,90 @@
=============================
MRP Serial Number Propagation
=============================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:30bb4002c776b791eaa84394c02858060e3a7a4d2c26bc1898484210ea63a7d5
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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%2Fmanufacture-lightgray.png?logo=github
:target: https://github.com/OCA/manufacture/tree/16.0/mrp_lot_number_propagation
:alt: OCA/manufacture
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/manufacture-16-0/manufacture-16-0-mrp_lot_number_propagation
: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/manufacture&target_branch=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
Allow to propagate a lot number from a component to a finished product.
**Table of contents**
.. contents::
:local:
Known issues / Roadmap
======================
* Add compatibility with lot number (in addition to serial number)
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/manufacture/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/manufacture/issues/new?body=module:%20mrp_lot_number_propagation%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
~~~~~~~
* Camptocamp
Contributors
~~~~~~~~~~~~
* Akim Juillerat <akim.juillerat@camptocamp.com>
* Sébastien Alix <sebastien.alix@camptocamp.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.
.. |maintainer-sebalix| image:: https://github.com/sebalix.png?size=40px
:target: https://github.com/sebalix
:alt: sebalix
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-sebalix|
This module is part of the `OCA/manufacture <https://github.com/OCA/manufacture/tree/16.0/mrp_lot_number_propagation>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View file

@ -0,0 +1,20 @@
# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
{
"name": "MRP Serial Number Propagation",
"version": "16.0.1.0.1",
"development_status": "Beta",
"license": "AGPL-3",
"author": "Camptocamp, Odoo Community Association (OCA)",
"maintainers": ["sebalix"],
"summary": "Propagate a serial number from a component to a finished product",
"website": "https://github.com/OCA/manufacture",
"category": "Manufacturing",
"depends": ["mrp"],
"data": [
"views/mrp_bom.xml",
"views/mrp_production.xml",
],
"installable": True,
"application": False,
}

View file

@ -0,0 +1,173 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mrp_lot_number_propagation
#
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: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/product_template.py:0
#, python-format
msgid ""
"A BoM propagating serial numbers requires this product to be tracked as "
"such."
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_bom__lot_number_propagation
msgid ""
"Allow to propagate the lot/serial number from a component to the finished "
"product."
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_bom
msgid "Bill of Material"
msgstr "Sastavnica"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_bom_line
msgid "Bill of Material Line"
msgstr "Stavka sastavnice"
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Bill of material is marked for lot number propagation, but there are "
"multiple components propagating lot number. Please check BOM configuration."
msgstr ""
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Bill of material is marked for lot number propagation, but there are no "
"components propagating lot number. Please check BOM configuration."
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom__display_lot_number_propagation
msgid "Display Lot Number Propagation"
msgstr "Prikaži propagaciju broja šarže"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom_line__display_propagate_lot_number
msgid "Display Propagate Lot Number"
msgstr "Prikaži propagaciju broja šarže"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_production__is_lot_number_propagated
msgid "Is Lot Number Propagated"
msgstr "Je broj šarže propagiran"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom__lot_number_propagation
msgid "Lot Number Propagation"
msgstr "Propagacija broja šarže"
#. module: mrp_lot_number_propagation
#: model_terms:ir.ui.view,arch_db:mrp_lot_number_propagation.mrp_production_form_view
msgid "Lot/Serial Number"
msgstr "Lot/Serijski broj"
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Lot/Serial number %s already exists and has been used. Unable to propagate "
"it."
msgstr ""
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Lot/Serial number is propagated from a component, you are not allowed to "
"change it."
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_production__is_lot_number_propagated
msgid ""
"Lot/serial number is propagated from a component to the finished product."
msgstr ""
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_bom_line.py:0
#, python-format
msgid ""
"Only components tracked by serial number can propagate its lot/serial number"
" to the finished product."
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_product_template
msgid "Product"
msgstr "Artikal"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_product_product
msgid "Product Variant"
msgstr "Varijanta proizvoda"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_production
msgid "Production Order"
msgstr "Proizvodni nalog"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom_line__propagate_lot_number
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_stock_move__propagate_lot_number
msgid "Propagate Lot Number"
msgstr "Propagiraj broj šarže"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_production__propagated_lot_producing
msgid "Propagated Lot Producing"
msgstr "Propagirana šarža u proizvodnji"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_stock_move
msgid "Stock Move"
msgstr "Skladišno kretanje"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_production__propagated_lot_producing
msgid ""
"The BoM used on this manufacturing order is set to propagate lot number from"
" one of its components. The value will be computed once the corresponding "
"component is selected."
msgstr ""
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/product_template.py:0
#, python-format
msgid ""
"This component is configured to propagate its serial number in the following"
" Bill of Materials:{boms}'"
msgstr ""
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_bom.py:0
#, python-format
msgid ""
"With 'Lot Number Propagation' enabled, a line has to be configured with the "
"'Propagate Lot Number' option."
msgstr ""

View file

@ -0,0 +1,200 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mrp_lot_number_propagation
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-03-25 21:33+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: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/product_template.py:0
#, python-format
msgid ""
"A BoM propagating serial numbers requires this product to be tracked as "
"such."
msgstr ""
"Una BoM que propague números de serie requiere que este producto sea "
"rastreado como tal."
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_bom__lot_number_propagation
msgid ""
"Allow to propagate the lot/serial number from a component to the finished "
"product."
msgstr ""
"Permite propagar el número de lote/serie de un componente al producto "
"acabado."
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_bom
msgid "Bill of Material"
msgstr "Lista de Material"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_bom_line
msgid "Bill of Material Line"
msgstr "Línea de Lista de Materiales"
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Bill of material is marked for lot number propagation, but there are "
"multiple components propagating lot number. Please check BOM configuration."
msgstr ""
"La lista de materiales está marcada para la propagación del número de lote, "
"pero hay varios componentes que propagan el número de lote. Compruebe la "
"configuración de la lista de materiales."
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Bill of material is marked for lot number propagation, but there are no "
"components propagating lot number. Please check BOM configuration."
msgstr ""
"La lista de materiales está marcada para la propagación del número de lote, "
"pero no hay componentes que propaguen el número de lote. Compruebe la "
"configuración de la lista de materiales."
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom__display_lot_number_propagation
msgid "Display Lot Number Propagation"
msgstr "Mostrar Número de Lote Propagación"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom_line__display_propagate_lot_number
msgid "Display Propagate Lot Number"
msgstr "Mostrar Propagación Número de Lote"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_production__is_lot_number_propagated
msgid "Is Lot Number Propagated"
msgstr "Es el Número de Lote Propagado"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom__lot_number_propagation
msgid "Lot Number Propagation"
msgstr "Propagación del Número de Lote"
#. module: mrp_lot_number_propagation
#: model_terms:ir.ui.view,arch_db:mrp_lot_number_propagation.mrp_production_form_view
msgid "Lot/Serial Number"
msgstr "Lote/Número de Serie"
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Lot/Serial number %s already exists and has been used. Unable to propagate "
"it."
msgstr ""
"El lote/número de serie %s ya existe y ha sido utilizado. No se ha podido "
"propagar."
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Lot/Serial number is propagated from a component, you are not allowed to "
"change it."
msgstr ""
"El número de lote/serie se propaga desde un componente, usted no está "
"autorizado a modificarlo."
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_production__is_lot_number_propagated
msgid ""
"Lot/serial number is propagated from a component to the finished product."
msgstr ""
"El número de lote/serie se propaga de un componente al producto acabado."
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_bom_line.py:0
#, python-format
msgid ""
"Only components tracked by serial number can propagate its lot/serial number"
" to the finished product."
msgstr ""
"Sólo los componentes rastreados por número de serie pueden propagar su "
"número de lote/serie al producto acabado."
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_product_template
msgid "Product"
msgstr "Producto"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_product_product
msgid "Product Variant"
msgstr "Variante del Producto"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_production
msgid "Production Order"
msgstr "Orden de Fabricación"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom_line__propagate_lot_number
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_stock_move__propagate_lot_number
msgid "Propagate Lot Number"
msgstr "Propagar el Número de Lote"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_production__propagated_lot_producing
msgid "Propagated Lot Producing"
msgstr "Producción de Lotes Propagados"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_stock_move
msgid "Stock Move"
msgstr "Movimiento de Existencias"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_production__propagated_lot_producing
msgid ""
"The BoM used on this manufacturing order is set to propagate lot number from"
" one of its components. The value will be computed once the corresponding "
"component is selected."
msgstr ""
"La lista de materiales utilizada en esta orden de producción está "
"configurada para propagar el número de lote desde uno de sus componentes. El "
"valor se calculará una vez seleccionado el componente correspondiente."
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/product_template.py:0
#, python-format
msgid ""
"This component is configured to propagate its serial number in the following"
" Bill of Materials:{boms}'"
msgstr ""
"Este componente está configurado para propagar su número de serie en la "
"siguiente lista de materiales:{boms}'"
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_bom.py:0
#, python-format
msgid ""
"With 'Lot Number Propagation' enabled, a line has to be configured with the "
"'Propagate Lot Number' option."
msgstr ""
"Con la \"Propagación del número de lote\" activada, debe configurarse una "
"línea con la opción \"Propagar número de lote\"."

View file

@ -0,0 +1,198 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mrp_lot_number_propagation
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-07-09 09:58+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: mrp_lot_number_propagation
#: code:addons/mrp_lot_number_propagation/models/product_template.py:0
#, python-format
msgid ""
"A BoM propagating serial numbers requires this product to be tracked as such."
msgstr ""
"Una distinta base che propaga i numeri di serie richiede che questo prodotto "
"sia tracciato come tale."
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_bom__lot_number_propagation
msgid ""
"Allow to propagate the lot/serial number from a component to the finished "
"product."
msgstr ""
"Consente di propagare il numero di lotto/matricola da un componente al "
"prodotto finito."
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_bom
msgid "Bill of Material"
msgstr "Distinta base"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_bom_line
msgid "Bill of Material Line"
msgstr "Riga distinta base"
#. module: mrp_lot_number_propagation
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Bill of material is marked for lot number propagation, but there are "
"multiple components propagating lot number. Please check BOM configuration."
msgstr ""
"La distinta base è impostata per la propagazione del numero di lotto, ma ci "
"sono più componenti che propagano il numero di lotto. Verificare la "
"configurazione della DB."
#. module: mrp_lot_number_propagation
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Bill of material is marked for lot number propagation, but there are no "
"components propagating lot number. Please check BOM configuration."
msgstr ""
"La distinta base è impostata per la propagazione del numero di lotto, ma non "
"ci sono componenti che propagano il numero di lotto. Verificare la "
"configurazione della DB."
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom__display_lot_number_propagation
msgid "Display Lot Number Propagation"
msgstr "Visualizza propagazione numero di lotto"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom_line__display_propagate_lot_number
msgid "Display Propagate Lot Number"
msgstr "Visualizza il numero di lotto propagato"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_production__is_lot_number_propagated
msgid "Is Lot Number Propagated"
msgstr "Il numero di lotto è propagato"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom__lot_number_propagation
msgid "Lot Number Propagation"
msgstr "Propagazione numero di lotto"
#. module: mrp_lot_number_propagation
#: model_terms:ir.ui.view,arch_db:mrp_lot_number_propagation.mrp_production_form_view
msgid "Lot/Serial Number"
msgstr "Numero di lotto/serie"
#. module: mrp_lot_number_propagation
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Lot/Serial number %s already exists and has been used. Unable to propagate "
"it."
msgstr ""
"Il lotto/seriale %s esiste ed è stato usato. Non è possibile propagarlo."
#. module: mrp_lot_number_propagation
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Lot/Serial number is propagated from a component, you are not allowed to "
"change it."
msgstr ""
"Il numero di lotto/matricola è propagato da un componente, non è consentito "
"modificarlo."
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_production__is_lot_number_propagated
msgid ""
"Lot/serial number is propagated from a component to the finished product."
msgstr ""
"Il numero di lotto/matricola è propagato da un componente al prodotto finito."
#. module: mrp_lot_number_propagation
#: code:addons/mrp_lot_number_propagation/models/mrp_bom_line.py:0
#, python-format
msgid ""
"Only components tracked by serial number can propagate its lot/serial number "
"to the finished product."
msgstr ""
"Solo i componenti tracciati da una matricola possono propagare il loro "
"numero di lotto/matricola al prodotto finito."
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_product_product
msgid "Product"
msgstr "Prodotto"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_product_template
msgid "Product Template"
msgstr "Modello prodotto"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_production
msgid "Production Order"
msgstr "Ordine di produzione"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom_line__propagate_lot_number
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_stock_move__propagate_lot_number
msgid "Propagate Lot Number"
msgstr "Propaga numero di lotto"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_production__propagated_lot_producing
msgid "Propagated Lot Producing"
msgstr "Produzione lotto propagato"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_stock_move
msgid "Stock Move"
msgstr "Movimento di magazzino"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_production__propagated_lot_producing
msgid ""
"The BoM used on this manufacturing order is set to propagate lot number from "
"one of its components. The value will be computed once the corresponding "
"component is selected."
msgstr ""
"La DiBa utilizzata in questo ordine di produzione è impostata per propagare "
"il nomero di lotto da uno dei suoi componenti. Il valore verrà calcolato una "
"volta che il componente corrispondente sarà selezionato."
#. module: mrp_lot_number_propagation
#: code:addons/mrp_lot_number_propagation/models/product_template.py:0
#, python-format
msgid ""
"This component is configured to propagate its serial number in the following "
"Bill of Materials:{boms}'"
msgstr ""
"Questo componente è configurato per propagare la sua matricola nella "
"seguente DiBa: {boms}'"
#. module: mrp_lot_number_propagation
#: code:addons/mrp_lot_number_propagation/models/mrp_bom.py:0
#, python-format
msgid ""
"With 'Lot Number Propagation' enabled, a line has to be configured with the "
"'Propagate Lot Number' option."
msgstr ""
"Con 'Propagazione numero di lotto' abilitata, una riga deve essere "
"configurata con l'opzione 'Propaga numero di lotto'."
#, python-format
#~ msgid ""
#~ "Only one BoM line can propagate its lot/serial number to the finished "
#~ "product."
#~ msgstr ""
#~ "Solo una riga di DiBa può propagare il suo numero di lotto/matricola al "
#~ "prodotto finito."

View file

@ -0,0 +1,173 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mrp_lot_number_propagation
#
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: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/product_template.py:0
#, python-format
msgid ""
"A BoM propagating serial numbers requires this product to be tracked as "
"such."
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_bom__lot_number_propagation
msgid ""
"Allow to propagate the lot/serial number from a component to the finished "
"product."
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_bom
msgid "Bill of Material"
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_bom_line
msgid "Bill of Material Line"
msgstr ""
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Bill of material is marked for lot number propagation, but there are "
"multiple components propagating lot number. Please check BOM configuration."
msgstr ""
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Bill of material is marked for lot number propagation, but there are no "
"components propagating lot number. Please check BOM configuration."
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom__display_lot_number_propagation
msgid "Display Lot Number Propagation"
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom_line__display_propagate_lot_number
msgid "Display Propagate Lot Number"
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_production__is_lot_number_propagated
msgid "Is Lot Number Propagated"
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom__lot_number_propagation
msgid "Lot Number Propagation"
msgstr ""
#. module: mrp_lot_number_propagation
#: model_terms:ir.ui.view,arch_db:mrp_lot_number_propagation.mrp_production_form_view
msgid "Lot/Serial Number"
msgstr ""
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Lot/Serial number %s already exists and has been used. Unable to propagate "
"it."
msgstr ""
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Lot/Serial number is propagated from a component, you are not allowed to "
"change it."
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_production__is_lot_number_propagated
msgid ""
"Lot/serial number is propagated from a component to the finished product."
msgstr ""
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_bom_line.py:0
#, python-format
msgid ""
"Only components tracked by serial number can propagate its lot/serial number"
" to the finished product."
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_product_template
msgid "Product"
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_product_product
msgid "Product Variant"
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_production
msgid "Production Order"
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom_line__propagate_lot_number
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_stock_move__propagate_lot_number
msgid "Propagate Lot Number"
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_production__propagated_lot_producing
msgid "Propagated Lot Producing"
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_stock_move
msgid "Stock Move"
msgstr ""
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_production__propagated_lot_producing
msgid ""
"The BoM used on this manufacturing order is set to propagate lot number from"
" one of its components. The value will be computed once the corresponding "
"component is selected."
msgstr ""
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/product_template.py:0
#, python-format
msgid ""
"This component is configured to propagate its serial number in the following"
" Bill of Materials:{boms}'"
msgstr ""
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_bom.py:0
#, python-format
msgid ""
"With 'Lot Number Propagation' enabled, a line has to be configured with the "
"'Propagate Lot Number' option."
msgstr ""

View file

@ -0,0 +1,198 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mrp_lot_number_propagation
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-04-11 21:24+0000\n"
"Last-Translator: Bosd <c5e2fd43-d292-4c90-9d1f-74ff3436329a@anonaddy.me>\n"
"Language-Team: none\n"
"Language: nl\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.10.4\n"
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/product_template.py:0
#, python-format
msgid ""
"A BoM propagating serial numbers requires this product to be tracked as "
"such."
msgstr ""
"Een stuklijst die serienummers doorgeeft, vereist dat dit product als "
"zodanig wordt gevolgd."
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_bom__lot_number_propagation
msgid ""
"Allow to propagate the lot/serial number from a component to the finished "
"product."
msgstr ""
"Staat toe om het lot-/serienummer van een onderdeel door te geven aan het "
"eindproduct."
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_bom
msgid "Bill of Material"
msgstr "Stuklijst"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_bom_line
msgid "Bill of Material Line"
msgstr "Stuklijstregel"
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Bill of material is marked for lot number propagation, but there are "
"multiple components propagating lot number. Please check BOM configuration."
msgstr ""
"De stuklijst is gemarkeerd voor de doorgave van het lotnummer, maar er zijn "
"meerdere componenten die het lotnummer doorgeven. Controleer de "
"stuklijstconfiguratie."
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Bill of material is marked for lot number propagation, but there are no "
"components propagating lot number. Please check BOM configuration."
msgstr ""
"De stuklijst is gemarkeerd voor de doorgave van het lotnummer, maar er zijn "
"geen componenten die het lotnummer doorgeven. Controleer de "
"stuklijstconfiguratie."
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom__display_lot_number_propagation
msgid "Display Lot Number Propagation"
msgstr "Lotnummer Doorgave Weergeven"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom_line__display_propagate_lot_number
msgid "Display Propagate Lot Number"
msgstr "Lotnummer Doorgeven Weergeven"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_production__is_lot_number_propagated
msgid "Is Lot Number Propagated"
msgstr "Lotnummer Is Doorgegeven"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom__lot_number_propagation
msgid "Lot Number Propagation"
msgstr "Lotnummer Doorgave"
#. module: mrp_lot_number_propagation
#: model_terms:ir.ui.view,arch_db:mrp_lot_number_propagation.mrp_production_form_view
msgid "Lot/Serial Number"
msgstr "Lot-/Serienummer"
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Lot/Serial number %s already exists and has been used. Unable to propagate "
"it."
msgstr "Lot-/serienummer %s bestaat al en is gebruikt. Kan het niet doorgeven."
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_production.py:0
#, python-format
msgid ""
"Lot/Serial number is propagated from a component, you are not allowed to "
"change it."
msgstr ""
"Lot-/serienummer wordt doorgegeven vanuit een onderdeel, u mag het niet "
"wijzigen."
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_production__is_lot_number_propagated
msgid ""
"Lot/serial number is propagated from a component to the finished product."
msgstr ""
"Lot-/serienummer wordt doorgegeven van een onderdeel naar het eindproduct."
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_bom_line.py:0
#, python-format
msgid ""
"Only components tracked by serial number can propagate its lot/serial number"
" to the finished product."
msgstr ""
"Alleen componenten die worden gevolgd op serienummer kunnen hun lot-/"
"serienummer doorgeven aan het eindproduct."
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_product_template
msgid "Product"
msgstr "Product"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_product_product
msgid "Product Variant"
msgstr "Productvariant"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_mrp_production
msgid "Production Order"
msgstr "Productieorder"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_bom_line__propagate_lot_number
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_stock_move__propagate_lot_number
msgid "Propagate Lot Number"
msgstr "Lotnummer Doorgeven"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,field_description:mrp_lot_number_propagation.field_mrp_production__propagated_lot_producing
msgid "Propagated Lot Producing"
msgstr "Gepropageerd Lot Producerend"
#. module: mrp_lot_number_propagation
#: model:ir.model,name:mrp_lot_number_propagation.model_stock_move
msgid "Stock Move"
msgstr "Voorraadmutatie"
#. module: mrp_lot_number_propagation
#: model:ir.model.fields,help:mrp_lot_number_propagation.field_mrp_production__propagated_lot_producing
msgid ""
"The BoM used on this manufacturing order is set to propagate lot number from"
" one of its components. The value will be computed once the corresponding "
"component is selected."
msgstr ""
"De stuklijst die wordt gebruikt voor deze productieorder is ingesteld om het "
"lotnummer van een van de componenten door te geven. De waarde wordt berekend "
"zodra het betreffende onderdeel is geselecteerd."
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/product_template.py:0
#, python-format
msgid ""
"This component is configured to propagate its serial number in the following"
" Bill of Materials:{boms}'"
msgstr ""
"Dit onderdeel is geconfigureerd om zijn serienummer over te dragen in de "
"volgende stuklijst:{boms}'"
#. module: mrp_lot_number_propagation
#. odoo-python
#: code:addons/mrp_lot_number_propagation/models/mrp_bom.py:0
#, python-format
msgid ""
"With 'Lot Number Propagation' enabled, a line has to be configured with the "
"'Propagate Lot Number' option."
msgstr ""
"Als 'Lotnummer Doorgave' is ingeschakeld, moet een regel worden "
"geconfigureerd met de optie 'Lotnummer Doorgeven'."

View file

@ -0,0 +1,6 @@
from . import mrp_bom
from . import mrp_bom_line
from . import mrp_production
from . import product_product
from . import product_template
from . import stock_move

View file

@ -0,0 +1,88 @@
# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
from odoo import _, api, fields, models, tools
from odoo.exceptions import ValidationError
class MrpBom(models.Model):
_inherit = "mrp.bom"
lot_number_propagation = fields.Boolean(
default=False,
help=(
"Allow to propagate the lot/serial number "
"from a component to the finished product."
),
)
display_lot_number_propagation = fields.Boolean(
compute="_compute_display_lot_number_propagation"
)
@api.depends(
"type",
"product_tmpl_id.tracking",
"product_qty",
"product_uom_id",
"bom_line_ids.product_id.tracking",
"bom_line_ids.product_qty",
"bom_line_ids.product_uom_id",
)
def _compute_display_lot_number_propagation(self):
"""Check if a lot number can be propagated.
A lot number can be propagated from a component to the finished product if:
- the type of the BoM is normal (Manufacture this product)
- the finished product is tracked by serial number
- the quantity of the finished product is 1 and its UoM is unit
- there is at least one bom line, with a component tracked by serial,
having a quantity of 1 and its UoM is unit
"""
uom_unit = self.env.ref("uom.product_uom_unit")
for bom in self:
bom.display_lot_number_propagation = (
bom.type in self._get_lot_number_propagation_bom_types()
and bom.product_tmpl_id.tracking == "serial"
and tools.float_compare(
bom.product_qty, 1, precision_rounding=bom.product_uom_id.rounding
)
== 0
and bom.product_uom_id == uom_unit
and bom._has_tracked_product_to_propagate()
)
def _get_lot_number_propagation_bom_types(self):
return ["normal"]
def _has_tracked_product_to_propagate(self):
self.ensure_one()
uom_unit = self.env.ref("uom.product_uom_unit")
for line in self.bom_line_ids:
if (
line.product_id.tracking == "serial"
and tools.float_compare(
line.product_qty, 1, precision_rounding=line.product_uom_id.rounding
)
== 0
and line.product_uom_id == uom_unit
):
return True
return False
@api.onchange("display_lot_number_propagation")
def onchange_display_lot_number_propagation(self):
if not self.display_lot_number_propagation:
self.lot_number_propagation = False
@api.constrains("lot_number_propagation")
def _check_propagate_lot_number(self):
for bom in self:
if not bom.lot_number_propagation:
continue
if not bom.bom_line_ids.filtered("propagate_lot_number"):
raise ValidationError(
_(
"With 'Lot Number Propagation' enabled, a line has "
"to be configured with the 'Propagate Lot Number' option."
)
)

View file

@ -0,0 +1,48 @@
# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class MrpBomLine(models.Model):
_inherit = "mrp.bom.line"
propagate_lot_number = fields.Boolean(
default=False,
)
display_propagate_lot_number = fields.Boolean(
compute="_compute_display_propagate_lot_number"
)
@api.depends(
"bom_id.display_lot_number_propagation",
"bom_id.lot_number_propagation",
)
def _compute_display_propagate_lot_number(self):
for line in self:
line.display_propagate_lot_number = (
line.bom_id.display_lot_number_propagation
and line.bom_id.lot_number_propagation
)
@api.constrains("propagate_lot_number")
def _check_propagate_lot_number(self):
"""
This function should check:
- if the bom has lot_number_propagation marked, there is one and
only one line of this bom with propagate_lot_number marked.
- the bom line being marked with lot_number_propagation is of the same
tracking type as the finished product
"""
for line in self:
if not line.bom_id.lot_number_propagation:
continue
if line.propagate_lot_number and line.product_id.tracking != "serial":
raise ValidationError(
_(
"Only components tracked by serial number can propagate "
"its lot/serial number to the finished product."
)
)

View file

@ -0,0 +1,193 @@
# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
from lxml import etree
from odoo import _, api, fields, models, tools
from odoo.exceptions import UserError
from odoo.osv import expression
from odoo.tools.safe_eval import safe_eval
from odoo.addons.base.models.ir_ui_view import (
transfer_modifiers_to_node,
transfer_node_to_modifiers,
)
class MrpProduction(models.Model):
_inherit = "mrp.production"
is_lot_number_propagated = fields.Boolean(
default=False,
readonly=True,
help=(
"Lot/serial number is propagated "
"from a component to the finished product."
),
)
propagated_lot_producing = fields.Char(
compute="_compute_propagated_lot_producing",
help=(
"The BoM used on this manufacturing order is set to propagate "
"lot number from one of its components. The value will be "
"computed once the corresponding component is selected."
),
)
@api.depends(
"move_raw_ids.propagate_lot_number",
"move_raw_ids.move_line_ids.qty_done",
"move_raw_ids.move_line_ids.lot_id",
)
def _compute_propagated_lot_producing(self):
for order in self:
order.propagated_lot_producing = False
move_with_lot = order._get_propagating_component_move()
line_with_sn = move_with_lot.move_line_ids.filtered(
lambda l: (
l.lot_id
and l.product_id.tracking == "serial"
and tools.float_compare(
l.qty_done, 1, precision_rounding=l.product_uom_id.rounding
)
== 0
)
)
if len(line_with_sn) == 1:
order.propagated_lot_producing = line_with_sn.lot_id.name
@api.onchange("bom_id")
def _onchange_bom_id_lot_number_propagation(self):
self.is_lot_number_propagated = self.bom_id.lot_number_propagation
def action_confirm(self):
res = super().action_confirm()
self._set_lot_number_propagation_data_from_bom()
return res
def _get_propagating_component_move(self):
self.ensure_one()
return self.move_raw_ids.filtered(lambda o: o.propagate_lot_number)
def _set_lot_number_propagation_data_from_bom(self):
"""Copy information from BoM to the manufacturing order."""
for order in self:
propagate_lot = order.bom_id.lot_number_propagation
if not propagate_lot:
continue
order.is_lot_number_propagated = propagate_lot
propagate_move = order.move_raw_ids.filtered(
lambda m: m.bom_line_id.propagate_lot_number
)
if not propagate_move:
raise UserError(
_(
"Bill of material is marked for lot number propagation, but "
"there are no components propagating lot number. "
"Please check BOM configuration."
)
)
elif len(propagate_move) > 1:
raise UserError(
_(
"Bill of material is marked for lot number propagation, but "
"there are multiple components propagating lot number. "
"Please check BOM configuration."
)
)
else:
propagate_move.propagate_lot_number = True
def _post_inventory(self, cancel_backorder=False):
self._create_and_assign_propagated_lot_number()
return super()._post_inventory(cancel_backorder=cancel_backorder)
def _create_and_assign_propagated_lot_number(self):
for order in self:
if not order.is_lot_number_propagated or order.lot_producing_id:
continue
finish_moves = order.move_finished_ids.filtered(
lambda m: m.product_id == order.product_id
and m.state not in ("done", "cancel")
)
if finish_moves and not finish_moves.quantity_done:
lot_model = self.env["stock.lot"]
lot = lot_model.search(
[
("product_id", "=", order.product_id.id),
("company_id", "=", order.company_id.id),
("name", "=", order.propagated_lot_producing),
],
limit=1,
)
if lot.quant_ids:
raise UserError(
_(
"Lot/Serial number %s already exists and has been used. "
"Unable to propagate it."
)
)
if not lot:
lot = self.env["stock.lot"].create(
{
"product_id": order.product_id.id,
"company_id": order.company_id.id,
"name": order.propagated_lot_producing,
}
)
order.with_context(lot_propagation=True).lot_producing_id = lot
def write(self, vals):
for order in self:
if (
order.is_lot_number_propagated
and "lot_producing_id" in vals
and not self.env.context.get("lot_propagation")
):
raise UserError(
_(
"Lot/Serial number is propagated from a component, "
"you are not allowed to change it."
)
)
return super().write(vals)
def fields_view_get(
self, view_id=None, view_type="form", toolbar=False, submenu=False
):
# Override to hide the "lot_producing_id" field + "action_generate_serial"
# button if the MO is configured to propagate a serial number
result = super().fields_view_get(
view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu
)
if result.get("name") in self._views_to_adapt():
result["arch"] = self._fields_view_get_adapt_lot_tags_attrs(result)
return result
def _views_to_adapt(self):
"""Return the form view names bound to 'mrp.production' to adapt."""
return ["mrp.production.form"]
def _fields_view_get_adapt_lot_tags_attrs(self, view):
"""Hide elements related to lot if it is automatically propagated."""
doc = etree.XML(view["arch"])
tags = (
"//label[@for='lot_producing_id']",
"//field[@name='lot_producing_id']/..", # parent <div>
)
for xpath_expr in tags:
attrs_key = "invisible"
nodes = doc.xpath(xpath_expr)
for field in nodes:
attrs = safe_eval(field.attrib.get("attrs", "{}"))
if not attrs[attrs_key]:
continue
invisible_domain = expression.OR(
[attrs[attrs_key], [("is_lot_number_propagated", "=", True)]]
)
attrs[attrs_key] = invisible_domain
field.set("attrs", str(attrs))
modifiers = {}
transfer_node_to_modifiers(field, modifiers, self.env.context)
transfer_modifiers_to_node(modifiers, field)
return etree.tostring(doc, encoding="unicode")

View file

@ -0,0 +1,13 @@
# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
from odoo import api, models
class ProductProduct(models.Model):
_inherit = "product.product"
@api.constrains("tracking")
def _check_bom_propagate_lot_number(self):
for product in self:
product.product_tmpl_id._check_bom_propagate_lot_number()

View file

@ -0,0 +1,42 @@
# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
from odoo import _, api, models
from odoo.exceptions import ValidationError
class ProductTemplate(models.Model):
_inherit = "product.template"
@api.constrains("tracking")
def _check_bom_propagate_lot_number(self):
"""Block tracking type updates if the product is used by a BoM."""
for product in self:
if product.tracking == "serial":
continue
# Check BoMs
for bom in product.bom_ids:
if bom.lot_number_propagation:
raise ValidationError(
_(
"A BoM propagating serial numbers requires "
"this product to be tracked as such."
)
)
# Check lines of BoMs
bom_lines = self.env["mrp.bom.line"].search(
[
("product_id", "in", product.product_variant_ids.ids),
("propagate_lot_number", "=", True),
("bom_id.lot_number_propagation", "=", True),
]
)
if bom_lines:
boms = "\n- ".join(bom_lines.mapped("bom_id.display_name"))
boms = "\n- " + boms
raise ValidationError(
_(
"This component is configured to propagate its "
"serial number in the following Bill of Materials:{boms}'"
).format(boms=boms)
)

View file

@ -0,0 +1,13 @@
# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
from odoo import fields, models
class StockMove(models.Model):
_inherit = "stock.move"
propagate_lot_number = fields.Boolean(
default=False,
readonly=True,
)

View file

@ -0,0 +1,2 @@
* Akim Juillerat <akim.juillerat@camptocamp.com>
* Sébastien Alix <sebastien.alix@camptocamp.com>

View file

@ -0,0 +1 @@
Allow to propagate a lot number from a component to a finished product.

View file

@ -0,0 +1 @@
* Add compatibility with lot number (in addition to serial number)

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View file

@ -0,0 +1,433 @@
<!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>MRP Serial Number Propagation</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="mrp-serial-number-propagation">
<h1 class="title">MRP Serial Number Propagation</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:30bb4002c776b791eaa84394c02858060e3a7a4d2c26bc1898484210ea63a7d5
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<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/manufacture/tree/16.0/mrp_lot_number_propagation"><img alt="OCA/manufacture" src="https://img.shields.io/badge/github-OCA%2Fmanufacture-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/manufacture-16-0/manufacture-16-0-mrp_lot_number_propagation"><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/manufacture&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>Allow to propagate a lot number from a component to a finished product.</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></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">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>
<ul class="simple">
<li>Add compatibility with lot number (in addition to serial number)</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/manufacture/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/manufacture/issues/new?body=module:%20mrp_lot_number_propagation%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-3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<ul class="simple">
<li>Camptocamp</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li>Akim Juillerat &lt;<a class="reference external" href="mailto:akim.juillerat&#64;camptocamp.com">akim.juillerat&#64;camptocamp.com</a>&gt;</li>
<li>Sébastien Alix &lt;<a class="reference external" href="mailto:sebastien.alix&#64;camptocamp.com">sebastien.alix&#64;camptocamp.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">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>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
<p><a class="reference external image-reference" href="https://github.com/sebalix"><img alt="sebalix" src="https://github.com/sebalix.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/manufacture/tree/16.0/mrp_lot_number_propagation">OCA/manufacture</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,2 @@
from . import test_mrp_bom
from . import test_mrp_production

View file

@ -0,0 +1,161 @@
# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
import random
import string
from odoo import fields
from odoo.tests import Form, common
class Common(common.TransactionCase):
LOT_NAME = "PROPAGATED-LOT"
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
cls.bom = cls.env.ref("mrp.mrp_bom_desk")
cls.bom_product_template = cls.env.ref(
"mrp.product_product_computer_desk_product_template"
)
cls.bom_product_product = cls.env.ref("mrp.product_product_computer_desk")
cls.product_tracked_by_lot = cls.env.ref(
"mrp.product_product_computer_desk_leg"
)
cls.product_tracked_by_sn = cls.env.ref(
"mrp.product_product_computer_desk_head"
)
cls.product_template_tracked_by_sn = cls.env.ref(
"mrp.product_product_computer_desk_head_product_template"
)
cls.line_tracked_by_lot = cls.bom.bom_line_ids.filtered(
lambda o: o.product_id == cls.product_tracked_by_lot
)
cls.line_tracked_by_sn = cls.bom.bom_line_ids.filtered(
lambda o: o.product_id == cls.product_tracked_by_sn
)
cls.line_no_tracking = fields.first(
cls.bom.bom_line_ids.filtered(lambda o: o.product_id.tracking == "none")
)
@classmethod
def _update_qty_in_location(
cls, location, product, quantity, package=None, lot=None, in_date=None
):
quants = cls.env["stock.quant"]._gather(
product, location, lot_id=lot, package_id=package, strict=True
)
# this method adds the quantity to the current quantity, so remove it
quantity -= sum(quants.mapped("quantity"))
cls.env["stock.quant"]._update_available_quantity(
product,
location,
quantity,
package_id=package,
lot_id=lot,
in_date=in_date,
)
@classmethod
def _update_stock_component_qty(cls, order=None, bom=None, location=None):
if not order and not bom:
return
if order:
bom = order.bom_id
if not location:
location = cls.env.ref("stock.stock_location_stock")
for line in bom.bom_line_ids:
if line.product_id.type != "product":
continue
lot = None
if line.product_id.tracking != "none":
lot_name = "".join(
random.choice(string.ascii_lowercase) for i in range(10)
)
if line.propagate_lot_number:
lot_name = cls.LOT_NAME
vals = {
"product_id": line.product_id.id,
"company_id": line.company_id.id,
"name": lot_name,
}
lot = cls.env["stock.lot"].create(vals)
cls._update_qty_in_location(
location,
line.product_id,
line.product_qty,
lot=lot,
)
@classmethod
def _get_lot_quants(cls, lot, location=None):
quants = lot.quant_ids.filtered(lambda q: q.quantity > 0)
if location:
quants = quants.filtered(
lambda q: q.location_id.parent_path in location.parent_path
)
return quants
@classmethod
def _add_color_and_legs_variants(cls, product_template):
color_attribute = cls.env.ref("product.product_attribute_2")
color_att_value_white = cls.env.ref("product.product_attribute_value_3")
color_att_value_black = cls.env.ref("product.product_attribute_value_4")
legs_attribute = cls.env.ref("product.product_attribute_1")
legs_att_value_steel = cls.env.ref("product.product_attribute_value_1")
legs_att_value_alu = cls.env.ref("product.product_attribute_value_2")
cls._add_variants(
product_template,
{
color_attribute: [color_att_value_white, color_att_value_black],
legs_attribute: [legs_att_value_steel, legs_att_value_alu],
},
)
@classmethod
def _add_variants(cls, product_template, attribute_values_dict):
for attribute, att_values_list in attribute_values_dict.items():
cls.env["product.template.attribute.line"].create(
{
"product_tmpl_id": product_template.id,
"attribute_id": attribute.id,
"value_ids": [
fields.Command.set([att_val.id for att_val in att_values_list])
],
}
)
@classmethod
def _create_bom_with_variants(cls):
attribute_values_dict = {
att_val.product_attribute_value_id.name: att_val.id
for att_val in cls.env["product.template.attribute.value"].search(
[("product_tmpl_id", "=", cls.bom_product_template.id)]
)
}
new_bom_form = Form(cls.env["mrp.bom"])
new_bom_form.product_tmpl_id = cls.bom_product_template
new_bom = new_bom_form.save()
bom_line_create_values = []
for product in cls.product_template_tracked_by_sn.product_variant_ids:
create_values = {"bom_id": new_bom.id}
create_values["product_id"] = product.id
att_values_commands = []
for att_value in product.product_template_attribute_value_ids:
att_values_commands.append(
fields.Command.link(attribute_values_dict[att_value.name])
)
create_values[
"bom_product_template_attribute_value_ids"
] = att_values_commands
bom_line_create_values.append(create_values)
cls.env["mrp.bom.line"].create(bom_line_create_values)
new_bom_form = Form(new_bom)
new_bom_form.lot_number_propagation = True
for line_position, _bom_line in enumerate(new_bom.bom_line_ids):
new_bom_line_form = new_bom_form.bom_line_ids.edit(line_position)
new_bom_line_form.propagate_lot_number = True
new_bom_line_form.save()
return new_bom_form.save()

View file

@ -0,0 +1,72 @@
# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
from odoo.exceptions import ValidationError
from odoo.tests.common import Form
from .common import Common
class TestMrpBom(Common):
def test_bom_display_lot_number_propagation(self):
self.assertTrue(self.bom.display_lot_number_propagation)
self.bom.product_tmpl_id.tracking = "none"
self.assertFalse(self.bom.display_lot_number_propagation)
def test_bom_line_check_propagate_lot_number_not_tracked(self):
form = Form(self.bom)
form.lot_number_propagation = True
# Flag a line that can't be propagated
line_form = form.bom_line_ids.edit(2) # line without tracking
line_form.propagate_lot_number = True
line_form.save()
with self.assertRaisesRegex(ValidationError, "Only components tracked"):
form.save()
def test_bom_line_check_propagate_lot_number_tracked_by_lot(self):
form = Form(self.bom)
form.lot_number_propagation = True
# Flag a line tracked by lot (not SN) which is not supported
line_form = form.bom_line_ids.edit(1)
line_form.propagate_lot_number = True
line_form.save()
with self.assertRaisesRegex(ValidationError, "Only components tracked"):
form.save()
def test_bom_line_check_propagate_lot_number_same_tracking(self):
form = Form(self.bom)
form.lot_number_propagation = True
# Flag a line whose tracking type is the same than the finished product
line_form = form.bom_line_ids.edit(0)
line_form.propagate_lot_number = True
line_form.save()
form.save()
def test_bom_check_propagate_lot_number(self):
# Configure the BoM to propagate the lot/SN without enabling any line
with self.assertRaisesRegex(ValidationError, "a line has to be configured"):
self.bom.lot_number_propagation = True
def test_reset_tracking_on_bom_product(self):
# Configure the BoM to propagate the lot/SN
with Form(self.bom) as form:
form.lot_number_propagation = True
line_form = form.bom_line_ids.edit(0) # Line tracked by SN
line_form.propagate_lot_number = True
line_form.save()
form.save()
# Reset the tracking on the finished product
with self.assertRaisesRegex(ValidationError, "A BoM propagating"):
self.bom.product_tmpl_id.tracking = "none"
def test_reset_tracking_on_bom_component(self):
# Configure the BoM to propagate the lot/SN
with Form(self.bom) as form:
form.lot_number_propagation = True
line_form = form.bom_line_ids.edit(0) # Line tracked by SN
line_form.propagate_lot_number = True
line_form.save()
form.save()
# Reset the tracking on the component which propagates the SN
with self.assertRaisesRegex(ValidationError, "This component is"):
self.line_tracked_by_sn.product_id.tracking = "none"

View file

@ -0,0 +1,144 @@
# Copyright 2022 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
from odoo.exceptions import UserError
from odoo.fields import Command
from odoo.tests.common import Form
from .common import Common
class TestMrpProduction(Common):
@classmethod
def setUpClass(cls):
super().setUpClass()
# Configure the BoM to propagate lot number
cls._configure_bom()
cls.order = cls._create_order(cls.bom_product_product, cls.bom)
@classmethod
def _configure_bom(cls):
with Form(cls.bom) as form:
form.lot_number_propagation = True
line_form = form.bom_line_ids.edit(0) # Line tracked by SN
line_form.propagate_lot_number = True
line_form.save()
form.save()
@classmethod
def _create_order(cls, product, bom):
with Form(cls.env["mrp.production"]) as form:
form.product_id = product
form.bom_id = bom
return form.save()
def _set_qty_done(self, order):
for line in order.move_raw_ids.move_line_ids:
line.qty_done = line.reserved_uom_qty
order.qty_producing = order.product_qty
def test_order_propagated_lot_producing(self):
self.assertTrue(self.order.is_lot_number_propagated) # set by onchange
self._update_stock_component_qty(self.order)
self.order.action_confirm()
self.assertTrue(self.order.is_lot_number_propagated) # set by action_confirm
self.assertTrue(any(self.order.move_raw_ids.mapped("propagate_lot_number")))
self._set_qty_done(self.order)
self.assertEqual(self.order.propagated_lot_producing, self.LOT_NAME)
def test_order_write_lot_producing_id_not_allowed(self):
with self.assertRaisesRegex(UserError, "not allowed"):
self.order.write({"lot_producing_id": False})
def test_order_post_inventory(self):
self._update_stock_component_qty(self.order)
self.order.action_confirm()
self._set_qty_done(self.order)
self.order.button_mark_done()
self.assertEqual(self.order.lot_producing_id.name, self.LOT_NAME)
def test_order_post_inventory_lot_already_exists_but_not_used(self):
self._update_stock_component_qty(self.order)
self.order.action_confirm()
self._set_qty_done(self.order)
self.assertEqual(self.order.propagated_lot_producing, self.LOT_NAME)
# Create a lot with the same number for the finished product
# without any stock/quants (so not used at all) before validating the MO
existing_lot = self.env["stock.lot"].create(
{
"product_id": self.order.product_id.id,
"company_id": self.order.company_id.id,
"name": self.order.propagated_lot_producing,
}
)
self.order.button_mark_done()
self.assertEqual(self.order.lot_producing_id, existing_lot)
def test_order_post_inventory_lot_already_exists_and_used(self):
self._update_stock_component_qty(self.order)
self.order.action_confirm()
self._set_qty_done(self.order)
self.assertEqual(self.order.propagated_lot_producing, self.LOT_NAME)
# Create a lot with the same number for the finished product
# with some stock/quants (so it is considered as used) before
# validating the MO
existing_lot = self.env["stock.lot"].create(
{
"product_id": self.order.product_id.id,
"company_id": self.order.company_id.id,
"name": self.order.propagated_lot_producing,
}
)
self._update_qty_in_location(
self.env.ref("stock.stock_location_stock"),
self.order.product_id,
1,
lot=existing_lot,
)
with self.assertRaisesRegex(UserError, "already exists and has been used"):
self.order.button_mark_done()
def test_confirm_with_variant_ok(self):
self._add_color_and_legs_variants(self.bom_product_template)
self._add_color_and_legs_variants(self.product_template_tracked_by_sn)
new_bom = self._create_bom_with_variants()
self.assertTrue(new_bom.lot_number_propagation)
# As all variants must have a single component
# where lot must be propagated, there should not be any error
for product in self.bom_product_template.product_variant_ids:
new_order = self._create_order(product, new_bom)
new_order.action_confirm()
def test_confirm_with_variant_multiple(self):
self._add_color_and_legs_variants(self.bom_product_template)
self._add_color_and_legs_variants(self.product_template_tracked_by_sn)
new_bom = self._create_bom_with_variants()
# Remove application on variant for first bom line
# with this only the first variant of the product template
# will have a single component where lot must be propagated
new_bom.bom_line_ids[0].bom_product_template_attribute_value_ids = [
Command.clear()
]
for cnt, product in enumerate(self.bom_product_template.product_variant_ids):
new_order = self._create_order(product, new_bom)
if cnt == 0:
new_order.action_confirm()
else:
with self.assertRaisesRegex(UserError, "multiple components"):
new_order.action_confirm()
def test_confirm_with_variant_no(self):
self._add_color_and_legs_variants(self.bom_product_template)
self._add_color_and_legs_variants(self.product_template_tracked_by_sn)
new_bom = self._create_bom_with_variants()
# Remove first bom line
# with this the first variant of the product template
# will not have any component where lot must be propagated
new_bom.bom_line_ids[0].unlink()
for cnt, product in enumerate(self.bom_product_template.product_variant_ids):
new_order = self._create_order(product, new_bom)
if cnt == 0:
with self.assertRaisesRegex(UserError, "no component"):
new_order.action_confirm()
else:
new_order.action_confirm()

View file

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2022 Camptocamp SA
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="mrp_bom_form_view" model="ir.ui.view">
<field name="name">mrp.bom.form.inherit</field>
<field name="model">mrp.bom</field>
<field name="inherit_id" ref="mrp.mrp_bom_form_view" />
<field name="arch" type="xml">
<field name="company_id" position="after">
<field name="display_lot_number_propagation" invisible="1" />
<field
name="lot_number_propagation"
attrs="{'invisible': [('display_lot_number_propagation', '=', False)]}"
/>
</field>
<xpath expr="//field[@name='bom_line_ids']/tree" position="inside">
<field name="display_propagate_lot_number" invisible="1" />
<field
name="propagate_lot_number"
attrs="{'column_invisible': ['|', ('parent.display_lot_number_propagation', '=', False), ('parent.lot_number_propagation', '=', False)]}"
/>
</xpath>
</field>
</record>
</odoo>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2022 Camptocamp SA
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="mrp_production_form_view" model="ir.ui.view">
<field name="name">mrp.production.form.inherit</field>
<field name="model">mrp.production</field>
<field name="inherit_id" ref="mrp.mrp_production_form_view" />
<field name="arch" type="xml">
<!-- Place new fields in the first group while being compatible with OE -->
<xpath expr="//field[@name='id']/.." position="inside">
<field name="is_lot_number_propagated" force_save="1" />
</xpath>
<label for="lot_producing_id" position="before">
<field
name="propagated_lot_producing"
string="Lot/Serial Number"
attrs="{'invisible': [('is_lot_number_propagated', '=', False)]}"
/>
</label>
</field>
</record>
</odoo>

View file

@ -0,0 +1,42 @@
[project]
name = "odoo-bringout-oca-manufacture-mrp_lot_number_propagation"
version = "16.0.0"
description = "MRP Serial Number Propagation - Propagate a serial number from a component to a finished product"
authors = [
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
]
dependencies = [
"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 = ["mrp_lot_number_propagation"]
[tool.rye]
managed = true
dev-dependencies = [
"pytest>=8.4.1",
]