feat: implement matchedVia tracking for receipt items and enhance user alias management
Test Suite / test (24.15.0) (push) Has been cancelled

This commit is contained in:
Nils-Johan Gynther
2026-05-07 13:57:41 +02:00
parent f7446cc2df
commit d92272e554
9 changed files with 287 additions and 8 deletions
@@ -540,15 +540,16 @@ class _ReceiptImportTabState extends ConsumerState<ReceiptImportTab> {
}
final normalizedReceiptName = item.rawName.trim().toLowerCase();
final shouldLearnAlias =
canManageAliases &&
normalizedReceiptName.isNotEmpty &&
item.matchedProductId != pid;
// Spara alias för alla användare (user-scope) när raden inte redan matchades via alias,
// eller admin sparar global alias.
final alreadyAliasMatch = item.matchedVia == 'alias' && item.matchedProductId == pid;
final shouldLearnAlias = normalizedReceiptName.isNotEmpty && !alreadyAliasMatch;
if (shouldLearnAlias) {
try {
await adminRepo.upsertReceiptAlias(
receiptName: normalizedReceiptName,
productId: pid,
isGlobal: canManageAliases,
);
aliasesLearned++;
} catch (e, st) {
@@ -644,6 +645,31 @@ class _ReceiptImportTabState extends ConsumerState<ReceiptImportTab> {
);
}
Widget _buildMatchedViaBadge(ParsedReceiptItem item, ThemeData theme) {
final via = item.matchedVia;
if (via == null || via == 'none') return const SizedBox.shrink();
final (label, bg, fg) = switch (via) {
'alias' => ('Alias', Colors.teal.shade50, Colors.teal.shade800),
'wordmatch' => ('Ordmatch', Colors.blue.shade50, Colors.blue.shade800),
'ai' => ('AI-kategori', Colors.purple.shade50, Colors.purple.shade800),
_ => ('Matchad', theme.colorScheme.surfaceContainerHighest, theme.colorScheme.onSurfaceVariant),
};
return Container(
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 2),
decoration: BoxDecoration(
color: bg,
borderRadius: BorderRadius.circular(999),
border: Border.all(color: fg.withOpacity(0.3)),
),
child: Text(
label,
style: theme.textTheme.labelSmall?.copyWith(color: fg, fontWeight: FontWeight.w600),
),
);
}
@override
Widget build(BuildContext context) {
final session = ref.watch(receiptImportSessionProvider);
@@ -797,6 +823,7 @@ class _ReceiptImportTabState extends ConsumerState<ReceiptImportTab> {
fontWeight: FontWeight.w500,
),
),
_buildMatchedViaBadge(item, theme),
if (edit.categorySource != null)
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),