Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 168 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ DJANGO_PROGRAM = {
"publisher": "pycon", # default
"flight": "sponsors", # default
},
# Feature toggles (all default to True)
"features": {
"registration_enabled": True,
"sponsors_enabled": True,
"travel_grants_enabled": True,
"programs_enabled": True,
"pretalx_sync_enabled": True,
"public_ui_enabled": True,
"manage_ui_enabled": True,
"all_ui_enabled": True,
},
# General
"cart_expiry_minutes": 30, # default
"pending_order_expiry_minutes": 15, # default
Expand Down Expand Up @@ -93,6 +104,157 @@ Most conferences can ignore this section entirely.
| `currency_symbol` | `str` | `"$"` | Display symbol for the currency. |
| `max_grant_amount` | `int` | `3000` | Maximum travel grant amount in the configured currency. |

### Feature toggles

Feature toggles disable entire modules and UI sections per-conference. Every toggle
defaults to `True` (enabled). Disable a module by setting its flag to `False` in
settings, or override it per-conference through the database.

#### Settings defaults

Add a `features` dict to `DJANGO_PROGRAM` in your Django settings:

```python
DJANGO_PROGRAM = {
"features": {
"registration_enabled": True,
"sponsors_enabled": True,
"travel_grants_enabled": False, # disable travel grants globally
"programs_enabled": True,
"pretalx_sync_enabled": True,
"public_ui_enabled": True,
"manage_ui_enabled": True,
"all_ui_enabled": True, # master switch for all UI
},
# ... other settings ...
}
```

Changing these values requires a server restart.

#### Available toggles

**Module toggles** control backend functionality:

| Key | Default | Controls |
|---|---|---|
| `registration_enabled` | `True` | Ticket types, cart, checkout, orders |
| `sponsors_enabled` | `True` | Sponsor levels, benefits, comp vouchers |
| `travel_grants_enabled` | `True` | Travel grant applications and review |
| `programs_enabled` | `True` | Activities and signups |
| `pretalx_sync_enabled` | `True` | Speaker/talk/room sync from Pretalx |

**UI toggles** control interface visibility:

| Key | Default | Controls |
|---|---|---|
| `public_ui_enabled` | `True` | Public-facing conference pages |
| `manage_ui_enabled` | `True` | Organizer management dashboard |
| `all_ui_enabled` | `True` | Master switch -- when `False`, both `public_ui` and `manage_ui` are forced off regardless of their individual values |

#### Per-conference database overrides

Each conference can override the global defaults through a `FeatureFlags` row in the
database. These overrides take effect immediately without a server restart.

The `FeatureFlags` model uses nullable booleans with three states:

- **`None`** (blank) -- use the default from `DJANGO_PROGRAM["features"]`
- **`True`** -- force the feature on for this conference
- **`False`** -- force the feature off for this conference

Resolution order for each flag:

1. If the conference has a `FeatureFlags` row with an explicit `True` or `False`, that value wins.
2. Otherwise, the default from `DJANGO_PROGRAM["features"]` is used.
3. For `public_ui` and `manage_ui`, the `all_ui_enabled` master switch is evaluated first.

#### Django admin

Open the Conference admin page. The **Feature flags** inline appears below the
conference fields, grouped into "Module Toggles" and "UI Toggles". Each dropdown
offers three choices:

- **Default (enabled)** -- inherit from settings
- **Yes -- force ON** -- override to enabled
- **No -- force OFF** -- override to disabled

Feature flags are also available as a standalone admin model at
**Conference > Feature flags** for a cross-conference overview.

#### Checking features in Python code

Use `is_feature_enabled()` to check a toggle at runtime:

```python
from django_program.features import is_feature_enabled

# Check against global settings only
if is_feature_enabled("registration"):
...

# Check with per-conference DB override
if is_feature_enabled("sponsors", conference=my_conference):
...
```

Raise a 404 when a feature is disabled:

```python
from django_program.features import require_feature

def my_view(request):
require_feature("registration", conference=request.conference)
# ... view logic ...
```

Guard a class-based view with the `FeatureRequiredMixin`:

```python
from django_program.features import FeatureRequiredMixin

class TicketListView(ConferenceMixin, FeatureRequiredMixin, ListView):
required_feature = ("registration", "public_ui")
```

The mixin checks all listed features during `dispatch()`. If the view also uses
`ConferenceMixin` (placed before `FeatureRequiredMixin` in the MRO), per-conference
overrides are picked up automatically from `self.conference`.

#### Using features in templates

Add the context processor to your `TEMPLATES` setting:

```python
TEMPLATES = [
{
"OPTIONS": {
"context_processors": [
# ... existing processors ...
"django_program.context_processors.program_features",
],
},
},
]
```

Then use `program_features` in your templates to conditionally render sections:

```html+django
{% if program_features.registration_enabled %}
<a href="{% url 'registration:ticket-list' %}">Buy Tickets</a>
{% endif %}

{% if program_features.sponsors_enabled %}
<a href="{% url 'sponsors:sponsor-list' %}">Our Sponsors</a>
{% endif %}
```

The context processor resolves each flag through `is_feature_enabled()`, so master
switch logic and per-conference DB overrides are applied. When the request has a
`conference` attribute (set by middleware or the view), that conference's `FeatureFlags`
row is consulted automatically.

### Accessing config in code

```python
Expand Down Expand Up @@ -145,8 +307,14 @@ slug = "pycon-us-2027" # optional, auto-generated from name
venue = "Convention Center" # optional
pretalx_event_slug = "pycon-us" # optional, for Pretalx sync
website_url = "https://..." # optional
total_capacity = 2500 # optional, 0 = unlimited (default)
```

`total_capacity` sets the maximum number of tickets sold across all ticket types for the
entire conference. Add-ons do not count toward this limit. Set to `0` or omit entirely
for unlimited capacity. See [Global Ticket Capacity](registration-flow.md#global-ticket-capacity)
for enforcement details.

### Sections (required, at least one)

```toml
Expand Down
14 changes: 14 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ Built for PyCon US but designed to work for any conference that uses Django.

Speaker and schedule sync architecture, schema regeneration, and the pretalx-client package.

.. grid-item-card:: Programs & Activities
:link: programs-activities
:link-type: doc

Travel grants, sprints, tutorials, open spaces, and activity signups.

.. grid-item-card:: Management Dashboard
:link: management-dashboard
:link-type: doc

Financial overview, voucher bulk generation, and organizer tools.

.. grid-item-card:: API Reference
:link: api/index
:link-type: doc
Expand Down Expand Up @@ -103,6 +115,8 @@ Quick Start
getting-started/index
configuration
registration-flow
programs-activities
management-dashboard

.. toctree::
:maxdepth: 2
Expand Down
136 changes: 136 additions & 0 deletions docs/management-dashboard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# Management Dashboard

The management dashboard is the organizer-facing interface for administering a conference. It lives under the `/manage/` URL prefix (configured in your project's `urls.py`) and requires authentication. All conference-scoped pages sit under `/manage/<conference-slug>/`.

Access to the standard management views is restricted to users who meet at least one of these criteria:

- Django superuser
- Holds the `program_conference.change_conference` permission

The financial overview dashboard at `/manage/<conference-slug>/financial/` additionally allows access to users who belong to the "Program: Finance & Accounting" group.

The sidebar organizes features into sections: **Content** (sections, rooms, speakers, talks, schedule, overrides), **Registration** (financial overview, orders, ticket types, add-ons, vouchers), **Sponsors** (levels, sponsors), and **Programs** (activities, travel grants).

---

## Financial Overview

The financial overview dashboard gives organizers a single-page summary of revenue, orders, payments, and ticket sales for a conference.

**URL**: `/manage/<conference-slug>/financial/`

Navigate to it from the sidebar under **Registration > Financial**.

### Summary Cards

Four headline metrics appear at the top of the page:

| Card | What It Shows |
|---|---|
| **Net Revenue** | Gross revenue from paid orders minus total refunds. Gross revenue is shown beneath when refunds exist. |
| **Total Orders** | Count of all orders in any status. Shows the paid count below when paid orders exist. |
| **Active Carts** | Number of open, non-expired carts. |
| **Credits Outstanding** | Remaining spendable balance of available credits. Shows the total applied amount beneath. |

Net revenue is calculated as: `SUM(total) of paid orders - SUM(amount) of credits linked to source orders`. Refund amounts come from `Credit` records tied to source orders rather than summing refunded order totals, so partial refunds are counted accurately.

### Orders by Status

A table breaking down order counts by status: **Paid**, **Pending**, **Refunded**, **Partial Refund**, and **Cancelled**.

### Carts by Status

Counts for each cart state: **Active** (open and not expired), **Checked Out**, **Expired**, and **Abandoned**.

### Payments by Method

For each payment method (Stripe, manual, etc.), the dashboard shows the number of payments and total dollar amount collected through that method.

### Ticket Type Sales

A per-ticket-type breakdown showing:

- **Ticket Type** name
- **Price** per unit
- **Sold** count (tickets on paid and partially-refunded orders)
- **Remaining** inventory (or an infinity symbol for uncapped ticket types)
- **Revenue** generated by that ticket type

### Recent Orders

The 20 most recent orders across all statuses, showing reference number (linked to the order detail page), user email, status badge, total, and creation date.

### Active Carts

All currently open, non-expired carts listing the user, item count, creation time, and expiration time.

---

## Voucher Management

### Bulk Code Generation

Generate a batch of voucher codes from a single form instead of creating them one at a time.

**URL**: `/manage/<conference-slug>/vouchers/bulk/generate/`

Navigate to it from the voucher list page or go directly to the URL. After generation, the dashboard redirects to the voucher list with a success message.

### Form Fields

| Field | Required | Description |
|---|---|---|
| **Prefix** | Yes | A fixed string prepended to every generated code (max 20 characters). Use something descriptive like `SPEAKER-` or `SPONSOR-`. |
| **Count** | Yes | Number of codes to create. Minimum 1, maximum 500. |
| **Voucher Type** | Yes | The discount model: **Complimentary** (100% off), **Percentage discount**, or **Fixed amount discount**. |
| **Discount Value** | Yes | The percentage (0--100) or fixed dollar amount. Ignored for comp vouchers. Defaults to 0. |
| **Applicable Ticket Types** | No | Restrict these vouchers to specific ticket types. Leave unchecked for all ticket types. Rendered as checkboxes scoped to the current conference. |
| **Applicable Add-ons** | No | Restrict these vouchers to specific add-ons. Leave unchecked for all add-ons. Rendered as checkboxes scoped to the current conference. |
| **Max Uses** | Yes | Maximum number of times each individual code can be redeemed. Defaults to 1. |
| **Valid From** | No | Start of the validity window (datetime picker). Leave blank for immediately valid. |
| **Valid Until** | No | End of the validity window (datetime picker). Leave blank for no expiration. |
| **Unlocks Hidden Tickets** | No | When checked, these vouchers reveal ticket types that are hidden behind a voucher requirement. |

### Generated Code Format

Each code follows the pattern `{prefix}{8 random characters}`. The random portion uses uppercase letters and digits (A-Z, 0-9) generated with `secrets.choice` for cryptographic randomness. Codes are checked against existing vouchers for the same conference and prefix before insertion.

All vouchers in the batch are created in a single database transaction. If any step fails, the entire batch is rolled back and no partial codes are left behind.

### After Generation

On success, the form redirects to the voucher list at `/manage/<conference-slug>/vouchers/` and displays a message confirming how many codes were created and the prefix used. Each generated voucher appears in the standard voucher list where it can be individually edited.

---

## Other Dashboard Features

The management sidebar exposes several additional views beyond financial reporting and voucher generation:

**Content**

- **Dashboard** -- Conference overview with key stats and quick actions.
- **Settings** -- Edit conference name, dates, slug, and configuration.
- **Sections** -- Create and manage conference sections (tracks or categories).
- **Rooms** -- Manage physical or virtual rooms for scheduling.
- **Speakers** -- Browse and view speaker profiles synced from Pretalx.
- **Talks** -- List, filter by submission type, view details, and edit talks. The sidebar shows submission type sub-navigation with counts.
- **Schedule** -- View and edit schedule slots.
- **Overrides** -- Override Pretalx-synced data for talks, speakers, rooms, sponsors, and submission type defaults.

**Registration**

- **Orders** -- Full order list with filtering, detail views, and manual payment recording.
- **Ticket Types** -- Create and edit ticket types with pricing, availability windows, and stock limits.
- **Add-ons** -- Manage conference add-ons (t-shirts, tutorials, etc.).
- **Vouchers** -- Individual voucher CRUD alongside the bulk generation tool.

**Sponsors**

- **Levels** -- Define sponsorship tiers and their associated benefits.
- **Sponsors** -- Manage individual sponsors and their level assignments.

**Programs**

- **Activities** -- Create sprints, tutorials, and open spaces with signup caps. Includes per-activity dashboards with attendee export and waitlist promotion.
- **Travel Grants** -- Review applications, send messages, and record disbursements. Includes receipt review queue with approve/flag workflow.
Loading