from datetime import datetime from uuid import uuid4 from fastapi import HTTPException from app.db.database import db player_inventory_collection = db.player_inventory marketplace_operations_collection = 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 InventoryService: async def list_items(self, username: str, server_ip: str, page: int = 1, limit: int = 20): q = {"username": username, "server_ip": server_ip, "status": {"$in": ["stored", "withdrawing"]}} skip = max(page - 1, 0) * limit items = await player_inventory_collection.find(q) \ .sort("created_at", -1) \ .skip(skip) \ .limit(limit) \ .to_list(length=limit) serialized_items = _serialize_mongodb_doc(items) total = await player_inventory_collection.count_documents(q) return {"items": serialized_items, "page": page, "limit": limit, "total": total} async def withdraw_item(self, username: str, item_id: str, server_ip: str): item = await player_inventory_collection.find_one({"id": item_id}) if not item: raise HTTPException(status_code=404, detail="Item not found") if item["username"] != username: raise HTTPException(status_code=403, detail="Not your item") if item["server_ip"] != server_ip: raise HTTPException(status_code=400, detail="Wrong server_ip for this item") if item.get("status") != "stored": raise HTTPException(status_code=400, detail="Item is not available for withdraw") # создаём операцию выдачи НА СЕРВЕР (тип оставляем case_reward) op_id = str(uuid4()) operation = { "id": op_id, "type": "case_reward", "player_name": username, "item_data": item["item_data"], "server_ip": server_ip, "status": "pending", "created_at": datetime.utcnow(), # важно: связка с инвентарём, чтобы confirm мог отметить delivered "inventory_item_id": item_id, "source": item.get("source"), } await marketplace_operations_collection.insert_one(operation) # помечаем предмет как withdrawing await player_inventory_collection.update_one( {"id": item_id}, {"$set": {"status": "withdrawing", "withdraw_operation_id": op_id}} ) return {"ok": True, "operation_id": op_id, "item_id": item_id}