""" Kanonische Speichereinheiten pro CSV-Zielfeld (module_registry: field.unit) und abwählbare Quelleinheiten → Faktor für type_conversions.source_unit. """ from __future__ import annotations from typing import Any from csv_parser.module_registry import get_module_definition # 1 kcal = 4.184 kJ (IEC/ISO 80000) _KJ_TO_KCAL = 1.0 / 4.184 # — Energie (Ziel kcal) — _ENERGY: list[dict[str, Any]] = [ {"id": "kcal", "label": "Kilokalorien (kcal), wie in DB", "factor": 1.0}, {"id": "kj", "label": "Kilojoule (kJ) → kcal", "factor": _KJ_TO_KCAL}, {"id": "j", "label": "Joule (J) → kcal", "factor": _KJ_TO_KCAL / 1000.0}, ] # — Masse klein (Ziel g): Makronährstoffe — _GRAM: list[dict[str, Any]] = [ {"id": "g", "label": "Gramm (g), wie in DB", "factor": 1.0}, {"id": "kg", "label": "Kilogramm (kg) → g", "factor": 1000.0}, {"id": "mg", "label": "Milligramm (mg) → g", "factor": 0.001}, ] # — Körpergewicht (Ziel kg) — _KG: list[dict[str, Any]] = [ {"id": "kg", "label": "Kilogramm (kg), wie in DB", "factor": 1.0}, {"id": "g", "label": "Gramm (g) → kg", "factor": 0.001}, {"id": "lb", "label": "Pfund / lb → kg", "factor": 0.45359237}, {"id": "oz", "label": "Unze / oz → kg", "factor": 0.028349523125}, ] # — Strecke (Ziel km) — _KM: list[dict[str, Any]] = [ {"id": "km", "label": "Kilometer (km), wie in DB", "factor": 1.0}, {"id": "m", "label": "Meter (m) → km", "factor": 0.001}, {"id": "mi", "label": "Meilen (mi) → km", "factor": 1.609344}, ] _UNIT_FAMILY: dict[str, list[dict[str, Any]]] = { "kcal": _ENERGY, "g": _GRAM, "kg": _KG, "km": _KM, } def get_canonical_unit(module: str, db_field: str) -> str | None: mod = get_module_definition(module) if not mod: return None finfo: dict[str, Any] | None = mod.get("fields", {}).get(db_field) if not finfo: return None u = finfo.get("unit") return str(u) if u else None def source_unit_choices_for_field(module: str, db_field: str) -> list[dict[str, Any]]: """Optionen für GUI: id, label, canonical_unit, is_canonical (Umrechnung serverseitig).""" cu = get_canonical_unit(module, db_field) if not cu: return [] choices = _UNIT_FAMILY.get(cu) if not choices: return [] out: list[dict[str, Any]] = [ { "id": c["id"], "label": c["label"], "canonical_unit": cu, "is_canonical": c["id"] == cu, } for c in choices ] out.append( { "id": "custom", "label": "Benutzerdefiniert (Konvertierungsfaktor, z. B. ml→g je nach Dichte)", "canonical_unit": cu, "is_canonical": False, } ) return out def factor_source_to_canonical(module: str, db_field: str, source_unit: str | None) -> float: """ Multiplikator: CSV-Zahl * Faktor → Wert in kanonischer DB-Einheit. Unbekannte/None/leer/Passthrough → 1.0 ``source_unit`` ``custom`` / ``none``: kein Registry-Faktor (1.0); freie Skalierung nur über ``conversion_factor`` in type_conversions (JSON). """ if source_unit is None: return 1.0 su = str(source_unit).strip().lower() if not su: return 1.0 if su in ("custom", "none"): return 1.0 cu = get_canonical_unit(module, db_field) if not cu: return 1.0 choices = _UNIT_FAMILY.get(cu) if not choices: return 1.0 for c in choices: if str(c["id"]).lower() == su: return float(c["factor"]) return 1.0