Repository: saleor/saleor

Issue:
Bug: Giftcard created event is not triggered when gift card is bought 
### What are you trying to achieve?

I'm trying to inform the external system about the creation of the gift card. 

### Steps to reproduce the problem

1. Create a Product type of Gift card
2. Create gift card -> Product
3. Create webhook which triggers on gift card creation 
4. Create draft order and add newly gift card 
5. Finalize draft order 

### What did you expect to happen?

Saleor should properly send a webhook after the gift card is created.

### Logs

_No response_

### Environment

Saleor version: 3.10



Discussion:
I'll work on this, @timuric 

Resolving patch:
diff --git a/saleor/giftcard/utils.py b/saleor/giftcard/utils.py
--- a/saleor/giftcard/utils.py
+++ b/saleor/giftcard/utils.py
@@ -11,6 +11,7 @@
 from ..checkout.models import Checkout
 from ..core.exceptions import GiftCardNotApplicable
 from ..core.tracing import traced_atomic_transaction
+from ..core.utils.events import call_event
 from ..core.utils.promo_code import InvalidPromoCode, generate_promo_code
 from ..order.actions import OrderFulfillmentLineInfo, create_fulfillments
 from ..order.models import OrderLine
@@ -199,6 +200,9 @@ def gift_cards_create(
     gift_cards = GiftCard.objects.bulk_create(gift_cards)
     events.gift_cards_bought_event(gift_cards, order, requestor_user, app)
 
+    for gift_card in gift_cards:
+        call_event(manager.gift_card_created, gift_card)
+
     channel_slug = order.channel.slug
     # send to customer all non-shippable gift cards
     transaction.on_commit(


Test patch:
diff --git a/saleor/giftcard/tests/test_utils.py b/saleor/giftcard/tests/test_utils.py
--- a/saleor/giftcard/tests/test_utils.py
+++ b/saleor/giftcard/tests/test_utils.py
@@ -1,17 +1,23 @@
+import json
 from datetime import date, timedelta
 from unittest.mock import patch
 
+import graphene
 import pytest
 from dateutil.relativedelta import relativedelta
 from django.utils import timezone
+from freezegun import freeze_time
 
 from ...core import TimePeriodType
 from ...core.exceptions import GiftCardNotApplicable
+from ...core.utils.json_serializer import CustomJsonEncoder
 from ...core.utils.promo_code import InvalidPromoCode
 from ...order.models import OrderLine
 from ...plugins.manager import get_plugins_manager
 from ...site import GiftCardSettingsExpiryType
 from ...tests.utils import flush_post_commit_hooks
+from ...webhook.event_types import WebhookEventAsyncType
+from ...webhook.payloads import generate_meta, generate_requestor
 from .. import GiftCardEvents, GiftCardLineData, events
 from ..models import GiftCard, GiftCardEvent
 from ..utils import (
@@ -403,6 +409,87 @@ def test_gift_cards_create_multiple_quantity(
     assert send_notification_mock.call_count == quantity
 
 
+@freeze_time("2022-05-12 12:00:00")
+@patch("saleor.plugins.webhook.plugin.get_webhooks_for_event")
+@patch("saleor.plugins.webhook.plugin.trigger_webhooks_async")
+@patch("saleor.giftcard.utils.send_gift_card_notification")
+def test_gift_cards_create_trigger_webhook(
+    send_notification_mock,
+    mocked_webhook_trigger,
+    mocked_get_webhooks_for_event,
+    any_webhook,
+    webhook_app,
+    settings,
+    order,
+    gift_card_shippable_order_line,
+    gift_card_non_shippable_order_line,
+    site_settings,
+    staff_user,
+):
+    # given
+    mocked_get_webhooks_for_event.return_value = [any_webhook]
+    settings.PLUGINS = ["saleor.plugins.webhook.plugin.WebhookPlugin"]
+
+    manager = get_plugins_manager()
+    line_1, line_2 = gift_card_shippable_order_line, gift_card_non_shippable_order_line
+    fulfillment = order.fulfillments.create(tracking_number="123")
+    fulfillment_line_1 = fulfillment.lines.create(
+        order_line=line_1,
+        quantity=line_1.quantity,
+        stock=line_1.allocations.get().stock,
+    )
+    fulfillment_line_2 = fulfillment.lines.create(
+        order_line=line_2,
+        quantity=line_2.quantity,
+        stock=line_2.allocations.get().stock,
+    )
+    lines_data = [
+        GiftCardLineData(
+            quantity=1,
+            order_line=line_1,
+            variant=line_1.variant,
+            fulfillment_line=fulfillment_line_1,
+        ),
+        GiftCardLineData(
+            quantity=1,
+            order_line=line_2,
+            variant=line_2.variant,
+            fulfillment_line=fulfillment_line_2,
+        ),
+    ]
+
+    # when
+    gift_cards = gift_cards_create(
+        order, lines_data, site_settings, staff_user, None, manager
+    )
+
+    # then
+    flush_post_commit_hooks()
+    assert len(gift_cards) == len(lines_data)
+
+    gift_card = gift_cards[-1]
+    gift_card_global_id = graphene.Node.to_global_id("GiftCard", gift_card.id)
+
+    mocked_webhook_trigger.assert_called_with(
+        json.dumps(
+            {
+                "id": gift_card_global_id,
+                "is_active": True,
+                "meta": generate_meta(
+                    requestor_data=generate_requestor(),
+                ),
+            },
+            cls=CustomJsonEncoder,
+        ),
+        WebhookEventAsyncType.GIFT_CARD_CREATED,
+        [any_webhook],
+        gift_card,
+        None,
+    )
+
+    send_notification_mock.assert_called()
+
+
 def test_get_gift_card_lines(
     gift_card_non_shippable_order_line, gift_card_shippable_order_line, order_line
 ):