From 6e6189d0934617a3559bb1d4f1821c429f3658b0 Mon Sep 17 00:00:00 2001 From: Stefan Rijnhart Date: Wed, 15 Jun 2022 17:35:17 +0200 Subject: [PATCH] [FIX] rma: prevent against warehouse mismatch or missing rules When creating pickings, ensure that the applied stock rule was taken from the operation's routes. Otherwise, the default procurement rules for a warehouse may kick in, creating incoming customer goods not from the customer location but from the resupply warehouse. --- rma/models/procurement_group.py | 24 +++++++++++++++++- rma/tests/test_rma.py | 45 +++++++++++++++++++++++++++++++-- rma/wizards/rma_make_picking.py | 6 ++++- 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/rma/models/procurement_group.py b/rma/models/procurement_group.py index 5cac27ba..bd8fe4ba 100644 --- a/rma/models/procurement_group.py +++ b/rma/models/procurement_group.py @@ -1,7 +1,8 @@ # Copyright (C) 2017-22 ForgeFlow S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from odoo import fields, models +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError class ProcurementGroup(models.Model): @@ -13,3 +14,24 @@ class ProcurementGroup(models.Model): rma_line_id = fields.Many2one( comodel_name="rma.order.line", string="RMA line", ondelete="set null" ) + + @api.model + def _get_rule(self, product_id, location_id, values): + """Ensure that the selected rule is from the configured route""" + res = super()._get_rule(product_id, location_id, values) + force_rule_ids = self.env.context.get("rma_force_rule_ids") + if force_rule_ids: + if res and res.id not in force_rule_ids: + raise ValidationError( + _( + "No rule found in this RMA's configured route for product " + "%(product)s and location %(location)s" + ) + % { + "product": product_id.default_code or product_id.name, + "location": location_id.complete_name, + } + ) + # Don't enforce rules on any chained moves + force_rule_ids.clear() + return res diff --git a/rma/tests/test_rma.py b/rma/tests/test_rma.py index e663ed12..2d82284b 100644 --- a/rma/tests/test_rma.py +++ b/rma/tests/test_rma.py @@ -1,8 +1,8 @@ # © 2017 ForgeFlow # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from odoo.exceptions import ValidationError -from odoo.tests import common +from odoo.exceptions import UserError, ValidationError +from odoo.tests import Form, common class TestRma(common.TransactionCase): @@ -1009,3 +1009,44 @@ class TestRma(common.TransactionCase): self.assertTrue(new_line.product_id.categ_id.rma_customer_operation_id) new_line._onchange_product_id() self.assertEqual(new_line.operation_id, rma_operation) + + def test_06_warehouse_mismatch(self): + """Mismatch between operation warehouse and stock rule warehouse is raised. + + * Create a second warehouse that is resupplied from the main warehouse + * Update an RMA to receive into the second warehouse + * When creating pickings, it is raised that the rules from the RMA + * config are not used. + """ + wh2 = self.env["stock.warehouse"].create( + { + "name": "Shop.", + "code": "SHP", + } + ) + wh2.resupply_wh_ids = self.env.ref("stock.warehouse0") + wh2.rma_in_this_wh = True + wh2.lot_rma_id = self.env["stock.location"].create( + { + "name": "WH2 RMA", + "usage": "internal", + "location_id": wh2.lot_stock_id.id, + } + ) + rma = self.rma_customer_id.copy() + rma.rma_line_ids = self.rma_customer_id.rma_line_ids[0].copy() + rma.rma_line_ids.product_id.sudo().route_ids += wh2.resupply_route_ids + rma_form = Form(rma) + rma_form.in_warehouse_id = wh2 + rma_form.save() + rma.rma_line_ids.action_rma_approve() + wizard = self.rma_make_picking.with_context( + **{ + "active_ids": rma.rma_line_ids.ids, + "active_model": "rma.order.line", + "picking_type": "incoming", + "active_id": 1, + } + ).create({}) + with self.assertRaisesRegex(UserError, "No rule found"): + wizard._create_picking() diff --git a/rma/wizards/rma_make_picking.py b/rma/wizards/rma_make_picking.py index ceb34563..2a4b9060 100644 --- a/rma/wizards/rma_make_picking.py +++ b/rma/wizards/rma_make_picking.py @@ -144,8 +144,10 @@ class RmaMakePicking(models.TransientModel): group = self.env["procurement.group"].create(pg_data) if picking_type == "incoming": qty = item.qty_to_receive + force_rule_ids = item.line_id.in_route_id.rule_ids.ids else: qty = item.qty_to_deliver + force_rule_ids = item.line_id.out_route_id.rule_ids.ids values = self._get_procurement_data(item, group, qty, picking_type) values = dict(values, rma_line_id=item.line_id, rma_id=item.line_id.rma_id) # create picking @@ -163,7 +165,9 @@ class RmaMakePicking(models.TransientModel): ) procurements.append(procurement) - self.env["procurement.group"].run(procurements) + self.env["procurement.group"].with_context( + rma_force_rule_ids=force_rule_ids + ).run(procurements) except UserError as error: errors.append(error.args[0]) if errors: