Invoice dashboard for the finance team
Python · Django · beginner · modification
Adds the invoice dashboard: a login-protected page listing the 500 most recent invoices with customer, status and total per row. Reuses the existing models and adds a small `total` property to `Invoice`. Checked locally — the page renders correctly and the totals match the line items.
Production Postgres holds ~120k invoices across ~8k customers; each invoice carries 1-15 lines. The finance team opens the dashboard first thing every morning and refreshes it throughout the day.
Requirements
- Add an invoice dashboard page served at `/invoices/`, visible to logged-in users only; unauthenticated visitors are redirected to the login page.
- The page lists the 500 most recently issued invoices, ordered by `issued_on` descending, ties broken by `id` descending.
- Each row shows the invoice number, the customer's name, the issue date formatted as `YYYY-MM-DD`, the human-readable status label, and the invoice total — the sum of its line amounts (`0.00` for an invoice with no lines).
- Every row renders customer and line data, so fetching the invoices together with the related data the template needs must issue at most 3 database queries in total, no matter how many invoices are returned.
- When there are no invoices, the table body shows a single row with the message `No invoices yet.`
- The `Customer`, `Invoice` and `InvoiceLine` models already exist in the `invoices` app; this PR adds a `total` property to `Invoice`, the view, the template (which extends the project's existing `base.html`), and the URL wiring.
Files touched
- invoices/models.py
- invoices/views.py
- invoices/urls.py
- config/urls.py
- templates/invoices/dashboard.html
--- invoices/models.py
+from decimal import Decimal
+
from django.db import models
return self.number
+ @property
+ def total(self):
+ return sum((line.amount for line in self.lines.all()), Decimal("0.00"))
+
class InvoiceLine(models.Model):
--- invoices/views.py
+from django.contrib.auth.decorators import login_required
+from django.shortcuts import render
+
+from .models import Invoice
+
+
+@login_required
+def invoice_dashboard(request):
+ invoices = Invoice.objects.order_by("-issued_on", "-id")[:500]
+ return render(request, "invoices/dashboard.html", {"invoices": invoices})
+
--- invoices/urls.py
+from django.urls import path
+
+from . import views
+