Files
@ 6139a13fde7a
Branch filter:
Location: website/conservancy/supporters/views.py
6139a13fde7a
6.1 KiB
text/x-python
Add payment time column to Stripe export
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | from datetime import datetime
import logging
from django.conf import settings
from django.http import HttpResponse
from django.shortcuts import render, redirect
from django.utils import timezone
import stripe
from .. import ParameterValidator
from . import forms
from .models import Supporter, SustainerOrder
logger = logging.getLogger(__name__)
def sustainers(request):
with ParameterValidator(request.GET, 'upgrade_id') as validator:
try:
amount_param = float(request.GET['upgrade'])
except (KeyError, ValueError):
validator.fail()
else:
validator.validate('{:.2f}'.format(amount_param))
partial_amount = amount_param if validator.valid else 0
context = {
'partial_amount': partial_amount,
'minimum_amount': 120 - partial_amount,
}
return render(request, "supporters/sustainers.html", context)
def sponsors(request):
"""Conservancy Sponsors Page view
Performs object queries necessary to render the sponsors page.
"""
supporters = Supporter.objects.all().filter(display_until_date__gte=datetime.now())
supporters_count = len(supporters)
anonymous_count = len(supporters.filter(display_name='Anonymous'))
supporters = supporters.exclude(display_name='Anonymous').order_by('ledger_entity_id')
c = {
'supporters' : supporters,
'supporters_count' : supporters_count,
'anonymous_count' : anonymous_count
}
return render(request, "supporters/sponsors.html", c)
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/api/checkout/sessions
YOUR_DOMAIN = base_url
try:
checkout_session = stripe.checkout.Session.create(
client_reference_id=str(reference_id),
line_items=[
{
'price_data': {
'currency': 'usd',
'product_data': {'name': 'Contribution'},
'unit_amount': amount * 100, # in cents
# https://docs.stripe.com/products-prices/pricing-models#variable-pricing
'recurring': {'interval': recurring} if recurring else None,
},
'quantity': 1,
},
],
customer_email=email,
mode='subscription' if recurring else 'payment',
success_url=YOUR_DOMAIN + '/sustainer/success/?session_id={CHECKOUT_SESSION_ID}',
cancel_url=YOUR_DOMAIN + '/sustainer/stripe/',
)
except Exception as e:
return str(e)
return checkout_session.url
def sustainers_stripe(request):
return render(request, 'supporters/sustainers_stripe.html', {})
def sustainers_stripe2(request):
if request.method == 'POST':
form = forms.SustainerForm(request.POST)
if form.is_valid():
order = form.save(commit=False)
order.recurring = form.data['recurring']
if order.recurring == 'month':
order.amount = form.cleaned_data['amount_monthly']
order.save()
base_url = f'{request.scheme}://{request.get_host()}'
stripe_checkout_url = create_checkout_session(order.id, order.email, order.amount, order.recurring, base_url)
return redirect(stripe_checkout_url)
else:
form = forms.SustainerForm()
return render(request, 'supporters/sustainers_stripe2.html', {'form': form})
stripe.api_key = settings.STRIPE_API_KEY
if stripe.api_key == '':
logger.warning('Missing STRIPE_API_KEY')
def fulfill_checkout(session_id):
print("Fulfilling Checkout Session", session_id)
# TODO: Make this function safe to run multiple times,
# even concurrently, with the same session ID
# TODO: Make sure fulfillment hasn't already been
# peformed for this Checkout Session
# Retrieve the Checkout Session from the API with line_items expanded
checkout_session = stripe.checkout.Session.retrieve(
session_id,
expand=['line_items', 'invoice'],
)
# Check the Checkout Session's payment_status property
# to determine if fulfillment should be peformed
if checkout_session.payment_status != 'unpaid':
# TODO: Perform fulfillment of the line items
# TODO: Record/save fulfillment status for this
# Checkout Session
logger.info(f'Session ID {session_id} PAID!')
try:
order = SustainerOrder.objects.get(id=checkout_session['client_reference_id'], paid_time=None)
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()
logger.info(f'Marked sustainer order {order.id} (order.email) as paid')
except SustainerOrder.DoesNotExist:
logger.info('No action')
def success(request):
fulfill_checkout(request.GET['session_id'])
return render(request, 'supporters/stripe_success.html', {})
def webhook(request):
payload = request.body
sig_header = request.META['HTTP_STRIPE_SIGNATURE']
event = None
# From webhook dashboard
endpoint_secret = settings.STRIPE_ENDPOINT_SECRET
if endpoint_secret == '':
logger.warning('Missing STRIPE_ENDPOINT_SECRET')
try:
event = stripe.Webhook.construct_event(
payload, sig_header, endpoint_secret
)
except ValueError:
# Invalid payload
return HttpResponse(status=400)
except stripe.error.SignatureVerificationError:
# Invalid signature
return HttpResponse(status=400)
if (
event['type'] == 'checkout.session.completed'
or event['type'] == 'checkout.session.async_payment_succeeded'
):
fulfill_checkout(event['data']['object']['id'])
return HttpResponse(status=200)
|