Fix incorrect category display in report for same merchant names#91
Fix incorrect category display in report for same merchant names#91terryaney wants to merge 3 commits into
Conversation
PR Build AvailableVersion: Install from this PRLinux / macOS: curl -fsSL https://raw.githubusercontent.com/davidfowl/tally/main/docs/install-pr.sh | bash -s -- 91Windows PowerShell: iex "& { $(irm https://raw.githubusercontent.com/davidfowl/tally/main/docs/install-pr.ps1) } 91"Manual download: View workflow run and download artifacts. Requirements
|
|
The first commit on the PR correctly fixes the Python-side bug — changing However, even after that fix, Root CauseIn // filteredViewTotals
const tags = merchant.tags || []; // ← merchant-level aggregate
const txns = merchant.filteredTxns || merchant.transactions || [];
for (const txn of txns) {
const c = categorizeAmount(txn.amount || 0, tags); // ← all txns get same tags// chartAggregations
const tags = merchant.tags || []; // ← same problem
for (const txn of merchant.filteredTxns || []) {
const c = categorizeAmount(txn.amount, tags);Each individual transaction already carries its own |
There was a problem hiding this comment.
Pull request overview
This PR updates merchant aggregation/reporting so identical merchant display names can appear as separate rows when categorized differently, while keeping merchant-name filtering logical across those category variants.
Changes:
- Uses composite merchant identity in analysis/report data for same-name merchants with different category/subcategory values.
- Updates HTML filtering/autocomplete behavior to filter by visible merchant name across duplicate category variants.
- Adds regression coverage for duplicate merchant names and updates tests for composite row IDs and “Uncategorized” fallback text.
Show a summary per file
| File | Description |
|---|---|
src/tally/analyzer.py |
Changes merchant aggregation keys to include category/subcategory and propagates merchant names from data. |
src/tally/report.py |
Builds composite merchant IDs and category-view rows for duplicate merchant names. |
src/tally/spending_report.js |
Adjusts merchant filtering/autocomplete and transaction-level categorization in filtered totals/charts. |
src/tally/commands/explain.py |
Updates explain lookup/filter paths for duplicate merchant-name entries. |
tests/test_report_html.py |
Adds duplicate-name regression tests and updates row locators/fallback expectations. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 5/5 changed files
- Comments generated: 5
| category = data.get('category', '') | ||
| subcategory = data.get('subcategory', '') | ||
| # Use a composite ID so same-named merchants with different categories are distinct | ||
| merchant_id = make_merchant_id(f"{merchant_name}_{category}_{subcategory}") |
| for entry in name_to_entries[merchant_query]: | ||
| _print_merchant_explanation(merchant_query, entry, args.format, verbose, stats['num_months'], views_config) |
| for entry in name_to_entries[matches[0]]: | ||
| _print_merchant_explanation(matches[0], entry, args.format, verbose, stats['num_months'], views_config) |
| print(f"Merchants matching '{merchant_query}':\n") | ||
| for m in sorted(partial_matches): | ||
| _print_merchant_explanation(m, all_merchants[m], args.format, verbose, stats['num_months'], views_config) | ||
| for n in sorted(partial_matches): | ||
| for entry in name_to_entries[n]: | ||
| _print_merchant_explanation(n, entry, args.format, verbose, stats['num_months'], views_config) |
| # Track by merchant - use composite key (merchant, category, subcategory) | ||
| # so same-named merchants with different categories appear as separate rows | ||
| merchant_key = (txn['merchant'], txn['category'], txn['subcategory']) | ||
| by_merchant[merchant_key]['name'] = txn['merchant'] |
|
There are some pr comments from copilot |
Working on them and testing. Curious, I used Copilot to help code up this branch and 4-5 comments above are troubling to me in that I feel Copilot should have found those (all the json format issues). Given that, I'm curious what kind of prompt is running the copilot review? Something custom you would share? Or just a standard review? And my plan/implementation via Copilot missed thinking about these somehow? |
…ags (#13) filteredViewTotals and chartAggregations to use per-transaction tags Fixes the Python-side bug — changing by_merchant to use a composite (merchant, category, subcategory) key so same-named merchants with different categories appear as separate rows. This significantly reduces the practical impact of the JavaScript-side bug described here. However, even after the PR fix, merchant.tags in the report data is still the union of all transaction tags within that merchant entry. When that union includes tags that not every transaction individually carries, filteredViewTotals misclassifies those transactions.
05694d9 to
e1adce4
Compare
Fixes #88 allowing merchants to different categorization rules with same name.
Instead of requiring:
Can instead be:
Allows easier auditing of spending to a merchant. Of course, if you prefer unique merchant names, that is still possible.