diff --git a/stores/billa.js b/stores/billa.js index 6a3ee15..ca16a6a 100644 --- a/stores/billa.js +++ b/stores/billa.js @@ -1,13 +1,48 @@ const axios = require("axios"); const HITS = Math.floor(30000 + Math.random() * 2000); +const conversions = { + "Beutel": { unit: 'stk', factor: 1 }, + "Blatt": { unit: 'stk', factor: 1 }, + "Bund": { unit: 'stk', factor: 1 }, + "g": { unit: 'g', factor: 1}, + "Gramm": { unit: 'g', factor: 1}, + "kg": { unit: 'g', factor: 1000}, + "Kilogramm": { unit: 'g', factor: 1}, + "l": { unit: 'ml', factor: 1000}, + "Liter": { unit: 'ml', factor: 1000}, + "Meter": { unit: 'cm', factor: 100}, + "Milliliter": { unit: 'ml', factor: 1}, + "ml": { unit: 'ml', factor: 1}, + "Paar": { unit: 'stk', factor: 1 }, + "Packung": { unit: 'stk', factor: 1 }, + "Portion": { unit: 'stk', factor: 1 }, + "Rollen": { unit: 'stk', factor: 1 }, + "Stk": { unit: 'stk', factor: 1 }, + "Stück": { unit: 'stk', factor: 1 }, + "Teebeutel": { unit: 'stk', factor: 1 }, + "Waschgang": { unit: 'wg', factor: 1 }, + "Zentimeter": { unit: 'cm', factor: 1 }, +}; + exports.getCanonical = function(item, today) { + let quantity = 1, unit = "kg"; + if(item.data.grammagePriceFactor == 1) { + const grammage = item.data.grammage !== "" && item.data.grammage.trim().split(' ').length>1 ? item.data.grammage : item.data.price.unit; + const [rawQuantity, rawUnit] = grammage.trim().split(' ').splice(0,2); + const conv = conversions[rawUnit]; + if(conv === undefined) + console.error(`Unknown unit in billa: "${JSON.stringify(item.data, null, 2)}"`) + quantity = parseFloat(rawQuantity.replace(',','.')) * conv.factor; + unit = conv.unit; + } return { id: item.data.articleId, name: item.data.name, price: item.data.price.final, priceHistory: [{ date: today, price: item.data.price.final }], - unit: item.data.grammagePriceFactor == 1 ? item.data.grammage : "kg", + unit, + quantity, bio: item.data.attributes && item.data.attributes.includes("s_bio") }; } @@ -15,4 +50,4 @@ exports.getCanonical = function(item, today) { exports.fetchData = async function() { const BILLA_SEARCH = `https://shop.billa.at/api/search/full?searchTerm=*&storeId=00-10&pageSize=${HITS}`; return (await axios.get(BILLA_SEARCH)).data.tiles; -} \ No newline at end of file +} diff --git a/stores/hofer.js b/stores/hofer.js index ca993ea..56d5255 100644 --- a/stores/hofer.js +++ b/stores/hofer.js @@ -1,12 +1,63 @@ const axios = require("axios"); +const conversions = { + "": {unit: "stk", factor: 1}, + "Blatt": {unit: "stk", factor: 1}, + "g": {unit: "g", factor: 1}, + "gg": {unit: "g", factor: 1}, + "gramm": {unit: "g", factor: 1}, + "kg": {unit: "g", factor: 1000}, + "KG": {unit: "g", factor: 1000}, + "cl": {unit: "ml", factor: 100}, + "l": {unit: "ml", factor: 1000}, + "L": {unit: "ml", factor: 1000}, + "ml": {unit: "ml", factor: 1}, + "Paar": {unit: "stk", factor: 1}, + "Stk.": {unit: "stk", factor: 1}, + "stück": {unit: "stk", factor: 1}, + "Stück": {unit: "stk", factor: 1}, + "er": {unit: "stk", factor: 1}, + "Teebeutel": {unit: "stk", factor: 1}, +}; + exports.getCanonical = function(item, today) { + // try to read quantity and unit from product name + let unit, quantity = 1; + const name = item.ProductName; + const nameTokens = name.trim().replaceAll('(','').replaceAll(')','').replaceAll(',', '.').split(' '); + const lastToken = nameTokens[nameTokens.length-1]; + const secondLastToken = nameTokens.length > 2 ? nameTokens[nameTokens.length-2] : null; + const regex = /^([0-9.x]+)(.*)$/; + const matches = lastToken.match(regex); + if(matches) { + matches[1].split('x').forEach( (q)=> { + quantity = quantity * parseFloat(q) + }) + unit = matches[2]; + } + else if(secondLastToken !== null && secondLastToken.match(/^([0-9.]+)$/)) { + quantity = parseFloat(secondLastToken) + unit = lastToken; + } + else { + // fallback: use given quantity and unit (including packaging) + quantity = item.Unit + unit= item.UnitType + } + if(unit in conversions) { + const conv = conversions[unit]; + quantity = conv.factor * quantity; + unit = conv.unit; + } + else + console.error("unknown hofer unit", unit, name) return { id: item.ProductID, name: item.ProductName, price: item.Price, priceHistory: [{ date: today, price: item.Price }], - unit: `${item.Unit} ${item.UnitType}`, + unit, + quantity, bio: item.IsBio }; } @@ -38,4 +89,4 @@ exports.fetchData = async function() { } return hoferItems; -} \ No newline at end of file +}