From 3e31cc070932804ae1baffb7bf714fd9538b0e45 Mon Sep 17 00:00:00 2001 From: dkendall Date: Wed, 10 Jun 2026 20:46:58 -0400 Subject: [PATCH] [FIX] ddmrp: drop the unreachable product-UoM-change buffer guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _check_buffer_procure_uom can never raise: procure_uom_id is a stored compute depending on the product UoM, so writing a new UoM on the template re-derives every buffer's procurement UoM before the constraint reads it — an incompatible pair is unobservable. On top of that, its 19.0 predicate (_compute_quantity with raise_if_failure=False, which never fails) was doubly inert. The auto-follow recompute plus the buffer-side _check_procure_uom constraint and the valid_uom_ids view domain are the effective guards; pin the auto-follow behavior with a test instead. --- ddmrp/models/product_template.py | 27 +-------------------------- ddmrp/tests/test_ddmrp.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/ddmrp/models/product_template.py b/ddmrp/models/product_template.py index c7afe6ce9..598b57974 100644 --- a/ddmrp/models/product_template.py +++ b/ddmrp/models/product_template.py @@ -1,8 +1,7 @@ # Copyright 2019-20 ForgeFlow S.L. (http://www.forgeflow.com) # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). -from odoo import api, fields, models -from odoo.exceptions import ValidationError +from odoo import fields, models class ProductTemplate(models.Model): @@ -16,29 +15,5 @@ def _compute_buffer_count(self): variant.buffer_count for variant in rec.product_variant_ids ) - # UOM: (stock_orderpoint_uom): - @api.constrains("uom_id") - def _check_buffer_procure_uom(self): - for rec in self: - buffers = self.env["stock.buffer"].search( - [ - ("product_id", "in", rec.product_variant_ids.ids), - ], - ) - uom_id = rec.uom_id - incompatible = buffers.filtered( - lambda b, uom_id=uom_id: b.procure_uom_id - and not b.procure_uom_id._compute_quantity( - 1.0, uom_id, raise_if_failure=False - ) - ) - if incompatible: - raise ValidationError( - rec.env._( - "At least one stock buffer for this product has a " - "different Procurement unit of measure category." - ) - ) - def action_view_stock_buffers(self): return self.product_variant_ids.action_view_stock_buffers() diff --git a/ddmrp/tests/test_ddmrp.py b/ddmrp/tests/test_ddmrp.py index 849db9f51..52b7b3b9a 100644 --- a/ddmrp/tests/test_ddmrp.py +++ b/ddmrp/tests/test_ddmrp.py @@ -1569,3 +1569,31 @@ def test_55_purchase_line_form_no_newid_domain_warning(self): with po_form.order_line.new() as line: line.product_id = self.product_purchased po_form.save() + + def test_53_procure_uom_follows_product_uom_change(self): + """Changing a product UoM resets the buffers' procurement UoM. + + _compute_procure_uom_id re-derives procure_uom_id from the product + UoM whenever it changes, so buffers can never be left with a + procurement UoM incompatible with the new product UoM. + """ + product = self.productModel.create( + { + "name": "Product UoM follow", + "is_storable": True, + "uom_id": self.uom_unit.id, + } + ) + buffer = self.bufferModel.create( + { + "buffer_profile_id": self.buffer_profile_pur.id, + "product_id": product.id, + "warehouse_id": self.warehouse.id, + "location_id": self.stock_location.id, + "adu_calculation_method": self.adu_fixed.id, + "procure_uom_id": self.dozen_unit.id, + } + ) + meter = self.env.ref("uom.product_uom_meter") + product.product_tmpl_id.uom_id = meter + self.assertEqual(buffer.procure_uom_id, meter)