Can send out information e-mails to people with paid invoices.

Merge branch 'chrisjrn/email_reminders'
This commit is contained in:
Christopher Neugebauer 2017-01-08 11:08:08 +11:00
commit cbb04cbdf4
5 changed files with 74 additions and 24 deletions

View file

@ -413,7 +413,16 @@ def staff_products_formset_factory(user):
return forms.formset_factory(form_type)
class InvoiceNagForm(forms.Form):
class InvoiceEmailForm(forms.Form):
ACTION_PREVIEW = 1
ACTION_SEND = 2
ACTION_CHOICES = (
(ACTION_PREVIEW, "Preview"),
(ACTION_SEND, "Send emails"),
)
invoice = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple,
queryset=commerce.Invoice.objects.all(),
@ -423,18 +432,26 @@ class InvoiceNagForm(forms.Form):
body = forms.CharField(
widget=forms.Textarea,
)
action = forms.TypedChoiceField(
widget=forms.RadioSelect,
coerce=int,
choices=ACTION_CHOICES,
initial=ACTION_PREVIEW,
)
def __init__(self, *a, **k):
category = k.pop('category', None) or []
product = k.pop('product', None) or []
status = int(k.pop('status', None) or 0)
category = [int(i) for i in category]
product = [int(i) for i in product]
super(InvoiceNagForm, self).__init__(*a, **k)
super(InvoiceEmailForm, self).__init__(*a, **k)
print status
qs = commerce.Invoice.objects.filter(
status=commerce.Invoice.STATUS_UNPAID,
status=status or commerce.Invoice.STATUS_UNPAID,
).filter(
Q(lineitem__product__category__in=category) |
Q(lineitem__product__in=product)

View file

@ -593,10 +593,11 @@ def attendee_data(request, form, user_id=None):
# Add invoice nag link
links = []
links.append((
reverse(views.nag_unpaid, args=[]) + "?" + request.META["QUERY_STRING"],
"Send invoice reminders",
))
invoice_mailout = reverse(views.invoice_mailout, args=[]) + "?" + request.META["QUERY_STRING"]
links += [
(invoice_mailout + "&status=1", "Send invoice reminders",),
(invoice_mailout + "&status=2", "Send mail for paid invoices",),
]
if items.count() > 0:
output.append(Links("Actions", links))

View file

@ -9,6 +9,15 @@ from urllib import urlencode
register = template.Library()
def user_for_context(context):
''' Returns either context.user or context.request.user if the former is
not defined. '''
try:
return context["user"]
except KeyError:
return context.request.user
@register.assignment_tag(takes_context=True)
def available_categories(context):
''' Gets all of the currently available products.
@ -18,13 +27,13 @@ def available_categories(context):
have Products that the current user can reserve.
'''
return CategoryController.available_categories(context.request.user)
return CategoryController.available_categories(user_for_context(context))
@register.assignment_tag(takes_context=True)
def missing_categories(context):
''' Adds the categories that the user does not currently have. '''
user = context.request.user
user = user_for_context(context)
categories_available = set(CategoryController.available_categories(user))
items = ItemController(user).items_pending_or_purchased()
@ -47,7 +56,7 @@ def available_credit(context):
'''
notes = commerce.CreditNote.unclaimed().filter(
invoice__user=context.request.user,
invoice__user=user_for_context(context),
)
ret = notes.values("amount").aggregate(Sum("amount"))["amount__sum"] or 0
return 0 - ret
@ -59,20 +68,29 @@ def invoices(context):
Returns:
[models.commerce.Invoice, ...]: All of the current user's invoices. '''
return commerce.Invoice.objects.filter(user=context.request.user)
return commerce.Invoice.objects.filter(user=user_for_context(context))
@register.assignment_tag(takes_context=True)
def items_pending(context):
''' Gets all of the items that the user from this context has reserved.'''
return ItemController(context.request.user).items_pending()
''' Gets all of the items that the user from this context has reserved.
The user will be either `context.user`, and `context.request.user` if
the former is not defined.
'''
return ItemController(user_for_context(context)).items_pending()
@register.assignment_tag(takes_context=True)
def items_purchased(context, category=None):
''' Returns the items purchased for this user. '''
''' Returns the items purchased for this user.
return ItemController(context.request.user).items_purchased(
The user will be either `context.user`, and `context.request.user` if
the former is not defined.
'''
return ItemController(user_for_context(context)).items_purchased(
category=category
)

View file

@ -12,8 +12,8 @@ from .views import (
guided_registration,
invoice,
invoice_access,
invoice_mailout,
manual_payment,
nag_unpaid,
product_category,
refund,
review,
@ -35,7 +35,7 @@ public = [
refund, name="refund"),
url(r"^invoice_access/([A-Z0-9]+)$", invoice_access,
name="invoice_access"),
url(r"^nag_unpaid$", nag_unpaid, name="nag_unpaid"),
url(r"^invoice_mailout$", invoice_mailout, name="invoice_mailout"),
url(r"^profile$", edit_profile, name="attendee_edit"),
url(r"^register$", guided_registration, name="guided_registration"),
url(r"^review$", review, name="review"),

View file

@ -920,19 +920,28 @@ def extend_reservation(request, user_id, days=7):
return redirect(request.META["HTTP_REFERER"])
Email = namedtuple(
"Email",
("subject", "body", "from_email", "recipient_list"),
)
@user_passes_test(_staff_only)
def nag_unpaid(request):
''' Allows staff to nag users with unpaid invoices. '''
def invoice_mailout(request):
''' Allows staff to send emails to users based on their invoice status. '''
category = request.GET.getlist("category", [])
product = request.GET.getlist("product", [])
status = request.GET.get("status")
form = forms.InvoiceNagForm(
form = forms.InvoiceEmailForm(
request.POST or None,
category=category,
product=product,
status=status,
)
emails = []
if form.is_valid():
emails = []
for invoice in form.cleaned_data["invoice"]:
@ -942,15 +951,20 @@ def nag_unpaid(request):
body = Template(form.cleaned_data["body"]).render(
Context({
"invoice" : invoice,
"user" : invoice.user,
})
)
recipient_list = [invoice.user.email]
emails.append((subject, body, from_email, recipient_list))
send_mass_mail(emails)
messages.info(request, "The e-mails have been sent.")
emails.append(Email(subject, body, from_email, recipient_list))
if form.cleaned_data["action"] == forms.InvoiceEmailForm.ACTION_SEND:
# Send e-mails *ONLY* if we're sending.
send_mass_mail(emails)
messages.info(request, "The e-mails have been sent.")
data = {
"form": form,
"emails": emails,
}
return render(request, "registrasion/nag_unpaid.html", data)
return render(request, "registrasion/invoice_mailout.html", data)