Commit Graph
46 Commits
Author SHA1 Message Date
Marcel PeterkauandClaude Sonnet 5 d4dfd0066a Fix reminder dialog sizing, item editing, and old-repo fee defaults
The dialog's base class sets resizable(False, False) before this
subclass's content (including the preset-populated items table) exists,
so its initial size stayed locked to a too-small guess and cut off the
bottom. It now explicitly sizes to its actual content after everything,
including the selected preset's items, has been built.

The items table only supported add/remove -- there was no way to change
an already-added row's amount (e.g. after picking the Rücklastschrift
preset, its prefilled fee couldn't be adjusted). Selecting a row now
loads it into the description/amount fields, and a new "Aktualisieren"
button applies edits back to that row.

The Rücklastschrift preset label was missing the "Stufe N:" prefix the
other presets have, inconsistent for no reason.

Also fixed a real gap: repositories created before standard_fee_items
existed had no such key in repository.json at all, so Optionen showed
an empty Standardpositionen table instead of the built-in defaults.
get_reminder_policy() now backfills the defaults when the key is
missing entirely, while still respecting a list the board intentionally
emptied and saved.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 03:13:04 +02:00
Marcel PeterkauandClaude Sonnet 5 a1719cad5e Handle failed direct debits through the same reminder mechanism
A Rücklastschrift is still the member's own failure to ensure cover or
provide valid bank details, so it belongs in the same escalation ladder
as a regular reminder -- it now occupies whatever level the claim is next
due for, alongside a "Rücklastschrift" preset next to the existing
Mahnstufe presets.

Mahnung vorbereiten no longer lets the board pick a level (it's computed
automatically from what's already been sent, since the sequencing was
already server-enforced) and replaces the single fee field with a small
items table (Beschreibung + Betrag), so a reminder can carry several
charges at once -- e.g. Rücklastschriftgebühr plus Bankgebühr plus Porto
-- each landing on the claim as its own line item instead of one lump
sum under a generic label. The description field offers the configured
standard texts but stays free-editable.

Those standard texts and amounts, plus the dunning levels themselves
(name/fee/deadline), are now configurable from Optionen -> Mahnungen
instead of only being editable by hand-editing repository.json, which
was the case for the whole reminder policy until now. Cleaned up
reminder_fee/failed_debit_fee on contribution rules while at it -- both
were unused leftovers superseded by this.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 03:13:04 +02:00
Marcel PeterkauandClaude Sonnet 5 ee99577b20 Run the housekeeper for a single member, optionally retroactively
Add a "Hausmeister für dieses Mitglied" button to the member view. It
runs every rule scoped to just that member -- e.g. after editing a
contribution override or payment frequency, to recompute their claims on
demand instead of waiting for or triggering a full run over every
member. A checkbox lets the board force retroactive claim creation for
just that one run, without changing the application-wide default
setting.

Housekeeper.run() gained member_id and retroactive_claims parameters.
Scoping to one member skips the asset checks and leaves every other
member's tasks completely untouched, since their rules never ran this
pass and so fall outside the resolved-scope set that
_resolve_stale_tasks uses to decide what to clear.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 00:59:01 +02:00
Marcel PeterkauandClaude Sonnet 5 2484a1631d Add individually agreed membership fees (contribution overrides)
Members are sometimes given a fee that deviates from the regular
schedule -- e.g. a reduced rate for students -- for a specific period.
Add a per-member "Beitrag" tab where such deviations can be recorded
with a month-granular date range (Ab/Bis), a mandatory reason, and
either a fixed annual amount or a percentage discount off whichever
base rate is in effect at the time.

Data model: ContributionData gets a contribution_overrides list, each
entry validated (month format, Bis >= Ab, non-overlapping ranges per
member, reason required) and CRUD'd through the repository
(record/update/delete/get_contribution_override), consistent with how
donations already work.

Integration: contribution_claims.py now computes each membership-fee
claim's amount month by month instead of a single rate for the whole
billing period, picking up whichever override (if any) covers each
individual month. That handles an override starting or ending mid
period correctly (e.g. a semiannual payer whose discount begins in
March) without changing behavior for members without overrides.
Already-created claims are never recalculated retroactively, matching
how changes to the global contribution rates already behave.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-15 00:57:51 +02:00
Marcel PeterkauandClaude Sonnet 5 195ae0e228 Replace the GnuCash import checkbox column with native multi-select
Selecting bookings to import now uses the Treeview's own multi-selection
(click, Ctrl+click, Shift+click for ranges) instead of a dedicated
checkbox column that had to be clicked precisely -- more standard and
much faster for marking many rows at once.

Bookings matching an existing payment's date+amount are no longer
blocked from selection; they're still flagged (red row, "Bereits
vorhanden"). If any selected booking is such a duplicate, importing now
asks whether to skip those or instead adopt the booking's description
onto the already-recorded payment. That relabeling is handled by a new
repository.update_payment_reference, which only touches the reference
and gnucash_transaction_id fields, leaving date/amount/allocations
untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 23:43:55 +02:00
Marcel PeterkauandClaude Sonnet 5 4e4aa22589 Stop double-reporting overdue claims and add SEPA-specific followup
The claim-status and reminder-due housekeeper rules used to run
independently, so once a claim was both overdue and past its dunning
grace period, both a generic "überfällig" task and a "Mahnung fällig"
task showed up for the same problem. Rules can't see each other's
output, so the fix is to give reminder-due sole ownership of the whole
overdue lifecycle: a plain overdue notice during the grace period, then
either the dunning escalation or a fallback overdue notice (dunning
hold active, or waiting between reminder levels) -- never both at once.
claim-status now only handles claims that aren't overdue yet ("bald
fällig").

Members with an active SEPA mandate get a new sepa_debit_overdue finding
instead of the postal dunning escalation once a claim is past its grace
period, since mailing a Mahnung makes no sense for a member who pays by
direct debit -- the board needs to check/retrigger the debit instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 23:02:37 +02:00
Marcel PeterkauandClaude Sonnet 5 42cde2a0c8 Remember the last-used GnuCash account per file
AppConfig now keeps a gnucash_last_accounts map (file path -> account
guid). When the import dialog opens a file it already knows, it
auto-selects whichever account was picked last time for that specific
file instead of always defaulting to the first one alphabetically;
picking a different account updates and persists the mapping right away.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 23:02:37 +02:00
Marcel PeterkauandClaude Sonnet 5 745e634a8b Import payments per member from a GnuCash file
Adds a "Zahlungen importieren" button to the member Zahlungen tab that opens
a dedicated window: point it at a GnuCash file (plain or gzip-compressed
XML, defaults to the file configured in Optionen), pick one of its accounts,
and narrow the account's bookings down with a description-contains filter
and an optional date range.

Each matching booking gets a checkbox to mark it for import as a payment.
Before anything is ticked, bookings are cross-checked against this member's
existing payments by date + amount; a match is highlighted and its checkbox
is refused, so re-importing the same statement can't create a duplicate
payment. Only bookings with a positive amount on the selected account are
offered, since those are the ones that make sense as an incoming payment.

Parsing lives in ccma.services.gnucash_import, independent of the UI, and
is covered by tests against a synthetic GnuCash XML fixture (plain and
gzip-compressed) -- no gnucash/piecash dependency needed since the native
file format is just XML.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 23:02:37 +02:00
Marcel PeterkauandClaude Sonnet 5 a5d9abd59a Allocate open claims and donations directly from the payment dialog
Recording a payment previously meant saving it bare, then separately
opening a claim to allocate money to it. Zahlung anlegen now lists a
member's open claims and donations right in the same dialog with a
select + amount field to assign parts of the payment on the spot, and a
"Neue Spende anlegen" button to create a donation inline and allocate to
it immediately -- covering members who pay more than the membership fee
in one transfer.

Shared the same allocation table in the existing payment-edit dialog so
editing a payment shows and preserves donation allocations too; before
this, saving an edited payment silently dropped any donation allocation
because update_payment only round-tripped claim allocations.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 21:22:08 +02:00
Marcel PeterkauandClaude Sonnet 5 42fb4c4224 Allow deleting claims, creating standalone payments, and add a donations tab
Claims could previously only be cancelled (stornieren), which blocks once a
payment is allocated. Add a hard delete that releases any linked
payments/credits back to being unallocated instead of destroying them.

Payments could only be created from within a claim, forcing immediate
allocation. Add a bare payment creation flow in the Zahlungen tab so
incoming transfers can be logged first and allocated later.

Add a per-member Spenden tab (donations, backed by a new donations list on
ContributionData) so amounts paid beyond the membership fee can be tracked
and existing free payments allocated to them.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 21:02:51 +02:00
Marcel Peterkau 5bacc005f6 Merge branch 'dev' into feature/payment-frequency-per-member 2026-07-30 17:40:45 +00:00
Marcel Peterkau 7a0cdbc04e feat: add application date to members 2026-07-30 19:35:48 +02:00
Marcel Peterkau c3cdf71506 feat: add per-member payment frequencies 2026-07-30 19:17:26 +02:00
Marcel Peterkau cfd5de42f2 feat: configure member number allocation strategy 2026-07-30 19:07:18 +02:00
Marcel Peterkau fc4eacb591 feat: add reminder email drafts 2026-07-30 01:17:33 +02:00
Marcel Peterkau 3d3b845d9f feat: add SEPA direct debit exports and notifications 2026-07-30 01:00:32 +02:00
Marcel Peterkau 9942e7aa22 fix: improve member list defaults and highlighting 2026-07-24 18:14:49 +02:00
Marcel Peterkau 7146615499 test: derive expected version from VERSION file 2026-07-22 23:48:39 +02:00
Marcel Peterkau 070684d9bc feat: extend inventory and administration workflows 2026-07-22 22:26:02 +02:00
Marcel Peterkau d8900d9767 Show credit settlements as positive amounts 2026-06-27 15:39:52 +02:00
Marcel Peterkau 532dc5c638 Update tests for current UI and rule behavior 2026-06-27 11:19:31 +02:00
Marcel Peterkau 3876f8c5ab Fix ruff lint violations 2026-06-27 10:46:54 +02:00
Marcel Peterkau 9944652dfb Refresh first release changelog 2026-06-27 10:41:06 +02:00
Marcel Peterkau 87e972bb43 Add JSON integrity hash checks 2026-06-27 10:35:35 +02:00
Marcel Peterkau d1dab793a6 Add asset records, claims, and credit workflows 2026-06-26 23:03:06 +02:00
Marcel Peterkau 30b6d253b2 Update member UI and related app changes 2026-06-26 21:57:11 +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 e6200f4a02 feat: pace startup housekeeper runs 2026-06-21 21:42:38 +02:00
Marcel Peterkau fc042f6711 feat: style timed splash progress 2026-06-21 18:51:31 +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 c717d6806b feat: allow deleting housekeeper tasks 2026-06-21 18:09:04 +02:00
Marcel Peterkau 3e9f347435 feat: show housekeeper task details 2026-06-21 17:59:49 +02:00
Marcel Peterkau 7596e47981 fix: preflight member records before rules 2026-06-21 17:54:09 +02:00
Marcel Peterkau 55bc3b666e fix: tolerate damaged contribution files 2026-06-21 17:50:56 +02:00
Marcel Peterkau 4bc1a8a200 feat: add scriptable housekeeper rule engine 2026-06-21 17:43:04 +02:00
Marcel Peterkau e63abbae81 fix: tolerate invalid member dates in views 2026-06-21 16:49:51 +02:00
Marcel Peterkau dfd5b1192b feat: initialize CCMA member administration 2026-06-21 16:46:15 +02:00