Plans, entitlements, and usage tracking for Django SaaS apps.
Project description
mroudai-django-subscriptions
Reusable Django app for plans, subscriptions, entitlements, and usage limits. It does not process payments.
Features
- Plans with feature flags and numeric limits.
- Subscriptions scoped to a tenant or user.
- Deterministic entitlement resolution (
resolve_entitlements). - Optional per-tenant/user overrides and metered usage tracking.
- Grace periods and trials with sensible defaults.
- Django admin for plans, subscriptions, overrides, and usage counters.
Installation
pip install mroudai-django-subscriptions
Add to INSTALLED_APPS:
INSTALLED_APPS = [
# ...
"subscriptions",
]
Run migrations:
python manage.py migrate subscriptions
Settings
SUBSCRIPTIONS_TENANT_MODEL = None # e.g. "tenants.Tenant" or None
SUBSCRIPTIONS_USER_MODEL = None # defaults to AUTH_USER_MODEL
SUBSCRIPTIONS_DEFAULT_PLAN_SLUG = "free"
SUBSCRIPTIONS_TRIAL_DAYS_DEFAULT = 14
SUBSCRIPTIONS_GRACE_DAYS_DEFAULT = 7
SUBSCRIPTIONS_ENABLE_OVERRIDES = True
SUBSCRIPTIONS_ENABLE_USAGE = True
Tenancy rules:
- If
SUBSCRIPTIONS_TENANT_MODELis set, subscriptions are tenant-first; user is optional for attribution. - If it is not set, subscriptions are user-scoped.
Defining plans
Plans are static and hold flags + limits:
from subscriptions.models import Plan
Plan.objects.create(
name="Free",
slug="free",
features={"booking_ui": True, "multi_staff": False},
limits={"providers_max": 1, "bookings_per_month": 50},
)
Features must be booleans. Limits must be integers >= 0 or None for unlimited.
Assigning subscriptions
from subscriptions.services import assign_plan
# user-mode example
subscription = assign_plan(plan="pro", user=request.user)
This expires any current subscription for the same tenant/user and starts a new one. Trials default to SUBSCRIPTIONS_TRIAL_DAYS_DEFAULT.
Cancel with optional grace:
from subscriptions.services import cancel_subscription
cancel_subscription(subscription, at_period_end=False)
Resolving entitlements
from subscriptions.selectors import resolve_entitlements
entitlements = resolve_entitlements(user=request.user)
entitlements == {
"features": {"booking_ui": True, ...},
"limits": {"bookings_per_month": 50, ...},
"status": "ACTIVE", # TRIAL/GRACE/EXPIRED etc determined by dates
}
Overrides (optional)
If SUBSCRIPTIONS_ENABLE_OVERRIDES is True, use the admin or create EntitlementOverride rows to tweak features/limits per tenant or user. Overrides are applied on top of the plan.
Usage tracking (optional)
If SUBSCRIPTIONS_ENABLE_USAGE is True, increment and enforce limits for keys ending with _per_month:
from subscriptions.services import increment_usage, enforce_limit
enforce_limit(key="bookings_per_month", user=request.user)
increment_usage(key="bookings_per_month", user=request.user)
check_limit returns (allowed, remaining); enforce_limit raises ValidationError if exceeded.
Decorators
from subscriptions.services import require_feature, require_limit
@require_feature("booking_ui")
def create_booking(*, user, **kwargs):
...
@require_limit("bookings_per_month")
def make_booking(*, user, **kwargs):
...
Admin
The Django admin registers plans, subscriptions, overrides, and usage counters. JSON fields use a simple textarea for quick editing.
What this app deliberately does not do
- No payment gateway integration (PayWise/Stripe/etc.).
- No invoicing or receipts.
- No domain-specific booking logic.
Development
Tests (using SQLite by default):
python test django-subscriptions
SQLite works for development; PostgreSQL is recommended for production.
Release to PyPI
Install build tooling:
python install_upload_dependencies.py
Build and upload (requires TWINE_USERNAME/TWINE_PASSWORD or TWINE_TOKEN):
python upload.py
Licence
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mroudai_django_subscriptions-0.1.0.tar.gz.
File metadata
- Download URL: mroudai_django_subscriptions-0.1.0.tar.gz
- Upload date:
- Size: 12.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
08d0bf7da56450f8de6d263916ee1658d1482be0dc790c210192e96f5a98478b
|
|
| MD5 |
02c59d0bf3e0bb7e263f1362cc3adbb8
|
|
| BLAKE2b-256 |
74f119a15afe91414d92dd2580800603a276806763981a00b7d3f9ed5b58dd54
|
File details
Details for the file mroudai_django_subscriptions-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mroudai_django_subscriptions-0.1.0-py3-none-any.whl
- Upload date:
- Size: 15.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
97cedff2f1ae06db7eb8d7e28d8c34e1c516f87b64359c89390e70ad5f24ba04
|
|
| MD5 |
d4a5cdfbc99d6795ea92332625e1a199
|
|
| BLAKE2b-256 |
27d375fae8c766fc1709425f1b006d349df2fe5f9ae3e0aaec20309557900596
|