Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion storage_file/views/storage_file_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
<record id="storage_file_view_tree" model="ir.ui.view">
<field name="model">storage.file</field>
<field name="arch" type="xml">
<list>
<list decoration-muted="not active">
<field name="active" column_invisible="True" />
<field name="name" />
<field name="backend_id" />
<field name="file_size" />
Expand All @@ -17,6 +18,13 @@
<field name="model">storage.file</field>
<field name="arch" type="xml">
<form string="File">
<field name="active" invisible="1" />
<widget
name="web_ribbon"
title="Archived"
bg_color="bg-danger"
invisible="active"
/>
<div class="oe_title">
<label for="name" class="oe_edit_only" />
<h1>
Expand Down Expand Up @@ -59,6 +67,18 @@
name="private"
domain="[('is_public', '=', False)]"
/>
<separator />
<filter
string="All"
name="all"
domain="['|', ('active', '=', False), ('active', '=', True)]"
/>
<separator />
<filter
string="Archived"
name="inactive"
domain="[('active', '=', False)]"
/>
<group string="Group By" expand="0">
<filter
string="Backend"
Expand Down
5 changes: 4 additions & 1 deletion storage_image/models/storage_image_relation_abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,7 @@ class ImageRelationAbstract(models.AbstractModel):
image_alt_name = fields.Char(related="image_id.alt_name")
image_url = fields.Char(related="image_id.image_medium_url")
is_public = fields.Boolean(related="image_id.file_id.is_public", readonly=True)
active = fields.Boolean(related="image_id.active", readonly=True)
# Gray out the relations of archived images.
# NOTE: do not call this field `active`, it would hide the relations
# (eg: on the product) and we want to display them anyway.
image_active = fields.Boolean(related="image_id.active", readonly=True)
22 changes: 21 additions & 1 deletion storage_image/views/storage_image.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
<record id="storage_image_view_tree" model="ir.ui.view">
<field name="model">storage.image</field>
<field name="arch" type="xml">
<list>
<list decoration-muted="not active">
<field name="active" column_invisible="True" />
<field name="write_date" />
<field name="name" />
<field name="alt_name" />
Expand All @@ -24,6 +25,13 @@
type="action"
/>
</header>
<field name="active" invisible="1" />
<widget
name="web_ribbon"
title="Archived"
bg_color="bg-danger"
invisible="active"
/>
<group string="Image" name="image">
<field
name="data"
Expand Down Expand Up @@ -104,6 +112,18 @@
name="private"
domain="[('is_public', '=', False)]"
/>
<separator />
<filter
string="All"
name="all"
domain="['|', ('active', '=', False), ('active', '=', True)]"
/>
<separator />
<filter
string="Archived"
name="inactive"
domain="[('active', '=', False)]"
/>
<group string="Group By" expand="0">
<filter
string="Backend"
Expand Down
10 changes: 9 additions & 1 deletion storage_image/views/storage_image_relation_abstract.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,14 @@
<field name="image_url" />
<field name="image_name" />
<field name="image_alt_name" />
<field name="image_active" />
<field name="sequence" widget="handle" />
<templates>
<t t-name="card" class="row g-0">
<aside class="col-3">
<aside
class="col-3"
t-att-class="record.image_active.raw_value ? '' : 'opacity-50'"
>
<field
name="image_url"
widget="image_url"
Expand All @@ -95,6 +99,10 @@
<field name="image_name" />
</span>
</div>
<span
t-if="!record.image_active.raw_value"
class="badge text-bg-secondary"
>Archived</span>
</main>
</t>
</templates>
Expand Down
15 changes: 9 additions & 6 deletions storage_image_product/models/product_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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)
10 changes: 8 additions & 2 deletions storage_image_product/models/product_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
25 changes: 25 additions & 0 deletions storage_image_product/tests/test_product_image_relation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
16 changes: 8 additions & 8 deletions storage_image_product/views/storage_image.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@
<page name="products" string="Products">
<field name="product_relation_ids" mode="list,form,kanban">
<list
decoration-success="is_public and active"
decoration-danger="not is_public and active"
decoration-muted="not active"
decoration-success="is_public and image_active"
decoration-danger="not is_public and image_active"
decoration-muted="not image_active"
>
<field name="product_tmpl_id" />
<field name="available_attribute_value_ids" invisible="1" />
<field name="attribute_value_ids" widget="many2many_tags" />
<field name="tag_id" />
<field name="is_public" optional="hide" />
<field name="active" column_invisible="True" />
<field name="image_active" column_invisible="True" />
</list>
<form>
<group>
Expand All @@ -34,14 +34,14 @@
<page name="categories" string="Categories">
<field name="category_relation_ids" mode="list,form,kanban">
<list
decoration-success="is_public and active"
decoration-danger="not is_public and active"
decoration-muted="not active"
decoration-success="is_public and image_active"
decoration-danger="not is_public and image_active"
decoration-muted="not image_active"
>
<field name="category_id" />
<field name="tag_id" />
<field name="is_public" optional="hide" />
<field name="active" column_invisible="True" />
<field name="image_active" column_invisible="True" />
</list>
<form>
<group>
Expand Down
5 changes: 4 additions & 1 deletion storage_media_product/models/product.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
1 change: 1 addition & 0 deletions storage_media_product/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_product_media
36 changes: 36 additions & 0 deletions storage_media_product/tests/test_product_media.py
Original file line number Diff line number Diff line change
@@ -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)
8 changes: 4 additions & 4 deletions storage_media_product/views/product.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@
<field name="model">product.media.relation</field>
<field name="arch" type="xml">
<list
decoration-success="is_public and active"
decoration-danger="not is_public and active"
decoration-muted="not active"
decoration-success="is_public and media_active"
decoration-danger="not is_public and media_active"
decoration-muted="not media_active"
>
<field name="media_id" />
<field name="media_type_id" readonly="True" />
<field name="is_public" optional="hide" />
<field name="active" column_invisible="True" />
<field name="media_active" column_invisible="True" />
</list>
</field>
</record>
Expand Down
Loading