mirror of
https://github.com/OCA/manufacture.git
synced 2025-01-28 16:37:15 +02:00
[ADD] purchase_mrp_distribution: New module to distribute qty of move in diferent products
This module aims to address the need to receive a generic product, but until the moment of reception, we do not know the quantity that we might receive of its specific products. Using kits was not suitable for us, because to account for a unit of the kit product, the quantity specified in the BoM must be received. Therefore, we opted to define a new type of BoM called distribution. In this way, upon receiving a unit of any product added to the BoM, it will be accounted for as a unit of the generic product and will be reflected in the svls as separate products, but they will be accounted for in the purchase line as part of the product.
This commit is contained in:
committed by
Pedro M. Baeza
parent
0ca8110827
commit
0ea4e392c8
132
purchase_mrp_distribution/README.rst
Normal file
132
purchase_mrp_distribution/README.rst
Normal file
@@ -0,0 +1,132 @@
|
||||
=========================
|
||||
Purchase MRP Distribution
|
||||
=========================
|
||||
|
||||
..
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:51d9b4cab80068fcea738841c68a570388273d7cde664d9603cad40b83184c13
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |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/15.0/purchase_mrp_distribution
|
||||
:alt: OCA/manufacture
|
||||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
||||
:target: https://translation.odoo-community.org/projects/manufacture-15-0/manufacture-15-0-purchase_mrp_distribution
|
||||
: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=15.0
|
||||
:alt: Try me on Runboat
|
||||
|
||||
|badge1| |badge2| |badge3| |badge4| |badge5|
|
||||
|
||||
This module allows you to buy a product that will be divided into others without
|
||||
knowing the exact quantity of the others. That quantity will be filled in the picking.
|
||||
|
||||
**Table of contents**
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
To use this module, we will need to configure n different distribution-type Bills of
|
||||
Materials (BoM) for n products. To do this, we will follow these steps:
|
||||
|
||||
#. Go to Manufacturing > Products > Bills of Materials
|
||||
#. Click on Create
|
||||
#. Select the product to be distributed in the receptions
|
||||
#. Select the BoM type "Distribution"
|
||||
#. In the components, add the products that can be filled in the reception (it is not
|
||||
necessary to mark the quantity as it will default to 0)
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
To see the module's functionality:
|
||||
|
||||
1. Create a new purchase order
|
||||
2. Add the product for which the BoM has been created
|
||||
3. Confirm the order
|
||||
4. Go to the created delivery order
|
||||
5. You will see a new button in the move that contains the product, click on it
|
||||
6. A wizard will open to define the quantity of each product to distribute
|
||||
7. By clicking on Distribute, the move lines will be added with the products from the
|
||||
BoM
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
#. The current module is not designed to handle multi-step receipts. It operates on a
|
||||
single-step process, making it unsuitable for more complex inventory management
|
||||
scenarios.
|
||||
#. The current module is not designed to handle multiple lots for a product.
|
||||
#. The current module is not designed to handle multiple packages for a product.
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
This module aims to address the need to receive a generic product, but until the
|
||||
moment of reception, we do not know the quantity that we might receive of its
|
||||
specific products.
|
||||
|
||||
Using kits was not suitable for us, because to account for a unit of the kit product,
|
||||
the quantity specified in the BoM must be received. Therefore, we opted to define a
|
||||
new type of BoM called distribution.
|
||||
|
||||
In this way, upon receiving a unit of any product added to the BoM, it will be
|
||||
accounted for as a unit of the generic product and will be reflected in the svls as
|
||||
separate products, but they will be accounted for in the purchase line as part of the
|
||||
product.
|
||||
|
||||
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:%20purchase_mrp_distribution%0Aversion:%2015.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
|
||||
~~~~~~~
|
||||
|
||||
* Tecnaiva
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* `Tecnativa <https://www.tecnativa.com>`_:
|
||||
|
||||
* Pedro M. Baeza
|
||||
* Carlos Roca
|
||||
|
||||
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/manufacture <https://github.com/OCA/manufacture/tree/15.0/purchase_mrp_distribution>`_ project on GitHub.
|
||||
|
||||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
||||
2
purchase_mrp_distribution/__init__.py
Normal file
2
purchase_mrp_distribution/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from . import models
|
||||
from . import wizards
|
||||
20
purchase_mrp_distribution/__manifest__.py
Normal file
20
purchase_mrp_distribution/__manifest__.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# Copyright 2024 Tecnatva - Carlos Roca
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
{
|
||||
"name": "Purchase MRP Distribution",
|
||||
"version": "15.0.1.0.0",
|
||||
"author": "Tecnaiva, Odoo Community Association (OCA)",
|
||||
"website": "https://github.com/OCA/manufacture",
|
||||
"category": "Manufacturing",
|
||||
"depends": ["purchase_mrp"],
|
||||
"data": [
|
||||
"security/ir.model.access.csv",
|
||||
"views/mrp_bom_views.xml",
|
||||
"views/stock_picking_views.xml",
|
||||
"wizards/stock_move_distribution_wiz_views.xml",
|
||||
],
|
||||
"license": "AGPL-3",
|
||||
"installable": True,
|
||||
"application": False,
|
||||
}
|
||||
189
purchase_mrp_distribution/i18n/es.po
Normal file
189
purchase_mrp_distribution/i18n/es.po
Normal file
@@ -0,0 +1,189 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * purchase_mrp_distribution
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 15.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-07-09 09:38+0000\n"
|
||||
"PO-Revision-Date: 2024-07-09 11:50+0200\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 3.0.1\n"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model_terms:ir.ui.view,arch_db:purchase_mrp_distribution.purchase_order_form
|
||||
msgid ""
|
||||
"A BoM of type distribution is used to select the quantities of components."
|
||||
msgstr ""
|
||||
"Una lista de materiales (BoM) de tipo distribución se utiliza para "
|
||||
"seleccionar las cantidades de componentes."
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model_terms:ir.ui.view,arch_db:purchase_mrp_distribution.purchase_order_form
|
||||
msgid "At a Stock Transfer."
|
||||
msgstr "En una transferencia de stock."
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model,name:purchase_mrp_distribution.model_mrp_bom
|
||||
msgid "Bill of Material"
|
||||
msgstr "Lista de material"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_mrp_bom__type
|
||||
msgid "BoM Type"
|
||||
msgstr "Tipo de LdM"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model_terms:ir.ui.view,arch_db:purchase_mrp_distribution.stock_move_distribution_wiz_form
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__create_uid
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__create_uid
|
||||
msgid "Created by"
|
||||
msgstr "Creado por"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__create_date
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__create_date
|
||||
msgid "Created on"
|
||||
msgstr "Creado el"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__demand_quantity
|
||||
msgid "Demand"
|
||||
msgstr "Demanda"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__display_name
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__display_name
|
||||
msgid "Display Name"
|
||||
msgstr "Nombre a mostrar"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model_terms:ir.ui.view,arch_db:purchase_mrp_distribution.stock_move_distribution_wiz_form
|
||||
msgid "Distribute"
|
||||
msgstr "Distribuir"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields.selection,name:purchase_mrp_distribution.selection__mrp_bom__type__distribution
|
||||
msgid "Distribution"
|
||||
msgstr "Distribución"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move__distribution_bom_id
|
||||
msgid "Distribution Bom"
|
||||
msgstr "LdM de distribución"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: code:addons/purchase_mrp_distribution/models/stock_move.py:0
|
||||
#, python-format
|
||||
msgid "Distribution for %s"
|
||||
msgstr "Distribución para %s"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__id
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__id
|
||||
msgid "ID"
|
||||
msgstr "ID"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz____last_update
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr "Última modificación el"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__write_uid
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__write_uid
|
||||
msgid "Last Updated by"
|
||||
msgstr "Última actualización por"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__write_date
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__write_date
|
||||
msgid "Last Updated on"
|
||||
msgstr "Última actualización el"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__line_ids
|
||||
msgid "Line"
|
||||
msgstr "Linea"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model,name:purchase_mrp_distribution.model_stock_move_distribution_wiz_line
|
||||
msgid "Lines of wizard to distribute product qty to diferent products"
|
||||
msgstr ""
|
||||
"Líneas del asistente para distribuir la cantidad del producto a diferentes "
|
||||
"productos"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__move_id
|
||||
msgid "Move"
|
||||
msgstr "Movimiento"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__product_id
|
||||
msgid "Product"
|
||||
msgstr "Producto"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model,name:purchase_mrp_distribution.model_purchase_order_line
|
||||
msgid "Purchase Order Line"
|
||||
msgstr "Línea de pedido de venta"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__quantity
|
||||
msgid "Quantity"
|
||||
msgstr "Cantidad"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model,name:purchase_mrp_distribution.model_stock_move
|
||||
msgid "Stock Move"
|
||||
msgstr "Movimiento de Stock"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,help:purchase_mrp_distribution.field_stock_move_distribution_wiz__demand_quantity
|
||||
msgid ""
|
||||
"This is the quantity of products from an inventory point of view. For moves "
|
||||
"in the state 'done', this is the quantity of products that were actually "
|
||||
"moved. For other moves, this is the quantity of product that is planned to "
|
||||
"be moved. Lowering this quantity does not generate a backorder. Changing "
|
||||
"this quantity on assigned moves affects the product reservation, and should "
|
||||
"be done with care."
|
||||
msgstr ""
|
||||
"Ésta es la cantidad de productos desde un punto de vista de inventario. "
|
||||
"Para movimientos en el estado 'Realizado', ésta es la cantidad de productos "
|
||||
"que se movieron realmente. Para otros movimientos, ésta es la cantidad de "
|
||||
"producto que está planeado mover. Disminuyendo esta cantidad no se genera "
|
||||
"un pedido en espera. Cambiando esta cantidad en movimientos asignados, "
|
||||
"afecta la reserva de producto, y debe ser realizado con cuidado."
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__move_uom_id
|
||||
msgid "UoM"
|
||||
msgstr "UdM"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__uom_id
|
||||
msgid "Uom"
|
||||
msgstr "UdM"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__wizard_id
|
||||
msgid "Wizard"
|
||||
msgstr "Asistente"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model,name:purchase_mrp_distribution.model_stock_move_distribution_wiz
|
||||
msgid "Wizard to distribute product qty to diferent products"
|
||||
msgstr ""
|
||||
"Asistente para distribuir la cantidad de producto a diferentes productos"
|
||||
176
purchase_mrp_distribution/i18n/purchase_mrp_distribution.pot
Normal file
176
purchase_mrp_distribution/i18n/purchase_mrp_distribution.pot
Normal file
@@ -0,0 +1,176 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * purchase_mrp_distribution
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 15.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-07-09 09:38+0000\n"
|
||||
"PO-Revision-Date: 2024-07-09 09:38+0000\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model_terms:ir.ui.view,arch_db:purchase_mrp_distribution.purchase_order_form
|
||||
msgid ""
|
||||
"A BoM of type distribution is used to select the quantities of components."
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model_terms:ir.ui.view,arch_db:purchase_mrp_distribution.purchase_order_form
|
||||
msgid "At a Stock Transfer."
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model,name:purchase_mrp_distribution.model_mrp_bom
|
||||
msgid "Bill of Material"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_mrp_bom__type
|
||||
msgid "BoM Type"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model_terms:ir.ui.view,arch_db:purchase_mrp_distribution.stock_move_distribution_wiz_form
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__create_uid
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__create_uid
|
||||
msgid "Created by"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__create_date
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__create_date
|
||||
msgid "Created on"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__demand_quantity
|
||||
msgid "Demand"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__display_name
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__display_name
|
||||
msgid "Display Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model_terms:ir.ui.view,arch_db:purchase_mrp_distribution.stock_move_distribution_wiz_form
|
||||
msgid "Distribute"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields.selection,name:purchase_mrp_distribution.selection__mrp_bom__type__distribution
|
||||
msgid "Distribution"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move__distribution_bom_id
|
||||
msgid "Distribution Bom"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: code:addons/purchase_mrp_distribution/models/stock_move.py:0
|
||||
#, python-format
|
||||
msgid "Distribution for %s"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__id
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz____last_update
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__write_uid
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__write_uid
|
||||
msgid "Last Updated by"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__write_date
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__write_date
|
||||
msgid "Last Updated on"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__line_ids
|
||||
msgid "Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model,name:purchase_mrp_distribution.model_stock_move_distribution_wiz_line
|
||||
msgid "Lines of wizard to distribute product qty to diferent products"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__move_id
|
||||
msgid "Move"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__product_id
|
||||
msgid "Product"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model,name:purchase_mrp_distribution.model_purchase_order_line
|
||||
msgid "Purchase Order Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__quantity
|
||||
msgid "Quantity"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model,name:purchase_mrp_distribution.model_stock_move
|
||||
msgid "Stock Move"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,help:purchase_mrp_distribution.field_stock_move_distribution_wiz__demand_quantity
|
||||
msgid ""
|
||||
"This is the quantity of products from an inventory point of view. For moves "
|
||||
"in the state 'done', this is the quantity of products that were actually "
|
||||
"moved. For other moves, this is the quantity of product that is planned to "
|
||||
"be moved. Lowering this quantity does not generate a backorder. Changing "
|
||||
"this quantity on assigned moves affects the product reservation, and should "
|
||||
"be done with care."
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz__move_uom_id
|
||||
msgid "UoM"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__uom_id
|
||||
msgid "Uom"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model.fields,field_description:purchase_mrp_distribution.field_stock_move_distribution_wiz_line__wizard_id
|
||||
msgid "Wizard"
|
||||
msgstr ""
|
||||
|
||||
#. module: purchase_mrp_distribution
|
||||
#: model:ir.model,name:purchase_mrp_distribution.model_stock_move_distribution_wiz
|
||||
msgid "Wizard to distribute product qty to diferent products"
|
||||
msgstr ""
|
||||
3
purchase_mrp_distribution/models/__init__.py
Normal file
3
purchase_mrp_distribution/models/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from . import mrp_bom
|
||||
from . import purchase
|
||||
from . import stock_move
|
||||
13
purchase_mrp_distribution/models/mrp_bom.py
Normal file
13
purchase_mrp_distribution/models/mrp_bom.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# Copyright 2024 Tecnativa - Carlos Roca
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class MrpBom(models.Model):
|
||||
_inherit = "mrp.bom"
|
||||
|
||||
type = fields.Selection(
|
||||
selection_add=[("distribution", "Distribution")],
|
||||
ondelete={"distribution": "set default"},
|
||||
)
|
||||
39
purchase_mrp_distribution/models/purchase.py
Normal file
39
purchase_mrp_distribution/models/purchase.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# Copyright 2024 Tecnativa - Carlos Roca
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import models
|
||||
|
||||
|
||||
class PurchaseOrderLine(models.Model):
|
||||
_inherit = "purchase.order.line"
|
||||
|
||||
def _prepare_stock_move_vals(
|
||||
self, picking, price_unit, product_uom_qty, product_uom
|
||||
):
|
||||
res = super()._prepare_stock_move_vals(
|
||||
picking, price_unit, product_uom_qty, product_uom
|
||||
)
|
||||
bom = (
|
||||
self.env["mrp.bom"]
|
||||
.sudo()
|
||||
._bom_find(
|
||||
self.product_id, company_id=self.company_id.id, bom_type="distribution"
|
||||
)[self.product_id]
|
||||
)
|
||||
if bom:
|
||||
res["distribution_bom_id"] = bom.id
|
||||
return res
|
||||
|
||||
def _get_po_line_moves(self):
|
||||
res = super()._get_po_line_moves()
|
||||
bom = (
|
||||
self.env["mrp.bom"]
|
||||
.sudo()
|
||||
._bom_find(
|
||||
self.product_id, company_id=self.company_id.id, bom_type="distribution"
|
||||
)[self.product_id]
|
||||
)
|
||||
res |= self.move_ids.filtered(
|
||||
lambda m: m.product_id in bom.bom_line_ids.product_id
|
||||
)
|
||||
return res
|
||||
50
purchase_mrp_distribution/models/stock_move.py
Normal file
50
purchase_mrp_distribution/models/stock_move.py
Normal file
@@ -0,0 +1,50 @@
|
||||
# Copyright 2024 Tecnativa - Carlos Roca
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import _, fields, models
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = "stock.move"
|
||||
|
||||
distribution_bom_id = fields.Many2one("mrp.bom")
|
||||
|
||||
def action_open_distribution_wizard(self):
|
||||
return {
|
||||
"name": _("Distribution for %s") % self.product_id.display_name,
|
||||
"type": "ir.actions.act_window",
|
||||
"view_mode": "form",
|
||||
"res_model": "stock.move.distribution.wiz",
|
||||
"target": "new",
|
||||
"context": {"active_model": "stock.move", "active_id": self.id},
|
||||
}
|
||||
|
||||
def _action_done(self, cancel_backorder=False):
|
||||
distribution_moves = self.filtered(lambda m: m.distribution_bom_id)
|
||||
new_moves = self.env["stock.move"]
|
||||
for move in distribution_moves:
|
||||
cancel_move = False
|
||||
for sml in move.move_line_ids.filtered(
|
||||
lambda ml, move=move: ml.product_id != move.product_id
|
||||
):
|
||||
# Create new moves with the corresponding product and the linked sml
|
||||
new_moves += self.env["stock.move"].create(
|
||||
{
|
||||
"picking_id": sml.picking_id.id,
|
||||
"product_id": sml.product_id.id,
|
||||
"name": sml.product_id.display_name,
|
||||
"purchase_line_id": move.purchase_line_id.id,
|
||||
"product_uom": sml.product_uom_id.id,
|
||||
"state": "assigned",
|
||||
"location_id": sml.location_id.id,
|
||||
"location_dest_id": sml.location_dest_id.id,
|
||||
"price_unit": move.price_unit,
|
||||
"move_line_ids": [(4, sml.id)],
|
||||
}
|
||||
)
|
||||
cancel_move = True
|
||||
if cancel_move:
|
||||
move.state = "cancel"
|
||||
return super(StockMove, self + new_moves)._action_done(
|
||||
cancel_backorder=cancel_backorder
|
||||
)
|
||||
9
purchase_mrp_distribution/readme/CONFIGURE.rst
Normal file
9
purchase_mrp_distribution/readme/CONFIGURE.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
To use this module, we will need to configure n different distribution-type Bills of
|
||||
Materials (BoM) for n products. To do this, we will follow these steps:
|
||||
|
||||
#. Go to Manufacturing > Products > Bills of Materials
|
||||
#. Click on Create
|
||||
#. Select the product to be distributed in the receptions
|
||||
#. Select the BoM type "Distribution"
|
||||
#. In the components, add the products that can be filled in the reception (it is not
|
||||
necessary to mark the quantity as it will default to 0)
|
||||
4
purchase_mrp_distribution/readme/CONTRIBUTORS.rst
Normal file
4
purchase_mrp_distribution/readme/CONTRIBUTORS.rst
Normal file
@@ -0,0 +1,4 @@
|
||||
* `Tecnativa <https://www.tecnativa.com>`_:
|
||||
|
||||
* Pedro M. Baeza
|
||||
* Carlos Roca
|
||||
2
purchase_mrp_distribution/readme/DESCRIPTION.rst
Normal file
2
purchase_mrp_distribution/readme/DESCRIPTION.rst
Normal file
@@ -0,0 +1,2 @@
|
||||
This module allows you to buy a product that will be divided into others without
|
||||
knowing the exact quantity of the others. That quantity will be filled in the picking.
|
||||
12
purchase_mrp_distribution/readme/HISTORY.rst
Normal file
12
purchase_mrp_distribution/readme/HISTORY.rst
Normal file
@@ -0,0 +1,12 @@
|
||||
This module aims to address the need to receive a generic product, but until the
|
||||
moment of reception, we do not know the quantity that we might receive of its
|
||||
specific products.
|
||||
|
||||
Using kits was not suitable for us, because to account for a unit of the kit product,
|
||||
the quantity specified in the BoM must be received. Therefore, we opted to define a
|
||||
new type of BoM called distribution.
|
||||
|
||||
In this way, upon receiving a unit of any product added to the BoM, it will be
|
||||
accounted for as a unit of the generic product and will be reflected in the svls as
|
||||
separate products, but they will be accounted for in the purchase line as part of the
|
||||
product.
|
||||
5
purchase_mrp_distribution/readme/ROADMAP.rst
Normal file
5
purchase_mrp_distribution/readme/ROADMAP.rst
Normal file
@@ -0,0 +1,5 @@
|
||||
#. The current module is not designed to handle multi-step receipts. It operates on a
|
||||
single-step process, making it unsuitable for more complex inventory management
|
||||
scenarios.
|
||||
#. The current module is not designed to handle multiple lots for a product.
|
||||
#. The current module is not designed to handle multiple packages for a product.
|
||||
10
purchase_mrp_distribution/readme/USAGE.rst
Normal file
10
purchase_mrp_distribution/readme/USAGE.rst
Normal file
@@ -0,0 +1,10 @@
|
||||
To see the module's functionality:
|
||||
|
||||
1. Create a new purchase order
|
||||
2. Add the product for which the BoM has been created
|
||||
3. Confirm the order
|
||||
4. Go to the created delivery order
|
||||
5. You will see a new button in the move that contains the product, click on it
|
||||
6. A wizard will open to define the quantity of each product to distribute
|
||||
7. By clicking on Distribute, the move lines will be added with the products from the
|
||||
BoM
|
||||
3
purchase_mrp_distribution/security/ir.model.access.csv
Normal file
3
purchase_mrp_distribution/security/ir.model.access.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
purchase_mrp_distribution.access_stock_move_distribution_wiz,access_stock_move_distribution_wiz,purchase_mrp_distribution.model_stock_move_distribution_wiz,stock.group_stock_user,1,1,1,1
|
||||
purchase_mrp_distribution.access_stock_move_distribution_wiz_line,access_stock_move_distribution_wiz_line,purchase_mrp_distribution.model_stock_move_distribution_wiz_line,stock.group_stock_user,1,1,1,1
|
||||
|
482
purchase_mrp_distribution/static/description/index.html
Normal file
482
purchase_mrp_distribution/static/description/index.html
Normal file
@@ -0,0 +1,482 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
|
||||
<title>Purchase MRP Distribution</title>
|
||||
<style type="text/css">
|
||||
|
||||
/*
|
||||
:Author: David Goodger (goodger@python.org)
|
||||
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
Despite the name, some widely supported CSS2 features are used.
|
||||
|
||||
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
*/
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
table.borderless td, table.borderless th {
|
||||
/* Override padding for "table.docutils td" with "! important".
|
||||
The right padding separates the table cells. */
|
||||
padding: 0 0.5em 0 0 ! important }
|
||||
|
||||
.first {
|
||||
/* Override more specific margin styles with "! important". */
|
||||
margin-top: 0 ! important }
|
||||
|
||||
.last, .with-subtitle {
|
||||
margin-bottom: 0 ! important }
|
||||
|
||||
.hidden {
|
||||
display: none }
|
||||
|
||||
.subscript {
|
||||
vertical-align: sub;
|
||||
font-size: smaller }
|
||||
|
||||
.superscript {
|
||||
vertical-align: super;
|
||||
font-size: smaller }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
blockquote.epigraph {
|
||||
margin: 2em 5em ; }
|
||||
|
||||
dl.docutils dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||
dl.docutils dt {
|
||||
font-weight: bold }
|
||||
*/
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||
div.hint, div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||
div.important p.admonition-title, div.note p.admonition-title,
|
||||
div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title, .code .error {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||
compound paragraphs.
|
||||
div.compound .compound-first, div.compound .compound-middle {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.compound .compound-last, div.compound .compound-middle {
|
||||
margin-top: 0.5em }
|
||||
*/
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
clear: both;
|
||||
font-size: smaller }
|
||||
|
||||
div.line-block {
|
||||
display: block ;
|
||||
margin-top: 1em ;
|
||||
margin-bottom: 1em }
|
||||
|
||||
div.line-block div.line-block {
|
||||
margin-top: 0 ;
|
||||
margin-bottom: 0 ;
|
||||
margin-left: 1.5em }
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em ;
|
||||
border: medium outset ;
|
||||
padding: 1em ;
|
||||
background-color: #ffffee ;
|
||||
width: 40% ;
|
||||
float: right ;
|
||||
clear: right }
|
||||
|
||||
div.sidebar p.rubric {
|
||||
font-family: sans-serif ;
|
||||
font-size: medium }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||
margin-top: 0.4em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr.docutils {
|
||||
width: 75% }
|
||||
|
||||
img.align-left, .figure.align-left, object.align-left, table.align-left {
|
||||
clear: left ;
|
||||
float: left ;
|
||||
margin-right: 1em }
|
||||
|
||||
img.align-right, .figure.align-right, object.align-right, table.align-right {
|
||||
clear: right ;
|
||||
float: right ;
|
||||
margin-left: 1em }
|
||||
|
||||
img.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table.align-center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left }
|
||||
|
||||
.align-center {
|
||||
clear: both ;
|
||||
text-align: center }
|
||||
|
||||
.align-right {
|
||||
text-align: right }
|
||||
|
||||
/* reset inner alignment in figures */
|
||||
div.align-right {
|
||||
text-align: inherit }
|
||||
|
||||
/* div.align-center * { */
|
||||
/* text-align: left } */
|
||||
|
||||
.align-top {
|
||||
vertical-align: top }
|
||||
|
||||
.align-middle {
|
||||
vertical-align: middle }
|
||||
|
||||
.align-bottom {
|
||||
vertical-align: bottom }
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.attribution {
|
||||
text-align: right ;
|
||||
margin-left: 50% }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.rubric {
|
||||
font-weight: bold ;
|
||||
font-size: larger ;
|
||||
color: maroon ;
|
||||
text-align: center }
|
||||
|
||||
p.sidebar-title {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold ;
|
||||
font-size: larger }
|
||||
|
||||
p.sidebar-subtitle {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font: inherit }
|
||||
|
||||
pre.literal-block, pre.doctest-block, pre.math, pre.code {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
pre.code .ln { color: gray; } /* line numbers */
|
||||
pre.code, code { background-color: #eeeeee }
|
||||
pre.code .comment, code .comment { color: #5C6576 }
|
||||
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
|
||||
pre.code .literal.string, code .literal.string { color: #0C5404 }
|
||||
pre.code .name.builtin, code .name.builtin { color: #352B84 }
|
||||
pre.code .deleted, code .deleted { background-color: #DEB0A1}
|
||||
pre.code .inserted, code .inserted { background-color: #A3D289}
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option {
|
||||
white-space: nowrap }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic, pre.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
/* font-size relative to parent (h1..h6 element) */
|
||||
font-size: 80% }
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
table.docutils {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
table.footnote {
|
||||
border-left: solid 1px black;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docutils td, table.docutils th,
|
||||
table.docinfo td, table.docinfo th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap ;
|
||||
padding-left: 0 }
|
||||
|
||||
/* "booktabs" style (no vertical lines) */
|
||||
table.docutils.booktabs {
|
||||
border: 0px;
|
||||
border-top: 2px solid;
|
||||
border-bottom: 2px solid;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.docutils.booktabs * {
|
||||
border: 0px;
|
||||
}
|
||||
table.docutils.booktabs th {
|
||||
border-bottom: thin solid;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||
font-size: 100% }
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document" id="purchase-mrp-distribution">
|
||||
<h1 class="title">Purchase MRP Distribution</h1>
|
||||
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:51d9b4cab80068fcea738841c68a570388273d7cde664d9603cad40b83184c13
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<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/15.0/purchase_mrp_distribution"><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-15-0/manufacture-15-0-purchase_mrp_distribution"><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&target_branch=15.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
|
||||
<p>This module allows you to buy a product that will be divided into others without
|
||||
knowing the exact quantity of the others. That quantity will be filled in the picking.</p>
|
||||
<p><strong>Table of contents</strong></p>
|
||||
<div class="contents local topic" id="contents">
|
||||
<ul class="simple">
|
||||
<li><a class="reference internal" href="#configuration" id="toc-entry-1">Configuration</a></li>
|
||||
<li><a class="reference internal" href="#usage" id="toc-entry-2">Usage</a></li>
|
||||
<li><a class="reference internal" href="#known-issues-roadmap" id="toc-entry-3">Known issues / Roadmap</a></li>
|
||||
<li><a class="reference internal" href="#changelog" id="toc-entry-4">Changelog</a></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="configuration">
|
||||
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
|
||||
<p>To use this module, we will need to configure n different distribution-type Bills of
|
||||
Materials (BoM) for n products. To do this, we will follow these steps:</p>
|
||||
<ol class="arabic simple">
|
||||
<li>Go to Manufacturing > Products > Bills of Materials</li>
|
||||
<li>Click on Create</li>
|
||||
<li>Select the product to be distributed in the receptions</li>
|
||||
<li>Select the BoM type “Distribution”</li>
|
||||
<li>In the components, add the products that can be filled in the reception (it is not
|
||||
necessary to mark the quantity as it will default to 0)</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="section" id="usage">
|
||||
<h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
|
||||
<p>To see the module’s functionality:</p>
|
||||
<ol class="arabic simple">
|
||||
<li>Create a new purchase order</li>
|
||||
<li>Add the product for which the BoM has been created</li>
|
||||
<li>Confirm the order</li>
|
||||
<li>Go to the created delivery order</li>
|
||||
<li>You will see a new button in the move that contains the product, click on it</li>
|
||||
<li>A wizard will open to define the quantity of each product to distribute</li>
|
||||
<li>By clicking on Distribute, the move lines will be added with the products from the
|
||||
BoM</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="section" id="known-issues-roadmap">
|
||||
<h1><a class="toc-backref" href="#toc-entry-3">Known issues / Roadmap</a></h1>
|
||||
<ol class="arabic simple">
|
||||
<li>The current module is not designed to handle multi-step receipts. It operates on a
|
||||
single-step process, making it unsuitable for more complex inventory management
|
||||
scenarios.</li>
|
||||
<li>The current module is not designed to handle multiple lots for a product.</li>
|
||||
<li>The current module is not designed to handle multiple packages for a product.</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="section" id="changelog">
|
||||
<h1><a class="toc-backref" href="#toc-entry-4">Changelog</a></h1>
|
||||
<p>This module aims to address the need to receive a generic product, but until the
|
||||
moment of reception, we do not know the quantity that we might receive of its
|
||||
specific products.</p>
|
||||
<p>Using kits was not suitable for us, because to account for a unit of the kit product,
|
||||
the quantity specified in the BoM must be received. Therefore, we opted to define a
|
||||
new type of BoM called distribution.</p>
|
||||
<p>In this way, upon receiving a unit of any product added to the BoM, it will be
|
||||
accounted for as a unit of the generic product and will be reflected in the svls as
|
||||
separate products, but they will be accounted for in the purchase line as part of the
|
||||
product.</p>
|
||||
</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/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:%20purchase_mrp_distribution%0Aversion:%2015.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>Tecnaiva</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="contributors">
|
||||
<h2><a class="toc-backref" href="#toc-entry-8">Contributors</a></h2>
|
||||
<ul class="simple">
|
||||
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
|
||||
<li>Pedro M. Baeza</li>
|
||||
<li>Carlos Roca</li>
|
||||
</ul>
|
||||
</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/manufacture/tree/15.0/purchase_mrp_distribution">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>
|
||||
1
purchase_mrp_distribution/tests/__init__.py
Normal file
1
purchase_mrp_distribution/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import test_purchase_mrp_distribution
|
||||
@@ -0,0 +1,105 @@
|
||||
# Copyright 2024 Tecnativa - Carlos Roca
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo.tests.common import Form, TransactionCase
|
||||
|
||||
|
||||
class TestPurchaseMrpDistribution(TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.category = cls.env["product.category"].create(
|
||||
{
|
||||
"name": "AVCO",
|
||||
"property_cost_method": "average",
|
||||
}
|
||||
)
|
||||
cls.product = cls.env["product.template"].create(
|
||||
{
|
||||
"name": "General product",
|
||||
"categ_id": cls.category.id,
|
||||
}
|
||||
)
|
||||
cls.subproduct_1 = cls.env["product.template"].create(
|
||||
{
|
||||
"name": "Product 1",
|
||||
"categ_id": cls.category.id,
|
||||
}
|
||||
)
|
||||
cls.subproduct_2 = cls.env["product.template"].create(
|
||||
{
|
||||
"name": "Product 2",
|
||||
"categ_id": cls.category.id,
|
||||
}
|
||||
)
|
||||
cls.bom = cls.env["mrp.bom"].create(
|
||||
{
|
||||
"product_tmpl_id": cls.product.id,
|
||||
"type": "distribution",
|
||||
"bom_line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": cls.subproduct_1.product_variant_id.id,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": cls.subproduct_2.product_variant_id.id,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
)
|
||||
cls.partner = cls.env["res.partner"].create(
|
||||
{
|
||||
"name": "Partner",
|
||||
}
|
||||
)
|
||||
|
||||
def _create_po_picking(self):
|
||||
purchase_form = Form(self.env["purchase.order"])
|
||||
purchase_form.partner_id = self.partner
|
||||
with purchase_form.order_line.new() as line_form:
|
||||
line_form.product_id = self.product.product_variant_id
|
||||
line_form.product_qty = 6
|
||||
line_form.price_unit = 2
|
||||
purchase = purchase_form.save()
|
||||
purchase.button_confirm()
|
||||
return purchase, purchase.picking_ids
|
||||
|
||||
def test_distribute_process(self):
|
||||
purchase, picking = self._create_po_picking()
|
||||
wiz_action = picking.move_lines.action_open_distribution_wizard()
|
||||
wiz = (
|
||||
self.env["stock.move.distribution.wiz"]
|
||||
.with_context(**wiz_action["context"])
|
||||
.create({})
|
||||
)
|
||||
self.assertIn(self.subproduct_1.product_variant_id, wiz.line_ids.product_id)
|
||||
self.assertIn(self.subproduct_2.product_variant_id, wiz.line_ids.product_id)
|
||||
wiz.line_ids.quantity = 3
|
||||
wiz.button_distribute_qty()
|
||||
self.assertEqual(len(picking.move_lines), 1)
|
||||
self.assertEqual(len(picking.move_lines.move_line_ids), 2)
|
||||
for sml in picking.move_lines.move_line_ids:
|
||||
self.assertEqual(sml.qty_done, 3)
|
||||
original_move = picking.move_lines
|
||||
picking.button_validate()
|
||||
self.assertEqual(len(picking.move_lines), 3)
|
||||
self.assertEqual(original_move.state, "cancel")
|
||||
self.assertIn(
|
||||
self.subproduct_1.product_variant_id, picking.move_lines.product_id
|
||||
)
|
||||
self.assertIn(
|
||||
self.subproduct_2.product_variant_id, picking.move_lines.product_id
|
||||
)
|
||||
self.assertEqual(purchase.order_line.qty_received, 6)
|
||||
svl_action = picking.action_view_stock_valuation_layers()
|
||||
svls = self.env["stock.valuation.layer"].search(svl_action["domain"])
|
||||
for svl in svls:
|
||||
self.assertEqual(svl.quantity, 3)
|
||||
self.assertEqual(svl.value, 6)
|
||||
23
purchase_mrp_distribution/views/mrp_bom_views.xml
Normal file
23
purchase_mrp_distribution/views/mrp_bom_views.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="purchase_order_form" model="ir.ui.view">
|
||||
<field name="model">mrp.bom</field>
|
||||
<field name="inherit_id" ref="mrp.mrp_bom_form_view" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='type']/../p" position="after">
|
||||
<p
|
||||
colspan="2"
|
||||
class="oe_grey oe_edit_only"
|
||||
attrs="{'invisible': [('type','!=','distribution')]}"
|
||||
>
|
||||
A BoM of type distribution is used to select the quantities of components.
|
||||
<ul>
|
||||
<li>
|
||||
At a Stock Transfer.
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
21
purchase_mrp_distribution/views/stock_picking_views.xml
Normal file
21
purchase_mrp_distribution/views/stock_picking_views.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="view_picking_form" model="ir.ui.view">
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath
|
||||
expr="//field[@name='move_ids_without_package']/tree/field[@name='quantity_done']"
|
||||
position="after"
|
||||
>
|
||||
<field name="distribution_bom_id" invisible="1" />
|
||||
<button
|
||||
name="action_open_distribution_wizard"
|
||||
type="object"
|
||||
icon="fa-sitemap"
|
||||
attrs="{'invisible': ['|', ('distribution_bom_id', '=', False), ('state', 'in', ['done', 'cancel'])]}"
|
||||
/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
1
purchase_mrp_distribution/wizards/__init__.py
Normal file
1
purchase_mrp_distribution/wizards/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import stock_move_distribution_wiz
|
||||
@@ -0,0 +1,98 @@
|
||||
# Copyright 2024 Tecnativa - Carlos Roca
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class StockMoveDistributionWiz(models.TransientModel):
|
||||
_name = "stock.move.distribution.wiz"
|
||||
_description = "Wizard to distribute product qty to diferent products"
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
ctx = self.env.context.copy()
|
||||
res = super().default_get(fields)
|
||||
if ctx.get("active_id") and ctx.get("active_model") == "stock.move":
|
||||
move = self.env["stock.move"].browse(ctx["active_id"])
|
||||
lines = []
|
||||
for bom_line in move.distribution_bom_id.bom_line_ids:
|
||||
if move_lines := move.move_line_ids.filtered(
|
||||
lambda ml, bom_line=bom_line: ml.product_id == bom_line.product_id
|
||||
):
|
||||
for sml in move_lines:
|
||||
lines.append(
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": bom_line.product_id.id,
|
||||
"quantity": sml.qty_done,
|
||||
"uom_id": bom_line.product_uom_id.id,
|
||||
"lot_id": sml.lot_id.id,
|
||||
"package_id": sml.result_package_id.id,
|
||||
"company_id": sml.company_id.id,
|
||||
},
|
||||
)
|
||||
)
|
||||
else:
|
||||
lines.append(
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": bom_line.product_id.id,
|
||||
"quantity": 0,
|
||||
"uom_id": bom_line.product_uom_id.id,
|
||||
"company_id": move.company_id.id,
|
||||
},
|
||||
)
|
||||
)
|
||||
res.update(
|
||||
{
|
||||
"move_id": move.id,
|
||||
"line_ids": lines,
|
||||
}
|
||||
)
|
||||
return res
|
||||
|
||||
move_id = fields.Many2one("stock.move")
|
||||
line_ids = fields.One2many("stock.move.distribution.wiz.line", "wizard_id")
|
||||
demand_quantity = fields.Float(related="move_id.product_uom_qty")
|
||||
move_uom_id = fields.Many2one(related="move_id.product_uom")
|
||||
|
||||
def button_distribute_qty(self):
|
||||
self.ensure_one()
|
||||
# Clean actual move lines
|
||||
self.move_id.move_line_ids.sudo().unlink()
|
||||
for line in self.line_ids:
|
||||
# Create new move_lines
|
||||
if line.quantity:
|
||||
self.env["stock.move.line"].create(
|
||||
{
|
||||
"move_id": self.move_id.id,
|
||||
"product_id": line.product_id.id,
|
||||
"qty_done": line.quantity,
|
||||
"product_uom_id": line.uom_id.id,
|
||||
"location_id": self.move_id.location_id.id,
|
||||
"location_dest_id": self.move_id.location_dest_id.id,
|
||||
"picking_id": self.move_id.picking_id.id,
|
||||
"company_id": self.move_id.company_id.id,
|
||||
"lot_id": line.lot_id.id,
|
||||
"result_package_id": line.package_id.id,
|
||||
}
|
||||
)
|
||||
if self.move_id.move_line_ids:
|
||||
self.move_id.state = "assigned"
|
||||
|
||||
|
||||
class StockMoveDistributionWizLine(models.TransientModel):
|
||||
_name = "stock.move.distribution.wiz.line"
|
||||
_description = "Lines of wizard to distribute product qty to diferent products"
|
||||
|
||||
wizard_id = fields.Many2one("stock.move.distribution.wiz")
|
||||
product_id = fields.Many2one("product.product")
|
||||
quantity = fields.Float(digits="Product Unit of Measure")
|
||||
uom_id = fields.Many2one("uom.uom")
|
||||
lot_id = fields.Many2one("stock.production.lot")
|
||||
package_id = fields.Many2one("stock.production.lot")
|
||||
company_id = fields.Many2one("res.company")
|
||||
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="stock_move_distribution_wiz_form" model="ir.ui.view">
|
||||
<field name="name">Stock Move Distribution Wiz Form</field>
|
||||
<field name="model">stock.move.distribution.wiz</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="move_id" invisible="1" />
|
||||
<label for="demand_quantity" />
|
||||
<div>
|
||||
<field name="demand_quantity" />
|
||||
<field name="move_uom_id" groups="uom.group_uom" />
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<field name="line_ids" nolabel="1">
|
||||
<tree editable="bottom" create="0" delete="0">
|
||||
<field name="company_id" invisible="1" />
|
||||
<field name="product_id" readonly="1" force_save="1" />
|
||||
<field
|
||||
name="lot_id"
|
||||
groups="stock.group_production_lot"
|
||||
domain="[('product_id', '=', product_id), ('company_id', '=', company_id)]"
|
||||
context="{
|
||||
'default_company_id': company_id,
|
||||
'default_product_id': product_id,
|
||||
}"
|
||||
/>
|
||||
<field
|
||||
name="package_id"
|
||||
groups="stock.group_tracking_lot"
|
||||
/>
|
||||
<field name="quantity" />
|
||||
<field name="uom_id" groups="uom.group_uom" />
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
|
||||
</sheet>
|
||||
<footer>
|
||||
<button
|
||||
name="button_distribute_qty"
|
||||
string="Distribute"
|
||||
type="object"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1 @@
|
||||
../../../../purchase_mrp_distribution
|
||||
6
setup/purchase_mrp_distribution/setup.py
Normal file
6
setup/purchase_mrp_distribution/setup.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['setuptools-odoo'],
|
||||
odoo_addon=True,
|
||||
)
|
||||
Reference in New Issue
Block a user