Record Stripe payment intent, export to CSV

This commit is contained in:
Ben Sturmfels 2024-10-09 02:01:32 +11:00
parent 36ecf098b0
commit a74244efb4
Signed by: bsturmfels
GPG key ID: 023C05E2C9C068F0
8 changed files with 86 additions and 7 deletions

View file

@ -1,3 +1,5 @@
import os
from .base import * # NOQA from .base import * # NOQA
DEBUG = True DEBUG = True
@ -13,3 +15,6 @@ DATABASES = {
SECRET_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' SECRET_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
STRIPE_API_KEY = os.getenv('STRIPE_API_KEY', '')
STRIPE_ENDPOINT_SECRET = os.getenv('STRIPE_ENDPOINT_SECRET', '')

View file

@ -37,3 +37,6 @@ def get_secret(secrets, setting):
SECRET_KEY = get_secret(secrets, 'SECRET_KEY') SECRET_KEY = get_secret(secrets, 'SECRET_KEY')
SESSION_COOKIE_SECURE = True SESSION_COOKIE_SECURE = True
STRIPE_API_KEY = get_secret(secrets, 'STRIPE_API_KEY')
STRIPE_ENDPOINT_SECRET = get_secret(secrets, 'STRIPE_ENDPOINT_SECRET')

View file

@ -13,6 +13,8 @@ class SustainerOrderAdmin(admin.ModelAdmin):
fields = [ fields = [
'created_time', 'created_time',
'paid_time', 'paid_time',
'payment_method',
'payment_id',
'name', 'name',
'email', 'email',
'amount', 'amount',
@ -26,6 +28,6 @@ class SustainerOrderAdmin(admin.ModelAdmin):
'country', 'country',
] ]
readonly_fields = ['created_time', 'paid_time'] readonly_fields = ['created_time', 'paid_time', 'payment_method', 'payment_id']
list_display = ['created_time', 'name', 'email', 'amount', 'paid'] list_display = ['created_time', 'name', 'email', 'amount', 'paid']
list_filter = ['paid_time'] list_filter = ['paid_time']

View file

@ -0,0 +1,31 @@
import csv
import sys
from django.core.management.base import BaseCommand
from ...models import SustainerOrder
class Command(BaseCommand):
help = "Closes the specified poll for voting"
def handle(self, *args, **options):
orders = SustainerOrder.objects.filter(paid_time__isnull=False)
columns = ['time', 'name', 'email', 'amount', 'transaction_id', 'public_ack', 'shirt_size', 'join_list', 'street', 'city', 'state', 'zip_code', 'country']
writer = csv.writer(sys.stdout)
writer.writerow(columns)
for order in orders:
writer.writerow([
order.created_time,
order.name,
order.email,
order.amount,
order.payment_id,
order.acknowledge_publicly,
repr(order.tshirt_size if order.tshirt_size else ''),
order.add_to_mailing_list,
order.street,
order.city,
order.state,
order.zip_code,
order.country,
])

View file

@ -0,0 +1,23 @@
# Generated by Django 4.2.11 on 2024-10-08 09:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('supporters', '0003_remove_sustainerorder_monthly_recurring_and_more'),
]
operations = [
migrations.AddField(
model_name='sustainerorder',
name='payment_id',
field=models.CharField(blank=True, max_length=255),
),
migrations.AddField(
model_name='sustainerorder',
name='payment_method',
field=models.CharField(default='Stripe', max_length=10),
),
]

View file

@ -27,7 +27,7 @@ class SustainerOrder(models.Model):
TSHIRT_CHOICES = [ TSHIRT_CHOICES = [
( (
'', '',
(("None", "None"),), (("", "None"),),
), ),
( (
"Men's", "Men's",
@ -69,10 +69,12 @@ class SustainerOrder(models.Model):
validators.MinValueValidator(100), validators.MinValueValidator(100),
]) ])
recurring = models.CharField(max_length=10) recurring = models.CharField(max_length=10)
payment_method = models.CharField(max_length=10, default='Stripe')
payment_id = models.CharField(max_length=255, blank=True)
paid_time = models.DateTimeField(null=True, blank=True) paid_time = models.DateTimeField(null=True, blank=True)
acknowledge_publicly = models.BooleanField(default=True) acknowledge_publicly = models.BooleanField(default=True)
add_to_mailing_list = models.BooleanField(default=True) add_to_mailing_list = models.BooleanField(default=True)
tshirt_size = models.CharField(max_length=50, choices=TSHIRT_CHOICES) tshirt_size = models.CharField(max_length=50, choices=TSHIRT_CHOICES, blank=True)
street = models.CharField(max_length=255, blank=True) street = models.CharField(max_length=255, blank=True)
city = models.CharField(max_length=255, blank=True) city = models.CharField(max_length=255, blank=True)
state = models.CharField(max_length=255, blank=True) state = models.CharField(max_length=255, blank=True)

View file

@ -1,6 +1,7 @@
from datetime import datetime from datetime import datetime
import logging import logging
from django.conf import settings
from django.http import HttpResponse from django.http import HttpResponse
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
from django.utils import timezone from django.utils import timezone
@ -47,6 +48,7 @@ def sponsors(request):
def create_checkout_session(reference_id, email: str, amount: int, recurring: str, base_url: str): def create_checkout_session(reference_id, email: str, amount: int, recurring: str, base_url: str):
# https://docs.stripe.com/payments/accept-a-payment # https://docs.stripe.com/payments/accept-a-payment
# https://docs.stripe.com/api/checkout/sessions
YOUR_DOMAIN = base_url YOUR_DOMAIN = base_url
try: try:
checkout_session = stripe.checkout.Session.create( checkout_session = stripe.checkout.Session.create(
@ -94,7 +96,10 @@ def sustainers_stripe2(request):
return render(request, 'supporters/sustainers_stripe2.html', {'form': form}) return render(request, 'supporters/sustainers_stripe2.html', {'form': form})
stripe.api_key = 'sk_test_zaAqrpHmpkXnHQfAs4UWkE3d' stripe.api_key = settings.STRIPE_API_KEY
if stripe.api_key == '':
logger.warning('Missing STRIPE_API_KEY')
def fulfill_checkout(session_id): def fulfill_checkout(session_id):
print("Fulfilling Checkout Session", session_id) print("Fulfilling Checkout Session", session_id)
@ -108,7 +113,7 @@ def fulfill_checkout(session_id):
# Retrieve the Checkout Session from the API with line_items expanded # Retrieve the Checkout Session from the API with line_items expanded
checkout_session = stripe.checkout.Session.retrieve( checkout_session = stripe.checkout.Session.retrieve(
session_id, session_id,
expand=['line_items'], expand=['line_items', 'invoice'],
) )
# Check the Checkout Session's payment_status property # Check the Checkout Session's payment_status property
@ -122,6 +127,12 @@ def fulfill_checkout(session_id):
try: try:
order = SustainerOrder.objects.get(id=checkout_session['client_reference_id'], paid_time=None) order = SustainerOrder.objects.get(id=checkout_session['client_reference_id'], paid_time=None)
order.paid_time = timezone.now() order.paid_time = timezone.now()
if checkout_session['payment_intent']:
# Payments get a payment intent directly
order.payment_id = checkout_session['payment_intent']
else:
# Subscriptions go get a payment intent generated on the invoice
order.payment_id = checkout_session['invoice']['payment_intent']
order.save() order.save()
logger.info(f'Marked sustainer order {order.id} (order.email) as paid') logger.info(f'Marked sustainer order {order.id} (order.email) as paid')
except SustainerOrder.DoesNotExist: except SustainerOrder.DoesNotExist:
@ -139,7 +150,9 @@ def webhook(request):
event = None event = None
# From webhook dashboard # From webhook dashboard
endpoint_secret = 'whsec_lLy9pqxAAHdl4fwiC0cFg1KwR6y4CvOH' endpoint_secret = settings.STRIPE_ENDPOINT_SECRET
if endpoint_secret == '':
logger.warning('Missing STRIPE_ENDPOINT_SECRET')
try: try:
event = stripe.Webhook.construct_event( event = stripe.Webhook.construct_event(