""" MTXtyle - Database operatsiyalari (SQLite + aiosqlite) """ import aiosqlite import time from config import DATABASE_PATH, CATEGORIES async def init_db(): """Jadvallarni yaratish""" async with aiosqlite.connect(DATABASE_PATH) as db: # Kategoriyalar jadvali await db.execute(""" CREATE TABLE IF NOT EXISTS categories ( id INTEGER PRIMARY KEY AUTOINCREMENT, slug TEXT UNIQUE NOT NULL, name TEXT NOT NULL, emoji TEXT DEFAULT '' ) """) # Mahsulotlar jadvali await db.execute(""" CREATE TABLE IF NOT EXISTS products ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, description TEXT DEFAULT '', price INTEGER NOT NULL, category_id INTEGER, photo_id TEXT DEFAULT '', in_stock INTEGER DEFAULT 1, created_at REAL DEFAULT 0, FOREIGN KEY (category_id) REFERENCES categories(id) ) """) # Savat jadvali await db.execute(""" CREATE TABLE IF NOT EXISTS cart_items ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, product_id INTEGER NOT NULL, quantity INTEGER DEFAULT 1, FOREIGN KEY (product_id) REFERENCES products(id) ) """) # Buyurtmalar jadvali await db.execute(""" CREATE TABLE IF NOT EXISTS orders ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, full_name TEXT NOT NULL, phone TEXT NOT NULL, address TEXT NOT NULL, total_price INTEGER DEFAULT 0, status TEXT DEFAULT 'yangi', created_at REAL DEFAULT 0 ) """) # Buyurtma elementlari await db.execute(""" CREATE TABLE IF NOT EXISTS order_items ( id INTEGER PRIMARY KEY AUTOINCREMENT, order_id INTEGER NOT NULL, product_id INTEGER NOT NULL, product_name TEXT NOT NULL, quantity INTEGER DEFAULT 1, price INTEGER DEFAULT 0, FOREIGN KEY (order_id) REFERENCES orders(id), FOREIGN KEY (product_id) REFERENCES products(id) ) """) # Users table for broadcast await db.execute(""" CREATE TABLE IF NOT EXISTS users ( user_id INTEGER PRIMARY KEY, username TEXT, full_name TEXT, joined_at REAL ) """) await db.commit() # Default kategoriyalarni qo'shish for slug, info in CATEGORIES.items(): try: await db.execute( "INSERT OR IGNORE INTO categories (slug, name, emoji) VALUES (?, ?, ?)", (slug, info["name"], info["emoji"]) ) except Exception: pass await db.commit() # ==================== KATEGORIYALAR ==================== async def get_categories(): """Barcha kategoriyalarni olish""" async with aiosqlite.connect(DATABASE_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute("SELECT * FROM categories ORDER BY id") rows = await cursor.fetchall() return [dict(row) for row in rows] async def get_category_by_slug(slug): """Slug bo'yicha kategoriya olish""" async with aiosqlite.connect(DATABASE_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute("SELECT * FROM categories WHERE slug = ?", (slug,)) row = await cursor.fetchone() return dict(row) if row else None async def get_category_by_id(category_id): """ID bo'yicha kategoriya olish""" async with aiosqlite.connect(DATABASE_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute("SELECT * FROM categories WHERE id = ?", (category_id,)) row = await cursor.fetchone() return dict(row) if row else None # ==================== MAHSULOTLAR ==================== async def add_product(name, description, price, category_id, photo_id=""): """Yangi mahsulot qo'shish""" async with aiosqlite.connect(DATABASE_PATH) as db: cursor = await db.execute( """INSERT INTO products (name, description, price, category_id, photo_id, created_at) VALUES (?, ?, ?, ?, ?, ?)""", (name, description, price, category_id, photo_id, time.time()) ) await db.commit() return cursor.lastrowid async def get_products_by_category(category_id, page=0, per_page=5): """Kategoriya bo'yicha mahsulotlarni olish (pagination bilan)""" async with aiosqlite.connect(DATABASE_PATH) as db: db.row_factory = aiosqlite.Row offset = page * per_page # Umumiy sonni olish cursor = await db.execute( "SELECT COUNT(*) as cnt FROM products WHERE category_id = ? AND in_stock = 1", (category_id,) ) row = await cursor.fetchone() total = row["cnt"] # Mahsulotlarni olish cursor = await db.execute( """SELECT * FROM products WHERE category_id = ? AND in_stock = 1 ORDER BY created_at DESC LIMIT ? OFFSET ?""", (category_id, per_page, offset) ) rows = await cursor.fetchall() products = [dict(r) for r in rows] return products, total async def get_product_by_id(product_id): """ID bo'yicha mahsulot olish""" async with aiosqlite.connect(DATABASE_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute("SELECT * FROM products WHERE id = ?", (product_id,)) row = await cursor.fetchone() return dict(row) if row else None async def get_all_products(): """Barcha mahsulotlarni olish""" async with aiosqlite.connect(DATABASE_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute( "SELECT p.*, c.name as category_name FROM products p LEFT JOIN categories c ON p.category_id = c.id ORDER BY p.created_at DESC" ) rows = await cursor.fetchall() return [dict(r) for r in rows] async def update_product(product_id, **kwargs): """Mahsulotni yangilash""" allowed_fields = {"name", "description", "price", "category_id", "photo_id", "in_stock"} fields = {k: v for k, v in kwargs.items() if k in allowed_fields} if not fields: return False set_clause = ", ".join(f"{k} = ?" for k in fields) values = list(fields.values()) + [product_id] async with aiosqlite.connect(DATABASE_PATH) as db: await db.execute(f"UPDATE products SET {set_clause} WHERE id = ?", values) await db.commit() return True async def delete_product(product_id): """Mahsulotni o'chirish""" async with aiosqlite.connect(DATABASE_PATH) as db: await db.execute("DELETE FROM products WHERE id = ?", (product_id,)) await db.commit() async def search_products(query): """Mahsulotlarni qidirish""" async with aiosqlite.connect(DATABASE_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute( "SELECT * FROM products WHERE in_stock = 1 AND (name LIKE ? OR description LIKE ?) ORDER BY created_at DESC", (f"%{query}%", f"%{query}%") ) rows = await cursor.fetchall() return [dict(r) for r in rows] # ==================== SAVAT (CART) ==================== async def add_to_cart(user_id, product_id, quantity=1): """Savatga mahsulot qo'shish""" async with aiosqlite.connect(DATABASE_PATH) as db: # Mavjudligini tekshirish cursor = await db.execute( "SELECT * FROM cart_items WHERE user_id = ? AND product_id = ?", (user_id, product_id) ) existing = await cursor.fetchone() if existing: new_qty = existing[3] + quantity if new_qty <= 0: await db.execute( "DELETE FROM cart_items WHERE user_id = ? AND product_id = ?", (user_id, product_id) ) else: await db.execute( "UPDATE cart_items SET quantity = ? WHERE user_id = ? AND product_id = ?", (new_qty, user_id, product_id) ) else: if quantity > 0: await db.execute( "INSERT INTO cart_items (user_id, product_id, quantity) VALUES (?, ?, ?)", (user_id, product_id, quantity) ) await db.commit() async def get_cart(user_id): """Foydalanuvchi savatini olish""" async with aiosqlite.connect(DATABASE_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute( """SELECT ci.*, p.name, p.price, p.photo_id FROM cart_items ci JOIN products p ON ci.product_id = p.id WHERE ci.user_id = ?""", (user_id,) ) rows = await cursor.fetchall() return [dict(r) for r in rows] async def get_cart_total(user_id): """Savat umumiy summasini olish""" async with aiosqlite.connect(DATABASE_PATH) as db: cursor = await db.execute( """SELECT COALESCE(SUM(ci.quantity * p.price), 0) as total FROM cart_items ci JOIN products p ON ci.product_id = p.id WHERE ci.user_id = ?""", (user_id,) ) row = await cursor.fetchone() return row[0] async def update_cart_quantity(user_id, product_id, quantity): """Savatdagi mahsulot miqdorini o'zgartirish""" async with aiosqlite.connect(DATABASE_PATH) as db: if quantity <= 0: await db.execute( "DELETE FROM cart_items WHERE user_id = ? AND product_id = ?", (user_id, product_id) ) else: await db.execute( "UPDATE cart_items SET quantity = ? WHERE user_id = ? AND product_id = ?", (quantity, user_id, product_id) ) await db.commit() async def remove_from_cart(user_id, product_id): """Savatdan mahsulotni o'chirish""" async with aiosqlite.connect(DATABASE_PATH) as db: await db.execute( "DELETE FROM cart_items WHERE user_id = ? AND product_id = ?", (user_id, product_id) ) await db.commit() async def clear_cart(user_id): """Savatni tozalash""" async with aiosqlite.connect(DATABASE_PATH) as db: await db.execute("DELETE FROM cart_items WHERE user_id = ?", (user_id,)) await db.commit() # ==================== USERS & BROADCAST ==================== async def add_user(user_id, username, full_name): """Yangi foydalanuvchini qo'shish""" async with aiosqlite.connect(DATABASE_PATH) as db: await db.execute( "INSERT OR IGNORE INTO users (user_id, username, full_name, joined_at) VALUES (?, ?, ?, ?)", (user_id, username, full_name, time.time()) ) await db.commit() async def get_all_users(): """Barcha foydalanuvchilarni olish""" async with aiosqlite.connect(DATABASE_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute("SELECT user_id FROM users") rows = await cursor.fetchall() return [row["user_id"] for row in rows] async def get_all_orders_with_items(): """Excel export uchun barcha buyurtmalar va mahsulotlar""" async with aiosqlite.connect(DATABASE_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute(""" SELECT o.id, o.user_id, o.full_name, o.phone, o.address, o.total_price, o.status, o.created_at, oi.product_name, oi.quantity, oi.price FROM orders o JOIN order_items oi ON o.id = oi.order_id ORDER BY o.created_at DESC """) rows = await cursor.fetchall() return [dict(r) for r in rows] # ==================== BUYURTMALAR ==================== async def create_order(user_id, full_name, phone, address): """Yangi buyurtma yaratish""" cart = await get_cart(user_id) if not cart: return None total = await get_cart_total(user_id) async with aiosqlite.connect(DATABASE_PATH) as db: cursor = await db.execute( """INSERT INTO orders (user_id, full_name, phone, address, total_price, status, created_at) VALUES (?, ?, ?, ?, ?, 'yangi', ?)""", (user_id, full_name, phone, address, total, time.time()) ) order_id = cursor.lastrowid # Savat elementlarini buyurtmaga ko'chirish for item in cart: await db.execute( """INSERT INTO order_items (order_id, product_id, product_name, quantity, price) VALUES (?, ?, ?, ?, ?)""", (order_id, item["product_id"], item["name"], item["quantity"], item["price"]) ) await db.commit() # Savatni tozalash await clear_cart(user_id) return order_id async def get_order(order_id): """Buyurtmani olish""" async with aiosqlite.connect(DATABASE_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute("SELECT * FROM orders WHERE id = ?", (order_id,)) row = await cursor.fetchone() return dict(row) if row else None async def get_order_items(order_id): """Buyurtma elementlarini olish""" async with aiosqlite.connect(DATABASE_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute( "SELECT * FROM order_items WHERE order_id = ?", (order_id,) ) rows = await cursor.fetchall() return [dict(r) for r in rows] async def get_user_orders(user_id): """Foydalanuvchi buyurtmalarini olish""" async with aiosqlite.connect(DATABASE_PATH) as db: db.row_factory = aiosqlite.Row cursor = await db.execute( "SELECT * FROM orders WHERE user_id = ? ORDER BY created_at DESC", (user_id,) ) rows = await cursor.fetchall() return [dict(r) for r in rows] async def update_order_status(order_id, status): """Buyurtma statusini o'zgartirish""" async with aiosqlite.connect(DATABASE_PATH) as db: await db.execute( "UPDATE orders SET status = ? WHERE id = ?", (status, order_id) ) await db.commit() async def get_all_orders(status=None): """Barcha buyurtmalarni olish (admin uchun)""" async with aiosqlite.connect(DATABASE_PATH) as db: db.row_factory = aiosqlite.Row if status: cursor = await db.execute( "SELECT * FROM orders WHERE status = ? ORDER BY created_at DESC", (status,) ) else: cursor = await db.execute( "SELECT * FROM orders ORDER BY created_at DESC LIMIT 50" ) rows = await cursor.fetchall() return [dict(r) for r in rows] # ==================== STATISTIKA ==================== async def get_stats(): """Umumiy statistika (admin uchun)""" async with aiosqlite.connect(DATABASE_PATH) as db: stats = {} cursor = await db.execute("SELECT COUNT(*) FROM products WHERE in_stock = 1") row = await cursor.fetchone() stats["products_count"] = row[0] cursor = await db.execute("SELECT COUNT(*) FROM orders") row = await cursor.fetchone() stats["orders_count"] = row[0] cursor = await db.execute("SELECT COUNT(*) FROM orders WHERE status = 'yangi'") row = await cursor.fetchone() stats["new_orders"] = row[0] cursor = await db.execute( "SELECT COALESCE(SUM(total_price), 0) FROM orders WHERE status != 'bekor_qilindi'" ) row = await cursor.fetchone() stats["total_revenue"] = row[0] cursor = await db.execute("SELECT COUNT(DISTINCT user_id) FROM orders") row = await cursor.fetchone() stats["unique_customers"] = row[0] return stats