diff --git a/registrasion/controllers/invoice.py b/registrasion/controllers/invoice.py index c5a527ca..de401d31 100644 --- a/registrasion/controllers/invoice.py +++ b/registrasion/controllers/invoice.py @@ -126,6 +126,23 @@ class InvoiceController(object): return invoice + def can_view(self, user=None, access_code=None): + ''' Returns true if the accessing user is allowed to view this invoice, + or if the given access code matches this invoice's user's access code. + ''' + + if user == self.invoice.user: + return True + + if user.is_staff: + return True + + if self.invoice.user.attendee.access_code == access_code: + return True + + return False + + def _refresh(self): ''' Refreshes the underlying invoice and cart objects. ''' self.invoice.refresh_from_db() diff --git a/registrasion/urls.py b/registrasion/urls.py index eb0606df..0949e4b4 100644 --- a/registrasion/urls.py +++ b/registrasion/urls.py @@ -7,8 +7,11 @@ urlpatterns = patterns( url(r"^category/([0-9]+)$", "product_category", name="product_category"), url(r"^checkout$", "checkout", name="checkout"), url(r"^invoice/([0-9]+)$", "invoice", name="invoice"), + url(r"^invoice/([0-9]+)/([A-Z0-9]+)$", views.invoice, name="invoice"), url(r"^invoice/([0-9]+)/manual_payment$", views.manual_payment, name="manual_payment"), + url(r"^invoice_access/([A-Z0-9]+)$", views.invoice_access, + name="invoice_access"), url(r"^profile$", "edit_profile", name="attendee_edit"), url(r"^register$", "guided_registration", name="guided_registration"), url(r"^register/([0-9]+)$", "guided_registration", diff --git a/registrasion/views.py b/registrasion/views.py index da8687cc..251f0fba 100644 --- a/registrasion/views.py +++ b/registrasion/views.py @@ -424,18 +424,41 @@ def checkout_errors(request, errors): return render(request, "registrasion/checkout_errors.html", data) -@login_required -def invoice(request, invoice_id): - ''' Displays an invoice for a given invoice id. ''' +def invoice_access(request, access_code): + ''' Redirects to the first unpaid invoice for the attendee that matches + the given access code, if any. ''' + + invoices = rego.Invoice.objects.filter( + user__attendee__access_code=access_code, + status=rego.Invoice.STATUS_UNPAID, + ).order_by("issue_time") + + if not invoices: + raise Http404() + + invoice = invoices[0] + + return redirect("invoice", invoice.id, access_code) + + +def invoice(request, invoice_id, access_code=None): + ''' Displays an invoice for a given invoice id. + This view is not authenticated, but it will only allow access to either: + the user the invoice belongs to; staff; or a request made with the correct + access code. + ''' invoice_id = int(invoice_id) inv = rego.Invoice.objects.get(pk=invoice_id) - if request.user != inv.cart.user and not request.user.is_staff: - raise Http404() - current_invoice = InvoiceController(inv) + if not current_invoice.can_view( + user=request.user, + access_code=access_code, + ): + raise Http404() + data = { "invoice": current_invoice.invoice, }