diff --git a/backend/src/products/products.controller.ts b/backend/src/products/products.controller.ts index 1341dc9e..f6b3b798 100644 --- a/backend/src/products/products.controller.ts +++ b/backend/src/products/products.controller.ts @@ -128,8 +128,8 @@ export class ProductsController { @Roles('admin') @Post() - create(@Body() body: CreateProductDto) { - return this.productsService.create(body); + create(@Body() body: CreateProductDto, @Request() req: { user: { id: number } }) { + return this.productsService.create(body, req.user.id); } // Tillgänglig för alla inloggade användare — req.user.id injiceras av JWT-guard diff --git a/backend/src/products/products.service.ts b/backend/src/products/products.service.ts index 39cf0e31..e90157cc 100644 --- a/backend/src/products/products.service.ts +++ b/backend/src/products/products.service.ts @@ -116,7 +116,7 @@ export class ProductsService { return product; } - async create(data: CreateProductDto) { + async create(data: CreateProductDto, ownerId?: number) { const name = data.name.trim(); const normalizedName = normalizeName(name); @@ -140,8 +140,13 @@ export class ProductsService { return existing; } + if (!ownerId) { + throw new Error('ownerId är obligatorisk för att skapa en produkt'); + } + return this.prisma.product.create({ data: { + ownerId, name, normalizedName, canonicalName: name, diff --git a/backend/src/receipt-import/receipt-import.service.ts b/backend/src/receipt-import/receipt-import.service.ts index ffb52e59..cc51263d 100644 --- a/backend/src/receipt-import/receipt-import.service.ts +++ b/backend/src/receipt-import/receipt-import.service.ts @@ -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) {