diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py index 42692b7528c..c2c620950af 100644 --- a/erpnext/controllers/item_variant.py +++ b/erpnext/controllers/item_variant.py @@ -7,6 +7,7 @@ import json import frappe from frappe import _ +from frappe.query_builder import Case from frappe.utils import cstr, flt from erpnext.utilities.product import get_item_codes_by_attributes @@ -156,18 +157,22 @@ def update_variant_attribute_values(item_attribute): item_variant_table = frappe.qb.DocType("Item Variant Attribute") item_table = frappe.qb.DocType("Item") + attribute_value = item_variant_table.attribute_value + attribute_value_case = Case() for old_value, new_value in value_map.items(): - ( - frappe.qb.update(item_variant_table) - .join(item_table) - .on(item_table.name == item_variant_table.parent) - .set(item_variant_table.attribute_value, new_value) - .where(item_table.variant_of.isnotnull()) - .where(item_table.variant_of != "") - .where(item_variant_table.attribute == item_attribute.name) - .where(item_variant_table.attribute_value == old_value) - ).run() + attribute_value_case = attribute_value_case.when(attribute_value == old_value, new_value) + + ( + frappe.qb.update(item_variant_table) + .join(item_table) + .on(item_table.name == item_variant_table.parent) + .set(attribute_value, attribute_value_case.else_(attribute_value)) + .where(item_table.variant_of.isnotnull()) + .where(item_table.variant_of != "") + .where(item_variant_table.attribute == item_attribute.name) + .where(attribute_value.isin(list(value_map))) + ).run() frappe.flags.attribute_values = None diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index b34ce5bd894..8072437a173 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -395,6 +395,54 @@ class TestItem(FrappeTestCase): "Larger", ) + def test_swapped_attribute_value_renames_update_variants(self): + frappe.delete_doc_if_exists("Item", "_Test Variant Item-L", force=1) + frappe.delete_doc_if_exists("Item", "_Test Variant Item-S", force=1) + + large_variant = create_variant("_Test Variant Item", {"Test Size": "Large"}) + large_variant.save() + + small_variant = create_variant("_Test Variant Item", {"Test Size": "Small"}) + small_variant.save() + + attribute = frappe.get_doc("Item Attribute", "Test Size") + original_values = {row.name: row.attribute_value for row in attribute.item_attribute_values} + + def restore_test_size_values(): + doc = frappe.get_doc("Item Attribute", "Test Size") + for row in doc.item_attribute_values: + row.attribute_value = original_values[row.name] + frappe.flags.attribute_values = None + doc.save() + + self.addCleanup(restore_test_size_values) + + for row in attribute.item_attribute_values: + if row.attribute_value == "Large": + row.attribute_value = "Small" + elif row.attribute_value == "Small": + row.attribute_value = "Large" + + frappe.flags.attribute_values = None + attribute.save() + + self.assertEqual( + frappe.db.get_value( + "Item Variant Attribute", + {"parent": large_variant.name, "attribute": "Test Size"}, + "attribute_value", + ), + "Small", + ) + self.assertEqual( + frappe.db.get_value( + "Item Variant Attribute", + {"parent": small_variant.name, "attribute": "Test Size"}, + "attribute_value", + ), + "Large", + ) + def test_make_item_variant(self): frappe.delete_doc_if_exists("Item", "_Test Variant Item-L", force=1)