Record Stripe payment intent, export to CSV
This commit is contained in:
parent
36ecf098b0
commit
a74244efb4
8 changed files with 86 additions and 7 deletions
|
@ -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', '')
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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']
|
||||||
|
|
0
conservancy/supporters/management/commands/__init__.py
Normal file
0
conservancy/supporters/management/commands/__init__.py
Normal file
31
conservancy/supporters/management/commands/export_stripe.py
Normal file
31
conservancy/supporters/management/commands/export_stripe.py
Normal 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,
|
||||||
|
])
|
|
@ -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),
|
||||||
|
),
|
||||||
|
]
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
@ -121,7 +126,13 @@ def fulfill_checkout(session_id):
|
||||||
logger.info(f'Session ID {session_id} PAID!')
|
logger.info(f'Session ID {session_id} PAID!')
|
||||||
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(
|
||||||
|
|
Loading…
Reference in a new issue