ibrohm's picture
Upload folder using huggingface_hub
9b5a86f verified
Raw
History Blame Contribute Delete
9.74 kB
import os
import logging
from datetime import datetime
from motor.motor_asyncio import AsyncIOMotorClient
from config import MONGO_URI, PRODUCTS
logger = logging.getLogger(__name__)
# MongoDB Client
client = AsyncIOMotorClient(MONGO_URI)
db = client.get_database("telegram_bot")
async def init_db():
"""MongoDB ulanishini tekshirish va dastlabki sozlashlarni bajarish."""
try:
# Indexlarni yaratish
await db.users.create_index("id", unique=True)
await db.products.create_index("id", unique=True)
await db.gift_codes.create_index("id", unique=True)
await db.gift_codes.create_index("gift_link", unique=True)
await db.orders.create_index("id", unique=True)
# Standart mahsulotlarni qo'shish (agar mavjud bo'lmasa)
for p in PRODUCTS:
await db.products.update_one(
{"id": p["id"]},
{"$setOnInsert": {
"id": p["id"],
"name": p["name"],
"description": p["description"],
"duration_months": p["duration_months"],
"stars_price": p["stars_price"],
"emoji": p["emoji"],
"is_active": 1
}},
upsert=True
)
logger.info("βœ… MongoDB indekslari va boshlang'ich mahsulotlar tayyor.")
except Exception as e:
logger.error(f"❌ MongoDB init_db xatosi: {e}", exc_info=True)
async def get_next_sequence_value(sequence_name: str) -> int:
"""Auto-increment integer ID yaratish (SQLite o'rniga ishlatiladi)."""
result = await db.counters.find_one_and_update(
{"_id": sequence_name},
{"$inc": {"sequence_value": 1}},
upsert=True,
return_document=True
)
return result["sequence_value"]
# ─────────────────────── USERS ───────────────────────
async def upsert_user(user_id: int, username: str | None, full_name: str):
"""Foydalanuvchini qo'shish yoki yangilash."""
await db.users.update_one(
{"id": user_id},
{"$set": {
"username": username,
"full_name": full_name,
"created_at": datetime.now().isoformat()
}},
upsert=True
)
async def get_all_user_ids() -> list[int]:
"""Barcha foydalanuvchilar ID larini olish (broadcast uchun)."""
cursor = db.users.find({}, {"id": 1})
rows = await cursor.to_list(length=None)
return [row["id"] for row in rows]
async def count_users() -> int:
"""Foydalanuvchilar sonini hisoblash."""
return await db.users.count_documents({})
# ─────────────────────── PRODUCTS ───────────────────────
async def get_active_products() -> list[dict]:
"""Faol mahsulotlar ro'yxatini olish."""
cursor = db.products.find({"is_active": 1}).sort("duration_months", 1)
rows = await cursor.to_list(length=None)
return rows
async def get_product_by_id(product_id: int) -> dict | None:
"""ID bo'yicha mahsulotni olish."""
return await db.products.find_one({"id": product_id})
async def update_product_price(product_id: int, new_price: int):
"""Mahsulot narxini yangilash."""
await db.products.update_one(
{"id": product_id},
{"$set": {"stars_price": new_price}}
)
# ─────────────────────── GIFT CODES ───────────────────────
async def add_gift_code(product_id: int, gift_link: str) -> bool:
"""Yangi sovg'a linkini zaxiraga qo'shish. Agar mavjud bo'lsa False qaytaradi."""
try:
# O'xshash link borligini tekshiramiz (unique constraint)
exists = await db.gift_codes.find_one({"gift_link": gift_link})
if exists:
return False
new_id = await get_next_sequence_value("gift_code_id")
await db.gift_codes.insert_one({
"id": new_id,
"product_id": product_id,
"gift_link": gift_link,
"is_used": 0,
"used_by": None,
"order_id": None,
"added_at": datetime.now().isoformat(),
"used_at": None
})
return True
except Exception:
return False
async def get_available_code(product_id: int) -> dict | None:
"""Berilgan mahsulot uchun birinchi ishlatilmagan linkni olish."""
return await db.gift_codes.find_one({
"product_id": product_id,
"is_used": 0
}, sort=[("id", 1)])
async def mark_code_used(code_id: int, user_id: int, order_id: int):
"""Linkni ishlatilgan deb belgilash."""
await db.gift_codes.update_one(
{"id": code_id},
{"$set": {
"is_used": 1,
"used_by": user_id,
"order_id": order_id,
"used_at": datetime.now().isoformat()
}}
)
async def count_available_codes(product_id: int) -> int:
"""Mahsulot uchun mavjud linklarni sanash."""
return await db.gift_codes.count_documents({
"product_id": product_id,
"is_used": 0
})
async def get_stock_summary() -> list[dict]:
"""Har bir mahsulot uchun zaxira holati."""
products = await get_active_products()
summary = []
for p in products:
available = await db.gift_codes.count_documents({"product_id": p["id"], "is_used": 0})
used = await db.gift_codes.count_documents({"product_id": p["id"], "is_used": 1})
total = available + used
summary.append({
"name": p["name"],
"emoji": p.get("emoji", "⭐"),
"stars_price": p["stars_price"],
"available": available,
"used": used,
"total": total
})
return summary
# ─────────────────────── ORDERS ───────────────────────
async def create_order(user_id: int, product_id: int, stars_amount: int) -> int:
"""Yangi buyurtma yaratish va uning ID sini qaytarish."""
new_id = await get_next_sequence_value("order_id")
await db.orders.insert_one({
"id": new_id,
"user_id": user_id,
"product_id": product_id,
"gift_code_id": None,
"status": "pending",
"charge_id": None,
"stars_amount": stars_amount,
"created_at": datetime.now().isoformat(),
"completed_at": None
})
return new_id
async def complete_order(order_id: int, gift_code_id: int, charge_id: str):
"""Buyurtmani yakunlash."""
await db.orders.update_one(
{"id": order_id},
{"$set": {
"status": "completed",
"gift_code_id": gift_code_id,
"charge_id": charge_id,
"completed_at": datetime.now().isoformat()
}}
)
async def fail_order(order_id: int, charge_id: str):
"""Buyurtmani (zaxira yo'qligi sababli) pending_delivery holatiga o'tkazish."""
await db.orders.update_one(
{"id": order_id},
{"$set": {
"status": "pending_delivery",
"charge_id": charge_id
}}
)
async def get_user_orders(user_id: int) -> list[dict]:
"""Foydalanuvchi buyurtmalari tarixi (oxirgi 10 ta)."""
cursor = db.orders.find({"user_id": user_id}).sort("created_at", -1).limit(10)
orders = await cursor.to_list(length=None)
result = []
for o in orders:
product = await db.products.find_one({"id": o["product_id"]})
gift_link = None
if o.get("gift_code_id"):
code = await db.gift_codes.find_one({"id": o["gift_code_id"]})
if code:
gift_link = code["gift_link"]
result.append({
"id": o["id"],
"status": o["status"],
"stars_amount": o.get("stars_amount"),
"created_at": o["created_at"],
"product_name": product["name"] if product else "Noma'lum",
"gift_link": gift_link
})
return result
async def get_total_stats() -> dict:
"""Umumiy statistika."""
total_completed = await db.orders.count_documents({"status": "completed"})
# Stars summasini hisoblash
pipeline = [
{"$match": {"status": "completed"}},
{"$group": {"_id": None, "total": {"$sum": "$stars_amount"}}}
]
cursor = db.orders.aggregate(pipeline)
agg_result = await cursor.to_list(length=1)
total_stars = agg_result[0]["total"] if agg_result else 0
pending_delivery = await db.orders.count_documents({"status": "pending_delivery"})
return {
"total_completed": total_completed,
"total_stars": total_stars,
"pending_delivery": pending_delivery
}
async def get_pending_delivery_orders() -> list[dict]:
"""Zaxira bo'lmaganligi sababli kutilayotgan buyurtmalar."""
cursor = db.orders.find({"status": "pending_delivery"}).sort("created_at", 1)
orders = await cursor.to_list(length=None)
result = []
for o in orders:
product = await db.products.find_one({"id": o["product_id"]})
user = await db.users.find_one({"id": o["user_id"]})
result.append({
"id": o["id"],
"user_id": o["user_id"],
"stars_amount": o.get("stars_amount"),
"created_at": o["created_at"],
"product_name": product["name"] if product else "Noma'lum",
"product_id": o["product_id"],
"username": user.get("username") if user else None,
"full_name": user.get("full_name") if user else "Noma'lum"
})
return result