devbro468/Dev_x_store_botPublic · Bot Template
AIThis bot operates a digital storefront (DEV X STORE) selling subscription-based products — likely game hacks, accounts, or access keys — categorized by platform (Android Root, Non-Root, iPhone). It features a reseller program with discounted pricing, a dual-currency wallet (INR balance + Telegram Stars/XTR), and a full admin/co-admin panel for managing products, plans, per-plan pricing, stock (keys/accounts), coupons, and API endpoints. Purchases flow through a plan selection screen offering wallet payment, Stars invoices (sendInvoice with XTR currency), and coupon application. Successful Stars payments are handled via successful_payment webhook, crediting wallet or delivering keys directly. Admin tools include user listing with chunked messaging, stock viewing/deletion with inline keyboards, co-admin management, and API registry updates. The bot registers users on first interaction and
commands/_onWebKeyReceive.js
javascript · 265 lines
1/**#command2name: /onWebKeyReceive3answer: 4keyboard: 5parse_mode: markdown6aliases: 7allow_only_group: false8need_reply: false9is_web: 010#command**/11 12try { 13 // Parse response safely only if content exists14 var response = null;15 if (typeof content === "string" && content.trim() !== "") {16 try {17 response = JSON.parse(content);18 } catch (e) {19 // Keep response as null if JSON parsing fails20 }21 }22 23 var userId = user.telegramid;24 var chatId = chat.chatid;25 26 // 🔄 PRODUCT DATA ACCURACY CORE (DYNAMIC)27 var dataOptions = options || {}; 28 29 // 🆔 1. PRODUCT ID LAYER (Added for flawless API requests)30 var prodId = dataOptions.prod_id || dataOptions.id || dataOptions.product_id || User.getProperty("last_pending_prod_id") || null;31 32 // 2. Raw options fallback mechanisms33 var rawProdName = dataOptions.prod_name || dataOptions.product || dataOptions.name || User.getProperty("last_pending_prod_name") || "Product";34 var planDays = String(dataOptions.plan_days || dataOptions.days || User.getProperty("last_pending_plan_days") || "1");35 var pDaysNumOnly = planDays.replace(/[^0-9]/g, "").trim(); 36 var planUnit = dataOptions.plan_unit || User.getProperty("last_pending_plan_unit") || "day";37 var unitLabelWordW = (planUnit === "hour") ? (Number(pDaysNumOnly) === 1 ? "Hour" : "Hours") :38 (planUnit === "minute") ? (Number(pDaysNumOnly) === 1 ? "Minute" : "Minutes") :39 (Number(pDaysNumOnly) === 1 ? "Day" : "Days");40 var durationDisplayW = pDaysNumOnly + " " + unitLabelWordW;41 42 // 3. Database validation layer to completely kill the "Product" fallback string bug43 var productList = Bot.getProperty("stored_products") || [];44 var prodName = rawProdName.trim(); 45 46 // ⚡ DEEP ADVANCED DATABASE SEARCH MATCH (Matches by ID first if available, then name)47 if (productList.length > 0) {48 var checkTerm = prodName.toLowerCase();49 var foundMatch = false;50 51 for (var i = 0; i < productList.length; i++) {52 var dbItem = productList[i];53 var dbName = dbItem.name ? dbItem.name.trim() : "";54 var dbId = dbItem.id || null;55 56 // If ID matches directly, use it!57 if (prodId && dbId && String(prodId) === String(dbId)) {58 prodName = dbName;59 foundMatch = true;60 break;61 }62 63 if (!dbName) continue;64 65 if (dbName.toLowerCase() === checkTerm || 66 (checkTerm !== "product" && (checkTerm.indexOf(dbName.toLowerCase()) > -1 || dbName.toLowerCase().indexOf(checkTerm) > -1))) {67 prodName = dbName; 68 if (dbId) { prodId = dbId; } // Backfill ID if name matched69 foundMatch = true;70 break;71 }72 }73 74 if (!foundMatch || prodName.toLowerCase() === "product") {75 var lastPending = User.getProperty("last_pending_prod_name");76 if (lastPending && lastPending.toLowerCase() !== "product") {77 prodName = lastPending.trim();78 } else if (productList.length === 1) {79 prodName = productList[0].name.trim();80 if (productList[0].id) { prodId = productList[0].id; }81 }82 }83 }84 85 var price = Number(dataOptions.price) || Number(User.getProperty("last_pending_price")) || 0;86 var firstName = dataOptions.first_name || user.first_name || "User";87 var usernameText = user.username ? "@" + user.username : "No Username";88 var currentWalletBal = Libs.ResourcesLib.userRes("balance").value().toFixed(2);89 90 var generatedKey = null;91 var isApiDelivery = false;92 var isBackupUsed = false;93 94 var cleanProdNameUpper = prodName.trim().toUpperCase();95 var manualKeysStorageKey = "manual_keys_" + cleanProdNameUpper + "_" + pDaysNumOnly;96 var backupStockKey = "stock_" + prodName.trim() + "_" + pDaysNumOnly + "_Day";97 98 // ⚡ STEP 1: FORCE CHECK MANUAL STOCK (CRITICAL OVERRIDE)99 var manualStock = Bot.getProperty(manualKeysStorageKey);100 101 if (!manualStock || (Array.isArray(manualStock) && manualStock.length === 0)) {102 manualStock = Bot.getProperty(backupStockKey);103 isBackupUsed = true;104 }105 106 if (typeof manualStock === "string" && manualStock.trim() !== "") {107 try {108 manualStock = JSON.parse(manualStock);109 } catch(err) {110 manualStock = manualStock.split("\n").map(function(k) { return k.trim(); }).filter(Boolean);111 }112 }113 114 if (Array.isArray(manualStock) && manualStock.length > 0) {115 generatedKey = manualStock.shift(); 116 117 if (isBackupUsed) {118 Bot.setProperty(backupStockKey, manualStock, "json");119 var mainStock = Bot.getProperty(manualKeysStorageKey) || [];120 if (typeof mainStock === "string") { mainStock = mainStock.split("\n").map(function(k) { return k.trim(); }).filter(Boolean); }121 if (Array.isArray(mainStock)) {122 var idx = mainStock.indexOf(generatedKey);123 if (idx > -1) { mainStock.splice(idx, 1); }124 Bot.setProperty(manualKeysStorageKey, mainStock, "json");125 }126 } else {127 Bot.setProperty(manualKeysStorageKey, manualStock, "json");128 var backupStock = Bot.getProperty(backupStockKey) || [];129 if (typeof backupStock === "string") { backupStock = backupStock.split("\n").map(function(k) { return k.trim(); }).filter(Boolean); }130 if (Array.isArray(backupStock)) {131 var idx = backupStock.indexOf(generatedKey);132 if (idx > -1) { backupStock.splice(idx, 1); }133 Bot.setProperty(backupStockKey, backupStock, "json");134 }135 }136 }137 138 // ⚡ STEP 2: FALLBACK TO API KEYS (IF NO MANUAL STOCK WAS FOUND)139 if (!generatedKey && response && response.status === "success") {140 generatedKey = response.key || response.code || response.serial;141 if (generatedKey) {142 isApiDelivery = true;143 }144 }145 146 // STEP 3: SUCCESS DELIVERY MECHANICS147 if (generatedKey) {148 Libs.ResourcesLib.userRes("balance").add(-price);149 150 var pastSpent = Bot.getProperty("total_spent_by_" + userId) || 0;151 Bot.setProperty("total_spent_by_" + userId, Number(pastSpent) + price, "number");152 153 var userKeysHistory = User.getProperty("my_purchased_keys") || [];154 userKeysHistory.push({155 product: prodName,156 product_id: prodId,157 days: pDaysNumOnly,158 price: price,159 key: generatedKey,160 date: new Date().toLocaleDateString()161 });162 User.setProperty("my_purchased_keys", userKeysHistory, "json");163 164 var remainingBal = Libs.ResourcesLib.userRes("balance").value().toFixed(2);165 166 var productDownloadLink = null;167 if (productList && Array.isArray(productList)) {168 for (var pd = 0; pd < productList.length; pd++) {169 if (productList[pd].name && String(productList[pd].name).trim().toLowerCase() === String(prodName).trim().toLowerCase()) {170 productDownloadLink = productList[pd].download_link || null;171 break;172 }173 }174 }175 var keyDeliveryButtons = [[{ text: "📋 Copy Key", copy_text: { text: generatedKey } }]];176 if (productDownloadLink) {177 keyDeliveryButtons.push([{ text: "📥 Download Link", url: productDownloadLink, style: "primary", icon_custom_emoji_id: "6091571559233755994" }]);178 }179 keyDeliveryButtons.push([{ text: "Back to Menu", callback_data: "/back", style: "primary", icon_custom_emoji_id: "5893163582194978381" }]);180 var keyDeliveryMarkup = JSON.stringify({ inline_keyboard: keyDeliveryButtons });181 182 var deliverText = "<blockquote>" +183 "<tg-emoji emoji-id='5350447674971660988'>✅</tg-emoji> <b>PURCHASE SUCCESSFUL!</b>\n\n" +184 "<tg-emoji emoji-id='6147767796097884213'>📦</tg-emoji> <b>Product:</b> <code>" + prodName + "</code>\n" +185 "<tg-emoji emoji-id='6284816251143331422'>🗝</tg-emoji> <b>Validity:</b> <code>" + durationDisplayW + "</code>\n" +186 "<tg-emoji emoji-id='5352825278672412291'>👆</tg-emoji> <b>Your Key:</b> <code>" + generatedKey + "</code>\n\n" +187 "━━━━━ <tg-emoji emoji-id='6147934084346682063'>#⃣</tg-emoji> <b>BALANCE DETAILS</b> ━━━━━\n" +188 "<tg-emoji emoji-id='6195037488898121775'>✨</tg-emoji> <b>Total Invest:</b> ₹" + price.toFixed(2) + "\n" +189 "<tg-emoji emoji-id='5409048419211682843'>💵</tg-emoji> <b>New Wallet Balance:</b> ₹" + remainingBal + "\n\n" +190 "<i>Enjoy your purchase. <tg-emoji emoji-id='6057881002540274780'>🥳</tg-emoji></i>" +191 "</blockquote>";192 193 // ✅ FIX: "Processing your order..." wala purana message ab delete ho jaata194 // hai, taaki chat me sirf final key-delivery message rahe.195 try {196 var procMsgId = Bot.getProperty("gen_msg_id_" + userId) || User.getProperty("gen_msg_id_" + userId);197 if (procMsgId) {198 Api.deleteMessage({ chat_id: chatId, message_id: Number(procMsgId) });199 Bot.setProperty("gen_msg_id_" + userId, null, "string");200 User.setProperty("gen_msg_id_" + userId, null, "string");201 }202 } catch (cleanupErr) {}203 204 Api.sendMessage({205 chat_id: chatId,206 text: deliverText,207 parse_mode: "HTML",208 reply_markup: keyDeliveryMarkup209 });210 211 var adminId = "8875810358"; 212 var deliveryMethodLabel = isApiDelivery ? "API" : "MANUAL STOCK";213 var adminMsg = "🔔 <b>NEW PURCHASE DELIVERED (" + deliveryMethodLabel + ")</b> ✔️\n\n" +214 "👤 <b>Buyer:</b> " + firstName + " (<code>" + userId + "</code>)\n" +215 "📦 <b>Product:</b> " + prodName + " (ID: " + (prodId || "N/A") + ")\n" +216 "⏳ <b>Plan:</b> " + durationDisplayW + "\n" +217 "💸 <b>Price Deducted:</b> ₹" + price.toFixed(2) + "\n" +218 "💳 <b>User Remaining Bal:</b> ₹" + remainingBal + "\n" +219 "🔑 <b>Key:</b> <code>" + generatedKey + "</code>";220 221 Api.sendMessage({ chat_id: adminId, text: adminMsg, parse_mode: "HTML" });222 223 User.setProperty("last_pending_price", null);224 User.setProperty("last_pending_prod_name", null);225 User.setProperty("last_pending_plan_days", null);226 User.setProperty("last_pending_prod_id", null);227 User.setProperty("last_pending_plan_unit", null);228 229 } else {230 // STEP 4: BOTH FAILED (System goes into error notification mode)231 Api.sendMessage({232 chat_id: chatId,233 text: "⏳ <b>Wait some time admin will stock refill soon</b>\n<i>Your funds were not deducted.</i>",234 parse_mode: "HTML"235 });236 237 var webBalance = "Low/Empty";238 var websiteErrorReason = "Website API Empty Response / Down";239 240 if (response) {241 webBalance = response.balance || response.website_balance || "Low/Empty";242 websiteErrorReason = response.msg || response.message || "Low Balance / Out of Stock";243 }244 245 var alertAdminId = "8875810358";246 var lowBalanceAdminMsg = "⚠️ <b>LOW BALANCE IN WEBSITE / API ERROR</b>\n" +247 "━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n" +248 "🛒 <b>PRODUCT DETAILS:</b>\n" +249 "📦 <b>Product Name:</b> <code>" + prodName + "</code>\n" +250 "🆔 <b>Product ID:</b> <code>" + (prodId || "Not Passed") + "</code>\n" +251 "⏳ <b>Days:</b> <code>" + pDaysNumOnly + " Days</code>\n" +252 "💰 <b>Your Balance Website:</b> <code>" + webBalance + "</code>\n" +253 "ℹ️ <b>API Reason:</b> <code>" + websiteErrorReason + "</code>\n\n" +254 "👤 <b>USER DETAILS:</b>\n" +255 "🗣 <b>User Name:</b> " + usernameText + "\n" +256 "📛 <b>Name:</b> " + firstName + "\n" +257 "🆔 <b>User ID:</b> <code>" + userId + "</code>\n" +258 "💳 <b>Available Balance (User Wallet):</b> ₹" + currentWalletBal + "\n\n" +259 "📌 <i>Action Required: Please refill your website API or add/deliver the key manually to this user!</i>";260 261 Api.sendMessage({ chat_id: alertAdminId, text: lowBalanceAdminMsg, parse_mode: "HTML" });262 }263} catch (e) {264 Bot.sendMessage("❌ Error executing delivery pipeline: " + e.message);265}