prepare for new payments module

master
alice 3 years ago
parent 775b96ae9f
commit 18ffc0af5f

@ -282,6 +282,14 @@ PAYMENTS_BACKENDS = {
PAYMENTS_CURRENCY = ('eur', '') PAYMENTS_CURRENCY = ('eur', '')
PLANS = {
'1m': {'monthly': 3.00, 'months': 1, },
'3m': {'monthly': 9.00, 'months': 3, },
'6m': {'monthly': 18.00, 'months': 6, },
'12m': {'monthly': 36.00, 'months': 12, 'default': 1},
}
CONSTANCE_BACKEND = 'constance.backends.database.DatabaseBackend' CONSTANCE_BACKEND = 'constance.backends.database.DatabaseBackend'
CONSTANCE_CONFIG = { CONSTANCE_CONFIG = {
'MOTD': ('', "Public site message, displayed on homepage"), 'MOTD': ('', "Public site message, displayed on homepage"),

@ -85,14 +85,14 @@ class SubscriptionAdmin(admin.ModelAdmin):
model = Subscription model = Subscription
list_display = ('user', 'created', 'status', 'backend', 'backend_extid') list_display = ('user', 'created', 'status', 'backend', 'backend_extid')
list_filter = ('backend_id', 'status') list_filter = ('backend_id', 'status')
readonly_fields = ('user_link', 'backend', 'period', 'created', 'status', readonly_fields = ('user_link', 'backend', 'created', 'status',
'last_confirmed_payment', 'payments_links', 'last_confirmed_payment', 'payments_links',
'backend_extid_link', 'backend_data_fmt') 'backend_extid_link', 'backend_data_fmt')
search_fields = ('user__username', 'user__email', 'backend_extid', 'backend_data') search_fields = ('user__username', 'user__email', 'backend_extid', 'backend_data')
actions = (subscr_mark_as_cancelled,) actions = (subscr_mark_as_cancelled,)
fieldsets = ( fieldsets = (
(None, { (None, {
'fields': ('backend', 'user_link', 'period', 'payments_links', 'status', 'fields': ('backend', 'user_link', 'payments_links', 'status',
'last_confirmed_payment'), 'last_confirmed_payment'),
}), }),
(_("Payment Data"), { (_("Payment Data"), {

@ -0,0 +1,99 @@
# Generated by Django 3.2.4 on 2021-07-21 19:31
from datetime import timedelta
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import jsonfield.fields
def field_to_plan_id(model_name, field_name):
def fun(apps, schema_editor):
keys = settings.PLANS.keys()
model = apps.get_model('payments', model_name)
for s in model.objects.all():
d = getattr(s, field_name)
if s.plan_id is not None:
continue
s.plan_id = str(round(d / timedelta(days=30))) + 'm'
if s.plan_id not in keys:
raise Exception(f"unknown plan: {s.plan_id}")
s.save()
return fun
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('payments', '0007_auto_20201114_1730'),
]
operations = [
migrations.RenameField("Subscription", 'period', 'plan_id'),
# Add plan_id to payments and convert from the time field
migrations.AddField(
model_name='payment',
name='plan_id',
field=models.CharField(choices=[('1m', 'Every 1 month'), ('3m', 'Every 3 months'), ('6m', 'Every 6 months'), ('12m', 'Every 12 months')], max_length=16, null=True),
),
migrations.RunPython(field_to_plan_id('Payment', 'time'), lambda x, y: ()),
# Make those two columns non-null once converted
migrations.AlterField(
model_name='payment',
name='plan_id',
field=models.CharField(choices=[('1m', 'Every 1 month'), ('3m', 'Every 3 months'), ('6m', 'Every 6 months'), ('12m', 'Every 12 months')], max_length=16),
),
migrations.AlterField(
model_name='subscription',
name='plan_id',
field=models.CharField(choices=[('1m', 'Every 1 month'), ('3m', 'Every 3 months'), ('6m', 'Every 6 months'), ('12m', 'Every 12 months')], max_length=16),
),
migrations.AddField(
model_name='payment',
name='ip_address',
field=models.GenericIPAddressField(blank=True, null=True),
),
migrations.AddField(
model_name='payment',
name='refund_date',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AddField(
model_name='payment',
name='refund_text',
field=models.CharField(blank=True, max_length=200),
),
migrations.AddField(
model_name='subscription',
name='next_payment_date',
field=models.DateTimeField(blank=True, null=True),
),
migrations.AlterField(
model_name='payment',
name='backend_data',
field=jsonfield.fields.JSONField(blank=True),
),
migrations.AlterField(
model_name='payment',
name='backend_id',
field=models.CharField(choices=[('bitcoin', 'Bitcoin'), ('paypal', 'PayPal'), ('stripe', 'Stripe')], max_length=16),
),
migrations.AlterField(
model_name='payment',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='subscription',
name='backend_data',
field=jsonfield.fields.JSONField(blank=True),
),
migrations.AlterField(
model_name='subscription',
name='backend_id',
field=models.CharField(choices=[('bitcoin', 'Bitcoin'), ('paypal', 'PayPal'), ('stripe', 'Stripe')], max_length=16),
),
]

@ -89,6 +89,27 @@ ACTIVE_BACKEND_CHOICES = sorted(ACTIVE_BACKEND_CHOICES, key=lambda x: x[0])
logger.info("payments: finished. %d/%d backends active", len(ACTIVE_BACKENDS), len(BACKEND_CLASSES)) logger.info("payments: finished. %d/%d backends active", len(ACTIVE_BACKENDS), len(BACKEND_CLASSES))
class PlanBase(object):
def __init__(self, name, months, monthly, saves="", default=False):
self.name = name
self.months = months
self.monthly = monthly
self.saves = saves
self.default = default
@property
def due_amount(self):
return round(self.months * self.monthly, 2)
@property
def time_display(self):
return "%d month%s" % (self.months, 's' if self.months > 1 else '')
def json(self):
return {'total': self.due_amount}
PLANS = {k: PlanBase(name=k, **settings.PLANS[k]) for k, v in settings.PLANS.items()}
PLAN_CHOICES = [(k, "Every " + p.time_display) for k, p in PLANS.items()]
SUBSCR_PLAN_CHOICES = PLAN_CHOICES
def period_months(p): def period_months(p):
return { return {
'3m': 3, '3m': 3,
@ -128,12 +149,17 @@ class Payment(models.Model, BackendData):
amount = models.IntegerField() amount = models.IntegerField()
paid_amount = models.IntegerField(default=0) paid_amount = models.IntegerField(default=0)
time = models.DurationField() time = models.DurationField()
plan_id = models.CharField(max_length=16, choices=SUBSCR_PLAN_CHOICES)
subscription = models.ForeignKey('Subscription', null=True, blank=True, on_delete=models.CASCADE) subscription = models.ForeignKey('Subscription', null=True, blank=True, on_delete=models.CASCADE)
status_message = models.TextField(blank=True, null=True) status_message = models.TextField(blank=True, null=True)
ip_address = models.GenericIPAddressField(blank=True, null=True)
backend_extid = models.CharField(max_length=256, null=True, blank=True) backend_extid = models.CharField(max_length=256, null=True, blank=True)
backend_data = JSONField(blank=True) backend_data = JSONField(blank=True)
refund_date = models.DateTimeField(blank=True, null=True)
refund_text = models.CharField(max_length=200, blank=True)
@property @property
def currency_code(self): def currency_code(self):
return CURRENCY_CODE return CURRENCY_CODE
@ -192,7 +218,8 @@ class Subscription(models.Model, BackendData):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
backend_id = models.CharField(max_length=16, choices=BACKEND_CHOICES) backend_id = models.CharField(max_length=16, choices=BACKEND_CHOICES)
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
period = models.CharField(max_length=16, choices=SUBSCR_PERIOD_CHOICES) plan_id = models.CharField(max_length=16, choices=SUBSCR_PLAN_CHOICES)
next_payment_date = models.DateTimeField(blank=True, null=True)
last_confirmed_payment = models.DateTimeField(blank=True, null=True) last_confirmed_payment = models.DateTimeField(blank=True, null=True)
status = models.CharField(max_length=16, choices=SUBSCR_STATUS_CHOICES, default='new') status = models.CharField(max_length=16, choices=SUBSCR_STATUS_CHOICES, default='new')

Loading…
Cancel
Save