From d36d545e35a79baab40ac2f6ee60f1327fe6d65b Mon Sep 17 00:00:00 2001 From: les-adhoc Date: Thu, 14 May 2026 14:21:25 +0000 Subject: [PATCH] Cherry pick of 19224d429c3ed6bd63a5dc8f8e4e0bc9a068fb65 failed stdout: CONFLICT (modify/delete): product_uoms_purchase/models/product_uoms.py deleted in 7c2d22002ef79238701e333602d5077099709394 and modified in 19224d429c3ed6bd63a5dc8f8e4e0bc9a068fb65. Version 19224d429c3ed6bd63a5dc8f8e4e0bc9a068fb65 of product_uoms_purchase/models/product_uoms.py left in tree. stderr: --- product_uoms_purchase/models/product_uoms.py | 43 +++++++++++++++++ product_uoms_purchase/tests/__init__.py | 1 + .../tests/test_product_uoms.py | 47 +++++++++++++++++++ product_uoms_sale/models/product_uoms.py | 27 ++++++++++- product_uoms_sale/tests/__init__.py | 1 + product_uoms_sale/tests/test_product_uoms.py | 40 ++++++++++++++++ 6 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 product_uoms_purchase/models/product_uoms.py create mode 100644 product_uoms_purchase/tests/__init__.py create mode 100644 product_uoms_purchase/tests/test_product_uoms.py create mode 100644 product_uoms_sale/tests/__init__.py create mode 100644 product_uoms_sale/tests/test_product_uoms.py diff --git a/product_uoms_purchase/models/product_uoms.py b/product_uoms_purchase/models/product_uoms.py new file mode 100644 index 000000000..140bded6b --- /dev/null +++ b/product_uoms_purchase/models/product_uoms.py @@ -0,0 +1,43 @@ +<<<<<<< HEAD +||||||| MERGE BASE +======= +############################################################################## +# For copyright and license notices, see __manifest__.py file in module root +# directory +############################################################################## +from odoo import _, fields, models +from odoo.exceptions import ValidationError +from odoo.osv import expression + + +class ProductUoms(models.Model): + _inherit = "product.uoms" + + purchase_ok = fields.Boolean( + default=True, + ) + + def unlink(self): + purchase_order_line = self._get_blocking_purchase_order_line() + if purchase_order_line: + raise ValidationError( + _( + "You cannot delete secondary unit of measure %(uom)s from %(product)s because it is used on purchase order %(order)s. Please update or remove the order line before deleting it.", + uom=purchase_order_line.product_uom.display_name, + product=purchase_order_line.product_id.display_name, + order=purchase_order_line.order_id.display_name, + ) + ) + return super().unlink() + + def _get_blocking_purchase_order_line(self): + pair_domains = [ + [("product_id.product_tmpl_id", "=", rec.product_tmpl_id.id), ("product_uom", "=", rec.uom_id.id)] + for rec in self + ] + if not pair_domains: + return self.env["purchase.order.line"] + domain = expression.AND([expression.OR(pair_domains), [("state", "!=", "cancel")]]) + return self.env["purchase.order.line"].search(domain, limit=1) + +>>>>>>> FORWARD PORTED diff --git a/product_uoms_purchase/tests/__init__.py b/product_uoms_purchase/tests/__init__.py new file mode 100644 index 000000000..1328048b8 --- /dev/null +++ b/product_uoms_purchase/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_uoms diff --git a/product_uoms_purchase/tests/test_product_uoms.py b/product_uoms_purchase/tests/test_product_uoms.py new file mode 100644 index 000000000..60d3e562e --- /dev/null +++ b/product_uoms_purchase/tests/test_product_uoms.py @@ -0,0 +1,47 @@ +from odoo import fields +from odoo.exceptions import ValidationError +from odoo.tests.common import TransactionCase + + +class TestProductUoms(TransactionCase): + def setUp(self): + super().setUp() + self.supplier = self.env["res.partner"].create({"name": "Test Supplier"}) + self.main_uom = self.env.ref("uom.product_uom_unit") + self.secondary_uom = self.env.ref("uom.product_uom_dozen") + self.product_template = self.env["product.template"].create( + { + "name": "Test Product With Purchase Secondary UoM", + "uom_id": self.main_uom.id, + "uom_po_id": self.main_uom.id, + "purchase_ok": True, + } + ) + self.secondary_product_uom = self.env["product.uoms"].create( + { + "product_tmpl_id": self.product_template.id, + "uom_id": self.secondary_uom.id, + "purchase_ok": True, + } + ) + self.purchase_order = self.env["purchase.order"].create( + { + "partner_id": self.supplier.id, + "date_order": fields.Date.today(), + } + ) + self.env["purchase.order.line"].create( + { + "order_id": self.purchase_order.id, + "name": self.product_template.name, + "product_id": self.product_template.product_variant_id.id, + "product_qty": 1.0, + "product_uom": self.secondary_uom.id, + "price_unit": 100.0, + "date_planned": fields.Datetime.now(), + } + ) + + def test_cannot_unlink_secondary_uom_used_in_purchase_order(self): + with self.assertRaises(ValidationError): + self.secondary_product_uom.unlink() diff --git a/product_uoms_sale/models/product_uoms.py b/product_uoms_sale/models/product_uoms.py index c7aba2a75..7d4b6c9a4 100644 --- a/product_uoms_sale/models/product_uoms.py +++ b/product_uoms_sale/models/product_uoms.py @@ -2,7 +2,9 @@ # For copyright and license notices, see __manifest__.py file in module root # directory ############################################################################## -from odoo import fields, models +from odoo import _, fields, models +from odoo.exceptions import ValidationError +from odoo.osv import expression class ProductUoms(models.Model): @@ -11,3 +13,26 @@ class ProductUoms(models.Model): sale_ok = fields.Boolean( default=True, ) + + def unlink(self): + sale_order_line = self._get_blocking_sale_order_line() + if sale_order_line: + raise ValidationError( + _( + "You cannot delete secondary unit of measure %(uom)s from %(product)s because it is used on sale order %(order)s. Please update or remove the order line before deleting it.", + uom=sale_order_line.product_uom.display_name, + product=sale_order_line.product_id.display_name, + order=sale_order_line.order_id.display_name, + ) + ) + return super().unlink() + + def _get_blocking_sale_order_line(self): + pair_domains = [ + [("product_id.product_tmpl_id", "=", rec.product_tmpl_id.id), ("product_uom", "=", rec.uom_id.id)] + for rec in self + ] + if not pair_domains: + return self.env["sale.order.line"] + domain = expression.AND([expression.OR(pair_domains), [("state", "!=", "cancel")]]) + return self.env["sale.order.line"].search(domain, limit=1) diff --git a/product_uoms_sale/tests/__init__.py b/product_uoms_sale/tests/__init__.py new file mode 100644 index 000000000..1328048b8 --- /dev/null +++ b/product_uoms_sale/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_uoms diff --git a/product_uoms_sale/tests/test_product_uoms.py b/product_uoms_sale/tests/test_product_uoms.py new file mode 100644 index 000000000..9ebdfb0be --- /dev/null +++ b/product_uoms_sale/tests/test_product_uoms.py @@ -0,0 +1,40 @@ +from odoo.exceptions import ValidationError +from odoo.tests.common import TransactionCase + + +class TestProductUoms(TransactionCase): + def setUp(self): + super().setUp() + self.partner = self.env["res.partner"].create({"name": "Test Customer"}) + self.main_uom = self.env.ref("uom.product_uom_unit") + self.secondary_uom = self.env.ref("uom.product_uom_dozen") + self.product_template = self.env["product.template"].create( + { + "name": "Test Product With Secondary UoM", + "uom_id": self.main_uom.id, + "uom_po_id": self.main_uom.id, + "list_price": 100.0, + } + ) + self.secondary_product_uom = self.env["product.uoms"].create( + { + "product_tmpl_id": self.product_template.id, + "uom_id": self.secondary_uom.id, + "sale_ok": True, + } + ) + self.sale_order = self.env["sale.order"].create({"partner_id": self.partner.id}) + self.env["sale.order.line"].create( + { + "order_id": self.sale_order.id, + "name": self.product_template.name, + "product_id": self.product_template.product_variant_id.id, + "product_uom": self.secondary_uom.id, + "product_uom_qty": 1.0, + "price_unit": 100.0, + } + ) + + def test_cannot_unlink_secondary_uom_used_in_sale_order(self): + with self.assertRaises(ValidationError): + self.secondary_product_uom.unlink()