refactor: heatmap single-query + decouple ActionQueueBuilder (#141, #143)#179
Merged
Conversation
Fixes #141. get_heatmap_data() previously called get_sessions_for_month() once per month in a loop (12 queries) then ran a 13th range query for client totals. The per-month results are a strict subset of the range data. Now: one InvoiceItem query covering the full date range; items are partitioned by (year, month) key in Python for the heatmap rows, and client totals fall out of the same pass at no extra cost. get_sessions_for_month() is kept as-is for its existing callers (test_analytics_integration, test_calculation_consistency). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes #143. Each widget builder now owns a get_action_items(today) method that returns ActionQueueItem-shaped dicts directly: - InvoiceActionsWidgetBuilder: overdue + draft rows - ClientAttentionWidgetBuilder: tagged + inactive client rows (includes the Session last-date query, formerly in ActionQueueBuilder) - TaxQuarterWidgetBuilder: tax prepayment warning row - ChecklistWidgetBuilder: pending checklist row - BankImportReminderWidgetBuilder: bank import reminder row ActionQueueBuilder.build() is now a thin aggregator that calls get_action_items() on each builder and sorts the result. It no longer walks context dict internals (ctx["overdue_invoices"], etc.) and is immune to key renames in widget builders. Shared helpers (_fmt_eur, _join_truncated, _TAG_LABELS) moved to dashboard_widgets.py where the logic lives; action_queue_builder.py no longer defines them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Import pgettext alongside gettext/ngettext
- Use pgettext("action category", ...) for "Invoice", "Tax", "Operations"
to avoid collisions with existing non-action-queue translations for
those same English msgids (e.g. "Invoice" → "Rechnungsnr.")
- Use pgettext("action label", "Complete") for the draft-invoice CTA,
which collided with "Aufnahme abgeschlossen"
- Fill all new German msgstrs; defuzz auto-matched entries (no session,
invoice ready, Revenue, etc.) with correct German translations
- Re-extract + compile both locales
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #141, fixes #143.
#141 — heatmap single range query
get_heatmap_data()previously calledget_sessions_for_month()once per month in a loop (12 queries by default) then ran a 13th range query for client totals — fetching the same data twice. Now:InvoiceItemquery covers the full date range withselect_related(year, month)key in a single Python passget_sessions_for_month()is preserved unchanged for its existing callers in the test suite.#143 — decouple ActionQueueBuilder from widget context dict internals
Each widget builder now owns
get_action_items(today) -> list[dict]that emitsActionQueueItem-shaped dicts directly:InvoiceActionsWidgetBuilderClientAttentionWidgetBuilderTaxQuarterWidgetBuilderChecklistWidgetBuilderBankImportReminderWidgetBuilderActionQueueBuilder.build()is now a thin aggregator (~10 lines) that callsget_action_items()on each builder and sorts. It no longer referencesctx["overdue_invoices"],ctx["tagged_clients"], etc. — a key rename in a widget builder can no longer silently break the action queue.Shared helpers (
_fmt_eur,_join_truncated,_TAG_LABELS) moved todashboard_widgets.pywhere the logic lives;action_queue_builder.pyis stripped to its aggregation role.P-039 — i18n wrapping for dashboard_widgets.py
All user-facing strings in
dashboard_widgets.pyare now wrapped withgettext/ngettext/_(). Four msgids collided with existing.poentries that carry different German translations in other UI contexts:"Invoice""Tax""Operations""Complete"Resolved with
pgettext("action category", ...)/pgettext("action label", ...)so each context gets its own.poentry. All fuzzy auto-matches from unrelated strings replaced with correct German translations.Tests
test_action_queue_builder,test_analytics_integration,test_calculation_consistency,test_views_dashboard,test_operational_checklist— all pass. Lint clean.🤖 Generated with Claude Code