Skip to content

Refactor: extract shared code, add TransactionService, consolidate utilities#21

Merged
7174Andy merged 5 commits intomainfrom
refactor/duplication-dialog-code
Feb 14, 2026
Merged

Refactor: extract shared code, add TransactionService, consolidate utilities#21
7174Andy merged 5 commits intomainfrom
refactor/duplication-dialog-code

Conversation

@7174Andy
Copy link
Copy Markdown
Owner

@7174Andy 7174Andy commented Feb 14, 2026

Summary

This PR tackles several architectural issues discovered during a code review, reducing duplication and improving consistency across the codebase:

  • Shared expense form builder — Extracted duplicated form construction (~30 identical lines) and amount validation from AddExpenseDialog and EditExpenseDialog into expense_form.py with build_expense_form() and validate_amount()
  • TransactionService — Created a centralized service layer that ensures consistent auto-categorization across all entry points (manual add, PDF import, edit). Previously, PDF uploads auto-categorized via MerchantCategoryService but manually added transactions skipped categorization entirely
  • Consolidated date parsing — Merged two independent date parsing implementations (UploadDialog._parse_date() and extract._parse_date()) into a single parse_date_from_str() utility in utils/date.py
  • Removed duplicated SQLget_top_spending_category() was nearly identical to get_spending_by_category() (differed only by LIMIT 1). Removed the former; StatisticsService now uses get_spending_by_category()[0]

Key changes

New files

  • expense_tracker/gui/dialogs/expense_form.py — Shared form builder and amount validator
  • expense_tracker/services/transaction.pyTransactionService with auto-categorization, merchant mapping updates, bulk import with dedup
  • expense_tracker/utils/date.py — Consolidated parse_date_from_str() utility
  • tests/services/test_transaction.py — 11 tests covering all TransactionService methods

Modified files

  • app.py — Creates MerchantCategoryService once, injects into TransactionService
  • main_window.py, transactions_tab.py — Accept TransactionService instead of raw repos
  • add_expense.py, edit_expense.py, upload.py — Refactored to use shared form + TransactionService
  • statistics.py — Uses get_spending_by_category()[0] instead of removed get_top_spending_category()
  • transaction_repository.py — Removed get_top_spending_category()
  • extract.py — Uses shared parse_date_from_str(), returns date objects instead of strings
  • test_extract.py — Updated assertions to expect date objects
  • test_repository.py — Removed 4 obsolete tests for deleted get_top_spending_category

Design decisions

  • TransactionService wraps MerchantCategoryService rather than exposing it to dialogs directly. This keeps categorization logic centralized — adding a new entry point (e.g., CSV import) only needs to call TransactionService.import_transactions().
  • update_transaction() returns bool to indicate whether merchant categories were updated, so the edit dialog can show appropriate feedback without needing to track category changes itself.
  • extract.py now returns date objects instead of ISO strings. This is more type-safe and avoids unnecessary string↔date conversions downstream.

Test plan

  • All 142 tests pass
  • ruff check . clean
  • Manual: verify add/edit/upload dialogs still work correctly
  • Manual: verify auto-categorization triggers on manual add and PDF import

🤖 Generated with Claude Code

@7174Andy 7174Andy merged commit 2294fda into main Feb 14, 2026
3 checks passed
@7174Andy 7174Andy deleted the refactor/duplication-dialog-code branch February 14, 2026 22:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant