feat: Update multipack handling in quantity rules and extraction logic

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Nils-Johan Gynther
2026-05-03 16:16:13 +02:00
parent 504cf1c947
commit a0bedcc9a9
@@ -32,8 +32,8 @@ Regler för quantity och unit:
Exempel: "BLANDFÄRS 20%" köpt 0.997 kg -> quantity=0.997, unit="kg" Exempel: "BLANDFÄRS 20%" köpt 0.997 kg -> quantity=0.997, unit="kg"
2. FÖRPACKAD VARA med storlek i namnet (mejeri, dryck, konserver, flingor): quantity=antal köpta förpackningar, unit="förp". 2. FÖRPACKAD VARA med storlek i namnet (mejeri, dryck, konserver, flingor): quantity=antal köpta förpackningar, unit="förp".
Exempel: "VISPGRÄDDE 5DL" köpt 1 -> quantity=1, unit="förp" Exempel: "VISPGRÄDDE 5DL" köpt 1 -> quantity=1, unit="förp"
3. MULTIPACK (NxYg/NxYml i namnet): quantity=1, unit="förp". Räkna INTE upp N som quantity. 3. MULTIPACK (NxYg/NxYml i namnet): quantity=antal innerförpackningar (N), unit="förp".
Exempel: "BACON 3X120G" -> quantity=1, unit="förp" Exempel: "BACON 3X120G" -> quantity=3, unit="förp"
4. FÖRPACKAT INNEHÅLL (bröd, kex, chips): quantity=antal köpta förpackningar, unit="förp". 4. FÖRPACKAT INNEHÅLL (bröd, kex, chips): quantity=antal köpta förpackningar, unit="förp".
5. LÖSA STYCKVAROR (enstaka frukt köpt lösvikt per styck): quantity=antal, unit="st". 5. LÖSA STYCKVAROR (enstaka frukt köpt lösvikt per styck): quantity=antal, unit="st".
`; `;
@@ -109,8 +109,6 @@ function isLikelyNameLikeText(value: string): boolean {
function extractNameCandidate(line: string): string | null { function extractNameCandidate(line: string): string | null {
const cleaned = line const cleaned = line
.replace(/\b\d+\s*[x×]\s*\d+(?:[\.,]\d+)?\s*(ml|cl|dl|l|g|kg)\b/gi, ' ')
.replace(/\b\d+(?:[\.,]\d+)?\s*(ml|cl|dl|l|g|kg|st|fp|pkt|pak|förp)\b/gi, ' ')
.replace(/\b\d+(?:[\.,]\d+)?\s*(kr|sek)\s*\/\s*(kg|g|mg|l|dl|cl|ml)\b/gi, ' ') .replace(/\b\d+(?:[\.,]\d+)?\s*(kr|sek)\s*\/\s*(kg|g|mg|l|dl|cl|ml)\b/gi, ' ')
.replace(/\b(kr|sek)\s*\/\s*(kg|g|mg|l|dl|cl|ml)\b/gi, ' ') .replace(/\b(kr|sek)\s*\/\s*(kg|g|mg|l|dl|cl|ml)\b/gi, ' ')
.replace(/\b(kr|sek)\b/gi, ' ') .replace(/\b(kr|sek)\b/gi, ' ')
@@ -208,7 +206,15 @@ function ruleBasedParseLine(line: string): ParsedReceiptItemRaw | null {
// Multipack: "3x120g", "2 x 1.5l" // Multipack: "3x120g", "2 x 1.5l"
const multiPack = /(\d+)\s*[x×]\s*(\d+(?:[\.,]\d+)?)\s*(ml|cl|dl|l|g|kg)\b/i.exec(normalized); const multiPack = /(\d+)\s*[x×]\s*(\d+(?:[\.,]\d+)?)\s*(ml|cl|dl|l|g|kg)\b/i.exec(normalized);
if (multiPack) { if (multiPack) {
return { rawName, quantity: 1, unit: 'förp', price: null, brand: null, origin: null }; const count = Number.parseInt(multiPack[1], 10);
return {
rawName,
quantity: Number.isFinite(count) && count > 0 ? count : 1,
unit: 'förp',
price: null,
brand: null,
origin: null,
};
} }
// Förpackad vara med volym/vikt i namn: "5dl", "1,5l", "100g" // Förpackad vara med volym/vikt i namn: "5dl", "1,5l", "100g"