Repository: saleor/saleor

Issue:
Bug: Exclude shipping method not working for shipping methods without channel listing.
### What are you trying to achieve?

When attempting to list shipping methods without a shipping channel in the order payload, an error will occur.

### Steps to reproduce the problem

1. create a webhook with `excluded_shipping_methods_for_order` or anything that generate order payload
2. create an order that has a shipping method without a channel listing for the current channel
3. trigger the webhookgenerates

### What did you expect to happen?

Webhook should be sent. 

### Logs

```
AttributeError: 'NoneType' object has no attribute 'currency'
  File "promise/promise.py", line 87, in try_catch
    return (handler(*args, **kwargs), None)
  File "saleor/graphql/order/types.py", line 1648, in with_listings
    return get_valid_shipping_methods_for_order(
  File "saleor/order/utils.py", line 608, in get_valid_shipping_methods_for_order
    excluded_methods = manager.excluded_shipping_methods_for_order(order, valid_methods)
  File "saleor/plugins/manager.py", line 1598, in excluded_shipping_methods_for_order
    return self.__run_method_on_plugins(
  File "saleor/plugins/manager.py", line 181, in __run_method_on_plugins
    value = self.__run_method_on_single_plugin(
  File "saleor/plugins/manager.py", line 203, in __run_method_on_single_plugin
    returned_value = plugin_method(
  File "saleor/plugins/webhook/plugin.py", line 1547, in excluded_shipping_methods_for_order
    return get_excluded_shipping_data(
  File "saleor/plugins/webhook/shipping.py", line 150, in get_excluded_shipping_data
    payload = payload_fun()
  File "saleor/plugins/webhook/plugin.py", line 1542, in <lambda>
    payload_fun = lambda: generate_function(  # noqa: E731
  File "saleor/webhook/__init__.py", line 10, in wrapper
    return func(*args, **kwargs)
  File "saleor/webhook/payloads.py", line 1201, in generate_excluded_shipping_methods_for_order_payload
    order_data = json.loads(generate_order_payload(order))[0]
  File "saleor/webhook/__init__.py", line 10, in wrapper
    return func(*args, **kwargs)
  File "saleor/webhook/payloads.py", line 332, in generate_order_payload
    "shipping_method": _generate_shipping_method_payload(
  File "saleor/webhook/payloads.py", line 255, in _generate_shipping_method_payload
    "currency": shipping_method_channel_listing.currency,
```

### Environment

Saleor version: 3.9
OS and version: Cloud



Discussion:
Sentry issue: [SALEOR-CORE-1EH](https://saleor.sentry.io/issues/3963310512/?referrer=github_integration)

Resolving patch:
diff --git a/saleor/webhook/payloads.py b/saleor/webhook/payloads.py
--- a/saleor/webhook/payloads.py
+++ b/saleor/webhook/payloads.py
@@ -241,13 +241,16 @@ def _generate_shipping_method_payload(shipping_method, channel):
     if not shipping_method:
         return None
 
-    serializer = PayloadSerializer()
-    shipping_method_fields = ("name", "type")
-
     shipping_method_channel_listing = shipping_method.channel_listings.filter(
         channel=channel,
     ).first()
 
+    if not shipping_method_channel_listing:
+        return None
+
+    serializer = PayloadSerializer()
+    shipping_method_fields = ("name", "type")
+
     payload = serializer.serialize(
         [shipping_method],
         fields=shipping_method_fields,


Test patch:
diff --git a/saleor/webhook/tests/test_webhook_sample_payloads.py b/saleor/webhook/tests/test_webhook_sample_payloads.py
--- a/saleor/webhook/tests/test_webhook_sample_payloads.py
+++ b/saleor/webhook/tests/test_webhook_sample_payloads.py
@@ -105,6 +105,27 @@ def test_generate_sample_payload_fulfillment_created(fulfillment):
     assert sample_fulfillment_payload == fulfillment_payload
 
 
+def test_generate_sample_payload_order_removed_channel_listing_from_shipping(
+    fulfilled_order, payment_txn_captured
+):
+    # given
+    event_name = WebhookEventAsyncType.ORDER_UPDATED
+    order_status = OrderStatus.CANCELED
+    order = fulfilled_order
+    order.status = order_status
+    order.shipping_method.channel_listings.all().delete()
+    order.save()
+    order_id = graphene.Node.to_global_id("Order", order.id)
+
+    # when
+    payload = generate_sample_payload(event_name)
+    order_payload = json.loads(generate_order_payload(order))
+    # then
+    assert order_id == payload[0]["id"]
+    assert order.user_email != payload[0]["user_email"]
+    assert order_payload[0]["shipping_method"] is None
+
+
 @pytest.mark.parametrize(
     "event_name",
     [