getting webhook events into database
This commit is contained in:
@@ -166,7 +166,7 @@ class CreateEventSerializer(serializers.ModelSerializer):
|
||||
# Update fields if there is any change.
|
||||
if tags is not None:
|
||||
# Clear existing tags and add the new ones
|
||||
# instance.tags.clear()
|
||||
instance.tags.clear()
|
||||
instance.tags.add(*tags)
|
||||
|
||||
if images_data is not None:
|
||||
|
||||
@@ -14,6 +14,7 @@ from manage_subscriptions.models import (
|
||||
Subscription,
|
||||
PrincipalSubscription,
|
||||
SubscriptionStatus,
|
||||
WebhookEvent,
|
||||
)
|
||||
from goodtimes.utils import ApiResponse
|
||||
from accounts.resource_action import (
|
||||
@@ -174,6 +175,28 @@ class StripeWebhookTest(APIView):
|
||||
event = None
|
||||
try:
|
||||
event = stripe.Event.construct_from(json.loads(payload), stripe.api_key)
|
||||
event_id = event["id"]
|
||||
# Check if the event has been processed already
|
||||
if WebhookEvent.objects.filter(event_id=event_id, status="processed").exists():
|
||||
return ApiResponse.success(
|
||||
status=status.HTTP_208_ALREADY_REPORTED,
|
||||
message="Event already processed",
|
||||
)
|
||||
|
||||
# Log event processing
|
||||
WebhookEvent.objects.create(
|
||||
event_id=event_id,
|
||||
event_payload=json.loads(payload), # optional
|
||||
)
|
||||
|
||||
payment_service = services.PaymentProcessingService(webhook_data=event)
|
||||
payment_service.process_event()
|
||||
webhook_event = WebhookEvent.objects.get(event_id=event_id)
|
||||
webhook_event.status = "processed"
|
||||
return ApiResponse.success(
|
||||
status=status.HTTP_200_OK, message="Event processed successfully"
|
||||
)
|
||||
|
||||
except ValueError as e:
|
||||
# Invalid payload
|
||||
return ApiResponse.error(
|
||||
@@ -188,16 +211,6 @@ class StripeWebhookTest(APIView):
|
||||
message="Invalid signature",
|
||||
errors=str(e),
|
||||
)
|
||||
|
||||
# Initialize the PaymentProcessingService with the webhook data
|
||||
payment_service = services.PaymentProcessingService(webhook_data=event)
|
||||
|
||||
try:
|
||||
# Process the event (handle both successful and failed charges)
|
||||
payment_service.process_event()
|
||||
return ApiResponse.success(
|
||||
status=status.HTTP_200_OK, message="Event processed successfully"
|
||||
)
|
||||
except Transaction.DoesNotExist:
|
||||
# Handle case where the transaction does not exist
|
||||
return ApiResponse.error(
|
||||
@@ -205,10 +218,16 @@ class StripeWebhookTest(APIView):
|
||||
)
|
||||
except Exception as e:
|
||||
# Handle any other exceptions
|
||||
WebhookEvent.objects.create(
|
||||
event_id=event_id,
|
||||
status="failed",
|
||||
error_message=str(e),
|
||||
event_payload=json.loads(payload) # Optionally store payload for audit
|
||||
)
|
||||
return ApiResponse.error(
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
message="Error processing event",
|
||||
errors=str(e),
|
||||
errors=str(e)
|
||||
)
|
||||
|
||||
|
||||
|
||||
69
manage_subscriptions/migrations/0004_webhookevent.py
Normal file
69
manage_subscriptions/migrations/0004_webhookevent.py
Normal file
@@ -0,0 +1,69 @@
|
||||
# Generated by Django 5.0.2 on 2024-04-19 07:29
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
(
|
||||
"manage_subscriptions",
|
||||
"0003_subscription_high_amount_subscription_image_and_more",
|
||||
),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="WebhookEvent",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("active", models.BooleanField(default=True)),
|
||||
("deleted", models.BooleanField(default=False)),
|
||||
("created_on", models.DateTimeField(auto_now_add=True)),
|
||||
("modified_on", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"event_id",
|
||||
models.CharField(db_index=True, max_length=255, unique=True),
|
||||
),
|
||||
("received_at", models.DateTimeField(auto_now_add=True)),
|
||||
("processed_at", models.DateTimeField(blank=True, null=True)),
|
||||
("status", models.CharField(default="received", max_length=20)),
|
||||
("error_message", models.TextField(blank=True, null=True)),
|
||||
("event_payload", models.JSONField(blank=True, null=True)),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="%(class)s_created",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"modified_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="%(class)s_modified",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"db_table": "webhook_event",
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -74,3 +74,22 @@ class PrincipalSubscription(BaseModel):
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.subscription} - {self.principal.first_name}"
|
||||
|
||||
|
||||
class WebhookEvent(BaseModel):
|
||||
event_id = models.CharField(max_length=255, unique=True, db_index=True)
|
||||
received_at = models.DateTimeField(auto_now_add=True)
|
||||
processed_at = models.DateTimeField(null=True, blank=True)
|
||||
status = models.CharField(
|
||||
max_length=20, default="received"
|
||||
) # e.g., 'received', 'processed', 'failed'
|
||||
error_message = models.TextField(null=True, blank=True)
|
||||
event_payload = models.JSONField(
|
||||
null=True, blank=True
|
||||
) # Optional: Store the payload for debugging.
|
||||
|
||||
def __str__(self):
|
||||
return f"Webhook Event {self.event_id} - Status: {self.status}"
|
||||
|
||||
class Meta:
|
||||
db_table = "webhook_event"
|
||||
|
||||
Reference in New Issue
Block a user