update dashboard
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
"""نامگذاری متریال — تفکیک «خانواده» از «مشخصه/واریانت» بهصورت عمومی.
|
||||
|
||||
برخی ردیفهای کاتالوگ، سایز/گرید را داخل نام ماده دارند
|
||||
(«بلوک سیمانی ۲۰×۲۰×۴۰»، «لوله پلیاتیلن PE100 سایز ۲۵»). این ماژول با قواعد
|
||||
الگویی (ابعاد NxNxN، کلیدواژههای مشخصه، کدهای گرید لاتین) نام را به
|
||||
«خانواده» و «واریانت» میشکند — بدون هیچ هاردکدِ نام محصول مشخصی.
|
||||
"""
|
||||
import re
|
||||
|
||||
_DIGIT_MAP = str.maketrans("۰۱۲۳۴۵۶۷۸۹٠١٢٣٤٥٦٧٨٩", "01234567890123456789")
|
||||
|
||||
# واژههایی که شروع بخش مشخصه را نشان میدهند (ابعاد/درجه/تیپ/مدل/…)
|
||||
_ATTRIBUTE_WORDS = {
|
||||
"سایز",
|
||||
"تیپ",
|
||||
"مدل",
|
||||
"درجه",
|
||||
"ضخامت",
|
||||
"قطر",
|
||||
"ابعاد",
|
||||
"طول",
|
||||
"عرض",
|
||||
"ارتفاع",
|
||||
"رنگ",
|
||||
"وزن",
|
||||
"ظرفیت",
|
||||
"شماره",
|
||||
"کلاس",
|
||||
}
|
||||
|
||||
# ابعاد ترکیبی: ۲۰×۲۰×۴۰ / ۲×۲٫۵ / 60x60 / 2*2.5
|
||||
_DIMENSION_RE = re.compile(r"^\d+(?:[×xX*]\d+(?:[.,٫/]\d+)?)+$")
|
||||
# کد گرید: PE100 / PN10 / DN50 / A3 / SN4 / ST37
|
||||
_GRADE_RE = re.compile(r"^(?:PN|PE|DN|SN|SCH|ST|A|B|C)[-]?\d+$")
|
||||
_NUMBER_RE = re.compile(r"^\d+(?:[.,٫/]\d+)?$")
|
||||
_LATIN_WORD_RE = re.compile(r"^[A-Za-z]{2,6}$")
|
||||
|
||||
STANDARD_VARIANT_LABEL = "استاندارد"
|
||||
|
||||
|
||||
def normalize_digits(text: str) -> str:
|
||||
return (text or "").translate(_DIGIT_MAP)
|
||||
|
||||
|
||||
def _is_spec_start(tokens: list[str], index: int) -> bool:
|
||||
token = tokens[index]
|
||||
normalized = normalize_digits(token)
|
||||
if normalized in _ATTRIBUTE_WORDS: # «سایز»، «تیپ»، «مدل»، …
|
||||
return True
|
||||
if _DIMENSION_RE.match(normalized): # ۲۰×۲۰×۴۰
|
||||
return True
|
||||
if _GRADE_RE.match(token): # PE100 / PN10 / A3
|
||||
return True
|
||||
# کد لاتین کوتاه که پشتش عدد میآید: «IPE ۱۴»
|
||||
if (
|
||||
_LATIN_WORD_RE.match(token)
|
||||
and index + 1 < len(tokens)
|
||||
and _NUMBER_RE.match(normalize_digits(tokens[index + 1]))
|
||||
):
|
||||
return True
|
||||
# عددِ تنها در انتهای نام (بدون کلیدواژه): «لوله مسی ۱۵»
|
||||
if _NUMBER_RE.match(normalized) and index == len(tokens) - 1 and index >= 1:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def split_material_name(name: str) -> tuple[str, str | None]:
|
||||
"""«لوله پلیاتیلن PE100 سایز ۲۵» → («لوله پلیاتیلن», «PE100 سایز ۲۵»)."""
|
||||
tokens = [token for token in (name or "").split() if token]
|
||||
for index in range(1, len(tokens)):
|
||||
if _is_spec_start(tokens, index):
|
||||
family = " ".join(tokens[:index]).strip()
|
||||
variant = " ".join(tokens[index:]).strip()
|
||||
if family and variant:
|
||||
return family, variant
|
||||
return " ".join(tokens).strip(), None
|
||||
|
||||
|
||||
def material_family(name: str) -> str:
|
||||
"""نام خانواده (بدون واریانت)."""
|
||||
family, _ = split_material_name(name)
|
||||
return " ".join(family.split())
|
||||
|
||||
|
||||
def material_family_key(name: str) -> str:
|
||||
"""شناسهی پایدار خانواده — همان نام نرمالشده (بدون UUID اختصاصی)."""
|
||||
return material_family(name)
|
||||
|
||||
|
||||
def variant_label(name: str) -> str:
|
||||
"""برچسب واریانت؛ در نبود واریانت، «استاندارد»."""
|
||||
_, variant = split_material_name(name)
|
||||
return variant or STANDARD_VARIANT_LABEL
|
||||
|
||||
|
||||
def spec_label_from_specs(specs: dict | None) -> str | None:
|
||||
"""برچسب کوتاه مشخصات از JSON موجودی (فقط مقدارها، نه «کلید: مقدار»)."""
|
||||
if not specs:
|
||||
return None
|
||||
values = [str(value).strip() for value in specs.values() if str(value).strip()]
|
||||
return "، ".join(values) if values else None
|
||||
|
||||
|
||||
def material_entry_labels(material_name: str, specs: dict | None) -> dict:
|
||||
"""برچسبهای نمایشی یک ردیف کاتالوگ: خانواده، واریانت، مشخصه.
|
||||
|
||||
`spec_label` (برچسب محور X) = مقدار مشخصات JSON اگر موجود باشد، وگرنه
|
||||
واریانتِ استخراجشده از نام، وگرنه «استاندارد».
|
||||
"""
|
||||
family = material_family(material_name)
|
||||
variant = variant_label(material_name)
|
||||
spec_from_json = spec_label_from_specs(specs)
|
||||
# برچسب محور X: واریانت (سایز/گرید) ترجیح دارد؛ در نبود آن مقدار مشخصات
|
||||
axis_label = variant if variant != STANDARD_VARIANT_LABEL else (spec_from_json or STANDARD_VARIANT_LABEL)
|
||||
return {
|
||||
"family_id": material_family_key(material_name),
|
||||
"family_name": family,
|
||||
"variant_label": variant,
|
||||
"spec_label": axis_label,
|
||||
"spec_detail": spec_from_json,
|
||||
}
|
||||
Reference in New Issue
Block a user