feat(products): include ownerId in product creation and enforce its requirement

This commit is contained in:
Nils-Johan Gynther
2026-05-02 19:12:26 +02:00
parent 4e568b4d2e
commit 5842646e77
3 changed files with 15 additions and 10 deletions
@@ -120,11 +120,11 @@ export class ReceiptImportService {
const [aliases, products] = await Promise.all([
this.prisma.receiptAlias.findMany({
where: aliasFilter,
select: { receiptName: true, productId: true, product: { select: { id: true, name: true, canonicalName: true, categoryId: true, categoryRef: { select: { id: true, name: true, path: true } } } } },
select: { receiptName: true, productId: true, product: { select: { id: true, name: true, canonicalName: true, categoryId: true, categoryRef: { select: { id: true, name: true } } } } },
}),
this.prisma.product.findMany({
where: productFilter,
select: { id: true, name: true, canonicalName: true, categoryId: true, categoryRef: { select: { id: true, name: true, path: true } } },
select: { id: true, name: true, canonicalName: true, categoryId: true, categoryRef: { select: { id: true, name: true } } },
}),
]);
@@ -140,7 +140,7 @@ export class ReceiptImportService {
...item,
matchedProductId: alias.product.id,
matchedProductName: alias.product.canonicalName ?? alias.product.name,
...(cat ? { categorySuggestion: { categoryId: cat.id, categoryName: cat.name, path: cat.path, confidence: 'high' as const, usedFallback: false } } : {}),
...(cat ? { categorySuggestion: { categoryId: cat.id, categoryName: cat.name, path: cat.name, confidence: 'high' as const, usedFallback: false } } : {}),
};
}
@@ -154,15 +154,15 @@ export class ReceiptImportService {
...item,
suggestedProductId: suggestion.id,
suggestedProductName: suggestion.canonicalName ?? suggestion.name,
...(cat ? { categorySuggestion: { categoryId: cat.id, categoryName: cat.name, path: cat.path, confidence: 'medium' as const, usedFallback: false } } : {}),
...(cat ? { categorySuggestion: { categoryId: cat.id, categoryName: cat.name, path: cat.name, confidence: 'medium' as const, usedFallback: false } } : {}),
};
});
}
private findWordMatch(
raw: string,
products: { id: number; name: string; canonicalName: string | null; categoryId: number | null; categoryRef: { id: number; name: string; path: string } | null }[],
): { id: number; name: string; canonicalName: string | null; categoryId: number | null; categoryRef: { id: number; name: string; path: string } | null } | undefined {
products: { id: number; name: string; canonicalName: string | null; categoryId: number | null; categoryRef: { id: number; name: string } | null }[],
): { id: number; name: string; canonicalName: string | null; categoryId: number | null; categoryRef: { id: number; name: string } | null } | undefined {
// Dela upp kvittonamnet i ord (min 3 tecken)
const rawWords = tokenize(raw);
if (rawWords.length === 0) return undefined;
@@ -173,7 +173,7 @@ export class ReceiptImportService {
const rawWordSetNorm = new Set(rawWordsNorm);
let best:
| { product: { id: number; name: string; canonicalName: string | null }; score: number }
| { product: { id: number; name: string; canonicalName: string | null; categoryId: number | null; categoryRef: { id: number; name: string } | null }; score: number }
| undefined;
for (const product of products) {