Membership invitations and order emails #47
|
@ -2,7 +2,11 @@
|
|||
|
||||
from django import forms
|
||||
from django.contrib import admin
|
||||
from django.contrib import messages
|
||||
from django.db.models import QuerySet
|
||||
from django.http import HttpRequest
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from membership.emails import OrderEmail
|
||||
|
||||
from . import models
|
||||
|
||||
|
@ -26,7 +30,7 @@ class OrderAdminForm(forms.ModelForm):
|
|||
model = models.Order
|
||||
exclude = () # noqa: DJ006
|
||||
|
||||
def clean(self): # noqa: D102, ANN201
|
||||
def clean(self): # noqa: ANN201
|
||||
cd = super().clean()
|
||||
if not cd["account"] and cd["member"]:
|
||||
try:
|
||||
|
@ -43,10 +47,25 @@ class OrderAdmin(admin.ModelAdmin):
|
|||
inlines = (OrderProductInline,)
|
||||
form = OrderAdminForm
|
||||
|
||||
actions = ("send_order",)
|
||||
|
||||
list_display = ("member", "description", "created", "is_paid", "total_with_vat")
|
||||
search_fields = ("member__email", "membership__membership_type__name", "description")
|
||||
list_filter = ("is_paid", "membership__membership_type")
|
||||
|
||||
@admin.action(description="Send order link to selected unpaid orders")
|
||||
def send_order(self, request: HttpRequest, queryset: QuerySet[models.Order]) -> None:
|
||||
for order in queryset:
|
||||
if order.is_paid:
|
||||
messages.error(
|
||||
request,
|
||||
f"Order pk={order.id} is already marked paid, not sending email to: {order.member.email}",
|
||||
)
|
||||
continue
|
||||
email = OrderEmail(order, request)
|
||||
email.send()
|
||||
messages.success(request, f"Sent an order for order pk={order.id} link to: {order.member.email}")
|
||||
|
||||
|
||||
@admin.register(models.Payment)
|
||||
class PaymentAdmin(admin.ModelAdmin):
|
||||
|
@ -61,15 +80,15 @@ class PaymentAdmin(admin.ModelAdmin):
|
|||
|
||||
|
||||
@admin.register(models.Product)
|
||||
class ProductAdmin(admin.ModelAdmin): # noqa: D101
|
||||
class ProductAdmin(admin.ModelAdmin):
|
||||
list_display = ("name", "price", "vat")
|
||||
|
||||
|
||||
class TransactionInline(admin.TabularInline): # noqa: D101
|
||||
class TransactionInline(admin.TabularInline):
|
||||
model = models.Transaction
|
||||
|
||||
|
||||
@admin.register(models.Account)
|
||||
class AccountAdmin(admin.ModelAdmin): # noqa: D101
|
||||
class AccountAdmin(admin.ModelAdmin):
|
||||
list_display = ("owner", "balance")
|
||||
inlines = (TransactionInline,)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Generally, an email consists of templates (for body and subject) and a get_context() method.
|
||||
"""
|
||||
|
||||
from accounting.models import Order
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.tokens import default_token_generator
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
|
@ -108,3 +109,18 @@ class InviteEmail(BaseEmail):
|
|||
c["token"] = default_token_generator.make_token(self.membership.user)
|
||||
c["referral_code"] = self.membership.referral_code
|
||||
return c
|
||||
|
||||
|
||||
class OrderEmail(BaseEmail):
|
||||
template = "membership/emails/order.txt"
|
||||
default_subject = _("Your data.coop order and payment")
|
||||
|
||||
def __init__(self, order: Order, request: HttpRequest, *args, **kwargs) -> None:
|
||||
self.order = order
|
||||
kwargs["user"] = order.member
|
||||
super().__init__(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self) -> dict:
|
||||
c = super().get_context_data()
|
||||
c["order"] = self.order
|
||||
return c
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
{% block content %}{% endblock %}
|
||||
|
||||
|
||||
Regards,
|
||||
{% trans "Cooperatively yours," %}
|
||||
{{ site_name }}
|
||||
|
||||
{{ protocol }}://{{ domain }}
|
||||
|
|
6
src/membership/templates/membership/emails/order.txt
Normal file
6
src/membership/templates/membership/emails/order.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
{% extends "membership/emails/base.txt" %}{% load i18n %}
|
||||
|
||||
{% block content %}{% url 'order:detail' order_id=order.id as order_url %}{% blocktrans %}You have an order in our system, you can pay it here:
|
||||
|
||||
{{ protocol }}://{{ domain }}{{ order_url }}
|
||||
{% endblocktrans %}{% endblock %}
|
|
@ -14,6 +14,10 @@
|
|||
It is very much under construction.
|
||||
</p>
|
||||
|
||||
{% for order in unpaid_orders %}
|
||||
<p>You have an unpaid order: <a href="{% url "order:detail" order_id=order.id %}">View Order ID {{ order.id }}</a></p>
|
||||
{% endfor %}
|
||||
|
||||
{% comment %}
|
||||
<hr>
|
||||
<br>
|
||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from accounting.models import Order
|
||||
from django_view_decorator import view
|
||||
from utils.view_utils import render
|
||||
|
||||
|
@ -19,7 +20,11 @@ if TYPE_CHECKING:
|
|||
)
|
||||
def index(request: HttpRequest) -> HttpResponse:
|
||||
"""View to show the index page."""
|
||||
return render(request, "index.html")
|
||||
unpaid_orders = Order.objects.filter(member=request.user, is_paid=False)
|
||||
|
||||
context = {"unpaid_orders": list(unpaid_orders)}
|
||||
|
||||
return render(request, "index.html", context=context)
|
||||
|
||||
|
||||
@view(
|
||||
|
|
Loading…
Reference in a new issue