Introduce subscription periods.
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Víðir Valberg Guðmundsson 2023-01-02 22:13:25 +01:00
parent 282b500a5e
commit 01715a7704
10 changed files with 159 additions and 11 deletions

View File

@ -1,4 +1,4 @@
DOCKER_COMPOSE = COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose
DOCKER_COMPOSE = COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 venv/bin/docker-compose
DOCKER_RUN = ${DOCKER_COMPOSE} run -u `id -u`
DOCKER_BUILD = DOCKER_BUILDKIT=1 docker build
DOCKER_CONTAINER_NAME = backend

View File

@ -1,4 +1,4 @@
Django==4.1
Django==4.1.5
django-money==1.3
django-allauth==0.46
psycopg2-binary==2.9.5

View File

@ -2,6 +2,7 @@ from django.contrib import admin
from .models import Membership
from .models import MembershipType
from .models import SubscriptionPeriod
@admin.register(Membership)
@ -12,3 +13,8 @@ class MembershipAdmin(admin.ModelAdmin):
@admin.register(MembershipType)
class MembershipTypeAdmin(admin.ModelAdmin):
pass
@admin.register(SubscriptionPeriod)
class SubscriptionPeriodAdmin(admin.ModelAdmin):
pass

View File

@ -0,0 +1,63 @@
# Generated by Django 4.1 on 2023-01-02 21:05
import django.contrib.postgres.constraints
import django.contrib.postgres.fields.ranges
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("membership", "0001_initial"),
]
operations = [
migrations.CreateModel(
name="SubscriptionPeriod",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"modified",
models.DateTimeField(auto_now=True, verbose_name="modified"),
),
(
"created",
models.DateTimeField(auto_now_add=True, verbose_name="created"),
),
(
"period",
django.contrib.postgres.fields.ranges.DateRangeField(
verbose_name="period"
),
),
],
),
migrations.RemoveField(
model_name="membership",
name="period",
),
migrations.AlterField(
model_name="membership",
name="created",
field=models.DateTimeField(auto_now_add=True, verbose_name="created"),
),
migrations.AlterField(
model_name="membershiptype",
name="created",
field=models.DateTimeField(auto_now_add=True, verbose_name="created"),
),
migrations.AddConstraint(
model_name="subscriptionperiod",
constraint=django.contrib.postgres.constraints.ExclusionConstraint(
expressions=[("period", "&&")], name="exclude_overlapping_periods"
),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 4.1 on 2023-01-02 21:05
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("membership", "0002_subscriptionperiod_remove_membership_period_and_more"),
]
operations = [
migrations.AddField(
model_name="membership",
name="period",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="membership.subscriptionperiod",
),
),
]

View File

@ -0,0 +1,22 @@
# Generated by Django 4.1 on 2023-01-02 21:06
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("membership", "0003_membership_period"),
]
operations = [
migrations.AlterField(
model_name="membership",
name="period",
field=models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="membership.subscriptionperiod",
),
),
]

View File

@ -1,18 +1,31 @@
from typing import Optional
from django.contrib.postgres.fields import DateTimeRangeField
from django.contrib.postgres.constraints import ExclusionConstraint
from django.contrib.postgres.fields import DateRangeField
from django.contrib.postgres.fields import RangeOperators
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext as _
from utils.mixins import CreatedModifiedAbstract
class CreatedModifiedAbstract(models.Model):
modified = models.DateTimeField(auto_now=True, verbose_name=_("modified"))
created = models.DateTimeField(auto_now_add=True, verbose_name=_("created"))
class SubscriptionPeriod(CreatedModifiedAbstract):
"""
Denotes a period for which members should pay their membership fee for.
"""
period = DateRangeField(verbose_name=_("period"))
class Meta:
abstract = True
constraints = [
ExclusionConstraint(
name="exclude_overlapping_periods",
expressions=[
("period", RangeOperators.OVERLAPS),
],
),
]
class Membership(CreatedModifiedAbstract):
@ -25,7 +38,7 @@ class Membership(CreatedModifiedAbstract):
return self.filter(user=user)
def _current(self):
return self.filter(period__contains=timezone.now())
return self.filter(period__period__contains=timezone.now())
def current(self) -> Optional["Membership"]:
try:
@ -54,7 +67,9 @@ class Membership(CreatedModifiedAbstract):
on_delete=models.PROTECT,
)
period = DateTimeRangeField(help_text=_("The duration this subscription is for. "))
period = models.ForeignKey(
"membership.SubscriptionPeriod", on_delete=models.PROTECT
)
def __str__(self):
return f"{self.user} - {self.period}"

View File

@ -16,7 +16,8 @@
{% else %}
<p>{% trans "You are a member!" %}</p>
<p>{% trans "Period" %}: {{ current_membership.period.lower|date:"SHORT_DATE_FORMAT" }} to {{ current_membership.period.upper|date:"SHORT_DATE_FORMAT" }}</p>
{% trans "next general assembly" as next_general_assembly %}
<p>{% trans "Period" %}: {{ current_period.lower|date:"SHORT_DATE_FORMAT" }} to {{ current_period.upper|date:"SHORT_DATE_FORMAT"|default:next_general_assembly }}</p>
<p>{% trans "Type" %}: {{ current_membership.membership_type }}</p>
{% endif %}
{% endblock %}

View File

@ -10,9 +10,16 @@ def membership_overview(request):
current_membership = memberships.current()
previous_memberships = memberships.previous()
current_period = current_membership.period.period if current_membership else None
context = {
"current_membership": current_membership,
"current_period": current_period,
"previous_memberships": previous_memberships,
}
return render(request, "membership_overview.html", context)
return render(
request=request,
template_name="membership_overview.html",
context=context,
)

11
src/utils/mixins.py Normal file
View File

@ -0,0 +1,11 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
class CreatedModifiedAbstract(models.Model):
modified = models.DateTimeField(auto_now=True, verbose_name=_("modified"))
created = models.DateTimeField(auto_now_add=True, verbose_name=_("created"))
class Meta:
abstract = True