kkapil9112/Aestheticmodes9_botPublic · Bot Template

AIA Telegram-based digital goods store bot with a full admin panel for managing products, plans, stock, keys, categories, resellers, balances, and coupons. It uses TeleBotHost APIs like Bot, Api, User, Libs.ResourcesLib, and HTTP to run a shop interface, handle admin-only commands, track users, and send inventory/balance summaries. The implementation appears focused on selling game-related accounts and keys such as FreeFire items, with customer-facing store, balance, coupon, and back-to-menu flows.

Commerceshopadmin-panelbalanceresellercouponsstock-management
ProfileTelegram
102 commands1 envUpdated 29d agoCreated Aug 9, 2026
Back to folder

commands/_confirm_buyitem.js

javascript · 310 lines

Raw
1/**#command2name: /confirm_buyitem3answer: 4keyboard: 5parse_mode: markdown6aliases: 7allow_only_group: false8need_reply: false9is_web: 010#command**/11 12// =========================================================13// ✅ ACTUAL PURCHASE EXECUTION — runs after user taps "Confirm" on the14// premium confirmation screen, OR automatically right after a shortfall15// QR payment is verified (see _onCheck.js), so key delivery is fully automatic.16// =========================================================17 18try {19  var productList = Bot.getProperty("stored_products") || [];20  var chatId = chat.chatid;21  var userId = user.telegramid;22 23  var parts = params ? String(params).trim().split(" ") : [];24  var prodIdx = Number(parts[0]);25  var planIdx = Number(parts[1]);26 27  var product = productList[prodIdx];28  if (!product || !product.plans || !product.plans[planIdx]) {29    Api.sendMessage({ chat_id: chatId, text: "❌ Product or Plan configuration missing!" });30    return;31  }32 33  var plan = product.plans[planIdx];34  var planUnit = plan.unit || "day";35  var isReseller = Bot.getProperty("is_reseller_" + userId) === true;36 37  var cleanProdName = product.name.trim().toUpperCase();38  var cleanPlanDays = String(plan.days).replace(/[^0-9.]/g, "").trim();39  var unitLabelWord = (planUnit === "hour") ? (Number(cleanPlanDays) === 1 ? "Hour" : "Hours") :40                       (planUnit === "minute") ? (Number(cleanPlanDays) === 1 ? "Minute" : "Minutes") :41                       (Number(cleanPlanDays) === 1 ? "Day" : "Days");42  var durationDisplay = plan.durationDisplay || (cleanPlanDays + " " + unitLabelWord);43 44  var priceKeySuffix = (planUnit === "day") ? cleanPlanDays : (cleanPlanDays + "_" + planUnit);45  var normalKey = "price_normal_" + cleanProdName + "_" + priceKeySuffix;46  var resellerKey = "price_reseller_" + cleanProdName + "_" + priceKeySuffix;47 48  var adminNormalPrice = Bot.getProperty(normalKey);49  var adminResellerPrice = Bot.getProperty(resellerKey);50 51  var currentNormal = (adminNormalPrice !== undefined && adminNormalPrice !== null) ? adminNormalPrice : plan.normal_price;52  var currentReseller = (adminResellerPrice !== undefined && adminResellerPrice !== null) ? adminResellerPrice : plan.reseller_price;53 54  var originalPrice = isReseller ? Number(currentReseller) : Number(currentNormal);55  var price = originalPrice;56 57  var planSpecificDiscKey = "auto_discount_" + cleanProdName + "_" + cleanPlanDays + "_" + planUnit.toUpperCase();58  var productWideDiscKey = "auto_discount_" + cleanProdName + "_ALL";59  var autoDiscountPercent = Bot.getProperty(planSpecificDiscKey) || Bot.getProperty(productWideDiscKey) || Bot.getProperty("auto_discount_global") || 0;60 61  // 🎟 Apply coupon discount (if any was applied for this exact prod/plan) — coupon overrides auto-discount62  var appliedCouponCode = User.getProperty("applied_coupon_" + prodIdx + "_" + planIdx);63  var couponDiscountPercent = 0;64  if (appliedCouponCode) {65    var couponRec0 = Bot.getProperty("coupon_" + appliedCouponCode);66    if (couponRec0 && couponRec0.discountPercent) {67      couponDiscountPercent = couponRec0.discountPercent;68      price = Number((originalPrice * (1 - couponDiscountPercent / 100)).toFixed(2));69    }70    User.setProperty("applied_coupon_" + prodIdx + "_" + planIdx, null, "string");71  } else if (autoDiscountPercent > 0) {72    couponDiscountPercent = autoDiscountPercent;73    price = Number((originalPrice * (1 - autoDiscountPercent / 100)).toFixed(2));74  }75 76  // 🛡️ Safety re-check: balance abhi bhi sufficient hai ya nahi (race-condition guard)77  var unifiedBal = (function () {78    var resBal = 0;79    try { resBal = Number(Libs.ResourcesLib.userRes("balance").value()) || 0; } catch (e) {}80    var bonusBal = Number(Bot.getProperty("balance" + userId) || 0);81    return resBal + bonusBal;82  })();83 84  if (unifiedBal < price) {85    Api.sendMessage({86      chat_id: chatId,87      text: "⚠️ <b>Balance abhi kam hai.</b> Kripya phir se try karein.",88      parse_mode: "HTML"89    });90    return;91  }92 93  // =====================================================94  // 🔑 STEP 0 — MANUAL STOCK FIRST CHECK (✅ NEW)95  // Agar admin ne manually koi key already daal rakhi hai, to wahi seedha96  // deliver karo aur PAID EXTERNAL API ko bilkul call hi mat karo — taaki97  // "1 available key ke liye 2 keys spend" (1 manual + 1 wasted API buy)98  // wala bug kabhi na ho. API sirf tabhi call hoga jab manual stock khaali ho.99  // =====================================================100  var pDaysNumOnly = cleanPlanDays;101  var manualKeysStorageKey = "manual_keys_" + cleanProdName + "_" + pDaysNumOnly;102  var backupStockKey = "stock_" + product.name.trim() + "_" + pDaysNumOnly + "_Day";103  var isBackupUsed = false;104 105  var manualStock = Bot.getProperty(manualKeysStorageKey);106  if (!manualStock || (Array.isArray(manualStock) && manualStock.length === 0)) {107    manualStock = Bot.getProperty(backupStockKey);108    isBackupUsed = true;109  }110  if (typeof manualStock === "string" && manualStock.trim() !== "") {111    try {112      manualStock = JSON.parse(manualStock);113    } catch (err) {114      manualStock = manualStock.split("\n").map(function (k) { return k.trim(); }).filter(Boolean);115    }116  }117 118  if (Array.isArray(manualStock) && manualStock.length > 0) {119    var generatedKey = manualStock.shift();120 121    if (isBackupUsed) {122      Bot.setProperty(backupStockKey, manualStock, "json");123      var mainStock = Bot.getProperty(manualKeysStorageKey) || [];124      if (typeof mainStock === "string") { mainStock = mainStock.split("\n").map(function (k) { return k.trim(); }).filter(Boolean); }125      if (Array.isArray(mainStock)) {126        var idx1 = mainStock.indexOf(generatedKey);127        if (idx1 > -1) { mainStock.splice(idx1, 1); }128        Bot.setProperty(manualKeysStorageKey, mainStock, "json");129      }130    } else {131      Bot.setProperty(manualKeysStorageKey, manualStock, "json");132      var backupStock2 = Bot.getProperty(backupStockKey) || [];133      if (typeof backupStock2 === "string") { backupStock2 = backupStock2.split("\n").map(function (k) { return k.trim(); }).filter(Boolean); }134      if (Array.isArray(backupStock2)) {135        var idx2 = backupStock2.indexOf(generatedKey);136        if (idx2 > -1) { backupStock2.splice(idx2, 1); }137        Bot.setProperty(backupStockKey, backupStock2, "json");138      }139    }140 141    // 💰 Deduct balance + record purchase (same accounting as API path)142    Libs.ResourcesLib.userRes("balance").add(-price);143    var pastSpent2 = Bot.getProperty("total_spent_by_" + userId) || 0;144    Bot.setProperty("total_spent_by_" + userId, Number(pastSpent2) + price, "number");145 146    var keysHistory2 = User.getProperty("my_purchased_keys") || [];147    keysHistory2.push({148      product: String(product.name).trim(),149      product_id: product.id || null,150      days: pDaysNumOnly,151      price: price,152      key: generatedKey,153      date: new Date().toLocaleDateString()154    });155    User.setProperty("my_purchased_keys", keysHistory2, "json");156 157    var remainingBal2 = Libs.ResourcesLib.userRes("balance").value().toFixed(2);158 159    // ✅ NEW: Key ke saath automatic "Join Updates" button attach hota hai (agar admin ne link set kiya ho)160    var updateLinkForKey = Bot.getProperty("update_channel_link");161    var keyDeliveryButtons = [[{ text: "📋 Copy Key", copy_text: { text: generatedKey } }]];162    if (updateLinkForKey) {163      keyDeliveryButtons.push([{ text: "📥 Join Updates", url: updateLinkForKey, style: "primary", icon_custom_emoji_id: "6091571559233755994" }]);164    }165    keyDeliveryButtons.push([{ text: "Back to Menu", callback_data: "/back", style: "primary", icon_custom_emoji_id: "5893163582194978381" }]);166    var keyDeliveryMarkup = JSON.stringify({ inline_keyboard: keyDeliveryButtons });167 168    var deliverText2 = "<blockquote>" +169      "<tg-emoji emoji-id='5350447674971660988'>✅</tg-emoji> <b>PURCHASE SUCCESSFUL!</b>\n\n" +170      "<tg-emoji emoji-id='6147767796097884213'>📦</tg-emoji> <b>Product:</b> <code>" + String(product.name).trim() + "</code>\n" +171      "<tg-emoji emoji-id='6284816251143331422'>🗝</tg-emoji> <b>Validity:</b> <code>" + durationDisplay + "</code>\n" +172      "<tg-emoji emoji-id='5352825278672412291'>👆</tg-emoji> <b>Your Key:</b> <code>" + generatedKey + "</code>\n\n" +173      "━━━━━ <tg-emoji emoji-id='6147934084346682063'>#⃣</tg-emoji> <b>BALANCE DETAILS</b> ━━━━━\n" +174      "<tg-emoji emoji-id='6195037488898121775'>✨</tg-emoji> <b>Total Invest:</b> ₹" + price.toFixed(2) + "\n" +175      "<tg-emoji emoji-id='5409048419211682843'>💵</tg-emoji> <b>New Wallet Balance:</b> ₹" + remainingBal2 + "\n\n" +176      "<i>Enjoy your purchase. <tg-emoji emoji-id='6057881002540274780'>🥳</tg-emoji></i>" +177      "</blockquote>";178 179    if (request && request.message) {180      try {181        Api.editMessageText({182          chat_id: String(chatId),183          message_id: Number(request.message.message_id),184          text: deliverText2,185          parse_mode: "HTML",186          reply_markup: keyDeliveryMarkup187        });188      } catch (e) {189        Api.sendMessage({ chat_id: chatId, text: deliverText2, parse_mode: "HTML", reply_markup: keyDeliveryMarkup });190      }191    } else {192      Api.sendMessage({ chat_id: chatId, text: deliverText2, parse_mode: "HTML", reply_markup: keyDeliveryMarkup });193    }194 195    var adminId3 = "8812621370";196    Api.sendMessage({197      chat_id: adminId3,198      text: "🔔 <b>NEW PURCHASE DELIVERED (MANUAL STOCK)</b> ✔️\n\n" +199            "👤 <b>Buyer:</b> " + (user.first_name || "User") + " (<code>" + userId + "</code>)\n" +200            "📦 <b>Product:</b> " + String(product.name).trim() + "\n" +201            "⏳ <b>Plan:</b> " + durationDisplay + "\n" +202            "💸 <b>Price Deducted:</b> ₹" + price.toFixed(2) + "\n" +203            "💳 <b>User Remaining Bal:</b> ₹" + remainingBal2 + "\n" +204            "🔑 <b>Key:</b> <code>" + generatedKey + "</code>\n\n" +205            "<i>✅ Manual stock se deliver hui — external paid API call SKIP ki gayi.</i>",206      parse_mode: "HTML"207    });208 209    var qId0 = request ? (request.id || (request.callback_query && request.callback_query.id)) : null;210    if (qId0) {211      try { Api.answerCallbackQuery({ callback_query_id: String(qId0), text: "✅ Key Delivered!", show_alert: false }); } catch (e) {}212    }213 214    return; // 🚫 STOP — external API bilkul call nahi hui215  }216 217  var webProductId = String(product.id || "PID_ID").trim();218  var prodNameLower = String(product.name).toLowerCase();219 220  var durationParam = (planUnit === "hour") ? (cleanPlanDays + " Hour" + (Number(cleanPlanDays) === 1 ? "" : "s")) :221                       (planUnit === "minute") ? (cleanPlanDays + " Minute" + (Number(cleanPlanDays) === 1 ? "" : "s")) :222                       cleanPlanDays + " Days";223  var rawPlanName = plan.name || plan.title || plan.name_on_website || "";224 225  if (rawPlanName.trim() !== "" && isNaN(rawPlanName)) {226    durationParam = rawPlanName.trim();227  } else {228    if (prodNameLower.indexOf("pato") > -1) {229      durationParam = cleanPlanDays + " DaYs All Colours Mix";230    } else if (prodNameLower.indexOf("prime") > -1 || prodNameLower.indexOf("hook") > -1) {231      durationParam = (cleanPlanDays === "7") ? "7 Days NonRoot" : cleanPlanDays + " Days Nonroot";232    } else if (prodNameLower.indexOf("nonroot") > -1 || prodNameLower.indexOf("non root") > -1) {233      durationParam = cleanPlanDays + " DaYs NONROOT";234    } else if (prodNameLower.indexOf("all android") > -1 || prodNameLower.indexOf("mix") > -1) {235      durationParam = cleanPlanDays + " DaYs All Colours Mix";236    } else {237      durationParam = cleanPlanDays + " Days";238    }239  }240 241  var postFieldsString = "api_key=" + encodeURIComponent("a12cf270b9df76b981974a120ce1dd7f") +242                         "&action=" + encodeURIComponent("buy") +243                         "&product_id=" + encodeURIComponent(webProductId) +244                         "&duration=" + encodeURIComponent(durationParam);245 246  var apiHeaders = {247    "Content-Type": "application/x-www-form-urlencoded",248    "x-master-key": "a7f3e8b2c9d1f4a6b8c2d5e9f1a3b6c8"249  };250 251  User.setProperty("last_pending_price", Number(price), "number");252  User.setProperty("last_pending_prod_id", webProductId, "string");253  User.setProperty("last_pending_prod_name", String(product.name).trim(), "string");254  User.setProperty("last_pending_plan_days", cleanPlanDays, "string");255  User.setProperty("last_pending_plan_unit", planUnit, "string");256 257  var queryId = request ? (request.id || (request.callback_query && request.callback_query.id)) : null;258 259  var processingText = "<tg-emoji emoji-id='6147936236125298267'>⏳</tg-emoji> <b>Processing your order... please wait!</b>";260  if (request && request.message) {261    try {262      Api.editMessageText({263        chat_id: String(chatId),264        message_id: Number(request.message.message_id),265        text: processingText,266        parse_mode: "HTML"267      });268      // ✅ FIX: is "Processing..." message ka ID save karo taaki key deliver269      // hone par ye delete ho jaaye — pehle ye chat me hamesha stuck rehta tha.270      Bot.setProperty("gen_msg_id_" + userId, request.message.message_id, "string");271      User.setProperty("gen_msg_id_" + userId, request.message.message_id, "string");272    } catch (e) {273      var pm1 = Api.sendMessage({ chat_id: chatId, text: processingText, parse_mode: "HTML" });274      try {275        var pmid1 = (pm1 && pm1.result && pm1.result.message_id) ? pm1.result.message_id : (pm1 && pm1.message_id ? pm1.message_id : null);276        if (pmid1) { Bot.setProperty("gen_msg_id_" + userId, pmid1, "string"); User.setProperty("gen_msg_id_" + userId, pmid1, "string"); }277      } catch (e2) {}278    }279  } else {280    var pm2 = Api.sendMessage({ chat_id: chatId, text: processingText, parse_mode: "HTML" });281    try {282      var pmid2 = (pm2 && pm2.result && pm2.result.message_id) ? pm2.result.message_id : (pm2 && pm2.message_id ? pm2.message_id : null);283      if (pmid2) { Bot.setProperty("gen_msg_id_" + userId, pmid2, "string"); User.setProperty("gen_msg_id_" + userId, pmid2, "string"); }284    } catch (e2) {}285  }286 287  HTTP.post({288    url: "https://xyzcheats.com/api/reseller_v1.php",289    body: postFieldsString,290    headers: apiHeaders,291    success: "/onWebKeyReceive",292    error: "/onWebKeyError"293  });294 295  if (queryId) {296    try {297      Api.answerCallbackQuery({298        callback_query_id: String(queryId),299        text: "⏳ Processing your order... Please wait!",300        show_alert: false301      });302    } catch (e) {}303  }304 305} catch (e) {306  var errChatId = (typeof chat !== "undefined" && chat && chat.chatid) ? chat.chatid : null;307  if (errChatId) {308    try { Api.sendMessage({ chat_id: errChatId, text: "❌ <b>Error:</b> <code>" + e.message + "</code>", parse_mode: "HTML" }); } catch (fatal) {}309  }310}