diff --git a/storage_file/views/storage_file_view.xml b/storage_file/views/storage_file_view.xml index acc313b06f..7d4a9fa929 100644 --- a/storage_file/views/storage_file_view.xml +++ b/storage_file/views/storage_file_view.xml @@ -3,7 +3,8 @@ storage.file - + + @@ -17,6 +18,13 @@ storage.file
+ +
+ Archived diff --git a/storage_image_product/models/product_product.py b/storage_image_product/models/product_product.py index cb73c4486d..ae0a8973ae 100644 --- a/storage_image_product/models/product_product.py +++ b/storage_image_product/models/product_product.py @@ -48,7 +48,7 @@ def _compute_variant_image_ids(self): img_relations.add(image_rel.id) variant.variant_image_ids = list(img_relations) if img_relations else False - @api.depends("variant_image_ids.sequence") + @api.depends("variant_image_ids.sequence", "variant_image_ids.image_active") def _compute_main_image_id(self): for record in self: record.main_image_id = record._get_main_image() @@ -59,12 +59,15 @@ def _select_main_image(self, images): ).image_id def _get_main_image(self): - match_image = self.variant_image_ids.filtered( - lambda i: i.attribute_value_ids - == self.mapped( - "product_template_attribute_value_ids.product_attribute_value_id" + images = self.variant_image_ids.filtered("image_active") + match_image = images.filtered( + lambda i: ( + i.attribute_value_ids + == self.mapped( + "product_template_attribute_value_ids.product_attribute_value_id" + ) ) ) if match_image: return self._select_main_image(match_image) - return self._select_main_image(self.variant_image_ids) + return self._select_main_image(images) diff --git a/storage_image_product/models/product_template.py b/storage_image_product/models/product_template.py index 705919cd3e..71d0d3bb2f 100644 --- a/storage_image_product/models/product_template.py +++ b/storage_image_product/models/product_template.py @@ -34,12 +34,18 @@ class ProductTemplate(models.Model): string="Main medium image URL", related="main_image_id.image_medium_url" ) - @api.depends("image_ids", "image_ids.sequence", "image_ids.image_id") + @api.depends( + "image_ids", + "image_ids.sequence", + "image_ids.image_id", + "image_ids.image_active", + ) def _compute_main_image_id(self): for record in self: record.main_image_id = record._get_main_image() def _get_main_image(self): + images = self.image_ids.filtered("image_active") return fields.first( - self.image_ids.sorted(key=lambda i: (i.sequence, i.image_id)) + images.sorted(key=lambda i: (i.sequence, i.image_id)) ).image_id diff --git a/storage_image_product/tests/test_product_image_relation.py b/storage_image_product/tests/test_product_image_relation.py index c7e33e5143..09e6f47801 100644 --- a/storage_image_product/tests/test_product_image_relation.py +++ b/storage_image_product/tests/test_product_image_relation.py @@ -202,3 +202,28 @@ def test_drop_template_attribute_value_propagation_to_image(self): self.env.ref("product.product_attribute_value_1") not in black_image.attribute_value_ids ) + + def test_archived_image(self): + logo_relation, white_relation = self.env["product.image.relation"].create( + [ + { + "product_tmpl_id": self.template.id, + "image_id": self.logo_image.id, + "sequence": 1, + }, + { + "product_tmpl_id": self.template.id, + "image_id": self.white_image.id, + "sequence": 2, + }, + ] + ) + self.assertEqual(self.template.main_image_id, self.logo_image) + self.assertEqual(self.product_a.main_image_id, self.logo_image) + self.logo_image.active = False + # Still listed, but not the main image anymore + self.assertEqual(self.template.image_ids, logo_relation | white_relation) + self.assertIn(logo_relation, self.product_a.variant_image_ids) + self.assertFalse(logo_relation.image_active) + self.assertEqual(self.template.main_image_id, self.white_image) + self.assertEqual(self.product_a.main_image_id, self.white_image) diff --git a/storage_image_product/views/storage_image.xml b/storage_image_product/views/storage_image.xml index c3a4cd140f..1c385fd2a5 100644 --- a/storage_image_product/views/storage_image.xml +++ b/storage_image_product/views/storage_image.xml @@ -8,16 +8,16 @@ - + @@ -34,14 +34,14 @@ - + diff --git a/storage_media_product/models/product.py b/storage_media_product/models/product.py index a885f7f80d..b1365da0c1 100644 --- a/storage_media_product/models/product.py +++ b/storage_media_product/models/product.py @@ -66,7 +66,10 @@ class ProductMediaRelation(models.Model): url_path = fields.Char(related="media_id.url_path", readonly=True) media_type_id = fields.Many2one(related="media_id.media_type_id", readonly=True) is_public = fields.Boolean(related="media_id.file_id.is_public", readonly=True) - active = fields.Boolean(related="media_id.active", readonly=True) + # Gray out the relations of archived media. + # NOTE: do not call this field `active`, it would hide the relations + # (eg: on the product) and we want to display them anyway. + media_active = fields.Boolean(related="media_id.active", readonly=True) @api.depends("media_id", "product_tmpl_id.attribute_line_ids.value_ids") def _compute_available_attribute(self): diff --git a/storage_media_product/tests/__init__.py b/storage_media_product/tests/__init__.py new file mode 100644 index 0000000000..5c2a90e059 --- /dev/null +++ b/storage_media_product/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_media diff --git a/storage_media_product/tests/test_product_media.py b/storage_media_product/tests/test_product_media.py new file mode 100644 index 0000000000..b5c0ae9743 --- /dev/null +++ b/storage_media_product/tests/test_product_media.py @@ -0,0 +1,36 @@ +# Copyright 2026 Camptocamp SA +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +import base64 + +from odoo.tests import Form + +from odoo.addons.component.tests.common import TransactionComponentCase + + +class TestProductMedia(TransactionComponentCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.media = cls.env["storage.media"].create( + {"name": "doc.txt", "data": base64.b64encode(b"doc")} + ) + cls.product = cls.env["product.product"].create({"name": "Media product"}) + cls.relation = cls.env["product.media.relation"].create( + { + "media_id": cls.media.id, + "product_tmpl_id": cls.product.product_tmpl_id.id, + } + ) + + def test_archived_relation_listed_on_template(self): + product_tmpl = self.product.product_tmpl_id + view = "storage_media_product.product_template_only_form_view" + self.media.active = False + self.assertFalse(self.relation.media_active) + self.assertEqual(len(Form(product_tmpl, view=view).media_ids), 1) + + def test_archived_relation_listed_on_variant(self): + view = "storage_media_product.product_normal_form_view" + self.media.active = False + self.assertEqual(len(Form(self.product, view=view).variant_media_ids), 1) diff --git a/storage_media_product/views/product.xml b/storage_media_product/views/product.xml index d03831bbfa..9a29a9a067 100644 --- a/storage_media_product/views/product.xml +++ b/storage_media_product/views/product.xml @@ -36,14 +36,14 @@ product.media.relation - +