diff --git a/app/settings.py b/app/settings.py index 720de0c..6d937d9 100644 --- a/app/settings.py +++ b/app/settings.py @@ -126,5 +126,7 @@ AUTH_USER_MODEL = "core.User" LOGIN_REDIRECT_URL = "/" +# ALLOWED_PAYMENT_METHODS = ["bacs_debit", "card"] +ALLOWED_PAYMENT_METHODS = ["card"] from app.local_settings import * # noqa diff --git a/app/urls.py b/app/urls.py index dd75772..405d03c 100644 --- a/app/urls.py +++ b/app/urls.py @@ -17,13 +17,20 @@ from django.conf import settings from django.conf.urls.static import static from django.contrib import admin from django.urls import include, path +from django.views.generic import TemplateView from core.ui.views.drilldown import Drilldown -from core.views import Billing, Home, Signup +from core.views import Billing, Home, Order, Portal, Signup urlpatterns = [ path("", Home.as_view(), name="home"), path("billing/", Billing.as_view(), name="billing"), + path("order//", Order.as_view(), name="order"), + path( + "success/", TemplateView.as_view(template_name="success.html"), name="success" + ), + path("cancel/", TemplateView.as_view(template_name="cancel.html"), name="cancel"), + path("portal", Portal.as_view(), name="portal"), path("admin/", admin.site.urls), path("accounts/", include("django.contrib.auth.urls")), path("accounts/signup/", Signup.as_view(), name="signup"), diff --git a/core/lib/customers.py b/core/lib/customers.py index 900bbda..d15c9d9 100644 --- a/core/lib/customers.py +++ b/core/lib/customers.py @@ -1,5 +1,10 @@ +import logging + import stripe +logger = logging.getLogger(__name__) + + def expand_name(first_name, last_name): """ Convert two name variables into one. @@ -13,6 +18,7 @@ def expand_name(first_name, last_name): name += f" {last_name}" return name + def get_or_create(email, first_name, last_name): """ Get a customer ID from Stripe if one with the given email exists. @@ -23,7 +29,7 @@ def get_or_create(email, first_name, last_name): matching_customers = stripe.Customer.list(email=email, limit=2) if len(matching_customers) == 2: # Something is horribly wrong - print("Two customers match!") + logger.error(f"Two customers found for email {email}") raise Exception(f"Two customers found for email {email}") elif len(matching_customers) == 1: @@ -41,9 +47,11 @@ def get_or_create(email, first_name, last_name): if name: cast["name"] = name customer = stripe.Customer.create(**cast) + logger.info(f"Created new Stripe customer {customer.id} with email {email}") return customer.id + def update_customer_fields(stripe_id, email=None, first_name=None, last_name=None): """ Update the customer fields in Stripe. @@ -52,7 +60,9 @@ def update_customer_fields(stripe_id, email=None, first_name=None, last_name=Non if email: print("Email modified") stripe.Customer.modify(stripe_id, email=email) + logger.info(f"Modified Stripe customer {stripe_id} to have email {email}") if first_name or last_name: print("Name modified") name = expand_name(first_name, last_name) - stripe.Customer.modify(stripe_id, name=name) \ No newline at end of file + stripe.Customer.modify(stripe_id, name=name) + logger.info(f"Modified Stripe customer {stripe_id} to have email {name}") diff --git a/core/lib/products.py b/core/lib/products.py new file mode 100644 index 0000000..ed38932 --- /dev/null +++ b/core/lib/products.py @@ -0,0 +1,16 @@ +from core.models import Plan + +def assemble_plan_map(product_id_filter=None): + """ + Get all the plans from the database and create an object Stripe wants. + """ + line_items = [] + for plan in Plan.objects.all(): + if product_id_filter: + if plan.product_id != product_id_filter: + continue + line_items.append({ + "price": plan.product_id, + "quantity": 1, + }) + return line_items \ No newline at end of file diff --git a/core/migrations/0002_alter_plan_product_id_alter_user_email.py b/core/migrations/0002_alter_plan_product_id_alter_user_email.py new file mode 100644 index 0000000..4459c4a --- /dev/null +++ b/core/migrations/0002_alter_plan_product_id_alter_user_email.py @@ -0,0 +1,23 @@ +# Generated by Django 4.0.6 on 2022-07-09 09:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='plan', + name='product_id', + field=models.CharField(blank=True, max_length=255, null=True, unique=True), + ), + migrations.AlterField( + model_name='user', + name='email', + field=models.EmailField(max_length=254, unique=True), + ), + ] diff --git a/core/migrations/0003_session.py b/core/migrations/0003_session.py new file mode 100644 index 0000000..1de8f6b --- /dev/null +++ b/core/migrations/0003_session.py @@ -0,0 +1,21 @@ +# Generated by Django 4.0.6 on 2022-07-09 15:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0002_alter_plan_product_id_alter_user_email'), + ] + + operations = [ + migrations.CreateModel( + name='Session', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('email', models.EmailField(max_length=254, unique=True)), + ('session', models.CharField(max_length=255)), + ], + ), + ] diff --git a/core/migrations/0004_alter_session_email.py b/core/migrations/0004_alter_session_email.py new file mode 100644 index 0000000..fb8f001 --- /dev/null +++ b/core/migrations/0004_alter_session_email.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.6 on 2022-07-09 15:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0003_session'), + ] + + operations = [ + migrations.AlterField( + model_name='session', + name='email', + field=models.EmailField(max_length=254), + ), + ] diff --git a/core/models.py b/core/models.py index bbce63b..6b7e149 100644 --- a/core/models.py +++ b/core/models.py @@ -1,14 +1,19 @@ +import logging + +import stripe from django.contrib.auth.models import AbstractUser from django.db import models from core.lib.customers import get_or_create, update_customer_fields +logger = logging.getLogger(__name__) + class Plan(models.Model): name = models.CharField(max_length=255, unique=True) description = models.CharField(max_length=1024, null=True, blank=True) cost = models.IntegerField() - product_id = models.UUIDField(null=True, blank=True) + product_id = models.CharField(max_length=255, unique=True, null=True, blank=True) image = models.CharField(max_length=1024, null=True, blank=True) def __str__(self): @@ -23,11 +28,11 @@ class User(AbstractUser): last_payment = models.DateTimeField(null=True, blank=True) paid = models.BooleanField(null=True, blank=True) plans = models.ManyToManyField(Plan, blank=True) + email = models.EmailField(unique=True) - -def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self._original = self + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._original = self def save(self, *args, **kwargs): """ @@ -48,8 +53,19 @@ def __init__(self, *args, **kwargs): super().save(*args, **kwargs) + def delete(self, *args, **kwargs): + if self.stripe_id: + stripe.Customer.delete(self.stripe_id) + logger.info(f"Deleted Stripe customer {self.stripe_id}") + super().delete(*args, **kwargs) + def has_plan(self, plan): if not self.paid: # We can't have any plans if we haven't paid return False plan_list = [plan.name for plan in self.plans.all()] return plan in plan_list + + +class Session(models.Model): + email = models.EmailField() + session = models.CharField(max_length=255) diff --git a/core/templates/billing.html b/core/templates/billing.html index 962dfea..490bdbc 100644 --- a/core/templates/billing.html +++ b/core/templates/billing.html @@ -34,6 +34,9 @@ Last payment +
+ +
@@ -46,6 +49,7 @@ + diff --git a/core/templates/partials/product-list.html b/core/templates/partials/product-list.html index 861f297..1201d3e 100644 --- a/core/templates/partials/product-list.html +++ b/core/templates/partials/product-list.html @@ -1,10 +1,10 @@ {% load static %} {% for plan in plans %} - {% if plan not in user_plans %} - + {% endif %} +
Data image
@@ -15,10 +15,10 @@ {% endif %}
- {% if plan not in user_plans %}
{% endif %} + {% endfor %}