mirror of
https://git.hiabuto.net/C3MA/CCMA.git
synced 2026-07-01 19:26:53 +02:00
221 lines
7.8 KiB
Markdown
221 lines
7.8 KiB
Markdown
# CCMA - Chaotic Creature Member Administration
|
|
|
|
File-based member administration for Chaos Computer Club Mannheim e.V.
|
|
|
|
The member store remains readable without this application. Every member has a
|
|
directory containing `member.json`, `contributions.json`, an append-only
|
|
`events.jsonl`, and a `files/` directory.
|
|
|
|
## Development
|
|
|
|
Requires Python 3.11+ with Tk support.
|
|
PDF generation from document templates additionally requires LibreOffice or
|
|
OpenOffice with a `soffice` command available on the system.
|
|
|
|
### Windows (PowerShell)
|
|
|
|
```powershell
|
|
python -m venv .venv
|
|
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
|
|
.\.venv\Scripts\ccma.exe
|
|
```
|
|
|
|
For development tools and tests, install the `dev` extra as well:
|
|
|
|
```powershell
|
|
.\.venv\Scripts\python.exe -m pip install -e .[dev]
|
|
```
|
|
|
|
Alternatively, without installation:
|
|
|
|
```powershell
|
|
$env:PYTHONPATH = "src"
|
|
.\.venv\Scripts\python.exe -m ccma
|
|
```
|
|
|
|
### Linux/macOS
|
|
|
|
```bash
|
|
python -m venv .venv
|
|
.venv/bin/pip install -r requirements.txt
|
|
.venv/bin/ccma
|
|
```
|
|
|
|
For development tools and tests, install the `dev` extra as well:
|
|
|
|
```bash
|
|
.venv/bin/pip install -e '.[dev]'
|
|
```
|
|
|
|
Alternatively, without installation:
|
|
|
|
```bash
|
|
PYTHONPATH=src python -m ccma
|
|
```
|
|
|
|
If LibreOffice is installed on Windows but `soffice` is not in `PATH`, CCMA
|
|
also checks the default install locations under `%PROGRAMFILES%` and
|
|
`%PROGRAMFILES(X86)%`.
|
|
|
|
## Building standalone executables
|
|
|
|
CCMA uses the same PyInstaller-based release flow locally and in CI. The
|
|
single-file executables are built from `build/ccma.spec`.
|
|
|
|
### Windows standalone build
|
|
|
|
```powershell
|
|
cd build
|
|
.\build.ps1
|
|
```
|
|
|
|
This creates two executables in the `dist/` directory:
|
|
- `ccma.exe` (generic)
|
|
- `ccma-<version>-windows-<arch>.exe` (version and architecture-specific, e.g. `ccma-0.1.0-windows-amd64.exe`)
|
|
|
|
The build script automatically:
|
|
- Creates a venv if missing
|
|
- Installs dependencies and PyInstaller
|
|
- Generates a Windows icon from the CCMA icon
|
|
- Runs PyInstaller to bundle the application
|
|
|
|
### Linux standalone build
|
|
|
|
```bash
|
|
python3 -m venv .venv
|
|
. .venv/bin/activate
|
|
python -m pip install -U pip
|
|
pip install -r requirements.txt
|
|
pip install pyinstaller
|
|
python -m PyInstaller --noconfirm --clean build/ccma.spec
|
|
```
|
|
|
|
This creates `dist/ccma`. In CI, release builds additionally rename artifacts
|
|
to `ccma-<version>-linux-<arch>` and `ccma-<version>-windows-<arch>.exe`.
|
|
|
|
### CI release builds
|
|
|
|
The Gitea workflows use the central `ci-templates` submodule and
|
|
`ci-config.yaml` to run PR checks, Linux smoke builds, and release packaging for
|
|
Linux amd64, Linux arm64, and Windows amd64. A release build is skipped when the
|
|
commit message contains `[nobuild]`.
|
|
|
|
On first start, select or create the central member-store directory. The
|
|
`VERSION` file is the single source for application and package versions.
|
|
|
|
The splash screen remains visible for at least five seconds by default. This
|
|
advanced setting is intentionally not exposed in the options dialog. It can be
|
|
changed directly in `config.json`, including disabling the minimum with `0`:
|
|
|
|
```json
|
|
"splash_minimum_seconds": 0
|
|
```
|
|
|
|
## Store layout
|
|
|
|
```text
|
|
member-store/
|
|
├── repository.json
|
|
├── housekeeper.json
|
|
├── rules/
|
|
├── templates/
|
|
│ ├── Forderung mit Positionen.fodt
|
|
│ ├── Mahnung.fodt
|
|
│ └── Mitglied.fodt
|
|
└── members/
|
|
└── <uuid>/
|
|
├── member.json
|
|
├── contributions.json
|
|
├── events.jsonl
|
|
└── files/
|
|
```
|
|
|
|
## Document templates
|
|
|
|
CCMA reads OpenDocument templates (`.fodt`, `.odt`, or `.ott`) from the
|
|
store's `templates/` directory. The three initial `.fodt` files are editable
|
|
with LibreOffice/OpenOffice and are copied only when their filename does not
|
|
already exist. PDF files are generated locally and stored below the member's
|
|
`files/documents/` directory. No office document content is sent to an
|
|
external service.
|
|
|
|
Placeholders use `{{group.field}}`. Available values include:
|
|
|
|
- Member: `member.number`, `member.first_name`, `member.last_name`,
|
|
`member.full_name`, `member.email`, `member.birth_date`, `member.status`,
|
|
`member.accepted_at`, `member.started_at`, `member.phone`, `member.street`,
|
|
`member.address_addition`, `member.postal_code`, `member.city`,
|
|
`member.country`, `member.address_line`, `member.account_holder`,
|
|
`member.iban`, `member.bic`, `member.mandate_reference`,
|
|
`member.mandate_signed_at`, `member.mandate_revoked_at`,
|
|
`member.mandate_active`
|
|
- Claim: `claim.id`, `claim.title`, `claim.due_date`, `claim.total`,
|
|
`claim.created_date`, `claim.created_at`, `claim.paid`, `claim.balance`,
|
|
`claim.status`, `claim.items`
|
|
- Reminder: `reminder.id`, `reminder.level`, `reminder.name`,
|
|
`reminder.status`, `reminder.created_at`, `reminder.sent_at`,
|
|
`reminder.payment_deadline`, `reminder.payment_deadline_days`,
|
|
`reminder.fee`, `reminder.detail`, `reminder.channel`
|
|
- Document: `document.created_date`, `document.created_at`
|
|
- Current time: `current_date`, `current_datetime`
|
|
- Organization: `organization.name`, `organization.street`,
|
|
`organization.postal_code`, `organization.city`, `organization.country`,
|
|
`organization.address_line`, `organization.email`, `organization.phone`,
|
|
`organization.website`, `organization.iban`, `organization.bic`,
|
|
`organization.creditor_id`
|
|
|
|
Claim placeholders are available from a claim tab. Reminder placeholders are
|
|
available when a reminder row is selected before opening the document dialog.
|
|
Unknown or unavailable placeholders stop generation with a clear error rather
|
|
than producing an incomplete letter.
|
|
|
|
To repeat a formatted table row for every claim item, place both loop markers
|
|
inside the same template row:
|
|
|
|
```text
|
|
{{#claim.items}}
|
|
{{item.description}} | {{item.type}} | {{item.quantity}} | {{item.unit_price}} | {{item.amount}}
|
|
{{/claim.items}}
|
|
```
|
|
|
|
The opening marker may share the first cell with its value and the closing
|
|
marker may share the last cell. CCMA removes both markers and clones the whole
|
|
row, including its formatting, once per item. With no items, the template row
|
|
is removed. A loop that is not closed in the same row is rejected.
|
|
|
|
## Housekeeper rules
|
|
|
|
The housekeeper runs every rule for every member. Built-in Python rules live in
|
|
`ccma/rules/scripts/`. A member store can add rules in its `rules/` directory.
|
|
If a store rule has the same filename as a built-in rule, the store version
|
|
replaces the built-in version.
|
|
|
|
Store rules are trusted executable Python code. Only place reviewed rules from
|
|
trusted sources in this directory. Rules return structured `RuleAction` objects;
|
|
CCMA performs all file writes, duplicate checks, audit events, and atomic updates.
|
|
|
|
`housekeeper.json` is written only after a complete run. Each refreshed task gets
|
|
the pending run ID. A failed run therefore cannot advance the stored counter or
|
|
silently resolve existing tasks.
|
|
|
|
## Claims and payments
|
|
|
|
Claims are stored in the member's `contributions.json`. A claim consists of
|
|
signed line items; fees increase and credits reduce its total. Payments remain
|
|
separate records and allocations connect one payment to one or more claims.
|
|
This supports partial payments, shared annual payments, unallocated credit, and
|
|
optional GnuCash transaction IDs without duplicating a bank transaction.
|
|
|
|
Claim status and outstanding balance are derived from line items and payment
|
|
allocations. Reminders are separate processes and only change the amount when
|
|
they explicitly add a fee line item. Every change is also appended to the
|
|
member's `events.jsonl` audit trail.
|
|
|
|
Overdue claims are evaluated by the reminder rule. It creates housekeeper tasks
|
|
for the next configured reminder level. Reminder drafts do not change a claim;
|
|
only confirming actual dispatch starts the new payment deadline and adds an
|
|
optional fee line item. A claim-level dunning hold suppresses automatic and
|
|
manual reminder preparation until it is removed or expires.
|
|
|
|
Do not place a real member store inside the source repository.
|