fix(billing): handle customer.subscription.created webhook + test isolation

- Add customer.subscription.created → subscription.activated mapping in
  stripe.parse_webhook so direct API subscription creation also creates DB rows
- Add customer.subscription.created to setup_stripe.py enabled_events
- Pin PAYMENT_PROVIDER=paddle and STRIPE_WEBHOOK_SECRET="" in test conftest
  so billing tests don't hit real Stripe API when env has Stripe keys
- Add 8 unit tests for stripe.parse_webhook covering all event types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Deeman
2026-03-03 17:29:13 +01:00
parent 7c5fa86fb8
commit 72c4de91b0
4 changed files with 119 additions and 1 deletions

View File

@@ -152,6 +152,7 @@ def parse_webhook(payload: bytes) -> dict:
Maps Stripe event types to the shared format used by _handle_webhook_event():
- checkout.session.completed (mode=subscription) → subscription.activated
- customer.subscription.created → subscription.activated
- customer.subscription.updated → subscription.updated
- customer.subscription.deleted → subscription.canceled
- invoice.payment_failed → subscription.past_due
@@ -218,6 +219,23 @@ def parse_webhook(payload: bytes) -> dict:
"custom_data": metadata,
}
elif stripe_type == "customer.subscription.created":
# New subscription — map to subscription.activated so the handler creates the DB row
status = _map_stripe_status(obj.get("status", ""))
return {
"event_type": "subscription.activated",
"subscription_id": obj.get("id", ""),
"customer_id": str(customer_id),
"user_id": user_id,
"supplier_id": supplier_id,
"plan": plan,
"status": status,
"current_period_end": _unix_to_iso(obj.get("current_period_end")),
"data": obj,
"items": _extract_sub_items(obj),
"custom_data": metadata,
}
elif stripe_type == "customer.subscription.updated":
status = _map_stripe_status(obj.get("status", ""))
return {

View File

@@ -189,6 +189,7 @@ def create(conn):
webhook_url = f"{BASE_URL}/billing/webhook/stripe"
enabled_events = [
"checkout.session.completed",
"customer.subscription.created",
"customer.subscription.updated",
"customer.subscription.deleted",
"invoice.payment_failed",