fixed salattheke prices
This commit is contained in:
@@ -1,10 +1,14 @@
|
|||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
from datetime import datetime, date
|
from datetime import datetime, date
|
||||||
from stw_potsdam.xml_types.canteen_xml import CanteenMeta, CanteenXML
|
from stw_potsdam.xml_types.canteen_xml import CanteenMeta, CanteenXML
|
||||||
from stw_potsdam.xml_types.times_xml import CanteenOpenTimespec, TimesXML
|
from stw_potsdam.xml_types.times_xml import CanteenOpenTimespec, TimesXML
|
||||||
from stw_potsdam.xml_types.meal_xml import MealXML
|
from stw_potsdam.xml_types.meal_xml import MealXML
|
||||||
|
|
||||||
|
|
||||||
|
EURO_PRICE_PATTERN = re.compile(r"(\d+(?:[,.]\d{1,2})?)\s*€")
|
||||||
|
|
||||||
|
|
||||||
class SWPWebspeiseplanParser:
|
class SWPWebspeiseplanParser:
|
||||||
"""Class method to parse SWP_Webspeiseplan."""
|
"""Class method to parse SWP_Webspeiseplan."""
|
||||||
|
|
||||||
@@ -56,6 +60,42 @@ class SWPWebspeiseplanParser:
|
|||||||
canteen = CanteenXML(canteen_meta, canteen_times)
|
canteen = CanteenXML(canteen_meta, canteen_times)
|
||||||
return canteen
|
return canteen
|
||||||
|
|
||||||
|
def _parse_price(self, value):
|
||||||
|
if value in (None, "", {}):
|
||||||
|
return None
|
||||||
|
return float(str(value).replace(",", "."))
|
||||||
|
|
||||||
|
def _parse_embedded_prices(
|
||||||
|
self, name: str, price: dict[str, float | None]
|
||||||
|
) -> tuple[str, dict[str, float | None]]:
|
||||||
|
if any(price.values()):
|
||||||
|
return name, price
|
||||||
|
|
||||||
|
matches = EURO_PRICE_PATTERN.findall(name)
|
||||||
|
if len(matches) < 2:
|
||||||
|
return name, price
|
||||||
|
|
||||||
|
parsed = [self._parse_price(match) for match in matches]
|
||||||
|
if len(parsed) >= 3:
|
||||||
|
price = {
|
||||||
|
"student": parsed[0],
|
||||||
|
"employee": parsed[1],
|
||||||
|
"other": parsed[2],
|
||||||
|
}
|
||||||
|
elif "Stud" in name and ("Gäste" in name or "Gaeste" in name):
|
||||||
|
price = {
|
||||||
|
"student": parsed[0],
|
||||||
|
"employee": price["employee"],
|
||||||
|
"other": parsed[1],
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return name, price
|
||||||
|
|
||||||
|
name = EURO_PRICE_PATTERN.sub("", name)
|
||||||
|
name = re.sub(r"\s*/\s*", " ", name)
|
||||||
|
name = re.sub(r"\s+", " ", name).strip()
|
||||||
|
return name, price
|
||||||
|
|
||||||
def parse_meals(
|
def parse_meals(
|
||||||
self, menu_data, meal_categories
|
self, menu_data, meal_categories
|
||||||
) -> list[tuple[date, str, MealXML]]:
|
) -> list[tuple[date, str, MealXML]]:
|
||||||
@@ -66,11 +106,20 @@ class SWPWebspeiseplanParser:
|
|||||||
info = meal_data["speiseplanAdvancedGericht"]
|
info = meal_data["speiseplanAdvancedGericht"]
|
||||||
additional_info = meal_data["zusatzinformationen"]
|
additional_info = meal_data["zusatzinformationen"]
|
||||||
price = {
|
price = {
|
||||||
"student": additional_info["mitarbeiterpreisDecimal2"],
|
"student": self._parse_price(
|
||||||
"employee": additional_info["price3Decimal2"],
|
additional_info["mitarbeiterpreisDecimal2"]
|
||||||
"other": additional_info["gaestepreisDecimal2"],
|
),
|
||||||
|
"employee": self._parse_price(
|
||||||
|
additional_info["price3Decimal2"]
|
||||||
|
),
|
||||||
|
"other": self._parse_price(
|
||||||
|
additional_info["gaestepreisDecimal2"]
|
||||||
|
),
|
||||||
}
|
}
|
||||||
meal = MealXML(name=info["gerichtname"], price=price)
|
name, price = self._parse_embedded_prices(
|
||||||
|
info["gerichtname"], price
|
||||||
|
)
|
||||||
|
meal = MealXML(name=name, price=price)
|
||||||
day = datetime.fromisoformat(info["datum"]).date()
|
day = datetime.fromisoformat(info["datum"]).date()
|
||||||
category = meal_categories[info["gerichtkategorieID"]]["name"]
|
category = meal_categories[info["gerichtkategorieID"]]["name"]
|
||||||
meals.append(
|
meals.append(
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
from stw_potsdam.swp_webspeiseplan_parser import SWPWebspeiseplanParser
|
||||||
|
|
||||||
|
|
||||||
|
def _menu_item(name):
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"speiseplanGerichtData": [
|
||||||
|
{
|
||||||
|
"speiseplanAdvancedGericht": {
|
||||||
|
"datum": "2026-05-01T00:00:00",
|
||||||
|
"gerichtkategorieID": 1,
|
||||||
|
"gerichtname": name,
|
||||||
|
},
|
||||||
|
"zusatzinformationen": {
|
||||||
|
"mitarbeiterpreisDecimal2": 0,
|
||||||
|
"price3Decimal2": 0,
|
||||||
|
"gaestepreisDecimal2": 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_meal(name):
|
||||||
|
parser = SWPWebspeiseplanParser()
|
||||||
|
meals = parser.parse_meals(_menu_item(name), {1: {"name": "Salattheke"}})
|
||||||
|
return meals[0]["meal"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_salad_bar_three_embedded_prices():
|
||||||
|
meal = _parse_meal(
|
||||||
|
"große Schale kleine Schale Relevo Schale 100g "
|
||||||
|
"1,10 €/ 1,70 €/ 1,90€"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert meal.name == "große Schale kleine Schale Relevo Schale 100g"
|
||||||
|
assert meal.price == {
|
||||||
|
"student": 1.10,
|
||||||
|
"employee": 1.70,
|
||||||
|
"other": 1.90,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_salad_bar_student_guest_embedded_prices():
|
||||||
|
meal = _parse_meal(
|
||||||
|
"große Schale\nkleine Schale\nRelevo Schale\n"
|
||||||
|
"100g Stud. 1,00€/ Gäste 1,45€"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert meal.name == (
|
||||||
|
"große Schale kleine Schale Relevo Schale 100g Stud. Gäste"
|
||||||
|
)
|
||||||
|
assert meal.price == {
|
||||||
|
"student": 1.00,
|
||||||
|
"employee": 0.0,
|
||||||
|
"other": 1.45,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user