feat(purchase/models.py): create payment links and sync name and description from coursepage
This commit is contained in:
@@ -7,6 +7,8 @@ from django.conf import settings
|
||||
from django.contrib.auth.models import Group
|
||||
from django.db import models
|
||||
from wagtail.admin.panels import FieldPanel
|
||||
from modelcluster.fields import ParentalKey
|
||||
from wagtail.models import Orderable
|
||||
|
||||
GITEA_ORG_NAME = "Studio77"
|
||||
logger = lg.getLogger(__name__)
|
||||
@@ -136,14 +138,14 @@ class CoursePurchase(models.Model):
|
||||
self.add_to_gitea_team()
|
||||
|
||||
|
||||
class PurchasableProduct(models.Model):
|
||||
class PurchasableProduct(Orderable, models.Model):
|
||||
"""A product that can be purchased. When created it will create a Stripe Product and Price.
|
||||
|
||||
On delete it will try to deactivate the Price and delete the Product in Stripe.
|
||||
The code is defensive: if STRIPE_API_KEY is not configured the model will still work locally.
|
||||
"""
|
||||
|
||||
name = models.CharField(max_length=255)
|
||||
name = models.CharField(max_length=255, blank=True)
|
||||
description = models.TextField(blank=True)
|
||||
price_cents = models.PositiveIntegerField(help_text="Price in cents")
|
||||
currency = models.CharField(
|
||||
@@ -151,13 +153,33 @@ class PurchasableProduct(models.Model):
|
||||
)
|
||||
stripe_product_id = models.CharField(max_length=255, blank=True, null=True)
|
||||
stripe_price_id = models.CharField(max_length=255, blank=True, null=True)
|
||||
stripe_payment_url = models.URLField(
|
||||
blank=True,
|
||||
null=True,
|
||||
help_text="Stripe Checkout URL for this product",
|
||||
)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
course = ParentalKey(
|
||||
"home.CoursePage",
|
||||
on_delete=models.CASCADE,
|
||||
related_name="purchasable_products",
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
panels = [
|
||||
FieldPanel("price_cents"),
|
||||
FieldPanel("currency"),
|
||||
FieldPanel("stripe_product_id", read_only=True),
|
||||
FieldPanel("stripe_price_id", read_only=True),
|
||||
FieldPanel("stripe_payment_url", read_only=True),
|
||||
]
|
||||
|
||||
@property
|
||||
def price(self):
|
||||
return self.price_cents / 100
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name} ({self.price_cents / 100:.2f} {self.currency.upper()})"
|
||||
|
||||
@@ -180,6 +202,15 @@ class PurchasableProduct(models.Model):
|
||||
except self.__class__.DoesNotExist:
|
||||
previous = None
|
||||
|
||||
# Get name, description and image from the linked course if not set explicitly on the product
|
||||
if self.course:
|
||||
course_name = self.course.title
|
||||
course_description = self.course.description or ""
|
||||
if not self.name:
|
||||
self.name = course_name
|
||||
if not self.description:
|
||||
self.description = course_description
|
||||
|
||||
# Persist local changes first so we have an id
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
@@ -222,6 +253,32 @@ class PurchasableProduct(models.Model):
|
||||
f"Created Stripe price {self.stripe_price_id} for PurchasableProduct {self.id}"
|
||||
)
|
||||
|
||||
# Create Stripe Payment Link if missing or if price changed
|
||||
if not self.stripe_payment_url and self.stripe_price_id:
|
||||
try:
|
||||
payment_link = stripe.PaymentLink.create(
|
||||
line_items=[{"price": self.stripe_price_id, "quantity": 1}],
|
||||
after_completion={
|
||||
"type": "redirect",
|
||||
"redirect": {
|
||||
"url": getattr(
|
||||
settings,
|
||||
"STRIPE_SUCCESS_URL",
|
||||
"https://example.com/success",
|
||||
)
|
||||
},
|
||||
},
|
||||
)
|
||||
self.stripe_payment_url = payment_link.url
|
||||
changed_fields.append("stripe_payment_url")
|
||||
logger.info(
|
||||
f"Created Stripe payment link {self.stripe_payment_url} for PurchasableProduct {self.id}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
f"Failed to create Stripe payment link for PurchasableProduct {self.id}: {e}"
|
||||
)
|
||||
|
||||
# If this is an update (we had previous state) perform updates
|
||||
if previous:
|
||||
# Update product metadata/name/description if they changed
|
||||
|
||||
Reference in New Issue
Block a user