Repository: saleor/saleor

Issue:
Bug: KeyError 'countries'
### What are you trying to achieve?

Call `shippingZoneUpdate` mutation with `default: true` input.

### Steps to reproduce the problem

1. Call a mutation for some existing shipping zone and pass `default: true` in the input:
```
mutation {
  shippingZoneUpdate(id: "U2hpcHBpbmdab25lOjY3", input:{ default: true }) {
    errors {
      code
      field
      message
    }
    shippingZone {
      id
    }
  }
}
```

### What did you expect to happen?

Error should be handled.

### Logs

https://saleor.sentry.io/share/issue/24f38163cb244629a06367a230416631/


### Environment

Saleor version: 3.11.17




Discussion:
Reported in: https://saleorcommerce.slack.com/archives/C038XPD8HLK/p1679413591787469
Shall I work on this bug? @maarcingebala  . If yes , Please assign this to me

Resolving patch:
diff --git a/saleor/graphql/shipping/mutations/shippings.py b/saleor/graphql/shipping/mutations/shippings.py
--- a/saleor/graphql/shipping/mutations/shippings.py
+++ b/saleor/graphql/shipping/mutations/shippings.py
@@ -279,8 +279,7 @@ def clean_default(cls, instance, data):
                     }
                 )
             else:
-                countries = get_countries_without_shipping_zone()
-                data["countries"].extend([country for country in countries])
+                cls._extend_shipping_zone_countries(data)
         else:
             data["default"] = False
         return data
@@ -372,6 +371,14 @@ def delete_invalid_shipping_zone_to_warehouse_relation(cls, shipping_zone):
             id__in=shipping_zone_warehouses_to_delete
         ).delete()
 
+    @classmethod
+    def _extend_shipping_zone_countries(cls, data):
+        countries = get_countries_without_shipping_zone()
+        try:
+            data["countries"].extend([country for country in countries])
+        except (KeyError, AttributeError):
+            data["countries"] = [country for country in countries]
+
 
 class ShippingZoneCreate(ShippingZoneMixin, ModelMutation):
     class Arguments:


Test patch:
diff --git a/saleor/graphql/shipping/tests/mutations/test_shipping_zone_update.py b/saleor/graphql/shipping/tests/mutations/test_shipping_zone_update.py
--- a/saleor/graphql/shipping/tests/mutations/test_shipping_zone_update.py
+++ b/saleor/graphql/shipping/tests/mutations/test_shipping_zone_update.py
@@ -2,6 +2,7 @@
 from unittest import mock
 
 import graphene
+import pytest
 from django.utils.functional import SimpleLazyObject
 from freezegun import freeze_time
 
@@ -59,6 +60,25 @@
     }
 """
 
+SHIPPING_ZONE_UPDATE_DEFAULT_TRUE_MUTATION = """
+    mutation ShippingZoneUpdate($id: ID!, $input: ShippingZoneUpdateInput!) {
+        shippingZoneUpdate(id: $id, input: $input) {
+            errors {
+                code
+                field
+                message
+            }
+            shippingZone {
+                id
+                default
+                countries {
+                    code
+                }
+            }
+        }
+    }
+"""
+
 
 def test_update_shipping_zone(
     staff_api_client, shipping_zone, permission_manage_shipping
@@ -641,3 +661,39 @@ def test_update_shipping_zone_remove_channels_remove_common_warehouse_channel(
     )
     assert len(shipping_zone_data["warehouses"]) == 1
     assert shipping_zone_data["warehouses"][0]["slug"] == warehouses[1].slug
+
+
+@pytest.mark.parametrize(
+    "input, expected_countries",
+    (
+        ({"default": True, "countries": ["PL"]}, [{"code": "PL"}]),
+        ({"default": True, "countries": []}, []),
+        ({"default": True, "countries": None}, []),
+        ({"default": True}, []),
+    ),
+)
+def test_shipping_method_update_countries(
+    staff_api_client,
+    shipping_zone,
+    permission_manage_shipping,
+    input,
+    expected_countries,
+):
+    # given
+    variables = {
+        "id": graphene.Node.to_global_id("ShippingZone", shipping_zone.id),
+        "input": input,
+    }
+
+    # when
+    staff_api_client.user.user_permissions.add(permission_manage_shipping)
+    response = staff_api_client.post_graphql(
+        SHIPPING_ZONE_UPDATE_DEFAULT_TRUE_MUTATION, variables
+    )
+
+    # then
+    content = get_graphql_content(response)
+    data = content["data"]["shippingZoneUpdate"]
+    assert data["errors"] == []
+    assert data["shippingZone"]["default"] is True
+    assert data["shippingZone"]["countries"] == expected_countries