A robust and automated Django application for managing, generating, and sending invoices, with first-class support for Swiss QR-Bills and automated payment reconciliation.
This project is designed to be run as a containerized service, controlled via a powerful Django admin interface and automated through a set of REST API endpoints. It's perfect for small businesses, freelancers, or associations that need a streamlined invoicing workflow.
- Full Bill Lifecycle Management: Create, track, and manage bills from "Pending" to "Paid" through a clean Django admin interface.
- Recurring Invoices: Automatically generate bills on flexible schedules (e.g., monthly, quarterly, weekly) using powerful
pandasDateOffsets. - Swiss QR-Bill Generation: Automatically generates valid Swiss QR-Bill PDFs for every invoice, ensuring compliance and ease of payment for your clients.
- Automated Emailing:
- Dispatches newly generated bills to contacts via email, with the PDF invoice attached.
- Sends automated overdue reminders for unpaid bills.
- Automated Payment Reconciliation: Upload your bank's transaction CSV file to automatically match payments to open invoices and mark them as paid.
- REST API for Automation: A set of secure API endpoints to trigger billing tasks, perfect for
cronjobs or other scheduled task runners. - Containerized & Production-Ready: Comes with
Dockerfileanddocker-compose.ymlconfigurations for easy deployment. - Secure Authentication: Designed to integrate seamlessly with reverse-proxy authentication systems like Authelia.
- CI/CD Pipeline: Includes a GitHub Actions workflow for automated testing, Docker image building, and deployment to GitHub Container Registry.
- Backend: Django, Django REST Framework
- Database: PostgreSQL (recommended), compatible with other Django DBs.
- PDF Generation:
qrbillfor QR-bill data,cairosvgfor PDF rendering. Data Handling:pandasfor CSV processing and date calculations. - Web Server: Gunicorn with WhiteNoise for serving static files.
- Containerization: Docker & Docker Compose.
- CI/CD: GitHub Actions.
- Python 3.11+
- uv (for package management)
- Docker & Docker Compose (for running the application)
Follow these steps to get a local development server running.
-
Clone the Repository:
git clone https://github.com/enucatl/send-bills.git cd send-bills -
Set Up Virtual Environment & Install Dependencies:
# Create a virtual environment python -m venv .venv source .venv/bin/activate # Install all dependencies using uv uv sync --all-extras
-
Configure Environment Variables: The application uses
dj-database-urlto configure the database. Create a.envfile in the root directory for your local environment variables.# .env DATABASE_URL=postgres://user:password@localhost:5432/bills_db # DJANGO_SETTINGS_MODULE defaults to development, so it's not strictly needed here.
For a simpler start, you can use SQLite:
# .env DATABASE_URL=sqlite:///db.sqlite3
-
Run Database Migrations:
python src/send_bills/manage.py migrate
-
Run the Development Server: The local server uses a development middleware to simulate authentication. By default, you will be logged in as
devuser.python src/send_bills/manage.py runserver
You can now access the Django Admin at
http://127.0.0.1:8000/admin/.
For a more production-like local environment, you can use Docker Compose.
-
Create a
.envfile with your database configuration:# .env DATABASE_URL=postgres://user:password@host.home.arpa:5432/bills_db
-
Build and Run the Container: The
docker-compose.override.ymlis configured for local development.docker-compose up --build
The application will be available at
http://localhost:8000/.
The primary interface for this application is the Django Admin. The core workflow is as follows:
-
Create Creditors and Contacts:
- Go to the
Creditorssection and add your company's details (Name, IBAN, etc.). - Go to the
Contactssection and add your clients' details.
- Go to the
-
Create Bills:
- One-off Bills: Navigate to
Billsand click "Add bill". Fill in the details. The status will default toPending. - Recurring Bills: Navigate to
Recurring billsand "Add recurring bill". Define a template, amount, and afrequency(e.g.,MonthEnd,QuarterBegin).
- One-off Bills: Navigate to
-
Automate Billing Tasks (via API): The following API endpoints are designed to be called by a scheduler like
cron.POST /api/generate-recurring-bills/: Checks all active recurring schedules and creates newBillinstances for any that are due.POST /api/send-pending-bills/: Finds all bills withPendingstatus, generates PDFs, and emails them to the contacts.POST /api/mark-overdue-bills/: Scans for sent bills whose due date has passed and marks them asOverdue.POST /api/notify-overdue-bills/: Sends email reminders for all bills marked asOverdue.
Example
cronsetup:# Daily tasks 0 2 * * * curl -X POST http://your-app-url/api/mark-overdue-bills/ 0 3 * * * curl -X POST http://your-app-url/api/generate-recurring-bills/ 0 4 * * * curl -X POST http://your-app-url/api/send-pending-bills/ # Weekly reminder 0 5 * * 1 curl -X POST http://your-app-url/api/notify-overdue-bills/
-
Reconcile Payments:
- In the
Creditorsadmin list view, click the "Upload CSV" button. - Upload your bank transaction export (specifically formatted CSVs, see
src/send_bills/bills/tests/transactions.csvfor an example). - The system will parse the file, find payments matching the
SCORreference, and automatically mark the corresponding bills asPaid.
- In the
The project has a comprehensive test suite. To run the tests:
# Set a temporary in-memory database and run tests for the `bills` and `api` apps
DATABASE_URL="sqlite:///:memory:" uv run python src/send_bills/manage.py test bills apiThis application is built to be deployed as a Docker container.
For production, you must configure the following environment variables:
DJANGO_SECRET_KEY: A long, random string.DJANGO_ALLOWED_HOSTS: Comma-separated list of allowed hostnames (e.g.,bills.example.com).CSRF_TRUSTED_ORIGINS: Comma-separated list of trusted origins (e.g.,https://bills.example.com).DATABASE_URL: The full connection string for your PostgreSQL database.DJANGO_EMAIL_HOST: Your SMTP server hostname.DJANGO_EMAIL_PORT: Your SMTP server port.DJANGO_EMAIL_HOST_USER: Your SMTP username.DJANGO_EMAIL_HOST_PASSWORD: Your SMTP password.
The included GitHub Actions workflow (.github/workflows/deploy.yml) automates the following process on every push to main:
- Build & Test: Installs dependencies and
uv sync --all-extras
DATABASE_URL=$(vault kv get -field=uri kv/airflow/connections/djangodev) uv run pytest
DATABASE_URL=$(vault kv get -field=uri kv/airflow/connections/djangodev) .venv/bin/python src/send_bills/manage.py runserver
VERSION=$(uv run setuptools-git-versioning) docker compose up --build
docker compose build --build-arg VERSION=$(uv run setuptools-git-versioning)
docker compose -f docker-compose.yml up -d