indrajitghosh20006/Testseller_01botPublic · Bot Template
AIThis bot provides an admin‑controlled system for managing user balances, products, and reseller roles. It includes commands to add balances (via manual input, Binance Pay, or UPI), approve and credit payments, and set up product listings with categories and pricing. Admins can also add resellers, view reseller info, and manage stock entries. The bot uses built‑in TeleBotHost APIs such as Bot, Api, HTTP, and Libs for database operations and message handling.
Commerceadminbalanceproductresellerpaymentsbinance
138 commands0 envUpdated 17h agoCreated Sep 27, 2026
commands/_confirm_buyitem.js
javascript · 423 lines
1/**#command2name: /confirm_buyitem3answer: 4keyboard: 5parse_mode: markdown6aliases: 7allow_only_group: false8need_reply: false9is_web: 010#command**/11 12function resolveApiDuration(plan, cleanPlanDays, planUnit, productNameOverride) {13 // IMPORTANT: Keep the admin/API duration name exactly as entered.14 // The product-specific day ranges below are used only when the stored plan15 // contains a plain numeric Day duration; this lets 1-30 Day plans target16 // the exact website/API names requested by the admin without changing any17 // other product data or purchase logic.18 var raw = String((plan && (plan.api_duration || plan.name_on_website || plan.durationDisplay || plan.name || plan.title)) || "").replace(/\s+/g, " ").trim();19 20 // Already-custom API labels (including casing/suffixes) must pass through unchanged.21 if (raw && !/^[0-9]+(?:\.[0-9]+)?\s*(day|days)$/i.test(raw)) {22 return raw;23 }24 25 var dayMatch = raw.match(/^([0-9]+(?:\.[0-9]+)?)\s*(day|days)$/i);26 var n = dayMatch ? dayMatch[1] : String(cleanPlanDays || "1");27 var productName = String(productNameOverride || (plan && (plan.product_name || plan.productName || plan.product || plan.category)) || "").trim().toLowerCase();28 29 // If product name is not stored on the plan, the caller's raw API label is30 // still preserved above. Generic numeric Day plans remain "N Days".31 if (/pc\s*aim\s*silent/.test(productName)) return n + " Day Pc Aim Silent";32 if (/pc\s*modmenu\s*x86/.test(productName)) return n + " Day Pc Modmenu x86";33 if (/pc\s*bypass\s*\+\s*silent/.test(productName) || /bypass\s*\+\s*silent/.test(productName)) return n + " Days Pc Bypass + Silent";34 if (/nonroot/.test(productName) && !/root\s*\+\s*nonroot/.test(productName)) return n + " DaYS NONROOT";35 if (/pc\s*aimkill/.test(productName) || /aimkill/.test(productName)) return n + " DaYS PC AIMKILL";36 if (/root\s*\+\s*nonroot/.test(productName)) return n + " DaYs Root + Nonroot";37 if (/fluo?rite\s*ff/.test(productName)) return n + " DAYs FluoRite FF";38 if (/\broot\b/.test(productName)) return n + " DaYs ROOT";39 if (/all\s*colou?rs\s*mix/.test(productName)) return n + " DaYs All Colours Mix";40 if (/\bbasic\b/.test(productName)) return n + " DaYs Basic";41 if (/\bpro\b/.test(productName)) return n + " DaYs PRO";42 if (/\bsafe\b/.test(productName)) return n + " DaYs SAFE";43 if (/\bbrutal\b/.test(productName)) return n + " DaYs BRUTAL";44 if (/\bbrutal\b/.test(productName)) return n + " DaYs";45 46 // Hours/minutes are preserved exactly; no existing API duration is removed.47 var gh = raw.match(/^([0-9]+(?:\.[0-9]+)?)\s*(hour|hours)$/i);48 if (gh) return gh[1] + " Hours";49 var gm = raw.match(/^([0-9]+(?:\.[0-9]+)?)\s*(minute|minutes)$/i);50 if (gm) return gm[1] + (Number(gm[1]) === 1 ? " Minute" : " Minutes");51 52 return raw || n + " Days";53}54 55 56// =========================================================57// ✅ ACTUAL PURCHASE EXECUTION — runs after user taps "Confirm" on the58// premium confirmation screen, OR automatically right after a shortfall59// QR payment is verified (see _onCheck.js), so key delivery is fully automatic.60// =========================================================61 62try {63 var productList = Bot.getProperty("stored_products") || [];64 var chatId = chat.chatid;65 var userId = user.telegramid;66 67 var parts = params ? String(params).trim().split(" ") : [];68 var prodIdx = Number(parts[0]);69 var planIdx = Number(parts[1]);70 71 var product = productList[prodIdx];72 if (!product || !product.plans || !product.plans[planIdx]) {73 Api.sendMessage({ chat_id: chatId, text: "❌ Product or Plan configuration missing!" });74 return;75 }76 77 var plan = product.plans[planIdx];78 var planUnit = plan.unit || "day";79 var isReseller = Bot.getProperty("is_reseller_" + userId) === true;80 81 var cleanProdName = product.name.trim().toUpperCase();82 var cleanPlanDays = String(plan.days).replace(/[^0-9.]/g, "").trim();83 var unitLabelWord = (planUnit === "hour") ? (Number(cleanPlanDays) === 1 ? "Hour" : "Hours") :84 (planUnit === "minute") ? (Number(cleanPlanDays) === 1 ? "Minute" : "Minutes") :85 (Number(cleanPlanDays) === 1 ? "Day" : "Days");86 var durationDisplay = plan.durationDisplay || (cleanPlanDays + " " + unitLabelWord);87 88 var priceKeySuffix = (planUnit === "day") ? cleanPlanDays : (cleanPlanDays + "_" + planUnit);89 var normalKey = "price_normal_" + cleanProdName + "_" + priceKeySuffix;90 var resellerKey = "price_reseller_" + cleanProdName + "_" + priceKeySuffix;91 92 var adminNormalPrice = Bot.getProperty(normalKey);93 var adminResellerPrice = Bot.getProperty(resellerKey);94 95 var currentNormal = (adminNormalPrice !== undefined && adminNormalPrice !== null) ? adminNormalPrice : plan.normal_price;96 var currentReseller = (adminResellerPrice !== undefined && adminResellerPrice !== null) ? adminResellerPrice : plan.reseller_price;97 98 var originalPrice = isReseller ? Number(currentReseller) : Number(currentNormal);99 var price = originalPrice;100 101 var planSpecificDiscKey = "auto_discount_" + cleanProdName + "_" + cleanPlanDays + "_" + planUnit.toUpperCase();102 var productWideDiscKey = "auto_discount_" + cleanProdName + "_ALL";103 var autoDiscountPercent = Bot.getProperty(planSpecificDiscKey) || Bot.getProperty(productWideDiscKey) || Bot.getProperty("auto_discount_global") || 0;104 105 // 🎟 Apply coupon discount (if any was applied for this exact prod/plan) — coupon overrides auto-discount106 var appliedCouponCode = User.getProperty("applied_coupon_" + prodIdx + "_" + planIdx);107 var couponDiscountPercent = 0;108 if (appliedCouponCode) {109 var couponRec0 = Bot.getProperty("coupon_" + appliedCouponCode);110 if (couponRec0 && couponRec0.discountPercent) {111 couponDiscountPercent = couponRec0.discountPercent;112 price = Number((originalPrice * (1 - couponDiscountPercent / 100)).toFixed(2));113 }114 User.setProperty("applied_coupon_" + prodIdx + "_" + planIdx, null, "string");115 } else if (autoDiscountPercent > 0) {116 couponDiscountPercent = autoDiscountPercent;117 price = Number((originalPrice * (1 - autoDiscountPercent / 100)).toFixed(2));118 }119 120 // 🛡️ Safety re-check: balance abhi bhi sufficient hai ya nahi (race-condition guard)121 var unifiedBal = (function () {122 var resBal = 0;123 try { resBal = Number(Libs.ResourcesLib.userRes("balance").value()) || 0; } catch (e) {}124 return resBal;125 })();126 127 if (unifiedBal < price) {128 Api.sendMessage({129 chat_id: chatId,130 text: "⚠️ <b>Balance abhi kam hai.</b> Kripya phir se try karein.",131 parse_mode: "HTML"132 });133 return;134 }135 136 // =====================================================137 // 🔑 STEP 0 — MANUAL STOCK FIRST CHECK (✅ NEW)138 // Agar admin ne manually koi key already daal rakhi hai, to wahi seedha139 // deliver karo aur PAID EXTERNAL API ko bilkul call hi mat karo — taaki140 // "1 available key ke liye 2 keys spend" (1 manual + 1 wasted API buy)141 // wala bug kabhi na ho. API sirf tabhi call hoga jab manual stock khaali ho.142 // =====================================================143 var pDaysNumOnly = cleanPlanDays;144 var manualKeysStorageKey = "manual_keys_" + cleanProdName + "_" + pDaysNumOnly;145 var backupStockKey = "stock_" + product.name.trim() + "_" + pDaysNumOnly + "_Day";146 var isBackupUsed = false;147 148 var manualStock = Bot.getProperty(manualKeysStorageKey);149 if (!manualStock || (Array.isArray(manualStock) && manualStock.length === 0)) {150 manualStock = Bot.getProperty(backupStockKey);151 isBackupUsed = true;152 }153 if (typeof manualStock === "string" && manualStock.trim() !== "") {154 try {155 manualStock = JSON.parse(manualStock);156 } catch (err) {157 manualStock = manualStock.split("\n").map(function (k) { return k.trim(); }).filter(Boolean);158 }159 }160 161 if (Array.isArray(manualStock) && manualStock.length > 0) {162 var generatedKey = manualStock.shift();163 164 if (isBackupUsed) {165 Bot.setProperty(backupStockKey, manualStock, "json");166 var mainStock = Bot.getProperty(manualKeysStorageKey) || [];167 if (typeof mainStock === "string") { mainStock = mainStock.split("\n").map(function (k) { return k.trim(); }).filter(Boolean); }168 if (Array.isArray(mainStock)) {169 var idx1 = mainStock.indexOf(generatedKey);170 if (idx1 > -1) { mainStock.splice(idx1, 1); }171 Bot.setProperty(manualKeysStorageKey, mainStock, "json");172 }173 } else {174 Bot.setProperty(manualKeysStorageKey, manualStock, "json");175 var backupStock2 = Bot.getProperty(backupStockKey) || [];176 if (typeof backupStock2 === "string") { backupStock2 = backupStock2.split("\n").map(function (k) { return k.trim(); }).filter(Boolean); }177 if (Array.isArray(backupStock2)) {178 var idx2 = backupStock2.indexOf(generatedKey);179 if (idx2 > -1) { backupStock2.splice(idx2, 1); }180 Bot.setProperty(backupStockKey, backupStock2, "json");181 }182 }183 184 // 💰 Deduct balance + record purchase (same accounting as API path)185 Libs.ResourcesLib.userRes("balance").add(-price);186 var pastSpent2 = Bot.getProperty("total_spent_by_" + userId) || 0;187 Bot.setProperty("total_spent_by_" + userId, Number(pastSpent2) + price, "number");188 189 // 🎁 REFER & EARN — referrer bonus jab referred friend PEHLI baar purchase kare190 try {191 var referredByBuy2 = User.getProperty("referred_by");192 if (referredByBuy2 && !User.getProperty("ref_buy_bonus_given")) {193 var refBonusBuy2 = Number(Bot.getProperty("refer_earn_buy_amount"));194 if (isNaN(refBonusBuy2)) refBonusBuy2 = 2;195 if (refBonusBuy2 > 0) {196 Libs.ResourcesLib.anotherUserRes("balance", referredByBuy2).add(refBonusBuy2);197 var pastEarnBuy2 = Number(Bot.getProperty("refer_earnings_" + referredByBuy2) || 0);198 Bot.setProperty("refer_earnings_" + referredByBuy2, pastEarnBuy2 + refBonusBuy2, "number");199 try {200 Api.sendMessage({201 chat_id: referredByBuy2,202 text: "<blockquote>💸 <b>Referral Bonus!</b>\n\nAapke referred friend ne pehli purchase ki — aapko ₹" + refBonusBuy2.toFixed(2) + " mile hain!</blockquote>",203 parse_mode: "HTML"204 });205 } catch (e) {}206 }207 User.setProperty("ref_buy_bonus_given", true, "boolean");208 }209 } catch (e) {}210 211 var keysHistory2 = User.getProperty("my_purchased_keys") || [];212 keysHistory2.push({213 product: String(product.name).trim(),214 product_id: product.id || null,215 days: pDaysNumOnly,216 price: price,217 key: generatedKey,218 date: new Date().toLocaleDateString()219 });220 User.setProperty("my_purchased_keys", keysHistory2, "json");221 222 var remainingBal2 = Libs.ResourcesLib.userRes("balance").value().toFixed(2);223 224 // ✅ NEW: Key ke saath automatic "Join Updates" button attach hota hai (agar admin ne link set kiya ho)225 var updateLinkForKey = Bot.getProperty("update_channel_link");226 var keyDeliveryButtons = [[{ text: "📋 Copy Key", copy_text: { text: generatedKey } }]];227 if (updateLinkForKey) {228 keyDeliveryButtons.push([{ text: "📥 Join Updates", url: updateLinkForKey, style: "primary", icon_custom_emoji_id: "6091571559233755994" }]);229 }230 keyDeliveryButtons.push([{ text: "Back to Menu", callback_data: "/back", style: "primary", icon_custom_emoji_id: "5877536313623711363" }]);231 var keyDeliveryMarkup = JSON.stringify({ inline_keyboard: keyDeliveryButtons });232 233 var deliverText2 = "<blockquote>" +234 "<tg-emoji emoji-id='5350447674971660988'>✅</tg-emoji> <b>PURCHASE SUCCESSFUL!</b>\n\n" +235 "<tg-emoji emoji-id='6147767796097884213'>📦</tg-emoji> <b>Product:</b> <code>" + String(product.name).trim() + "</code>\n" +236 "<tg-emoji emoji-id='6284816251143331422'>🗝</tg-emoji> <b>Validity:</b> <code>" + durationDisplay + "</code>\n" +237 "<tg-emoji emoji-id='5352825278672412291'>👆</tg-emoji> <b>Your Key:</b> <code>" + generatedKey + "</code>\n\n" +238 "━━━━━ <tg-emoji emoji-id='6147934084346682063'>#⃣</tg-emoji> <b>BALANCE DETAILS</b> ━━━━━\n" +239 "<tg-emoji emoji-id='6195037488898121775'>✨</tg-emoji> <b>Total Invest:</b> ₹" + price.toFixed(2) + "\n" +240 "<tg-emoji emoji-id='5409048419211682843'>💵</tg-emoji> <b>New Wallet Balance:</b> ₹" + remainingBal2 + "\n\n" +241 "<i>Enjoy your purchase. <tg-emoji emoji-id='6057881002540274780'>🥳</tg-emoji></i>" +242 "</blockquote>";243 244 if (request && request.message) {245 try {246 Api.editMessageText({247 chat_id: String(chatId),248 message_id: Number(request.message.message_id),249 text: deliverText2,250 parse_mode: "HTML",251 reply_markup: keyDeliveryMarkup252 });253 } catch (e) {254 Api.sendMessage({ chat_id: chatId, text: deliverText2, parse_mode: "HTML", reply_markup: keyDeliveryMarkup });255 }256 } else {257 Api.sendMessage({ chat_id: chatId, text: deliverText2, parse_mode: "HTML", reply_markup: keyDeliveryMarkup });258 }259 260 var adminId3 = "8875810358";261 Api.sendMessage({262 chat_id: adminId3,263 text: "🔔 <b>NEW PURCHASE DELIVERED (MANUAL STOCK)</b> ✔️\n\n" +264 "👤 <b>Buyer:</b> " + (user.first_name || "User") + " (<code>" + userId + "</code>)\n" +265 "📦 <b>Product:</b> " + String(product.name).trim() + "\n" +266 "⏳ <b>Plan:</b> " + durationDisplay + "\n" +267 "💸 <b>Price Deducted:</b> ₹" + price.toFixed(2) + "\n" +268 "💳 <b>User Remaining Bal:</b> ₹" + remainingBal2 + "\n" +269 "🔑 <b>Key:</b> <code>" + generatedKey + "</code>\n\n" +270 "<i>✅ Manual stock se deliver hui — external paid API call SKIP ki gayi.</i>",271 parse_mode: "HTML"272 });273 274 var qId0 = request ? (request.id || (request.callback_query && request.callback_query.id)) : null;275 if (qId0) {276 try { Api.answerCallbackQuery({ callback_query_id: String(qId0), text: "✅ Key Delivered!", show_alert: false }); } catch (e) {}277 }278 279 return; // 🚫 STOP — external API bilkul call nahi hui280 }281 282 var webProductId = String(product.id || "PID_ID").trim();283 var prodNameLower = String(product.name).toLowerCase();284 285 var durationParam = resolveApiDuration(plan, cleanPlanDays, planUnit, product && product.name);286 287 // =====================================================288 // 🔌 MULTI-API SYSTEM289 // Admin can add/update/select multiple reseller APIs.290 // The active API is used for external purchases.291 // =====================================================292 var apiRegistry = Bot.getProperty("api_registry") || {};293 var activeApiId = Bot.getProperty("active_reseller_api");294 var selectedApi = activeApiId ? apiRegistry[activeApiId] : null;295 296 // Backward-compatible bootstrap from the existing API configuration.297 if (!selectedApi) {298 selectedApi = {299 id: "default",300 name: "Default Reseller API",301 url: "https://bantibhaiya.to/api/reseller_v1.php",302 api_key: "1a46ed123070dbe5d2e2366f98e4e34a",303 master_key: "a7f3e8b2c9d1f4a6b8c2d5e9f1a3b6c8",304 mode: "reseller_v1",305 android_required: false,306 enabled: true307 };308 apiRegistry.default = selectedApi;309 Bot.setProperty("api_registry", apiRegistry, "json");310 Bot.setProperty("active_reseller_api", "default", "string");311 }312 313 if (selectedApi.enabled === false) {314 Api.sendMessage({chat_id: chatId, text: "❌ Selected API is disabled. Admin ko /apiset se another API select karna hoga."});315 return;316 }317 318 var webProductId = String(product.id || "PID_ID").trim();319 var prodNameLower = String(product.name).toLowerCase();320 321 var durationParam = resolveApiDuration(plan, cleanPlanDays, planUnit, product && product.name);322 323 // Product-level API override is supported: product.api_id.324 var productApiId = product.api_id ? String(product.api_id).trim() : "";325 if (productApiId && apiRegistry[productApiId] && apiRegistry[productApiId].enabled !== false) {326 selectedApi = apiRegistry[productApiId];327 activeApiId = productApiId;328 }329 330 var postFields = {331 api_key: selectedApi.api_key || "",332 action: "buy",333 product_id: webProductId,334 duration: durationParam335 };336 337 // Device-bound APIs can require android_id. The value may be saved by338 // your existing product/user flow as android_id_<USER_ID>.339 var savedAndroidId = User.getProperty("android_id") || User.getProperty("android_id_" + userId) ||340 Bot.getProperty("android_id_" + userId) || "";341 if (selectedApi.android_required) {342 if (!savedAndroidId) {343 Api.sendMessage({344 chat_id: chatId,345 text: "⚠️ <b>Android ID required</b>\nIs API/product ke liye Android ID zaroori hai. Pehle user ka Android ID save karein.",346 parse_mode: "HTML"347 });348 return;349 }350 postFields.android_id = String(savedAndroidId);351 } else if (savedAndroidId) {352 // Optional APIs may also accept it.353 postFields.android_id = String(savedAndroidId);354 }355 356 var apiHeaders = {357 "Content-Type": "application/x-www-form-urlencoded"358 };359 if (selectedApi.master_key) apiHeaders["x-master-key"] = selectedApi.master_key;360 361 var postFieldsString = Object.keys(postFields).map(function(k) {362 return encodeURIComponent(k) + "=" + encodeURIComponent(postFields[k]);363 }).join("&");364 365 User.setProperty("last_pending_price", Number(price), "number");366 User.setProperty("last_pending_prod_id", webProductId, "string");367 User.setProperty("last_pending_prod_name", String(product.name).trim(), "string");368 User.setProperty("last_pending_plan_days", cleanPlanDays, "string");369 User.setProperty("last_pending_plan_unit", planUnit, "string");370 User.setProperty("last_pending_api_id", String(selectedApi.id || activeApiId || ""), "string");371 372 var queryId = request ? (request.id || (request.callback_query && request.callback_query.id)) : null;373 374 var processingText = "<tg-emoji emoji-id='6147936236125298267'>⏳</tg-emoji> <b>Processing your order... please wait!</b>";375 if (request && request.message) {376 try {377 Api.editMessageText({378 chat_id: String(chatId),379 message_id: Number(request.message.message_id),380 text: processingText,381 parse_mode: "HTML"382 });383 Bot.setProperty("gen_msg_id_" + userId, request.message.message_id, "string");384 User.setProperty("gen_msg_id_" + userId, request.message.message_id, "string");385 } catch (e) {386 var pm1 = Api.sendMessage({ chat_id: chatId, text: processingText, parse_mode: "HTML" });387 try {388 var pmid1 = (pm1 && pm1.result && pm1.result.message_id) ? pm1.result.message_id : (pm1 && pm1.message_id ? pm1.message_id : null);389 if (pmid1) { Bot.setProperty("gen_msg_id_" + userId, pmid1, "string"); User.setProperty("gen_msg_id_" + userId, pmid1, "string"); }390 } catch (e2) {}391 }392 } else {393 var pm2 = Api.sendMessage({ chat_id: chatId, text: processingText, parse_mode: "HTML" });394 try {395 var pmid2 = (pm2 && pm2.result && pm2.result.message_id) ? pm2.result.message_id : (pm2 && pm2.message_id ? pm2.message_id : null);396 if (pmid2) { Bot.setProperty("gen_msg_id_" + userId, pmid2, "string"); User.setProperty("gen_msg_id_" + userId, pmid2, "string"); }397 } catch (e2) {}398 }399 400 HTTP.post({401 url: selectedApi.url,402 body: postFieldsString,403 headers: apiHeaders,404 success: "/onWebKeyReceive",405 error: "/onWebKeyError"406 });407 408 if (queryId) {409 try {410 Api.answerCallbackQuery({411 callback_query_id: String(queryId),412 text: "⏳ Processing your order... Please wait!",413 show_alert: false414 });415 } catch (e) {}416 }417 418} catch (e) {419 var errChatId = (typeof chat !== "undefined" && chat && chat.chatid) ? chat.chatid : null;420 if (errChatId) {421 try { Api.sendMessage({ chat_id: errChatId, text: "❌ <b>Error:</b> <code>" + e.message + "</code>", parse_mode: "HTML" }); } catch (fatal) {}422 }423}