diff --git a/MoneyMap/Pages/Receipts.cshtml.cs b/MoneyMap/Pages/Receipts.cshtml.cs
index 211f5dd..d0f377f 100644
--- a/MoneyMap/Pages/Receipts.cshtml.cs
+++ b/MoneyMap/Pages/Receipts.cshtml.cs
@@ -254,32 +254,30 @@ namespace MoneyMap.Pages
var candidates = await query
.ToListAsync();
- // If receipt has merchant, sort matches by relevance (but don't exclude)
+ // Sort by merchant/name relevance using word matching
if (!string.IsNullOrWhiteSpace(receipt.Merchant))
{
- var merchantLower = receipt.Merchant.ToLower();
+ var receiptWords = receipt.Merchant.ToLower().Split(new[] { ' ', '-', '_', '.' }, StringSplitOptions.RemoveEmptyEntries);
- // Sort: exact matches first, then partial matches, then others
candidates = candidates
.OrderByDescending(t =>
{
var merchantName = t.Merchant?.Name?.ToLower() ?? "";
var transactionName = t.Name?.ToLower() ?? "";
- // Exact match on merchant or transaction name
- if (merchantName == merchantLower || transactionName == merchantLower)
- return 3;
+ // Exact match
+ if (merchantName == receipt.Merchant.ToLower() || transactionName == receipt.Merchant.ToLower())
+ return 1000;
- // Contains match on merchant
- if (merchantName.Contains(merchantLower))
- return 2;
+ // Count matching words
+ var merchantWords = merchantName.Split(new[] { ' ', '-', '_', '.' }, StringSplitOptions.RemoveEmptyEntries);
+ var transactionWords = transactionName.Split(new[] { ' ', '-', '_', '.' }, StringSplitOptions.RemoveEmptyEntries);
- // Contains match on transaction name
- if (transactionName.Contains(merchantLower))
- return 1;
+ var merchantMatches = receiptWords.Count(rw => merchantWords.Any(mw => mw.Contains(rw) || rw.Contains(mw)));
+ var transactionMatches = receiptWords.Count(rw => transactionWords.Any(tw => tw.Contains(rw) || rw.Contains(tw)));
- // No match
- return 0;
+ // Return the higher match count
+ return Math.Max(merchantMatches * 10, transactionMatches * 10);
})
.ThenByDescending(t => t.Date)
.ThenByDescending(t => t.Id)
diff --git a/MoneyMap/Services/ReceiptAutoMapper.cs b/MoneyMap/Services/ReceiptAutoMapper.cs
index 883ea44..1fbbb82 100644
--- a/MoneyMap/Services/ReceiptAutoMapper.cs
+++ b/MoneyMap/Services/ReceiptAutoMapper.cs
@@ -118,18 +118,38 @@ namespace MoneyMap.Services
return new List();
}
- // Filter by merchant if available
- if (!string.IsNullOrWhiteSpace(receipt.Merchant))
- {
- // Try to find matching merchant name
- query = query.Where(t =>
- (t.Merchant != null && t.Merchant.Name.Contains(receipt.Merchant)) ||
- t.Name.Contains(receipt.Merchant));
- }
-
// Get candidates
var candidates = await query.ToListAsync();
+ // Sort by merchant/name relevance using word matching if merchant available
+ if (!string.IsNullOrWhiteSpace(receipt.Merchant))
+ {
+ var receiptWords = receipt.Merchant.ToLower().Split(new[] { ' ', '-', '_', '.' }, StringSplitOptions.RemoveEmptyEntries);
+
+ candidates = candidates
+ .OrderByDescending(t =>
+ {
+ var merchantName = t.Merchant?.Name?.ToLower() ?? "";
+ var transactionName = t.Name?.ToLower() ?? "";
+
+ // Exact match
+ if (merchantName == receipt.Merchant.ToLower() || transactionName == receipt.Merchant.ToLower())
+ return 1000;
+
+ // Count matching words
+ var merchantWords = merchantName.Split(new[] { ' ', '-', '_', '.' }, StringSplitOptions.RemoveEmptyEntries);
+ var transactionWords = transactionName.Split(new[] { ' ', '-', '_', '.' }, StringSplitOptions.RemoveEmptyEntries);
+
+ var merchantMatches = receiptWords.Count(rw => merchantWords.Any(mw => mw.Contains(rw) || rw.Contains(mw)));
+ var transactionMatches = receiptWords.Count(rw => transactionWords.Any(tw => tw.Contains(rw) || rw.Contains(tw)));
+
+ // Return the higher match count
+ return Math.Max(merchantMatches * 10, transactionMatches * 10);
+ })
+ .ThenByDescending(t => t.Date)
+ .ToList();
+ }
+
// If we have a total amount, filter by amount match (±10% tolerance)
if (receipt.Total.HasValue)
{