/
Paff
/
declarant
Обзор
Документация
Войти
/
Paff
/
declarant
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
flower_db.py
230 строк
10 KB
1pash1985-gif
Декларант - веб-версия для Timeweb Cloud
15 июл 2026, 09:36
15 июл 2026, 09:36
a6b08b8
Код
Авторство
О чём код?
""" База данных цветов с хранением в JSON. Поддерживает поиск по названию и синонимам, добавление новых цветов. """ import json import os from typing import Optional from models import Flower # Путь к файлу базы данных DB_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "flowers_db.json") class FlowerDatabase: """База данных цветов с поддержкой поиска и добавления.""" def __init__(self, db_path: str = DB_PATH): self.db_path = db_path self.flowers: list[Flower] = [] self.load() def load(self): """Загрузить базу данных из JSON файла.""" if os.path.exists(self.db_path): try: with open(self.db_path, 'r', encoding='utf-8') as f: data = json.load(f) self.flowers = [] for item in data.get("flowers", []): flower = Flower( full_name_en=item.get("full_name_en", ""), full_name_ru=item.get("full_name_ru", ""), synonyms=item.get("synonyms", []), bg_color=item.get("bg_color", None) ) self.flowers.append(flower) except (json.JSONDecodeError, IOError) as e: print(f"Ошибка загрузки базы цветов: {e}") self.flowers = [] else: # Создать начальную базу self._create_default_db() def save(self): """Сохранить базу данных в JSON файл.""" data = { "flowers": [ { "full_name_en": f.full_name_en, "full_name_ru": f.full_name_ru, "synonyms": f.synonyms, "bg_color": f.bg_color } for f in self.flowers ] } with open(self.db_path, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=2) def find_flower(self, raw_text: str) -> Optional[Flower]: """ Найти цветок по исходному тексту из инвойса. Возвращает Flower если найден, иначе None. """ text_upper = raw_text.upper().strip() # Сначала ищем точное совпадение по полному имени for flower in self.flowers: if flower.full_name_en.upper() == text_upper: return flower # Потом ищем по вхождению полного имени for flower in self.flowers: if flower.full_name_en.upper() in text_upper: return flower # Потом ищем по синонимам (от длинных к коротким для точности) sorted_flowers = sorted(self.flowers, key=lambda f: max([len(s) for s in f.synonyms] + [0]), reverse=True) for flower in sorted_flowers: for synonym in flower.synonyms: if synonym.upper() in text_upper: return flower return None def add_flower(self, full_name_en: str, full_name_ru: str, synonyms: list[str] = None) -> Flower: """Добавить новый цветок в базу.""" flower = Flower( full_name_en=full_name_en, full_name_ru=full_name_ru, synonyms=synonyms or [] ) self.flowers.append(flower) self.save() return flower def add_synonym(self, flower: Flower, synonym: str): """Добавить синоним к существующему цветку.""" if synonym.upper() not in [s.upper() for s in flower.synonyms]: flower.synonyms.append(synonym) self.save() def set_flower_color(self, flower_en: str, color: str | None): """Установить или сбросить цвет фона для цветка.""" for flower in self.flowers: if flower.full_name_en.upper() == flower_en.upper(): flower.bg_color = color self.save() return True return False def get_flower_color(self, flower_en: str) -> str | None: """Получить цвет фона для цветка.""" for flower in self.flowers: if flower.full_name_en.upper() == flower_en.upper(): return flower.bg_color return None def get_all_flowers(self) -> list[Flower]: """Получить все цветы в базе.""" return self.flowers def get_flower_names(self) -> list[str]: """Получить список всех названий цветов (для GUI).""" return [f.full_name_en for f in self.flowers] def _create_default_db(self): """Создать начальную базу данных с распространенными цветами.""" default_flowers = [ Flower("Hydrangea", "Гортензия", ["HYDR", "HYDRANG"]), Flower("Rosa", "Роза", ["ROSE", "ROS"]), Flower("Alstroemeria", "Альстромерия", ["ALSTRO", "ALST"]), Flower("Chrysanthemum", "Хризантема", ["CHRYS", "MUMS"]), Flower("Carnation", "Гвоздика", ["CARN", "CARNATIO", "DIANTHUS", "DIANTH", "MINI CARNATION", "SPRAY CARNATION", "CLAVEL", "ГВОЗДИКА"]), Flower("Lilium", "Лилия", ["LILY", "LILIUM"]), Flower("Tulipa", "Тюльпан", ["TULIP", "TUL"]), Flower("Gerbera", "Гербера", ["GERB"]), Flower("Orchid", "Орхидея", ["ORCH", "PHALAENOPSIS"]), Flower("Gypsophila", "Гипсофила", ["GYPSO", "GYP"]), Flower("Solidago", "Солидаго", ["SOLID", "GOLDENROD"]), Flower("Hypericum", "Гиперикум", ["HYPER"]), Flower("Eryngium", "Эрингиум", ["ERYNG"]), Flower("Eucalyptus", "Эвкалипт", ["EUCAL"]), Flower("Statice", "Статица", ["LIMONIUM", "STAT"]), Flower("Delphinium", "Дельфиниум", ["DELPH"]), Flower("Astilbe", "Астильба", ["ASTIL"]), Flower("Bouvardia", "Бувальдия", ["BOUV"]), Flower("Dianthus", "Гвоздика", ["DIANTH", "DIANTHUS", "CARNATION", "CARNATIO", "CARN", "MINI CARNATION", "SPRAY CARNATION", "CLAVEL", "ГВОЗДИКА"]), Flower("Leucadendron", "Леукадендрон", ["LEUC"]), Flower("Protea", "Протея", ["PROT"]), Flower("Ruscus", "Рускус", ["RUSC"]), Flower("Pittosporum", "Питтоспорум", ["PITT"]), Flower("Aspidistra", "Аспидистра", ["ASPID"]), Flower("Agapanthus", "Агапантус", ["AGAP"]), Flower("Amaranthus", "Амарантус", ["AMAR"]), Flower("Anemone", "Анемон", ["ANEM"]), Flower("Anthurium", "Антуриум", ["ANTH"]), Flower("Aster", "Астра", ["AST"]), Flower("Bupleurum", "Буплерум", ["BUPL"]), Flower("Calla", "Калла", ["ZANTEDESCHIA"]), Flower("Celosia", "Целозия", ["CELOS"]), Flower("Craspedia", "Краспедия", ["CRASP"]), Flower("Dahlia", "Георгин", ["DAHL"]), Flower("Freesia", "Фрезия", ["FREES"]), Flower("Gladiolus", "Гладиолус", ["GLAD"]), Flower("Heliconia", "Геликония", ["HELIC"]), Flower("Iris", "Ирис", ["IRIS"]), Flower("Lavandula", "Лаванда", ["LAVAND", "LAVENDER"]), Flower("Limonium", "Лимониум", ["LIMON"]), Flower("Matthiola", "Маттиола", ["MATTH", "STOCK"]), Flower("Narcissus", "Нарцисс", ["NARC"]), Flower("Paeonia", "Пион", ["PAEON", "PEONY"]), Flower("Ranunculus", "Ранункулюс", ["RANUN"]), Flower("Salix", "Ива", ["WILLOW", "SALIX"]), Flower("Scabiosa", "Скабиоза", ["SCAB"]), Flower("Snapdragon", "Львиный зев", ["ANTIRRHINUM", "SNAP"]), Flower("Sunflower", "Подсолнух", ["HELIANTHUS", "SUNFL"]), Flower("Trachelium", "Трахелиум", ["TRACH"]), Flower("Veronica", "Вероника", ["VERON"]), Flower("Zinnia", "Цинния", ["ZINN"]), Flower("Allium", "Аллиум", ["ALLI"]), Flower("Aloe", "Алое", ["ALOE"]), Flower("Alpinia", "Альпиния", ["ALPIN"]), Flower("Amarine", "Амарина", ["AMAR"]), Flower("Amaryllis", "Амариллис", ["AMARYLL", "HIPPEASTRUM"]), Flower("Amarcrinum", "Амаркринум", ["AMARCR"]), Flower("Ammi", "Амми", ["AMMI"]), Flower("Amsonia", "Амсония", ["AMSON"]), Flower("Ananas", "Ананас", ["ANAN"]), Flower("Anethum", "Анетум", ["ANETH", "DILL"]), ] self.flowers = default_flowers self.save() def extract_client_from_folder(folder_name: str) -> str: """ Извлечь имя клиента из названия папки. Пример: "1561 AIGUL" -> "AIGUL" """ parts = folder_name.strip().split(maxsplit=1) if len(parts) > 1: return parts[1].strip() return folder_name.strip() def extract_client_from_po(po_text: str) -> str: """ Извлечь имя клиента из PO# в инвойсе. Пример: "B-AIGUL X BEST FLORA-2" -> "AIGUL" """ if not po_text: return "" # Ищем паттерн B-XXXX или просто имя import re # Паттерн: B-NAME (где NAME - имя клиента до пробела или X) match = re.search(r'B-([A-ZА-Я]+)', po_text.upper()) if match: return match.group(1) # Если не нашли B- паттерн, возвращаем первое слово parts = po_text.strip().split() if parts: return parts[0].strip("-") return ""