Files
Odoo-18.0-20251222/sale_mrp_bom/models/procurement_group.py
tocmo0nlord adbe430761
Some checks failed
pre-commit / pre-commit (push) Has been cancelled
tests / Detect unreleased dependencies (push) Has been cancelled
tests / test with OCB (push) Has been cancelled
tests / test with Odoo (push) Has been cancelled
Initial commit: Odoo 18.0-20251222 extra-addons
2026-03-13 20:43:25 +00:00

96 lines
4.1 KiB
Python
Executable File

# Copyright 2025 360ERP (<https://www.360erp.com>)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, models
class ProcurementGroup(models.Model):
_inherit = "procurement.group"
@api.model
def run(self, procurements, raise_user_error=True):
"""
Handle phantom BoM (kit) procurements linked to sale order lines.
If a procurement is for a kit product associated with a sale order line,
this method explodes the kit into its components and generates new
procurements for those components. Original procurements that are not
kits, or not linked to a sale order line with a phantom BoM, are passed through.
:param procurements: A list of Procurement namedtuples
:param raise_user_error: Whether to raise UserError on failure
:return: Result of the original run method
"""
# Collect unique sale_line_ids from procurements that have them
sale_line_ids = list(
set(
p.values.get("sale_line_id")
for p in procurements
if p.values.get("sale_line_id")
)
)
# Pre-fetch sale lines and create a mapping for quick access
sale_lines = self.env["sale.order.line"].browse(sale_line_ids)
sale_lines_map = {sl.id: sl for sl in sale_lines}
procurements_without_kit = []
for procurement in procurements:
sale_line_id = procurement.values.get("sale_line_id")
sale_line = sale_lines_map.get(sale_line_id)
bom_kit = (
sale_line.bom_id.filtered(
lambda bm, pr=procurement: bm.type == "phantom"
and (
# If BoM has product_id, match the procurement's product_id
(bm.product_id and bm.product_id == pr.product_id)
or
# Otherwise (if BoM has no product_id), match the template_id
(
not bm.product_id
and bm.product_tmpl_id == pr.product_id.product_tmpl_id
)
)
)
if sale_line
else False
)
if bom_kit:
order_qty = procurement.product_uom._compute_quantity(
procurement.product_qty, bom_kit.product_uom_id, round=False
)
qty_to_produce = order_qty / bom_kit.product_qty
_dummy, bom_sub_lines = bom_kit.explode(
procurement.product_id,
qty_to_produce,
never_attribute_values=procurement.values.get(
"never_product_template_attribute_value_ids"
),
)
for bom_line, bom_line_data in bom_sub_lines:
bom_line_uom = bom_line.product_uom_id
quant_uom = bom_line.product_id.uom_id
# recreate dict of values since each child has its own bom_line_id
values = dict(procurement.values, bom_line_id=bom_line.id)
component_qty, procurement_uom = (
bom_line_uom._adjust_uom_quantities(
bom_line_data["qty"], quant_uom
)
)
procurements_without_kit.append(
self.env["procurement.group"].Procurement(
bom_line.product_id,
component_qty,
procurement_uom,
procurement.location_id,
procurement.name,
procurement.origin,
procurement.company_id,
values,
)
)
else:
procurements_without_kit.append(procurement)
return super().run(procurements_without_kit, raise_user_error=raise_user_error)