Repository: saleor/saleor

Issue:
Add external reference to updateWarehouse
Currently, the `updateWarehouse` mutations takes only two parameters: id and input.
What I'd like to pass is the `externalReference` to avoid unnecessary query for ID and then do the update.


Discussion:

Resolving patch:
diff --git a/saleor/graphql/warehouse/mutations/warehouse_update.py b/saleor/graphql/warehouse/mutations/warehouse_update.py
--- a/saleor/graphql/warehouse/mutations/warehouse_update.py
+++ b/saleor/graphql/warehouse/mutations/warehouse_update.py
@@ -4,14 +4,15 @@
 from ....warehouse import models
 from ...account.i18n import I18nMixin
 from ...core import ResolveInfo
-from ...core.mutations import ModelMutation
+from ...core.descriptions import ADDED_IN_316
+from ...core.mutations import ModelWithExtRefMutation
 from ...core.types import WarehouseError
 from ...plugins.dataloaders import get_plugin_manager_promise
 from ..types import Warehouse, WarehouseUpdateInput
 from .base import WarehouseMixin
 
 
-class WarehouseUpdate(WarehouseMixin, ModelMutation, I18nMixin):
+class WarehouseUpdate(WarehouseMixin, ModelWithExtRefMutation):
     class Meta:
         model = models.Warehouse
         object_type = Warehouse
@@ -21,10 +22,14 @@ class Meta:
         error_type_field = "warehouse_errors"
 
     class Arguments:
-        id = graphene.ID(description="ID of a warehouse to update.", required=True)
+        id = graphene.ID(description="ID of a warehouse to update.", required=False)
         input = WarehouseUpdateInput(
             required=True, description="Fields required to update warehouse."
         )
+        external_reference = graphene.String(
+            required=False,
+            description="External reference of a warehouse." + ADDED_IN_316,
+        )
 
     @classmethod
     def prepare_address(cls, cleaned_data, instance):
@@ -35,7 +40,7 @@ def prepare_address(cls, cleaned_data, instance):
         address = instance.address
         if address_data is None:
             return address
-        address_form = cls.validate_address_form(address_data, instance=address)
+        address_form = I18nMixin.validate_address_form(address_data, instance=address)
         if address_metadata:
             cls.update_metadata(address, address_metadata)
         return address_form.save()


Test patch:
diff --git a/saleor/graphql/warehouse/tests/mutations/test_warehouse_update.py b/saleor/graphql/warehouse/tests/mutations/test_warehouse_update.py
--- a/saleor/graphql/warehouse/tests/mutations/test_warehouse_update.py
+++ b/saleor/graphql/warehouse/tests/mutations/test_warehouse_update.py
@@ -464,3 +464,109 @@ def test_update_click_and_collect_option_invalid_input(
 
     assert warehouse.is_private == warehouse_is_private
     assert warehouse.click_and_collect_option == warehouse_click_and_collect
+
+
+MUTATION_UPDATE_WAREHOUSE_BY_EXTERNAL_REFERENCE = """
+    mutation updateWarehouse($input: WarehouseUpdateInput!,
+            $id: ID, $externalReference: String) {
+    updateWarehouse(id: $id, input: $input, externalReference: $externalReference) {
+    errors {
+      message
+      field
+      code
+    }
+    warehouse {
+      name
+      slug
+      externalReference
+    }
+  }
+}
+"""
+
+
+def test_mutation_update_warehouse_by_external_reference(
+    staff_api_client, warehouse, permission_manage_products
+):
+    # given
+    external_reference = "test-ext-ref"
+    warehouse.external_reference = external_reference
+    warehouse.save(update_fields=["external_reference"])
+    variables = {
+        "externalReference": external_reference,
+        "input": {
+            "name": "New name",
+            "externalReference": external_reference,
+        },
+    }
+
+    # when
+    response = staff_api_client.post_graphql(
+        MUTATION_UPDATE_WAREHOUSE_BY_EXTERNAL_REFERENCE,
+        variables=variables,
+        permissions=[permission_manage_products],
+    )
+    content = get_graphql_content(response)
+
+    # then
+    warehouse.refresh_from_db()
+    data = content["data"]["updateWarehouse"]["warehouse"]
+    assert data["name"] == "New name"
+    assert warehouse.name == "New name"
+    assert warehouse.external_reference == external_reference
+
+
+def test_update_warehouse_by_both_id_and_external_reference(
+    staff_api_client, warehouse, permission_manage_products
+):
+    # given
+    external_reference = "test-ext-ref"
+    warehouse.external_reference = external_reference
+    warehouse.save(update_fields=["external_reference"])
+    variables = {
+        "externalReference": external_reference,
+        "id": warehouse.id,
+        "input": {"name": "New name"},
+    }
+
+    # when
+    response = staff_api_client.post_graphql(
+        MUTATION_UPDATE_WAREHOUSE_BY_EXTERNAL_REFERENCE,
+        variables=variables,
+        permissions=[permission_manage_products],
+    )
+    content = get_graphql_content(response)
+    data = content["data"]["updateWarehouse"]
+    # then
+    assert data["errors"]
+    assert (
+        data["errors"][0]["message"]
+        == "Argument 'id' cannot be combined with 'external_reference'"
+    )
+
+
+def test_update_product_external_reference_not_existing(
+    staff_api_client, permission_manage_products
+):
+    # given
+    external_reference = "non-existing-ext-ref"
+    variables = {
+        "externalReference": external_reference,
+        "input": {},
+    }
+
+    # when
+    response = staff_api_client.post_graphql(
+        MUTATION_UPDATE_WAREHOUSE_BY_EXTERNAL_REFERENCE,
+        variables=variables,
+        permissions=[permission_manage_products],
+    )
+    content = get_graphql_content(response)
+    data = content["data"]["updateWarehouse"]
+
+    # then
+    assert data["errors"]
+    assert (
+        data["errors"][0]["message"]
+        == f"Couldn't resolve to a node: {external_reference}"
+    )