Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Syncing from upstream OCA/product-variant (18.0) #370

Merged
merged 10 commits into from
Feb 26, 2025
Merged
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
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ product-variant

[//]: # (addons)

This part will be replaced when running the oca-gen-addons-table script from OCA/maintainer-tools.
Available addons
----------------
addon | version | maintainers | summary
--- | --- | --- | ---
[product_attribute_value_archive](product_attribute_value_archive/) | 18.0.1.0.0 | [![mmequignon](https://github.com/mmequignon.png?size=30px)](https://github.com/mmequignon) | Allows to archive a `product.attribute.value` referenced by archived `product.product`.

[//]: # (end addons)

Expand Down
101 changes: 101 additions & 0 deletions product_attribute_value_archive/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
===============================
Product Attribute Value Archive
===============================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:28b1eea2d96064c6c66782393d5c6a6815f6b44efd2c141654d47f99a9de36c2
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproduct--variant-lightgray.png?logo=github
:target: https://github.com/OCA/product-variant/tree/18.0/product_attribute_value_archive
:alt: OCA/product-variant
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/product-variant-18-0/product-variant-18-0-product_attribute_value_archive
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/product-variant&target_branch=18.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

Allows to archive a product.attribute.value which is referenced by
archived product.product.

In std odoo, removing a product.attribute.value from a product.template
either leads to a product.product unlink or archive, depending on if the
variant is referenced on a sale.order.line or not. Then, if user tries
to remove the product.attribute.value from the product.attribute, he
will get an error because of the ondelete restrict on product.product.

**Table of contents**

.. contents::
:local:

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/product-variant/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/product-variant/issues/new?body=module:%20product_attribute_value_archive%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Camptocamp SA

Contributors
------------

- Matthieu Méquignon <[email protected]>

[Trobz]

- Nhan Tran <[email protected]>

Other credits
-------------

The migration of this module from 14.0 to 18.0 was financially supported
by Camptocamp.

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

.. |maintainer-mmequignon| image:: https://github.com/mmequignon.png?size=40px
:target: https://github.com/mmequignon
:alt: mmequignon

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-mmequignon|

This module is part of the `OCA/product-variant <https://github.com/OCA/product-variant/tree/18.0/product_attribute_value_archive>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions product_attribute_value_archive/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
16 changes: 16 additions & 0 deletions product_attribute_value_archive/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "Product Attribute Value Archive",
"summary": (
"Allows to archive a `product.attribute.value` "
"referenced by archived `product.product`."
),
"version": "18.0.1.0.0",
"category": "Product",
"website": "https://github.com/OCA/product-variant",
"author": "Camptocamp SA, Odoo Community Association (OCA)",
"maintainers": ["mmequignon"],
"license": "AGPL-3",
"installable": True,
"auto_install": True,
"depends": ["product", "sale"],
}
37 changes: 37 additions & 0 deletions product_attribute_value_archive/i18n/it.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * product_attribute_value_archive
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 18.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-02-25 15:06+0000\n"
"Last-Translator: mymage <[email protected]>\n"
"Language-Team: none\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.6.2\n"

#. module: product_attribute_value_archive
#: model:ir.model.fields,field_description:product_attribute_value_archive.field_product_attribute_value__active
msgid "Active"
msgstr "Attivo"

#. module: product_attribute_value_archive
#: model:ir.model,name:product_attribute_value_archive.model_product_attribute_value
msgid "Attribute Value"
msgstr "Valore attributo"

#. module: product_attribute_value_archive
#: model:ir.model,name:product_attribute_value_archive.model_product_template_attribute_value
msgid "Product Template Attribute Value"
msgstr "Valore attributo modello prodotto"

#. module: product_attribute_value_archive
#: model:ir.model,name:product_attribute_value_archive.model_product_product
msgid "Product Variant"
msgstr "Variante prodotto"
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * product_attribute_value_archive
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 18.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: product_attribute_value_archive
#: model:ir.model.fields,field_description:product_attribute_value_archive.field_product_attribute_value__active
msgid "Active"
msgstr ""

#. module: product_attribute_value_archive
#: model:ir.model,name:product_attribute_value_archive.model_product_attribute_value
msgid "Attribute Value"
msgstr ""

#. module: product_attribute_value_archive
#: model:ir.model,name:product_attribute_value_archive.model_product_template_attribute_value
msgid "Product Template Attribute Value"
msgstr ""

#. module: product_attribute_value_archive
#: model:ir.model,name:product_attribute_value_archive.model_product_product
msgid "Product Variant"
msgstr ""
3 changes: 3 additions & 0 deletions product_attribute_value_archive/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import product_product
from . import product_attribute_value
from . import product_template_attribute_value
85 changes: 85 additions & 0 deletions product_attribute_value_archive/models/product_attribute_value.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Copyright 2021 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

from odoo import api, fields, models


class ProductAttributeValue(models.Model):
_inherit = "product.attribute.value"

active = fields.Boolean(default=True)

def _get_related_variants(self):
"""Returns all related archived products.

When product is referenced from a SO, the variant is archived instead
of unlinked when it becomes not necessary. Thus, it can happen
that a product.attribute.value is still referenced by an archived
product.
"""
self.ensure_one()
self.flush_model()
query = """
SELECT array_agg(pp.id)
FROM product_product pp
JOIN product_variant_combination pvc
ON pp.id = pvc.product_product_id
JOIN product_template_attribute_value ptav
ON pvc.product_template_attribute_value_id = ptav.id
JOIN product_attribute_value pav
ON pav.id = ptav.product_attribute_value_id
WHERE pav.id = %(value_id)s;
"""
self.env.cr.execute(query, {"value_id": self.id})
# result is `[(None,)]` if nothing matched, `[([ids],)]` otherwise
product_ids = self.env.cr.fetchall()[0][0]
return self.env["product.product"].browse(product_ids)

def _archive(self):
return self.write({"active": False})

def _unarchive(self):
return self.write({"active": True})

def _get_pav_to_archive(self):
pav_to_archive_ids = set()
for pav in self:
related_variants = pav._get_related_variants()
# Archive only if all related variants are archived
# (none is active)
active_variants = related_variants.with_context(
prefetch_fields=False
).mapped("active")
# Performance optimization:
# fetch only 'active' field instead of prefetching all fields
all_variants_are_archived = related_variants and not any(active_variants)
if all_variants_are_archived:
pav_to_archive_ids.add(pav.id)
return self.browse(pav_to_archive_ids)

def unlink(self):
pav_to_archive = self._get_pav_to_archive()
pav_to_unlink = self - pav_to_archive
if pav_to_archive:
pav_to_archive._archive()
return super(ProductAttributeValue, pav_to_unlink).unlink()

@api.model_create_multi
def create(self, values):
values_to_create = []
unarchived_record_ids = set()
for value in values:
existing_archived_value = self.search(
[
("active", "=", False),
("name", "=", value["name"]),
("attribute_id", "=", value["attribute_id"]),
]
)
if existing_archived_value:
existing_archived_value.active = True
unarchived_record_ids.add(existing_archived_value.id)
continue
values_to_create.append(value)
created_records = super().create(values_to_create)
return created_records | self.browse(unarchived_record_ids)
24 changes: 24 additions & 0 deletions product_attribute_value_archive/models/product_product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2021 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

from odoo import models


class ProductProduct(models.Model):
_inherit = "product.product"

def _unarchive_tmpl_attr_vals(self):
"""Unarchives related `product_attribute_value` and
`product_template_attribute_value`.
"""
tmpl_attr_vals = self.mapped("product_template_attribute_value_ids")
archived_tmpl_attr_vals = tmpl_attr_vals.filtered(lambda v: not v.ptav_active)
for tmpl_attr_val in archived_tmpl_attr_vals:
tmpl_attr_val._unarchive()

def write(self, values):
res = super().write(values)
to_unarchive = values.get("active")
if to_unarchive:
self._unarchive_tmpl_attr_vals()
return res
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright 2021 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)

from odoo import models


class ProductTemplateAttributeValue(models.Model):
_inherit = "product.template.attribute.value"

def _unarchive(self):
"""Unarchive"""
self.ensure_one()
self.write({"ptav_active": True})
# get related archived product_attribute_value and unarchive it
attr_val = self.product_attribute_value_id
if not attr_val.active:
attr_val._unarchive()
# Rebuild the product_template_attribute_line link if it has been
# archived.
tmpl_attr_line = self.attribute_line_id
vals = {"value_ids": [(4, attr_val.id, 0)]}
if not tmpl_attr_line.active:
# As soon as we unarchive the product_template_attribute_line,
# odoo will try to create new variants, which we don't want here.
# If this code is executed, it is because a variant is about
# to be unarchived (the same that odoo will try to create),
# which would violate the "product_product_combination_unique"
# constaint.
# Set the update_product_template_attribute_values context key
# to disable this.
tmpl_attr_line = tmpl_attr_line.with_context(
update_product_template_attribute_values=False
)
vals["active"] = True
tmpl_attr_line.write(vals)
3 changes: 3 additions & 0 deletions product_attribute_value_archive/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
4 changes: 4 additions & 0 deletions product_attribute_value_archive/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- Matthieu Méquignon \<[email protected]\>

[Trobz]
- Nhan Tran \<[email protected]\>
2 changes: 2 additions & 0 deletions product_attribute_value_archive/readme/CREDITS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The migration of this module from 14.0 to 18.0 was financially supported
by Camptocamp.
8 changes: 8 additions & 0 deletions product_attribute_value_archive/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Allows to archive a product.attribute.value which is referenced by
archived product.product.

In std odoo, removing a product.attribute.value from a product.template
either leads to a product.product unlink or archive, depending on if the
variant is referenced on a sale.order.line or not. Then, if user tries
to remove the product.attribute.value from the product.attribute, he
will get an error because of the ondelete restrict on product.product.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading