Changes to payment models #32

Merged
valberg merged 35 commits from benjaoming/membersystem:payment-updates into main 2024-08-03 17:55:33 +00:00
4 changed files with 62 additions and 2 deletions
Showing only changes of commit 3193cafe4b - Show all commits

View file

@ -23,6 +23,7 @@ dependencies = [
"django-registries==0.0.3",
"django-view-decorator==0.0.4",
"django-oauth-toolkit==2.4.0",
"django_stubs_ext",
benjaoming marked this conversation as resolved
Review

Noting that this got reintroduced... I don't use it... but is it used? Or did you remove it on purpose @valberg ?

Noting that this got reintroduced... I don't use it... but is it used? Or did you remove it on purpose @valberg ?
Review

I did not do it on purpose no 😊 my all means remove it if it is isn't being used

I did not do it on purpose no 😊 my all means remove it if it is isn't being used
Review

Oh god now I know what's going on... it's for the mypy django-stubs thing...

Yes, we need it for running mypy with Django. I think I spend 2 minutes to get it working. But I didn't actually fix any errors. I think we can keep it for now and then we should open an issue if we want to keep using it.

Or we can decide that we don't want to spend time on this because it doesn't find any real issues.

Oh god now I know what's going on... it's for the mypy django-stubs thing... Yes, we need it for running mypy with Django. I think I spend 2 minutes to get it working. But I didn't actually fix any errors. I think we can keep it for now and then we should open an issue if we want to keep using it. Or we can decide that we don't want to spend time on this because it doesn't find any real issues.
Review

https://git.data.coop/data.coop/membersystem/issues/37
]
version = "0.0.1"
@ -104,10 +105,10 @@ show_error_codes = true
strict = true
warn_unreachable = true
follow_imports = "normal"
#plugins = ["mypy_django_plugin.main"]
plugins = ["mypy_django_plugin.main"]
[tool.django-stubs]
#django_settings_module = "tests.settings"
django_settings_module = "project.settings"
[[tool.mypy.overrides]]
module = "tests.*"

View file

@ -1,8 +1,14 @@
"""Admin configuration for membership app."""
from collections.abc import Callable
from django.contrib import admin
from django.contrib.admin import ModelAdmin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from django.db.models import QuerySet
from django.http import HttpRequest
from django.http import HttpResponse
from . import models
@ -31,11 +37,39 @@ class MembershipInlineAdmin(admin.TabularInline):
model = models.Membership
def decorate_ensure_membership_type_exists(membership_type: models.MembershipType, label: str) -> Callable:
"""Generate an admin action for given membership type and label."""
@admin.action(description=label)
def admin_action(modeladmin: ModelAdmin, request: HttpRequest, queryset: QuerySet) -> HttpResponse: # noqa: ARG001
return ensure_membership_type_exists(request, queryset, membership_type)
return admin_action
def ensure_membership_type_exists(
request: HttpRequest, # noqa: ARG001
queryset: QuerySet, # noqa: ARG001
membership_type: models.MembershipType, # noqa: ARG001
) -> HttpResponse:
"""Inner function that ensures that a membership exists for a given queryset of Member objects."""
@admin.register(models.Member)
class MemberAdmin(UserAdmin):
"""Member admin is actually an admin for User objects."""
inlines = (MembershipInlineAdmin,)
actions: list[Callable] = [] # noqa: RUF012
def get_actions(self, request: HttpRequest) -> dict:
"""Populate actions with dynamic data (MembershipType)."""
current_period = models.SubscriptionPeriod.objects.current()
if current_period:
for mtype in models.MembershipType.objects.filter(active=True):
action_label = f"Ensure membership {mtype.name}, {current_period.period}, {mtype.total_including_vat}"
self.actions.append(decorate_ensure_membership_type_exists(mtype, action_label))
return super().get_actions(request)
@admin.register(models.WaitingListEntry)

View file

@ -10,6 +10,7 @@ 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 djmoney.money import Money
from utils.mixins import CreatedModifiedAbstract
@ -53,6 +54,22 @@ class SubscriptionPeriod(CreatedModifiedAbstract):
Denotes a period for which members should pay their membership fee for.
"""
class QuerySet(models.QuerySet):
"""QuerySet for the Membership model."""
def _current(self) -> Self:
"""Filter memberships for the current period."""
return self.filter(period__contains=timezone.now())
def current(self) -> "Membership | None":
"""Get the current membership."""
try:
return self._current().get()
except self.model.DoesNotExist:
return None
objects = QuerySet.as_manager()
period = DateRangeField(verbose_name=_("period"))
class Meta:
@ -179,6 +196,11 @@ class MembershipType(CreatedModifiedAbstract):
period=get_current_subscription_period(),
)
@property
def total_including_vat(self) -> Money:
"""Calculate the total price of this membership (including VAT)."""
return sum(product.price + product.vat for product in self.products.all())
class WaitingListEntry(CreatedModifiedAbstract):
"""People who for some reason could want to be added to a waiting list and invited to join later."""

View file

@ -2,9 +2,12 @@
from pathlib import Path
import django_stubs_ext
from django.utils.translation import gettext_lazy as _
from environs import Env
django_stubs_ext.monkeypatch()
benjaoming marked this conversation as resolved
Review

This is where django-stubs is used. It's said to be "production safe" :)

This is where django-stubs is used. It's said to be "production safe" :)
Review

Ah yes! I can vouch for it - we use it at $WORK without issues

Ah yes! I can vouch for it - we use it at $WORK without issues
Review

Nice! I'm gonna vouch that we keep it for now and see if we'll start using mypy checks or not... now at least, it can be run.

Nice! I'm gonna vouch that we keep it for now and see if we'll start using mypy checks or not... now at least, it can be run.
Review

https://git.data.coop/data.coop/membersystem/issues/37
env = Env()
env.read_env()