mirror of
https://github.com/OCA/manufacture.git
synced 2025-01-28 16:37:15 +02:00
[IMP] mrp_sale_info: Materialize link between sale order lines and created MOs
Improve test with 3 steps delivery route and use RecordCapturer
This commit is contained in:
@@ -2,4 +2,6 @@
|
||||
|
||||
from . import mrp_production
|
||||
from . import mrp_workorder
|
||||
from . import sale_order_line
|
||||
from . import stock_move
|
||||
from . import stock_rule
|
||||
|
||||
57
mrp_sale_info/models/sale_order_line.py
Normal file
57
mrp_sale_info/models/sale_order_line.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# Copyright 2024 Camptocamp SA
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class SaleOrderLine(models.Model):
|
||||
_inherit = "sale.order.line"
|
||||
|
||||
created_production_ids = fields.Many2many(
|
||||
"mrp.production",
|
||||
compute="_compute_created_production_ids",
|
||||
store=True,
|
||||
)
|
||||
|
||||
@api.depends(lambda sol: sol._created_prod_move_deps())
|
||||
def _compute_created_production_ids(self):
|
||||
for line in self:
|
||||
delivery_moves = line.move_ids
|
||||
mrp_production_ids = set()
|
||||
for move in delivery_moves:
|
||||
mrp_production_ids.update(move._get_orig_created_production_ids().ids)
|
||||
# Consider MO Backorders for serial numbers
|
||||
mrp_production_ids.update(
|
||||
self.env["mrp.production"]
|
||||
.browse(mrp_production_ids)
|
||||
.mapped("procurement_group_id.mrp_production_ids")
|
||||
.ids
|
||||
)
|
||||
line.created_production_ids = [fields.Command.set(list(mrp_production_ids))]
|
||||
|
||||
def _created_prod_move_deps(self):
|
||||
fnames = [
|
||||
"move_ids",
|
||||
"move_ids.created_production_id",
|
||||
"move_ids.created_production_id.procurement_group_id.mrp_production_ids",
|
||||
]
|
||||
# Allow customizing how many levels of recursive moves must be considered to
|
||||
# compute the created_production_ids field on sale.order.line.
|
||||
# This value must be at least equal to the number of:
|
||||
# delivery steps + post manufacturing operations of the warehouse - 1.
|
||||
# FIXME: Check if there's a way to recompute the dependency without having to
|
||||
# restart Odoo.
|
||||
try:
|
||||
levels = int(
|
||||
self.env["ir.config_parameter"]
|
||||
.sudo()
|
||||
.get_param("mrp_sale_info.compute.created_prod_ids_move_dep_levels", 3)
|
||||
)
|
||||
except ValueError:
|
||||
levels = 3
|
||||
for num in range(1, levels + 1):
|
||||
fnames.append("move_ids.%screated_production_id" % ("move_orig_ids." * num))
|
||||
fnames.append(
|
||||
"move_ids.%screated_production_id.procurement_group_id.mrp_production_ids"
|
||||
% ("move_orig_ids." * num)
|
||||
)
|
||||
return fnames
|
||||
16
mrp_sale_info/models/stock_move.py
Normal file
16
mrp_sale_info/models/stock_move.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# Copyright 2024 Camptocamp SA
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
||||
from odoo import models
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = "stock.move"
|
||||
|
||||
def _get_orig_created_production_ids(self):
|
||||
self.ensure_one()
|
||||
if self.created_production_id:
|
||||
return self.created_production_id
|
||||
mrp_production_ids = set()
|
||||
for move in self.move_orig_ids:
|
||||
mrp_production_ids.update(move._get_orig_created_production_ids().ids)
|
||||
return self.env["mrp.production"].browse(mrp_production_ids)
|
||||
@@ -1,13 +1,17 @@
|
||||
# Copyright 2020 Tecnativa - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo.tests import common
|
||||
from odoo.tests import RecordCapturer, common
|
||||
|
||||
|
||||
class TestMrpSaleInfo(common.TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
warehouse = cls.env.ref("stock.warehouse0")
|
||||
warehouse.write(
|
||||
{"delivery_steps": "pick_pack_ship", "manufacture_steps": "pbm_sam"}
|
||||
)
|
||||
route_manufacture_1 = cls.env.ref("mrp.route_warehouse0_manufacture")
|
||||
route_manufacture_2 = cls.env.ref("stock.route_warehouse0_mto")
|
||||
route_manufacture_2.active = True
|
||||
@@ -21,6 +25,26 @@ class TestMrpSaleInfo(common.TransactionCase):
|
||||
],
|
||||
}
|
||||
)
|
||||
cls.product_kit = cls.env["product.product"].create(
|
||||
{
|
||||
"name": "Test kit",
|
||||
"type": "product",
|
||||
"route_ids": [
|
||||
(4, route_manufacture_1.id),
|
||||
(4, route_manufacture_2.id),
|
||||
],
|
||||
}
|
||||
)
|
||||
cls.product_kit_comp = cls.env["product.product"].create(
|
||||
{
|
||||
"name": "Test kit comp",
|
||||
"type": "product",
|
||||
"route_ids": [
|
||||
(4, route_manufacture_1.id),
|
||||
(4, route_manufacture_2.id),
|
||||
],
|
||||
}
|
||||
)
|
||||
cls.bom = cls.env["mrp.bom"].create(
|
||||
{
|
||||
"product_tmpl_id": cls.product.product_tmpl_id.id,
|
||||
@@ -36,6 +60,28 @@ class TestMrpSaleInfo(common.TransactionCase):
|
||||
],
|
||||
}
|
||||
)
|
||||
cls.bom_kit = cls.env["mrp.bom"].create(
|
||||
{
|
||||
"product_tmpl_id": cls.product_kit.product_tmpl_id.id,
|
||||
"type": "phantom",
|
||||
"bom_line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": cls.product.id,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": cls.product_kit_comp.id,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
)
|
||||
cls.partner = cls.env["res.partner"].create({"name": "Test client"})
|
||||
cls.sale_order = cls.env["sale.order"].create(
|
||||
{
|
||||
@@ -56,17 +102,42 @@ class TestMrpSaleInfo(common.TransactionCase):
|
||||
)
|
||||
|
||||
def test_mrp_sale_info(self):
|
||||
prev_productions = self.env["mrp.production"].search([])
|
||||
self.sale_order.action_confirm()
|
||||
production = self.env["mrp.production"].search([]) - prev_productions
|
||||
with RecordCapturer(self.env["mrp.production"], []) as capture:
|
||||
self.sale_order.action_confirm()
|
||||
production = capture.records
|
||||
self.assertEqual(production.sale_id, self.sale_order)
|
||||
self.assertEqual(production.partner_id, self.partner)
|
||||
self.assertEqual(production.client_order_ref, self.sale_order.client_order_ref)
|
||||
self.assertEqual(self.sale_order.order_line.created_production_ids, production)
|
||||
|
||||
def test_mrp_workorder(self):
|
||||
prev_workorders = self.env["mrp.workorder"].search([])
|
||||
self.sale_order.action_confirm()
|
||||
workorder = self.env["mrp.workorder"].search([]) - prev_workorders
|
||||
with RecordCapturer(self.env["mrp.workorder"], []) as capture:
|
||||
self.sale_order.action_confirm()
|
||||
workorder = capture.records
|
||||
self.assertEqual(workorder.sale_id, self.sale_order)
|
||||
self.assertEqual(workorder.partner_id, self.partner)
|
||||
self.assertEqual(workorder.client_order_ref, self.sale_order.client_order_ref)
|
||||
|
||||
def test_kit(self):
|
||||
self.sale_order.write(
|
||||
{
|
||||
"order_line": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product_kit.id,
|
||||
"product_uom_qty": 2,
|
||||
"price_unit": 1,
|
||||
},
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
with RecordCapturer(self.env["mrp.production"], []) as capture:
|
||||
self.sale_order.action_confirm()
|
||||
productions = capture.records
|
||||
for order_line in self.sale_order.order_line:
|
||||
for created_prod in order_line.created_production_ids:
|
||||
self.assertIn(created_prod, productions)
|
||||
self.assertEqual(created_prod.product_qty, order_line.product_uom_qty)
|
||||
|
||||
Reference in New Issue
Block a user