import uuid from datetime import datetime from fastapi import HTTPException from app.db.database import db from app.services.coins import CoinsService from app.services.server.command import CommandService # Коллекция для хранения товаров на торговой площадке marketplace_collection = db.marketplace_items # Добавьте новую коллекцию для операций marketplace_operations = db.marketplace_operations # Добавьте эту функцию def _serialize_mongodb_doc(doc): """Преобразует MongoDB документ для JSON сериализации""" if doc is None: return None # Добавить проверку на список if isinstance(doc, list): return [_serialize_mongodb_doc(item) for item in doc] result = {} for key, value in doc.items(): # Обработка ObjectId if key == "_id": result["_id"] = str(value) continue # Обработка ISODate if isinstance(value, datetime): result[key] = value.isoformat() # Обработка вложенных словарей elif isinstance(value, dict): if "$date" in value: # Это ISODate result[key] = datetime.fromisoformat(value["$date"].replace("Z", "+00:00")).isoformat() else: result[key] = _serialize_mongodb_doc(value) # Обработка списков elif isinstance(value, list): result[key] = [_serialize_mongodb_doc(item) if isinstance(item, dict) else item for item in value] else: result[key] = value return result class MarketplaceService: async def list_items(self, server_ip: str = None, page: int = 1, limit: int = 20): """Получить список предметов на торговой площадке""" query = {} if server_ip: query["server_ip"] = server_ip total = await marketplace_collection.count_documents(query) items_cursor = marketplace_collection.find(query) \ .sort("created_at", -1) \ .skip((page - 1) * limit) \ .limit(limit) items = await items_cursor.to_list(limit) # Преобразуем каждый документ serialized_items = [_serialize_mongodb_doc(item) for item in items] return { "items": serialized_items, "total": total, "page": page, "pages": (total + limit - 1) // limit } async def get_item(self, item_id: str): """Получить информацию о конкретном предмете""" item = await marketplace_collection.find_one({"id": item_id}) if not item: raise HTTPException(status_code=404, detail="Предмет не найден") return _serialize_mongodb_doc(item) async def add_item(self, username: str, slot_index: int, amount: int, price: int, server_ip: str): """Выставить предмет на продажу""" # Создаем операцию продажи operation_id = str(uuid.uuid4()) operation = { "id": operation_id, "type": "sell", "player_name": username, "slot_index": slot_index, "amount": amount, "price": price, "server_ip": server_ip, "status": "pending", "created_at": datetime.utcnow() } await marketplace_operations.insert_one(operation) return {"status": "pending", "operation_id": operation_id} async def get_pending_operations(self, server_ip: str): """Получить список операций для выполнения на сервере""" operations = await marketplace_operations.find({ "server_ip": server_ip, "status": "pending" }).to_list(100) return { "operations": _serialize_mongodb_doc(operations) } async def confirm_operation(self, operation_id: str, status: str = "success", error: str = None): """Подтвердить выполнение операции""" update = { "status": status } if error: update["error"] = error result = await marketplace_operations.update_one( {"id": operation_id}, {"$set": update} ) return {"status": "success"} async def update_item_details(self, operation_id: str, item_data: dict): """Обновить детальную информацию о предмете""" operation = await marketplace_operations.find_one({"id": operation_id}) if not operation: return {"status": "error", "message": "Операция не найдена"} # Создаем запись о предмете на торговой площадке item_id = str(uuid.uuid4()) marketplace_item = { "id": item_id, "material": item_data.get("material"), "amount": item_data.get("amount"), "price": operation.get("price"), "seller_name": operation.get("player_name"), "server_ip": operation.get("server_ip"), "display_name": item_data.get("meta", {}).get("display_name"), "lore": item_data.get("meta", {}).get("lore"), "enchants": item_data.get("meta", {}).get("enchants"), "durability": item_data.get("meta", {}).get("durability"), "item_data": item_data, "created_at": datetime.utcnow() } await marketplace_collection.insert_one(marketplace_item) # Обновляем операцию await marketplace_operations.update_one( {"id": operation_id}, {"$set": {"item_id": item_id, "status": "completed"}} ) return {"status": "success"} async def buy_item(self, buyer_username: str, item_id: str): """Купить предмет с торговой площадки""" # 1. Находим предмет item = await marketplace_collection.find_one({"id": item_id}) if not item: raise HTTPException(status_code=404, detail="Предмет не найден") # 2. Проверяем, что покупатель не является продавцом if item["seller_name"] == buyer_username: raise HTTPException(status_code=400, detail="Вы не можете купить свой же предмет") # 3. Проверяем баланс покупателя coins_service = CoinsService() buyer_balance = await coins_service.get_balance(buyer_username) if buyer_balance < item["price"]: raise HTTPException(status_code=400, detail=f"Недостаточно монет. Требуется: {item['price']}, имеется: {buyer_balance}") # 4. Создаем операцию покупки operation_id = str(uuid.uuid4()) operation = { "id": operation_id, "type": "buy", "player_name": buyer_username, "item_id": item_id, "item_data": item["item_data"], "price": item["price"], "server_ip": item["server_ip"], "status": "pending", "created_at": datetime.utcnow() } await marketplace_operations.insert_one(operation) # 5. Списываем деньги с покупателя await coins_service.decrease_balance(buyer_username, item["price"]) # 6. Начисляем деньги продавцу await coins_service.increase_balance(item["seller_name"], item["price"]) # 7. Удаляем предмет с торговой площадки await marketplace_collection.delete_one({"id": item_id}) return { "status": "pending", "operation_id": operation_id, "message": "Покупка в обработке. Предмет будет добавлен в ваш инвентарь." }