@@ -0,0 +1,129 @@
|
||||
"""AgroStar табличные форматы (PDF, xlsx) → те же AgrostarSample, что и XML."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
from app.modules.zootech.lab.etl.agrostar_xml_import import (
|
||||
AgrostarParseResult,
|
||||
AgrostarSample,
|
||||
_parse_float,
|
||||
_pct_dm_to_g_per_kg_sv,
|
||||
finalize_agrostar_sample,
|
||||
)
|
||||
|
||||
# Подпись в отчёте → ключ AgroStar XML (дальше — общий _AGROSTAR_MAP)
|
||||
_TABULAR_LABEL_TO_AGRO: dict[str, str] = {
|
||||
"Сухое вещество (DM)": "DM",
|
||||
"Сырой протеин (Crude Protein)": "CP",
|
||||
"КДК (ADF)": "ADF",
|
||||
"НДК (aNDF)": "NDF",
|
||||
"НДК по орг. веществу (aNDFom)": "aNDFom",
|
||||
"Сырой жир (Fat EE)": "Fat_EE",
|
||||
"Сырая зола (Ash)": "Ash",
|
||||
"Кальций (Ca)": "Ca",
|
||||
"Фосфор (P)": "P",
|
||||
"Магний (Mg)": "Mg",
|
||||
"Калий (K)": "K",
|
||||
"Сера (S)": "S",
|
||||
"Хлор (Cl)": "Cl",
|
||||
"Водорастворимый сахар (WSC)": "Sugar_WSC",
|
||||
"Cпирторастворимый сахар (ESC)": "Sugar_ESC",
|
||||
"Крахмал (Starch)": "Starch",
|
||||
"Безволокнистые углеводы (NFC)": "NFC",
|
||||
"Переваримые питательные вещества (TDN)": "TDN",
|
||||
"НДК протеин (ND-ICP)": "NDICP_CP",
|
||||
"Лизин": "Lys",
|
||||
"Метионин": "Met",
|
||||
"Лейцин": "Leu",
|
||||
"Изолейцин": "Ile",
|
||||
"Валин": "Val",
|
||||
"Усваиваемость НДК 30 ч (NDFD30)": "NDFDom_IV_30hr",
|
||||
}
|
||||
|
||||
_SECTION_HEADERS = frozenset(
|
||||
{
|
||||
"Протеин:",
|
||||
"Клетчатка:",
|
||||
"Сахара и крахмал:",
|
||||
"Жир и жирные кислоты:",
|
||||
"Минералы:",
|
||||
"Энергия:",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def map_tabular_label(label: str) -> str | None:
|
||||
text = (label or "").strip()
|
||||
if not text or text in _SECTION_HEADERS:
|
||||
return None
|
||||
if text in _TABULAR_LABEL_TO_AGRO:
|
||||
return _TABULAR_LABEL_TO_AGRO[text]
|
||||
lowered = text.lower()
|
||||
for key, ag_key in sorted(_TABULAR_LABEL_TO_AGRO.items(), key=lambda item: len(item[0]), reverse=True):
|
||||
if key.lower() in lowered:
|
||||
return ag_key
|
||||
return None
|
||||
|
||||
|
||||
def tabular_rows_to_agro_fields(rows: list[tuple[str, str]]) -> dict[str, float]:
|
||||
"""[(label, raw_value), ...] → raw_fields AgroStar."""
|
||||
out: dict[str, float] = {}
|
||||
for label, raw in rows:
|
||||
ag_key = map_tabular_label(label)
|
||||
if not ag_key:
|
||||
continue
|
||||
val = _parse_float(raw)
|
||||
if val is not None:
|
||||
out[ag_key] = val
|
||||
return out
|
||||
|
||||
|
||||
def sample_from_agro_fields(
|
||||
*,
|
||||
sample_no: str,
|
||||
farm_name: str,
|
||||
farm_id: str = "",
|
||||
date_printed: str = "",
|
||||
feed_type: str = "Mixed haylage",
|
||||
desc_1: str = "",
|
||||
desc_2: str = "",
|
||||
desc_3: str = "",
|
||||
agro_fields: dict[str, float],
|
||||
) -> AgrostarSample:
|
||||
sample = AgrostarSample(
|
||||
sample_no=sample_no,
|
||||
farm_name=farm_name,
|
||||
farm_id=farm_id,
|
||||
date_printed=date_printed,
|
||||
feed_type=feed_type,
|
||||
desc_1=desc_1,
|
||||
desc_2=desc_2,
|
||||
desc_3=desc_3,
|
||||
dry_matter_pct=agro_fields.get("DM"),
|
||||
)
|
||||
sample.raw_fields = {k: v for k, v in agro_fields.items() if k != "DM"}
|
||||
return finalize_agrostar_sample(sample)
|
||||
|
||||
|
||||
def parse_tabular_triplet_lines(lines: list[str]) -> list[tuple[str, str, str]]:
|
||||
"""Строки PDF: name, unit (%DM|%CP|%), value."""
|
||||
rows: list[tuple[str, str, str]] = []
|
||||
i = 0
|
||||
units = frozenset({"%DM", "%CP", "%"})
|
||||
while i < len(lines):
|
||||
line = lines[i]
|
||||
if line in units and i >= 1:
|
||||
name = lines[i - 1]
|
||||
val = lines[i + 1] if i + 1 < len(lines) else ""
|
||||
if val and (val[0].isdigit() or val.startswith("<")):
|
||||
rows.append((name, line, val))
|
||||
i += 2
|
||||
continue
|
||||
i += 1
|
||||
return rows
|
||||
|
||||
|
||||
def rows_to_label_values(triplets: list[tuple[str, str, str]]) -> list[tuple[str, str]]:
|
||||
return [(name, val) for name, _unit, val in triplets]
|
||||
Reference in New Issue
Block a user