[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:
Carlos Roca
2024-07-09 13:36:22 +02:00
committed by Pedro M. Baeza
parent 0ca8110827
commit 0ea4e392c8
26 changed files with 1461 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
from . import mrp_bom
from . import purchase
from . import stock_move

View 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"},
)

View 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

View 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
)