Repository: saleor/saleor

Issue:
Product variants override price doesn't update when removed
### What I'm trying to achieve
Remove the override prices from a product variant.

I've set a price override to a test product variant; when trying update the price with a new value it works fine, the problem appears when you try to remove the price by saving the variant with empty price override: the change simply gets ignored and the variant keeps it's previous values of price override.

### Steps to reproduce the problem
1. Add a variant to a product
2. Set a selling or cost price override to the variant (example: 10)
3. Save
4. Remove the price override (empty input)
5. Save
6. Reload page
7. Product variant still has the price override (example: 10)

### What I expected to happen
Price override to be removed

**System information**
Operating system: Windows
Browser: Chrome

**Additional information**
I cloned and installed saleor + saleor-dashboard from the official repositories yesterday (so everything is up to date).


Discussion:
Hi! Thank you the finding, it is actually a bug in the GraphQL API (from #4639).

Resolving patch:
diff --git a/saleor/graphql/product/mutations/products.py b/saleor/graphql/product/mutations/products.py
--- a/saleor/graphql/product/mutations/products.py
+++ b/saleor/graphql/product/mutations/products.py
@@ -1036,13 +1036,11 @@ def clean_attributes(
     def clean_input(cls, info, instance: models.ProductVariant, data: dict):
         cleaned_input = super().clean_input(info, instance, data)
 
-        cost_price_amount = cleaned_input.pop("cost_price", None)
-        if cost_price_amount is not None:
-            cleaned_input["cost_price_amount"] = cost_price_amount
+        if "cost_price" in cleaned_input:
+            cleaned_input["cost_price_amount"] = cleaned_input.pop("cost_price")
 
-        price_override_amount = cleaned_input.pop("price_override", None)
-        if price_override_amount is not None:
-            cleaned_input["price_override_amount"] = price_override_amount
+        if "price_override" in cleaned_input:
+            cleaned_input["price_override_amount"] = cleaned_input.pop("price_override")
 
         # Attributes are provided as list of `AttributeValueInput` objects.
         # We need to transform them into the format they're stored in the


Test patch:
diff --git a/tests/api/test_variant.py b/tests/api/test_variant.py
--- a/tests/api/test_variant.py
+++ b/tests/api/test_variant.py
@@ -1,5 +1,6 @@
 import graphene
 import pytest
+from graphene.utils.str_converters import to_camel_case
 
 from tests.api.utils import get_graphql_content
 
@@ -337,6 +338,66 @@ def test_update_product_variant(staff_api_client, product, permission_manage_pro
     assert data["sku"] == sku
 
 
+@pytest.mark.parametrize("field", ("cost_price", "price_override"))
+def test_update_product_variant_unset_amounts(
+    staff_api_client, product, permission_manage_products, field
+):
+    """Ensure setting nullable amounts to null is properly handled
+    (setting the amount to none) and doesn't override the currency.
+    """
+    query = """
+        mutation updateVariant (
+            $id: ID!,
+            $sku: String!,
+            $costPrice: Decimal,
+            $priceOverride: Decimal) {
+                productVariantUpdate(
+                    id: $id,
+                    input: {
+                        sku: $sku,
+                        costPrice: $costPrice,
+                        priceOverride: $priceOverride
+                    }) {
+                    productVariant {
+                        name
+                        sku
+                        quantity
+                        costPrice {
+                            currency
+                            amount
+                            localized
+                        }
+                        priceOverride {
+                            currency
+                            amount
+                            localized
+                        }
+                    }
+                }
+            }
+
+    """
+    variant = product.variants.first()
+    variant_id = graphene.Node.to_global_id("ProductVariant", variant.pk)
+    sku = variant.sku
+
+    camel_case_field_name = to_camel_case(field)
+
+    variables = {"id": variant_id, "sku": sku, camel_case_field_name: None}
+
+    response = staff_api_client.post_graphql(
+        query, variables, permissions=[permission_manage_products]
+    )
+    variant.refresh_from_db()
+
+    assert variant.currency is not None
+    assert getattr(variant, field) is None
+
+    content = get_graphql_content(response)
+    data = content["data"]["productVariantUpdate"]["productVariant"]
+    assert data[camel_case_field_name] is None
+
+
 QUERY_UPDATE_VARIANT_ATTRIBUTES = """
     mutation updateVariant (
         $id: ID!,