"""Каталог показателей норм профиля стада.""" from __future__ import annotations import re import unicodedata from app.lab.indicators import RATION_ALL_INDICATORS, calc_indicator_keys _CALC_META = {d["key"]: d for d in RATION_ALL_INDICATORS} # Заголовок колонки CSV «Нормы Дойн/КРС» (после нормализации) → indicator_key в lab_profile_norm NORM_HEADER_TO_KEY: dict[str, str] = { "Сухое Вещество": "dry_matter", "Сыр. Протеин": "crude_protein", "уСП": "usp", "RNB": "rnb", "БРА": "rnb", "ЧЭЛ- КРС": "nel", "ОЭ-КРС": "oe", "Сырая клетч": "ndf", "Сырая клетчат": "ndf", "Сырая клетчатка": "ndf", "Структур клетчатк": "structural_fiber", "Сырой жир": "crude_fat", "Сирой жир": "crude_fat", "Ca": "calcium", "P": "phosphorus", "Mg": "magnesium", "Na": "sodium", "DCAB": "dcab", "Сахар и Крохм": "sugar_starch", "Нераств. Крохмал": "insoluble_starch", "Нерозч. Крохмал": "insoluble_starch", "Сахар": "sugar", "Крохмал": "starch", "Каротин": "carotene", "b -Каротин": "beta_carotene", "Линолевая к-та": "linoleic_acid", "Линоленовая ки-та": "linolenic_acid", "Масляная ки-та": "butyric_acid", "Мочевина": "urea", "СВ Основной корм": "dm_main", "КРС Орг Вещ": "tdn_cattle", "Перевар Орг Вещ": "digestible_organic_matter", "КРС Протеин": "cp_cattle", "Перевар Протеин": "digestible_protein", "КРС Сирий жир": "fat_cattle", "КРС Сирой жир": "fat_cattle", "Перевар Сырой жир": "digestible_fat", "Перевар Сирой жир": "digestible_fat", "КРС Сырая клетч": "fiber_cattle", "Перевар сыр клетч": "digestible_fiber", "КРС БЭВ": "nfe_cattle", "Перевар БЭВ": "digestible_nfe", "ВЕ": "feed_value", "НДК Общ": "ndf_total", "НДК Осн. Корм": "ndf_main_feed", "КДК общ": "adf_total", "% нераств. протеин": "insoluble_protein_pct", "Нераствор протеин": "insoluble_protein", "СЖ/кг СВ": "fat_per_kg_dm", "НСП/кг СВ": "nsp_per_kg_dm", "СП/кг СВ": "cp_per_kg_dm", "пОВ/кг СВ": "dom_per_kg_dm", "пСЖ/кг СВ": "digestible_fat_per_kg_dm", "уСП<7%CЖ": "usp_low_fat", "уСП>7%CЖ": "usp_high_fat", "уСП/кг СВ": "usp_per_kg_dm", "уСП в ОВ": "usp_in_om", "Нераств крохмал": "insoluble_starch_alt", "Метаб ОЕТ": "metab_oet", "Метаб лизин": "metab_lysine", "Метабол Треон": "metab_threonine", "Метаб Лейц": "metab_leucine", "Метаб Изол": "metab_isoleucine", "Метаб Вал": "metab_valine", "НДК % від СВ ()": "ndf_pct_dm_uk", "НДК % от СВ ()": "ndf_pct_dm", "НДК-ОК % від СВ ()": "ndf_main_pct_dm_uk", "НДК-ОК % от СВ ()": "ndf_main_pct_dm", "КДК % від СВ ()": "adf_pct_dm_uk", "КДК % от СВ ()": "adf_pct_dm", "НКВ % від СВ ()": "nfc_pct_dm_uk", "НКВ % от СВ ()": "nfc_pct_dm", "SW / кг СВ ()": "sw_per_kg_dm", "ЧЕЛ/кг СВ (МДж)": "nel_per_kg_dm", "Нер. СП / кг СВ": "rup_per_kg_dm", "%СК/кг СВ ()": "fiber_pct_per_kg_dm", "%-СЖ/кг СВ ()": "fat_pct_per_kg_dm", "%-уСП / кг СВ ()": "usp_pct_per_kg_dm", "% уСП/кг СВ": "usp_pct_dm", "%-Ca / кг СВ ()": "ca_pct_per_kg_dm", "%-P / кг СВ ()": "p_pct_per_kg_dm", "%-К / кг СВ ()": "k_pct_per_kg_dm", "%-Na / кг СВ ()": "na_pct_per_kg_dm", "%-Mg / кг СВ ()": "mg_pct_per_kg_dm", "% стр Сыр. Клетчатк.": "structural_fiber_pct", "% стр Сыр. Клетч.": "structural_fiber_pct", "% Крохмал. СВ": "starch_pct_dm", "% Нераств крохм": "insoluble_starch_pct", "Са:P": "ca_p_ratio", "K:Na": "k_na_ratio", "Рацион % СВ от Веса КРС": "ration_dm_pct_bw", "Рацион % от Веса КРС": "ration_pct_bw", "Витамин А": "vitamin_a", "Витамин D": "vitamin_d", "Витамин Е": "vitamin_e", "Витамин В1": "vitamin_b1", "Витамин В2": "vitamin_b2", "Витамин В6": "vitamin_b6", "Витамин В12": "vitamin_b12", "Пантеонат Кальция": "calcium_pantothenate", "Пантеонат Кальцию": "calcium_pantothenate", "Никотиновая кислота": "niacin", "Фолиева кислота": "folic_acid", "Фолиевач кислота": "folic_acid", "Холин": "choline", "Биотин": "biotin", "Fe": "iron", "Zn": "zinc", "Cu": "copper", "Co": "cobalt", "Mn": "manganese", "Se": "selenium", "J": "iodine", "K": "potassium", "Сахар и усв. крох": "sugar_digestible_starch", "Сырая зола": "crude_ash", "Сірая зола": "crude_ash", "БЭВ": "nfe", "БЄВ": "nfe", "Арахидоновая ки-та": "arachidonic_acid", "Полиэновая ки-та": "polyenoic_acid", "OET": "oet", "Синтез Мдж": "synthesis_mj", } # Метаданные для UI (label/unit) — показатели вне расчёта рациона _EXTRA_NORM_META: dict[str, dict[str, str]] = { "beta_carotene": {"label": "β-каротин", "unit": "мг"}, "linoleic_acid": {"label": "Линолевая к-та", "unit": "г"}, "linolenic_acid": {"label": "Линоленовая к-та", "unit": "г"}, "butyric_acid": {"label": "Масляная к-та", "unit": "г"}, "urea": {"label": "Мочевина", "unit": "г"}, "tdn_cattle": {"label": "КРС орг. вещество", "unit": "г"}, "digestible_organic_matter": {"label": "Перевар. орг. вещество", "unit": "г"}, "cp_cattle": {"label": "КРС протеин", "unit": "г"}, "digestible_protein": {"label": "Перевар. протеин", "unit": "г"}, "fat_cattle": {"label": "КРС сырой жир", "unit": "г"}, "digestible_fat": {"label": "Перевар. сырой жир", "unit": "г"}, "fiber_cattle": {"label": "КРС сырая клетчатка", "unit": "г"}, "digestible_fiber": {"label": "Перевар. сырая клетчатка", "unit": "г"}, "nfe_cattle": {"label": "КРС БЭВ", "unit": "г"}, "digestible_nfe": {"label": "Перевар. БЭВ", "unit": "г"}, "feed_value": {"label": "ВЕ", "unit": ""}, "ndf_total": {"label": "НДК общ", "unit": "г"}, "ndf_main_feed": {"label": "НДК осн. корм", "unit": "г"}, "adf_total": {"label": "КДК общ", "unit": "г"}, "insoluble_protein_pct": {"label": "% нераств. протеин", "unit": "%"}, "fat_per_kg_dm": {"label": "СЖ/кг СВ", "unit": "г"}, "nsp_per_kg_dm": {"label": "НСП/кг СВ", "unit": "г"}, "cp_per_kg_dm": {"label": "СП/кг СВ", "unit": "г"}, "dom_per_kg_dm": {"label": "пОВ/кг СВ", "unit": "г"}, "digestible_fat_per_kg_dm": {"label": "пСЖ/кг СВ", "unit": "г"}, "usp_low_fat": {"label": "уСП <7% СЖ", "unit": "г"}, "usp_high_fat": {"label": "уСП >7% СЖ", "unit": "г"}, "usp_per_kg_dm": {"label": "уСП/кг СВ", "unit": "г"}, "usp_in_om": {"label": "уСП в ОВ", "unit": "г"}, "insoluble_starch_alt": {"label": "Нераств. крахмал (2)", "unit": "г"}, "metab_oet": {"label": "Метаб. ОЕТ", "unit": "г"}, "metab_lysine": {"label": "Метаб. лизин", "unit": "г"}, "metab_threonine": {"label": "Метаб. треонин", "unit": "г"}, "metab_leucine": {"label": "Метаб. лейцин", "unit": "г"}, "metab_isoleucine": {"label": "Метаб. изолейцин", "unit": "г"}, "metab_valine": {"label": "Метаб. валин", "unit": "г"}, "ndf_pct_dm": {"label": "НДК % от СВ", "unit": "%"}, "ndf_pct_dm_uk": {"label": "НДК % від СВ", "unit": "%"}, "ndf_main_pct_dm": {"label": "НДК-ОК % от СВ", "unit": "%"}, "ndf_main_pct_dm_uk": {"label": "НДК-ОК % від СВ", "unit": "%"}, "adf_pct_dm": {"label": "КДК % от СВ", "unit": "%"}, "adf_pct_dm_uk": {"label": "КДК % від СВ", "unit": "%"}, "nfc_pct_dm": {"label": "НКВ % от СВ", "unit": "%"}, "nfc_pct_dm_uk": {"label": "НКВ % від СВ", "unit": "%"}, "sw_per_kg_dm": {"label": "SW / кг СВ", "unit": ""}, "fiber_pct_per_kg_dm": {"label": "%СК/кг СВ", "unit": "%"}, "fat_pct_per_kg_dm": {"label": "%-СЖ/кг СВ", "unit": "%"}, "usp_pct_per_kg_dm": {"label": "%-уСП / кг СВ", "unit": "%"}, "ca_pct_per_kg_dm": {"label": "%-Ca / кг СВ", "unit": "%"}, "p_pct_per_kg_dm": {"label": "%-P / кг СВ", "unit": "%"}, "k_pct_per_kg_dm": {"label": "%-К / кг СВ", "unit": "%"}, "na_pct_per_kg_dm": {"label": "%-Na / кг СВ", "unit": "%"}, "mg_pct_per_kg_dm": {"label": "%-Mg / кг СВ", "unit": "%"}, "structural_fiber_pct": {"label": "% стр. клетчатки", "unit": "%"}, "starch_pct_dm": {"label": "% крахмала СВ", "unit": "%"}, "insoluble_starch_pct": {"label": "% нераств. крахмала", "unit": "%"}, "ca_p_ratio": {"label": "Са:P", "unit": ""}, "k_na_ratio": {"label": "K:Na", "unit": ""}, "ration_dm_pct_bw": {"label": "Рацион % СВ от веса", "unit": "%"}, "ration_pct_bw": {"label": "Рацион % от веса", "unit": "%"}, "vitamin_a": {"label": "Витамин А", "unit": "МЕ"}, "vitamin_d": {"label": "Витамин D", "unit": "МЕ"}, "vitamin_e": {"label": "Витамин Е", "unit": "мг"}, "vitamin_b1": {"label": "Витамин В1", "unit": "мг"}, "vitamin_b2": {"label": "Витамин В2", "unit": "мг"}, "vitamin_b6": {"label": "Витамин В6", "unit": "мг"}, "vitamin_b12": {"label": "Витамин В12", "unit": "мкг"}, "calcium_pantothenate": {"label": "Пантотенат кальция", "unit": "мг"}, "niacin": {"label": "Никотиновая к-та", "unit": "мг"}, "folic_acid": {"label": "Фолиевая к-та", "unit": "мг"}, "choline": {"label": "Холин", "unit": "мг"}, "biotin": {"label": "Биотин", "unit": "мкг"}, "iron": {"label": "Fe", "unit": "мг"}, "zinc": {"label": "Zn", "unit": "мг"}, "copper": {"label": "Cu", "unit": "мг"}, "cobalt": {"label": "Co", "unit": "мг"}, "manganese": {"label": "Mn", "unit": "мг"}, "selenium": {"label": "Se", "unit": "мг"}, "iodine": {"label": "J", "unit": "мг"}, "potassium": {"label": "K", "unit": "г"}, "sugar_digestible_starch": {"label": "Сахар и усв. крахмал", "unit": "г"}, "crude_ash": {"label": "Сырая зола", "unit": "г"}, "nfe": {"label": "БЭВ", "unit": "г"}, "arachidonic_acid": {"label": "Арахидоновая к-та", "unit": "г"}, "polyenoic_acid": {"label": "Полиэновая к-та", "unit": "г"}, "oet": {"label": "OET", "unit": ""}, "synthesis_mj": {"label": "Синтез", "unit": "МДж"}, } _CALC_KEYS = calc_indicator_keys() def norm_header(value: str) -> str: return " ".join((value or "").split()).strip() def norm_title_to_key(title: str) -> str | None: """Заголовок колонки CSV → indicator_key (или None).""" key = NORM_HEADER_TO_KEY.get(norm_header(title)) if key: return key return _fallback_key(title) def _fallback_key(title: str) -> str | None: n = norm_header(title) if not n: return None low = n.lower().replace("і", "и").replace("є", "е") for header, key in NORM_HEADER_TO_KEY.items(): if header.lower() == low: return key slug = re.sub(r"[^a-z0-9]+", "_", unicodedata.normalize("NFKD", low).encode("ascii", "ignore").decode()) slug = slug.strip("_")[:48] return f"norm_{slug}" if slug else None def norm_indicator_meta(key: str) -> dict[str, str | bool]: calc = _CALC_META.get(key) if calc: return { "key": key, "label": str(calc["label"]), "unit": str(calc.get("unit") or ""), "inCalc": True, } extra = _EXTRA_NORM_META.get(key, {}) return { "key": key, "label": extra.get("label", key), "unit": extra.get("unit", ""), "inCalc": key in _CALC_KEYS, } def list_norm_indicators() -> list[dict[str, str | bool]]: keys: list[str] = [] seen: set[str] = set() for key in NORM_HEADER_TO_KEY.values(): if key not in seen: seen.add(key) keys.append(key) for key in sorted(_EXTRA_NORM_META): if key not in seen: keys.append(key) return [norm_indicator_meta(k) for k in keys] def calc_norm_keys() -> frozenset[str]: return _CALC_KEYS