Commit Graph
19 Commits
Author SHA1 Message Date
Marcel PeterkauandClaude Opus 5 31c1646571 Tell members which reference to put on a transfer
A data-review mail that lists the payment frequency but not how to pay leaves the
board matching anonymous transfers by hand. The mail now closes with the
reference to quote -- member number and full name, joined only where both exist
so a missing half cannot leave a dangling dash. Both are offered because either
identifies the payment on its own: a member who has forgotten their number falls
back on the name, and two members sharing a name are told apart by the number.

The note about the shortened IBAN moved out of the fixed template text into
{{data.iban_hint}}, filled only for members whose bank details are actually
listed -- it used to explain a masked IBAN to members who pay by transfer and see
no IBAN at all. It sits directly under the record as a parenthesised footnote,
which also keeps the dropped line from leaving a blank one behind.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 22:08:40 +02:00
Marcel PeterkauandClaude Opus 5 9e9bb7d668 Ask every member to check the data the club stores about them
The club has to keep its member data current, and until now that meant writing
to each member by hand. "Datenüberprüfung anfragen" in the members tab sends one
mail per member, each listing that member's own record: number, name, nickname,
birth date, contact data, address, status, member since, payment frequency, and
the bank details only for members who have any.

Two decisions the record itself forced:

A field with no value is printed as "(nicht hinterlegt)" rather than left out.
The point of the mail is to have gaps filled in, and a missing line is a gap
nobody sees.

The IBAN is masked down to its country code and last four digits. That is enough
to recognise the account, and it keeps a full account number out of a mail the
club sends to dozens of people at once.

Every member is listed as a recipient, with the live memberships that have an
address preselected -- a member who resigned at year's end may still need to
confirm their address, so the board can add them by hand. Members without an
address are skipped and reported instead of failing the run.

Delivery reuses the existing mail machinery: the configured delivery mode, one
SMTP/IMAP connection for the whole run, an archive copy in the member file, a
"data_review_email_sent" event, and the read-only guard before anything is
rendered. A member whose mail fails is reported as a warning and the run
continues -- one bad address must not stop a mailing to the whole club halfway
through. Because the run cannot be taken back, the recipient count is confirmed
once more before it starts.

Subject and text come from a new "Datenüberprüfung" template, editable like the
others, with {{data.sheet}} for the whole record and a {{#data}} block for a
layout of the board's own.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 22:05:38 +02:00
Marcel PeterkauandClaude Opus 5 528c24ad42 Clear every read-only marker when the store becomes writable again
"Erneut prüfen" refreshed the banner but left the window title and the status bar
reading "NUR LESEN" -- both were built once and never updated -- while the banner
itself asked for a restart that the recheck exists to avoid.

Title, status bar and banner are refreshed from one place now, so none of them can
be left behind, and the main window owns the title instead of app.py setting it
once at startup. The banner points at "Erneut prüfen" and says outright that no
restart is needed. Since the startup pass was skipped, its task list is empty
rather than current, so a successful recheck offers the housekeeper run that
fills it.

UI tests cover both directions of the recheck; their Tk root moved into a shared
conftest fixture, because a second root in another module invalidates the icon
images bound to the first.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 00:01:37 +02:00
Marcel PeterkauandClaude Opus 5 ae53c168fd Merge branch 'dev' into feature/read-only-store
dev gained the editable mail templates, which live in the store like everything
else -- so they follow the same read-only rules: the options dialog skips saving
them, save_mail_template() reports the store instead of a raw PermissionError,
and a store that cannot keep its own copy simply renders from the shipped
default.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 21:26:40 +02:00
Marcel PeterkauandClaude Opus 5 be042949a2 Keep CCMA usable when the member store is mounted read-only
The encrypted volume holding the member data can be mounted without write
access, but starting against such a store failed: the housekeeper takes a lock
file before doing anything, so its startup pass died with a PermissionError and
took the whole start with it.

The store is now probed with an actual write once at startup -- permissions,
mount options and filesystem state all matter, and only an attempt covers them
together -- and a read-only store opens as a read-only session. The housekeeper
is skipped rather than attempted, every write inside the repository goes through
one guard that reports ReadOnlyStoreError (a RepositoryError, so the dialogs
already handle it) instead of letting an OS error surface, and the services that
archive into the member file check before they start sending or rendering.

The session says so permanently: a warning banner above the tabs, "NUR LESEN" in
the window title and status bar, and refused actions explaining why. Program
settings still save -- they live in the user's config directory -- while the
store-backed ones are skipped with a notice. "Erneut prüfen" picks up a volume
that was remounted writable without restarting.

A store that was never initialized still fails, but says that creating one needs
write access.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 21:10:31 +02:00
Marcel PeterkauandClaude Opus 5 d6cd58a788 Render every outgoing e-mail from an editable text template
The wording of the dunning and SEPA pre-notification mails was hard-coded in
Python, so adjusting a single sentence required a new release. Both texts now
live in plain text templates that ship as defaults, are copied into the store's
templates/mail/ directory on first start and can be edited there or under
Optionen -> E-Mail-Vorlagen; an existing file is never overwritten and a deleted
one is restored from the shipped default.

A template carries its subject in the first line and the body after a blank
line. Placeholders use the same {{ ... }} syntax as the document templates and
share their member/organization values, so a name means the same thing in a
letter and in the mail that carries it. Unknown placeholders are rejected while
editing instead of during a send run, a line holding nothing but placeholders
that render empty is dropped, and {{#claims}} ... {{/claims}} repeats per entry.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 20:49:08 +02:00
Marcel Peterkau 0e3087a780 ci: add CCMA release builds 2026-06-23 20:19:53 +02:00
Marcel Peterkau 302170230a feat: Add Windows compatibility, PyInstaller build setup, and custom icon
- Add Windows LibreOffice detection fallback for soffice path
  - Check standard install locations (%PROGRAMFILES%, %PROGRAMFILES(X86)%)
  - Graceful fallback with clear error messages

- Add PyInstaller build infrastructure
  - build/ccma.spec: PyInstaller configuration with icon generation
  - build/build.ps1: Automated build script for standalone exe
  - main.py: Entry point for PyInstaller
  - Supports versioning and architecture tagging

- Create custom CCMA icon
  - Person + Gear symbol representing member administration
  - Cyan/White/Orange color scheme
  - Auto-converts PNG to ICO during build

- Update documentation
  - README: Windows PowerShell setup instructions
  - README: Linux/macOS bash setup instructions
  - README: Standalone executable build guide
  - pyproject.toml: Add 'build' extra with pyinstaller+pillow

- Add regression tests
  - Test office executable detection and Windows fallback
  - Verify all tests pass (80 passed)
2026-06-23 11:08:18 +02:00
Marcel Peterkau 576220ccd5 refactor: remove template timestamp aliases 2026-06-21 22:44:09 +02:00
Marcel Peterkau 3c842f29a3 feat: add template creation timestamps 2026-06-21 22:41:53 +02:00
Marcel Peterkau c58072fe45 feat: repeat claim items in document tables 2026-06-21 22:33:24 +02:00
Marcel Peterkau 6c7bf63280 feat: add member address and SEPA data 2026-06-21 22:14:45 +02:00
Marcel Peterkau 0622a22794 feat: add OpenDocument PDF templates 2026-06-21 22:10:16 +02:00
Marcel Peterkau e1d2b87ca1 feat: configure minimum splash duration 2026-06-21 18:48:08 +02:00
Marcel Peterkau e6d2f77d1e feat: add staged reminder workflow 2026-06-21 18:40:54 +02:00
Marcel Peterkau e7962f77e1 refactor: localize UI labels and store filenames 2026-06-21 18:25:58 +02:00
Marcel Peterkau 80d4d5ef90 feat: add itemized claims and payments 2026-06-21 18:20:55 +02:00
Marcel Peterkau 4bc1a8a200 feat: add scriptable housekeeper rule engine 2026-06-21 17:43:04 +02:00
Marcel Peterkau 4c6a1191ee first commit 2026-06-21 15:04:06 +02:00