Spaces:
Paused
Paused
| const { Scenes, Markup } = require('telegraf'); | |
| const Product = require('../../models/Product'); | |
| const User = require('../../models/User'); | |
| const flashSaleScene = new Scenes.WizardScene( | |
| 'admin_flash_sale', | |
| // Step 1: Menu | |
| async (ctx) => { | |
| const text = "π₯ **Flash Sale (Aksiya) Boshqaruvi**\n\nNima qilmoqchisiz?"; | |
| const buttons = [ | |
| [Markup.button.callback("π Aksiya Boshlash", "start_sale")], | |
| [Markup.button.callback("π Aksiyani To'xtatish (Narxlarni tiklash)", "stop_sale")], | |
| [Markup.button.callback("π Asosiy menyu", "back_dashboard")] | |
| ]; | |
| if (ctx.callbackQuery) { | |
| await ctx.editMessageText(text, { parse_mode: 'Markdown', ...Markup.inlineKeyboard(buttons) }); | |
| } else { | |
| await ctx.replyWithMarkdown(text, Markup.inlineKeyboard(buttons)); | |
| } | |
| return ctx.wizard.next(); | |
| }, | |
| // Step 2: Handle Choice | |
| async (ctx) => { | |
| if (!ctx.callbackQuery && !ctx.message) return; | |
| const txt = ctx.message ? ctx.message.text : ''; | |
| if (txt === '/start' || txt === 'β Bekor qilish') return ctx.scene.leave(); | |
| if (ctx.callbackQuery) { | |
| const data = ctx.callbackQuery.data; | |
| if (data === 'back_dashboard') { | |
| await ctx.scene.leave(); | |
| const adminController = require('../../controllers/adminController'); | |
| return adminController.showDashboard(ctx); | |
| } | |
| if (data === 'stop_sale') { | |
| await ctx.answerCbQuery("Narxlar tiklanmoqda..."); | |
| // Revert Logic | |
| const products = await Product.find({ originalPrice: { $ne: null } }); | |
| if (products.length === 0) { | |
| await ctx.reply("β οΈ Tiklash uchun o'zgartirilgan mahsulotlar topilmadi."); | |
| return ctx.scene.leave(); | |
| } | |
| let count = 0; | |
| for (let p of products) { | |
| p.price = p.originalPrice; | |
| p.originalPrice = null; // Clear history | |
| p.discountPercent = 0; // Reset discount | |
| await p.save(); | |
| count++; | |
| } | |
| await ctx.reply(`β <b>Aksiya tugatildi.</b>\n${count} ta mahsulot narxi joyiga qaytarildi.`, { parse_mode: 'HTML' }); | |
| return ctx.scene.leave(); | |
| } | |
| if (data === 'start_sale') { | |
| await ctx.reply("π <b>Chegirma foizini kiriting:</b>\nMasalan: 10 (10% arzonlashadi)\n\n<i>Eslatma: Bu barcha mahsulotlarga ta'sir qiladi!</i>", { parse_mode: 'HTML', ...Markup.keyboard([['β Bekor qilish']]).resize() }); | |
| ctx.wizard.state.action = 'get_percent'; | |
| return ctx.wizard.next(); | |
| } | |
| } | |
| }, | |
| // Step 3: Apply Discount | |
| async (ctx) => { | |
| const txt = ctx.message ? ctx.message.text : ''; | |
| if (txt === 'β Bekor qilish') { | |
| await ctx.reply("Bekor qilindi.", Markup.removeKeyboard()); | |
| await ctx.scene.leave(); | |
| const adminController = require('../../controllers/adminController'); | |
| return adminController.showDashboard(ctx); | |
| } | |
| const percent = parseInt(txt); | |
| if (isNaN(percent) || percent <= 0 || percent >= 100) { | |
| await ctx.reply("β οΈ Iltimos, to'g'ri foiz kiriting (1-99 oralig'ida)."); | |
| return; | |
| } | |
| await ctx.reply(`β³ ${percent}% chegirma qo'llanmoqda...`); | |
| const products = await Product.find({}); | |
| let count = 0; | |
| for (let p of products) { | |
| try { | |
| // Skip invalid products (corrupt data) | |
| if (!p.id || !p.name) { | |
| console.warn(`Skipping invalid product (Missing ID/Name): ${p._id}`); | |
| continue; | |
| } | |
| // Only update if not already discounted (prevent double discount) | |
| // Or overwrite? Let's assume overwrite logic: | |
| // If already has originalPrice, use THAT as base. If not, use current price. | |
| let basePrice = p.originalPrice || p.price; | |
| // Save original price if not already saved | |
| if (!p.originalPrice) { | |
| p.originalPrice = basePrice; | |
| } | |
| // Calculate new price | |
| const discountAmount = (basePrice * percent) / 100; | |
| p.price = Math.round(basePrice - discountAmount); | |
| p.discountPercent = percent; // Save percent display | |
| await p.save(); | |
| count++; | |
| } catch (err) { | |
| console.error(`Failed to update product ${p.id}:`, err.message); | |
| } | |
| } | |
| const User = require('../../models/User'); // Ensure User model is required at top | |
| // ... inside the scene ... | |
| await ctx.reply(`β <b>Aksiya Boshlandi!</b>\n\n${count} ta mahsulot narxi ${percent}% ga arzonlashtirildi.`, { parse_mode: 'HTML', ...Markup.removeKeyboard() }); | |
| // --- BROADCAST NOTIFICATION --- | |
| await ctx.reply("π’ Foydalanuvchilarga xabar yuborilmoqda..."); | |
| const users = await User.find({}); | |
| let sent = 0; | |
| const message = `π₯ <b>DIQQAT AKSIYA!</b>\n\nπ Do'konimizda <b>FLASH SALE</b> boshlandi!\n\nπ Barcha mahsulotlarga <b>${percent}% CHEGIRMA</b> e'lon qilindi.\n\nHoziroq xarid qiling, aksiya vaqti chegaralangan! β³\n\nπππ`; | |
| for (let user of users) { | |
| try { | |
| await ctx.telegram.sendMessage(user.id, message, { parse_mode: 'HTML' }); | |
| sent++; | |
| } catch (e) { | |
| // User blocked bot or inactive | |
| } | |
| // Small delay to prevent spam flood | |
| await new Promise(r => setTimeout(r, 50)); | |
| } | |
| await ctx.reply(`π’ Xabar ${sent} ta foydalanuvchiga yuborildi.`); | |
| await ctx.scene.leave(); | |
| const adminController = require('../../controllers/adminController'); | |
| return adminController.showDashboard(ctx); | |
| } | |
| ); | |
| module.exports = flashSaleScene; | |