mirror of
https://github.com/lemeow125/DRF_Template.git
synced 2025-06-28 16:15:44 +08:00
Clean up docker-compose and run Black formatter over entire codebase
This commit is contained in:
parent
6c232b3e89
commit
069aba80b1
60 changed files with 1946 additions and 1485 deletions
|
@ -6,10 +6,24 @@ from unfold.contrib.filters.admin import RangeDateFilter
|
|||
|
||||
@admin.register(StripePrice)
|
||||
class StripePriceAdmin(ModelAdmin):
|
||||
search_fields = ["id", "lookup_key",
|
||||
"stripe_price_id","price","currency", "prorated", "annual"]
|
||||
list_display = ["id", "lookup_key",
|
||||
"stripe_price_id", "price", "currency", "prorated", "annual"]
|
||||
search_fields = [
|
||||
"id",
|
||||
"lookup_key",
|
||||
"stripe_price_id",
|
||||
"price",
|
||||
"currency",
|
||||
"prorated",
|
||||
"annual",
|
||||
]
|
||||
list_display = [
|
||||
"id",
|
||||
"lookup_key",
|
||||
"stripe_price_id",
|
||||
"price",
|
||||
"currency",
|
||||
"prorated",
|
||||
"annual",
|
||||
]
|
||||
|
||||
|
||||
@admin.register(SubscriptionPlan)
|
||||
|
@ -21,9 +35,6 @@ class SubscriptionPlanAdmin(ModelAdmin):
|
|||
@admin.register(UserSubscription)
|
||||
class UserSubscriptionAdmin(ModelAdmin):
|
||||
list_filter_submit = True
|
||||
list_filter = ((
|
||||
"date", RangeDateFilter
|
||||
),)
|
||||
list_display = ["id", "__str__", "valid", "annual",
|
||||
"date"]
|
||||
list_filter = (("date", RangeDateFilter),)
|
||||
list_display = ["id", "__str__", "valid", "annual", "date"]
|
||||
search_fields = ["id", "date"]
|
||||
|
|
|
@ -2,8 +2,8 @@ from django.apps import AppConfig
|
|||
|
||||
|
||||
class SubscriptionConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'subscriptions'
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "subscriptions"
|
||||
|
||||
def ready(self):
|
||||
import subscriptions.signals
|
||||
|
|
|
@ -11,46 +11,118 @@ class Migration(migrations.Migration):
|
|||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('user_groups', '0001_initial'),
|
||||
("user_groups", "0001_initial"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='StripePrice',
|
||||
name="StripePrice",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('annual', models.BooleanField(default=False)),
|
||||
('stripe_price_id', models.CharField(max_length=100)),
|
||||
('price', models.DecimalField(decimal_places=2, default=0.0, max_digits=10)),
|
||||
('currency', models.CharField(max_length=20)),
|
||||
('lookup_key', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('prorated', models.BooleanField(default=False)),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("annual", models.BooleanField(default=False)),
|
||||
("stripe_price_id", models.CharField(max_length=100)),
|
||||
(
|
||||
"price",
|
||||
models.DecimalField(decimal_places=2, default=0.0, max_digits=10),
|
||||
),
|
||||
("currency", models.CharField(max_length=20)),
|
||||
("lookup_key", models.CharField(blank=True, max_length=100, null=True)),
|
||||
("prorated", models.BooleanField(default=False)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SubscriptionPlan',
|
||||
name="SubscriptionPlan",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('description', models.TextField(max_length=1024, null=True)),
|
||||
('stripe_product_id', models.CharField(max_length=100)),
|
||||
('group_exclusive', models.BooleanField(default=False)),
|
||||
('annual_price', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='annual_plan', to='subscriptions.stripeprice')),
|
||||
('monthly_price', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='monthly_plan', to='subscriptions.stripeprice')),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=100)),
|
||||
("description", models.TextField(max_length=1024, null=True)),
|
||||
("stripe_product_id", models.CharField(max_length=100)),
|
||||
("group_exclusive", models.BooleanField(default=False)),
|
||||
(
|
||||
"annual_price",
|
||||
models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="annual_plan",
|
||||
to="subscriptions.stripeprice",
|
||||
),
|
||||
),
|
||||
(
|
||||
"monthly_price",
|
||||
models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="monthly_plan",
|
||||
to="subscriptions.stripeprice",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserSubscription',
|
||||
name="UserSubscription",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('stripe_id', models.CharField(max_length=100)),
|
||||
('date', models.DateTimeField(default=django.utils.timezone.now, editable=False)),
|
||||
('valid', models.BooleanField()),
|
||||
('annual', models.BooleanField()),
|
||||
('subscription', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='subscriptions.subscriptionplan')),
|
||||
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
('user_group', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='user_groups.usergroup')),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("stripe_id", models.CharField(max_length=100)),
|
||||
(
|
||||
"date",
|
||||
models.DateTimeField(
|
||||
default=django.utils.timezone.now, editable=False
|
||||
),
|
||||
),
|
||||
("valid", models.BooleanField()),
|
||||
("annual", models.BooleanField()),
|
||||
(
|
||||
"subscription",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to="subscriptions.subscriptionplan",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"user_group",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="user_groups.usergroup",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
from django.db import models
|
||||
from accounts.models import CustomUser
|
||||
from user_groups.models import UserGroup
|
||||
|
@ -25,9 +24,11 @@ class SubscriptionPlan(models.Model):
|
|||
description = models.TextField(max_length=1024, null=True)
|
||||
stripe_product_id = models.CharField(max_length=100)
|
||||
annual_price = models.ForeignKey(
|
||||
StripePrice, on_delete=models.SET_NULL, related_name='annual_plan', null=True)
|
||||
StripePrice, on_delete=models.SET_NULL, related_name="annual_plan", null=True
|
||||
)
|
||||
monthly_price = models.ForeignKey(
|
||||
StripePrice, on_delete=models.SET_NULL, related_name='monthly_plan', null=True)
|
||||
StripePrice, on_delete=models.SET_NULL, related_name="monthly_plan", null=True
|
||||
)
|
||||
group_exclusive = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
|
@ -39,11 +40,14 @@ class SubscriptionPlan(models.Model):
|
|||
|
||||
class UserSubscription(models.Model):
|
||||
user = models.ForeignKey(
|
||||
CustomUser, on_delete=models.CASCADE, blank=True, null=True)
|
||||
CustomUser, on_delete=models.CASCADE, blank=True, null=True
|
||||
)
|
||||
user_group = models.ForeignKey(
|
||||
UserGroup, on_delete=models.CASCADE, blank=True, null=True)
|
||||
UserGroup, on_delete=models.CASCADE, blank=True, null=True
|
||||
)
|
||||
subscription = models.ForeignKey(
|
||||
SubscriptionPlan, on_delete=models.SET_NULL, blank=True, null=True)
|
||||
SubscriptionPlan, on_delete=models.SET_NULL, blank=True, null=True
|
||||
)
|
||||
stripe_id = models.CharField(max_length=100)
|
||||
date = models.DateTimeField(default=now, editable=False)
|
||||
valid = models.BooleanField()
|
||||
|
@ -51,6 +55,6 @@ class UserSubscription(models.Model):
|
|||
|
||||
def __str__(self):
|
||||
if self.user:
|
||||
return f'Subscription {self.subscription.name} for {self.user}'
|
||||
return f"Subscription {self.subscription.name} for {self.user}"
|
||||
else:
|
||||
return f'Subscription {self.subscription.name} for {self.user_group}'
|
||||
return f"Subscription {self.subscription.name} for {self.user_group}"
|
||||
|
|
|
@ -7,38 +7,46 @@ class SimpleStripePriceSerializer(serializers.ModelSerializer):
|
|||
|
||||
class Meta:
|
||||
model = StripePrice
|
||||
fields = ['price', 'currency', 'prorated']
|
||||
fields = ["price", "currency", "prorated"]
|
||||
|
||||
|
||||
class SubscriptionPlanSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = SubscriptionPlan
|
||||
fields = ['id', 'name', 'description',
|
||||
'annual_price', 'monthly_price', 'group_exclusive']
|
||||
fields = [
|
||||
"id",
|
||||
"name",
|
||||
"description",
|
||||
"annual_price",
|
||||
"monthly_price",
|
||||
"group_exclusive",
|
||||
]
|
||||
|
||||
def to_representation(self, instance):
|
||||
representation = super().to_representation(instance)
|
||||
representation['annual_price'] = SimpleStripePriceSerializer(
|
||||
instance.annual_price, many=False).data
|
||||
representation['monthly_price'] = SimpleStripePriceSerializer(
|
||||
instance.monthly_price, many=False).data
|
||||
representation["annual_price"] = SimpleStripePriceSerializer(
|
||||
instance.annual_price, many=False
|
||||
).data
|
||||
representation["monthly_price"] = SimpleStripePriceSerializer(
|
||||
instance.monthly_price, many=False
|
||||
).data
|
||||
return representation
|
||||
|
||||
|
||||
class UserSubscriptionSerializer(serializers.ModelSerializer):
|
||||
date = serializers.DateTimeField(
|
||||
format="%m-%d-%Y %I:%M %p", read_only=True)
|
||||
date = serializers.DateTimeField(format="%m-%d-%Y %I:%M %p", read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = UserSubscription
|
||||
fields = ['id', 'user', 'user_group', 'subscription',
|
||||
'date', 'valid', 'annual']
|
||||
fields = ["id", "user", "user_group", "subscription", "date", "valid", "annual"]
|
||||
|
||||
def to_representation(self, instance):
|
||||
representation = super().to_representation(instance)
|
||||
representation['user'] = SimpleCustomUserSerializer(
|
||||
instance.user, many=False).data
|
||||
representation['subscription'] = SubscriptionPlanSerializer(
|
||||
instance.subscription, many=False).data
|
||||
representation["user"] = SimpleCustomUserSerializer(
|
||||
instance.user, many=False
|
||||
).data
|
||||
representation["subscription"] = SubscriptionPlanSerializer(
|
||||
instance.subscription, many=False
|
||||
).data
|
||||
return representation
|
||||
|
|
|
@ -4,6 +4,7 @@ from .models import UserSubscription, StripePrice, SubscriptionPlan
|
|||
from django.core.cache import cache
|
||||
from config.settings import STRIPE_SECRET_KEY
|
||||
import stripe
|
||||
|
||||
stripe.api_key = STRIPE_SECRET_KEY
|
||||
|
||||
# Template for running actions after user have paid for a subscription
|
||||
|
@ -12,7 +13,7 @@ stripe.api_key = STRIPE_SECRET_KEY
|
|||
@receiver(post_save, sender=SubscriptionPlan)
|
||||
def clear_cache_after_plan_updates(sender, instance, **kwargs):
|
||||
# Clear cache
|
||||
cache.delete('subscriptionplans')
|
||||
cache.delete("subscriptionplans")
|
||||
|
||||
|
||||
@receiver(post_save, sender=UserSubscription)
|
||||
|
@ -25,8 +26,8 @@ def scan_after_payment(sender, instance, **kwargs):
|
|||
|
||||
@receiver(post_migrate)
|
||||
def create_subscriptions(sender, **kwargs):
|
||||
if sender.name == 'subscriptions':
|
||||
print('Importing data from Stripe')
|
||||
if sender.name == "subscriptions":
|
||||
print("Importing data from Stripe")
|
||||
created_prices = 0
|
||||
created_plans = 0
|
||||
skipped_prices = 0
|
||||
|
@ -35,16 +36,19 @@ def create_subscriptions(sender, **kwargs):
|
|||
prices = stripe.Price.list(expand=["data.tiers"], active=True)
|
||||
|
||||
# Create the StripePrice
|
||||
for price in prices['data']:
|
||||
annual = (price['recurring']['interval'] ==
|
||||
'year') if price['recurring'] else False
|
||||
for price in prices["data"]:
|
||||
annual = (
|
||||
(price["recurring"]["interval"] == "year")
|
||||
if price["recurring"]
|
||||
else False
|
||||
)
|
||||
STRIPE_PRICE, CREATED = StripePrice.objects.get_or_create(
|
||||
stripe_price_id=price['id'],
|
||||
price=price['unit_amount'] / 100,
|
||||
stripe_price_id=price["id"],
|
||||
price=price["unit_amount"] / 100,
|
||||
annual=annual,
|
||||
lookup_key=price['lookup_key'],
|
||||
prorated=price['recurring']['usage_type'] == 'metered',
|
||||
currency=price['currency']
|
||||
lookup_key=price["lookup_key"],
|
||||
prorated=price["recurring"]["usage_type"] == "metered",
|
||||
currency=price["currency"],
|
||||
)
|
||||
if CREATED:
|
||||
created_prices += 1
|
||||
|
@ -52,13 +56,13 @@ def create_subscriptions(sender, **kwargs):
|
|||
skipped_prices += 1
|
||||
|
||||
# Create the SubscriptionPlan
|
||||
for product in products['data']:
|
||||
for product in products["data"]:
|
||||
ANNUAL_PRICE = None
|
||||
MONTHLY_PRICE = None
|
||||
for price in prices['data']:
|
||||
if price['product'] == product['id']:
|
||||
for price in prices["data"]:
|
||||
if price["product"] == product["id"]:
|
||||
STRIPE_PRICE = StripePrice.objects.get(
|
||||
stripe_price_id=price['id'],
|
||||
stripe_price_id=price["id"],
|
||||
)
|
||||
if STRIPE_PRICE.annual:
|
||||
ANNUAL_PRICE = STRIPE_PRICE
|
||||
|
@ -66,12 +70,12 @@ def create_subscriptions(sender, **kwargs):
|
|||
MONTHLY_PRICE = STRIPE_PRICE
|
||||
if ANNUAL_PRICE or MONTHLY_PRICE:
|
||||
SUBSCRIPTION_PLAN, CREATED = SubscriptionPlan.objects.get_or_create(
|
||||
name=product['name'],
|
||||
description=product['description'],
|
||||
stripe_product_id=product['id'],
|
||||
name=product["name"],
|
||||
description=product["description"],
|
||||
stripe_product_id=product["id"],
|
||||
annual_price=ANNUAL_PRICE,
|
||||
monthly_price=MONTHLY_PRICE,
|
||||
group_exclusive=product['metadata']['group_exclusive'] == 'True'
|
||||
group_exclusive=product["metadata"]["group_exclusive"] == "True",
|
||||
)
|
||||
if CREATED:
|
||||
created_plans += 1
|
||||
|
@ -79,13 +83,12 @@ def create_subscriptions(sender, **kwargs):
|
|||
skipped_plans += 1
|
||||
# Skip over plans with missing pricing rates
|
||||
else:
|
||||
print('Skipping plan' +
|
||||
product['name'] + 'with missing pricing data')
|
||||
print("Skipping plan" + product["name"] + "with missing pricing data")
|
||||
|
||||
# Assign the StripePrice to the SubscriptionPlan
|
||||
SUBSCRIPTION_PLAN.save()
|
||||
|
||||
print('Created', created_plans, 'new plans')
|
||||
print('Skipped', skipped_plans, 'existing plans')
|
||||
print('Created', created_prices, 'new prices')
|
||||
print('Skipped', skipped_prices, 'existing prices')
|
||||
print("Created", created_plans, "new plans")
|
||||
print("Skipped", skipped_plans, "existing plans")
|
||||
print("Created", created_prices, "new prices")
|
||||
print("Skipped", skipped_prices, "existing prices")
|
||||
|
|
|
@ -12,10 +12,10 @@ def get_user_subscription(user_id):
|
|||
active_subscriptions = None
|
||||
if USER.user_group:
|
||||
active_subscriptions = UserSubscription.objects.filter(
|
||||
user_group=USER.user_group, valid=True)
|
||||
user_group=USER.user_group, valid=True
|
||||
)
|
||||
else:
|
||||
active_subscriptions = UserSubscription.objects.filter(
|
||||
user=USER, valid=True)
|
||||
active_subscriptions = UserSubscription.objects.filter(user=USER, valid=True)
|
||||
|
||||
# Return first valid subscription if there is one
|
||||
if len(active_subscriptions) > 0:
|
||||
|
@ -33,7 +33,8 @@ def get_user_group_subscription(user_group):
|
|||
# Get a list of subscriptions for the specified user
|
||||
active_subscriptions = None
|
||||
active_subscriptions = UserSubscription.objects.filter(
|
||||
user_group=USER_GROUP, valid=True)
|
||||
user_group=USER_GROUP, valid=True
|
||||
)
|
||||
|
||||
# Return first valid subscription if there is one
|
||||
if len(active_subscriptions) > 0:
|
||||
|
|
|
@ -3,12 +3,11 @@ from subscriptions import views
|
|||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r'plans', views.SubscriptionPlanViewset,
|
||||
basename="Subscription Plans")
|
||||
router.register(r'self', views.UserSubscriptionViewset,
|
||||
basename="Self Subscriptions")
|
||||
router.register(r'user_group', views.UserGroupSubscriptionViewet,
|
||||
basename="Group Subscriptions")
|
||||
router.register(r"plans", views.SubscriptionPlanViewset, basename="Subscription Plans")
|
||||
router.register(r"self", views.UserSubscriptionViewset, basename="Self Subscriptions")
|
||||
router.register(
|
||||
r"user_group", views.UserGroupSubscriptionViewet, basename="Group Subscriptions"
|
||||
)
|
||||
urlpatterns = [
|
||||
path('', include(router.urls)),
|
||||
path("", include(router.urls)),
|
||||
]
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
from subscriptions.serializers import SubscriptionPlanSerializer, UserSubscriptionSerializer
|
||||
from subscriptions.serializers import (
|
||||
SubscriptionPlanSerializer,
|
||||
UserSubscriptionSerializer,
|
||||
)
|
||||
from subscriptions.models import SubscriptionPlan, UserSubscription
|
||||
from rest_framework.permissions import AllowAny, IsAuthenticated
|
||||
from rest_framework import viewsets
|
||||
|
@ -6,38 +9,38 @@ from django.core.cache import cache
|
|||
|
||||
|
||||
class SubscriptionPlanViewset(viewsets.ModelViewSet):
|
||||
http_method_names = ['get']
|
||||
http_method_names = ["get"]
|
||||
serializer_class = SubscriptionPlanSerializer
|
||||
permission_classes = [AllowAny]
|
||||
queryset = SubscriptionPlan.objects.all()
|
||||
|
||||
def get_queryset(self):
|
||||
key = 'subscriptionplans'
|
||||
key = "subscriptionplans"
|
||||
queryset = cache.get(key)
|
||||
if not queryset:
|
||||
queryset = super().get_queryset()
|
||||
cache.set(key, queryset, 60*60)
|
||||
cache.set(key, queryset, 60 * 60)
|
||||
return queryset
|
||||
|
||||
|
||||
class UserSubscriptionViewset(viewsets.ModelViewSet):
|
||||
http_method_names = ['get']
|
||||
http_method_names = ["get"]
|
||||
serializer_class = UserSubscriptionSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
queryset = UserSubscription.objects.all()
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
key = f'subscriptions_user:{user.id}'
|
||||
key = f"subscriptions_user:{user.id}"
|
||||
queryset = cache.get(key)
|
||||
if not queryset:
|
||||
queryset = UserSubscription.objects.filter(user=user)
|
||||
cache.set(key, queryset, 60*60)
|
||||
cache.set(key, queryset, 60 * 60)
|
||||
return queryset
|
||||
|
||||
|
||||
class UserGroupSubscriptionViewet(viewsets.ModelViewSet):
|
||||
http_method_names = ['get']
|
||||
http_method_names = ["get"]
|
||||
serializer_class = UserSubscriptionSerializer
|
||||
permission_classes = [IsAuthenticated]
|
||||
queryset = UserSubscription.objects.all()
|
||||
|
@ -47,10 +50,9 @@ class UserGroupSubscriptionViewet(viewsets.ModelViewSet):
|
|||
if not user.user_group:
|
||||
return UserSubscription.objects.none()
|
||||
else:
|
||||
key = f'subscriptions_usergroup:{user.user_group.id}'
|
||||
key = f"subscriptions_usergroup:{user.user_group.id}"
|
||||
queryset = cache.get(key)
|
||||
if not cache:
|
||||
queryset = UserSubscription.objects.filter(
|
||||
user_group=user.user_group)
|
||||
cache.set(key, queryset, 60*60)
|
||||
queryset = UserSubscription.objects.filter(user_group=user.user_group)
|
||||
cache.set(key, queryset, 60 * 60)
|
||||
return queryset
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue