from datetime import datetime from utils import logger, saveImage, safeFilename, deleteImage from db import CRUD from db.schemas.toolkit import Toolkit from sqlalchemy import select from db.handlers.records import ServiceRecordsHandler def handleToolkitImage(imageData, title: str): title = safeFilename(title) fileName = f"tools/{title}.png" if not saveImage(imageData, fileName): return None return fileName class ToolkitHandler: async def add(toolkitData: dict, user_id: int = None): title = toolkitData.get("title", None) if not title: logger.error("Не указано название инструмента") return {} query = select(Toolkit).where(Toolkit.title == title) toolkit = await CRUD.read(query) if toolkit: logger.error("Инструмент с таким названием уже существует") return {} try: imageDict = {"main": "static/images/tools/default.png", "additional": []} if "image" in toolkitData: imageData = toolkitData.pop("image") mainImage = imageData.get("main") if isinstance(mainImage, str) and mainImage.startswith( "static/images/" ): imageDict["main"] = mainImage else: imageFileName = handleToolkitImage(mainImage, title) if imageFileName: imageDict["main"] = imageFileName additionalImages = imageData.get("additional", []) if len(additionalImages) > 0: for image in additionalImages: if isinstance(image, str) and image.startswith( "static/images/" ): imageDict["additional"].append(image) else: imageFileName = handleToolkitImage(image, title) if imageFileName: imageDict["additional"].append(imageFileName) toolkitData["image"] = imageDict newToolkit = await Toolkit(**toolkitData).save() except Exception as e: logger.error(f"Ошибка сохранения инструмента: {str(e)}") return {} if not newToolkit: logger.error("Инструмент не сохранен") return {} logger.info(f"Инструмент {newToolkit.title} успешно создан") await ServiceRecordsHandler.add(user_id, {"Добавлен инструмент": toolkitData}) return newToolkit async def updateMovindDate(toolkitId: int): editedToolkit = await ToolkitHandler.edit(toolkitId, moved_at=datetime.now()) if not editedToolkit: logger.error("Инструмент не обновлен") return False return True async def updateRefillDate(toolkitId: int): logger.info(f"Обновление даты пополнения инструмента {toolkitId}...") editedToolkit = await ToolkitHandler.edit(toolkitId, refilled_at=datetime.now()) if not editedToolkit: logger.error("Инструмент не обновлен") return False return True async def edit(toolkitId: int, **kwargs): query = select(Toolkit).where(Toolkit.id == toolkitId) toolkit = await CRUD.read(query) if not toolkit: logger.error("Инструмент не найден") return {} try: if "image" in kwargs: title = kwargs.get("title", toolkit.title) imageData = kwargs.pop("image") imageDict = {"main": "", "additional": []} existImagesList = [toolkit.image.get("main")] existImagesList.extend(toolkit.image.get("additional")) newImagesList = [imageData.get("main")] newImagesList.extend(imageData.get("additional")) for existImage in existImagesList: if existImage not in newImagesList: deleteImage(existImage) if toolkit.image.get("main") != imageData.get("main"): if imageData.get("main") in existImagesList: imageDict["main"] = imageData.get("main") else: imageFileName = handleToolkitImage(imageData.get("main"), title) if imageFileName: imageDict["main"] = imageFileName else: imageDict["main"] = "images/tools/default.png" imageDict["additional"].extend(imageData.get("additional")) uploadList = imageData.get("upload", []) if len(uploadList) > 0: for image in uploadList: imageFileName = handleToolkitImage(image, title) if imageFileName: imageDict["additional"].append(imageFileName) kwargs["image"] = imageDict user_id = kwargs.pop("user_id", None) logger.debug(f"Обновление инструмента {toolkit.title}...") editedToolkit = await toolkit.edit(**kwargs) except Exception as e: logger.error(f"Ошибка обновления инструмента: {str(e)}") return {} if not editedToolkit: logger.error("Инструмент не обновлен") return {} logger.info( f"Инструмент {editedToolkit.title} успешно обновлен, изменены данные: {kwargs.keys()}" ) await ServiceRecordsHandler.add( user_id, {f"Обновлен инструмент {toolkit.title}": editedToolkit.toDict()} ) return editedToolkit.toDict() async def getAll(): query = select(Toolkit) toolkits = await CRUD.read(query, True) return [toolkit.toDict() for toolkit in toolkits] if toolkits else [] async def get(toolkitId: int): query = select(Toolkit).where(Toolkit.id == toolkitId) toolkit = await CRUD.read(query) if not toolkit: logger.error("Инструмент не найден") return {} return toolkit.toDict() async def getSeveral(toolkitIds: list[int]) -> list[dict]: query = select(Toolkit).where(Toolkit.id.in_(toolkitIds)) toolkits = await CRUD.read(query, True) return [toolkit.toDict() for toolkit in toolkits] if toolkits else [] async def checkCatogoryUse(category_id: int): query = select(Toolkit).where(Toolkit.category_id == category_id) toolkit = await CRUD.read(query) return True if toolkit else False async def delete(toolkitId: int, user_id: int = None): query = select(Toolkit).where(Toolkit.id == toolkitId) toolkit = await CRUD.read(query) if not toolkit: logger.error("Инструмент не найден") return False try: toolkitTitle = toolkit.title result = await CRUD.delete(toolkit) except Exception as e: logger.error(f"Ошибка удаления инструмента: {str(e)}") return False logger.info( f"Инструмент {toolkitTitle} {'успешно удален' if result else 'не удален'}" ) await ServiceRecordsHandler.add( user_id, {"Удален инструмент": f"Название: {toolkitTitle}"} ) return result async def initialize(): from .categories import CategoryHandler logger.info("Инициализация инструментов") categoriesList = await CategoryHandler.getAll() categories = {category["title"]: category["id"] for category in categoriesList} baseToolkits = [ { "title": "Фреза №1", "description": "Фреза такая сякая этакая #1", "specifications": { "Диаметр": "10", "Длина": "20", "Ещё что-то": "Ещё столько-то", }, "category_id": categories["Фрезеровка"], "quantity_min": 20, "quantity_min_extra": 10, "external_link": "https://nazv.ru", }, { "title": "Фреза №2", "description": "Фреза такая сякая этакая #2", "specifications": { "Диаметр": "10", "Длина": "20", "Ещё что-то": "Ещё столько-то", }, "category_id": categories["Фрезеровка"], "quantity_min": 20, "quantity_min_extra": 10, "external_link": "https://nazv.ru", }, { "title": "Фреза №3", "description": "Фреза такая сякая этакая #3", "specifications": { "Диаметр": "10", "Длина": "20", "Ещё что-то": "Ещё столько-то", }, "category_id": categories["Фрезеровка"], "quantity_min": 20, "quantity_min_extra": 10, "external_link": "https://nazv.ru", }, { "title": "Пластина №1", "description": "Пластина такая сякая этакая #1", "specifications": { "Размер": "10", "Радиус": "0.4", "Ещё что-то": "Ещё столько-то", }, "image": { "main": "static/images/tools/default.png", "additional": [ "static/images/users/default.png", "static/images/logo.png", ], }, "category_id": categories["Токарка"], "quantity_min": 20, "quantity_min_extra": 10, "external_link": "https://nazv.ru", }, { "title": "Пластина №2", "description": "Пластина такая сякая этакая #2", "specifications": { "Размер": "10", "Радиус": "0.4", "Ещё что-то": "Ещё столько-то", }, "category_id": categories["Токарка"], "quantity_min": 20, "quantity_min_extra": 10, "external_link": "https://nazv.ru", }, { "title": "Пластина №3", "description": "Пластина такая сякая этакая #3", "specifications": { "Размер": "10", "Радиус": "0.4", "Ещё что-то": "Ещё столько-то", }, "category_id": categories["Токарка"], "quantity_min": 20, "quantity_min_extra": 10, "external_link": "https://nazv.ru", }, { "title": "Сверло №1", "description": "Сверло такое сякое этакое #1", "specifications": { "Длина": "30", "Диаметр": "5", "Ещё что-то": "Ещё столько-то", }, "category_id": categories["Слесарка"], "quantity_min": 20, "quantity_min_extra": 10, "external_link": "https://nazv.ru", }, { "title": "Сверло №2", "description": "Сверло такое сякое этакое #2", "specifications": { "Длина": "30", "Диаметр": "5", "Ещё что-то": "Ещё столько-то", }, "category_id": categories["Слесарка"], "quantity_min": 20, "quantity_min_extra": 10, "external_link": "https://nazv.ru", }, { "title": "Сверло №3", "description": "Сверло такое сякое этакое #3", "specifications": { "Длина": "30", "Диаметр": "5", "Ещё что-то": "Ещё столько-то", }, "category_id": categories["Слесарка"], "quantity_min": 20, "quantity_min_extra": 10, "external_link": "https://nazv.ru", }, ] for toolkit in baseToolkits: await ToolkitHandler.add(toolkit) logger.info("Базовые инструменты успешно созданы") return