Indico Group Registration
Participant-run group registration with plan-based discounts for Indico 3.3.
A participant picks a group plan while registering, gets a code and a join link, and shares them however they like. Everyone who joins pays that plan's rate straight away. The group confirms itself the moment the plan's seat count is filled — there is no button to press. If it never fills, the plugin reprices it at the reconciliation deadline and reports what each member still owes.
Organizers set the plans and the disclaimer. They never have to create a group.
How it works
Plans
An organizer defines plans per registration form. A plan is a seat count and a rate:
[
{"id": "p3", "label": "Group of 3", "size": 3, "type": "percent", "value": 10},
{"id": "p10", "label": "Group of 10", "size": 10, "type": "percent", "value": 15},
{"id": "p25", "label": "Group of 25", "size": 25, "type": "amount", "value": 50}
]
The seat count is both the target and the cap: filling it confirms the group, and the group is then full.
Lifecycle
| State | What it means |
|---|---|
forming |
Seats filling. Members pay the chosen plan's rate, whenever they like. |
confirmed |
The seat count was reached. Automatic. The rate is final and never gets worse. |
short |
The deadline passed with seats empty. Repriced to whatever the group does qualify for; balances may be due. |
dissolved |
A manager took it apart. Everyone is back on the standard rate. |
The only transition a human triggers is dissolution.
Reconciliation, and the one thing to know before enabling this
Members may pay before their group fills. If the group then falls short, the plugin reprices everyone — including people who have already paid.
Indico has no concept of a partial payment or a balance. A transaction is
one amount against one registration, and its checkout would charge the whole
new price again rather than the difference. So an already-paid member whose
price rises stays complete as far as Indico is concerned, and only this
plugin knows they owe anything.
The plugin gives organizers a Balances due list (paid amount, new price, delta) and e-mails every affected member, but a person collects the money — at the desk or by transfer, recorded as a manual payment. Two settings soften it:
- set the reconciliation deadline well before the event, so balances surface while there is still time to chase them;
- turn off allow early payment if you would rather not chase anyone.
Sharing a group
The group panel shows the group code and the join link, each with a copy button. The plugin sends no invitations. There is no invite box and no way for a participant to make your server e-mail a stranger. Leaders share the link themselves.
The plugin does send e-mails that nobody can trigger on demand: group confirmed, group short with the new rate, and group dissolved.
Installation
Do not let pip upgrade Indico by accident. This plugin declares
indico>=3.3,<3.4, and pip will happily upgrade an installed Indico to satisfy that. An Indico whose code is newer than its database fails on every page that touches a migrated table — the whole site, not just registration. Install into the existing Indico virtualenv and check what pip says it is about to do:/opt/indico/.venv/bin/pip install indico-plugin-group-registrationIf Indico appears in the "Installing collected packages" line, run the core migrations before restarting (see below). To keep pip away from Indico entirely:
/opt/indico/.venv/bin/pip install --no-deps indico-plugin-group-registration
Add it to indico.conf:
PLUGINS = {'group_registration'}
Then migrate. --all-plugins runs core migrations too, which is what you
want — if pip moved Indico forward, this is the step that moves the database
with it:
indico db --all-plugins upgrade
Sanity-check that nothing is pending:
indico db alembic current # should match
indico db alembic heads
Build the assets:
python bin/maintenance/build-assets.py plugin /path/to/IndicoGroupRegistration
Restart Indico and its Celery workers — the reconciliation task runs every fifteen minutes from the Celery beat schedule.
If the site is throwing UndefinedColumn errors
Indico's code is ahead of its database. Nothing to do with this plugin's tables; run the migrations:
indico db --all-plugins upgrade
Or put Indico back where it was and migrate later:
/opt/indico/.venv/bin/pip install 'indico==<your previous version>'
Configuration
Event management → Group registration, then pick a registration form. Nothing changes on a form until group registration is enabled for it.
| Setting | Default | Notes |
|---|---|---|
| Plans | – | JSON, validated on save |
| Discount applies to | Registration fee | Or the whole price, including paid options |
| Reconciliation deadline | Registration end | Set it well before the event |
| Allow paying before the group fills | on | |
| Groups per person | 1 | 0 for no limit |
| Count registrations awaiting approval | on | Withdrawn and rejected never count |
| Reprice a confirmed group that loses a member | off | Nobody should be rebilled over somebody else's moderation |
| Disclaimer | a sensible default | Versioned; the version and time of acceptance are stored per membership |
Enabling group registration provisions two fields on the form:
ext__group_plan— the plan picker the participant fills in. Put it wherever you like in the form.ext__group_discount— a manager-only field carrying the discount. It is locked, written only by the plugin, and appears as a named line on the invoice. Leave it alone; the plugin puts it back if it is removed.
Development
pip install -e '.[dev]'
pytest
ruff check .
The tests here are unit tests over the money arithmetic and the code handling; they do not need a database or Indico's pytest plugin.
How it hooks into Indico
Nothing in core is patched. See docs/EXTENSION-POINTS.md for the full map
with file-and-line references, and docs/PLAN.md for the design. The short
version:
- registration field types via
signals.core.get_fields - the registration lifecycle via
registration_created,registration_deletedandregistration_state_updated is_field_data_lockedto keep core out of the plugin's own fieldregistrant_list_itemsfor the Group columnbefore-render-registration-infofor the group panel- the React field registry via
regformCustomFields get_template_customization_pathsto name the discount on the checkout page, using{% extends '~...' %}so it inherits the core template rather than forking it
Licence
MIT.
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 indico_plugin_group_registration-0.1.1.tar.gz.
File metadata
- Download URL: indico_plugin_group_registration-0.1.1.tar.gz
- Upload date:
- Size: 39.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66e7e2c86167867f29206d4aefad6c42010cb2231c9f18a7db73a75f92506390
|
|
| MD5 |
854a6cac42ed8ca3e2cbf265a1334f55
|
|
| BLAKE2b-256 |
0ceb3fc73f3012d1051947e52e4b144e16ed2e1e3696ebe75ec9b0b7defa83a5
|
Provenance
The following attestation bundles were made for indico_plugin_group_registration-0.1.1.tar.gz:
Publisher:
publish.yml on RobotHanzo/IndicoGroupRegistration
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
indico_plugin_group_registration-0.1.1.tar.gz -
Subject digest:
66e7e2c86167867f29206d4aefad6c42010cb2231c9f18a7db73a75f92506390 - Sigstore transparency entry: 2665528268
- Sigstore integration time:
-
Permalink:
RobotHanzo/IndicoGroupRegistration@2d8434776245d9add8e99ba7f26d50e3debb70e2 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/RobotHanzo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2d8434776245d9add8e99ba7f26d50e3debb70e2 -
Trigger Event:
release
-
Statement type:
File details
Details for the file indico_plugin_group_registration-0.1.1-py3-none-any.whl.
File metadata
- Download URL: indico_plugin_group_registration-0.1.1-py3-none-any.whl
- Upload date:
- Size: 57.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea0b5a97ba5df47258cabb3fdd376fa007c0c7ec26819c948a770d4770f5b203
|
|
| MD5 |
b3c1f97949d3ff042bb14252f1bdf31d
|
|
| BLAKE2b-256 |
06531fc0adc5fc51c6f2c14ada08987470e0643e15b0b2ffab487c162cc3020c
|
Provenance
The following attestation bundles were made for indico_plugin_group_registration-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on RobotHanzo/IndicoGroupRegistration
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
indico_plugin_group_registration-0.1.1-py3-none-any.whl -
Subject digest:
ea0b5a97ba5df47258cabb3fdd376fa007c0c7ec26819c948a770d4770f5b203 - Sigstore transparency entry: 2665528335
- Sigstore integration time:
-
Permalink:
RobotHanzo/IndicoGroupRegistration@2d8434776245d9add8e99ba7f26d50e3debb70e2 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/RobotHanzo
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2d8434776245d9add8e99ba7f26d50e3debb70e2 -
Trigger Event:
release
-
Statement type: