export default { async fetch(request, env, ctx) { const url = new URL(request.url); if (url.pathname === "/") return new Response("subsship bot ok ✅"); if (url.pathname !== "/tg") return new Response("Not found", { status: 404 }); const secret = request.headers.get("X-Telegram-Bot-Api-Secret-Token"); if (env.TG_SECRET && secret !== env.TG_SECRET) { return new Response("Unauthorized", { status: 403 }); } const update = await request.json(); ctx.waitUntil(handleUpdate(update, env)); return new Response("ok"); }, }; const BRAND = "subsship"; const CARD_NUMBER = "5859471035374309"; const CARD_NAME = "آرتین حسن راشدی"; // ====== UPDATED PRICES (Toman) ====== const BASE_PRICES = { // Spotify SPOTIFY: { // اکانت جدید - فقط ۳ ماه ECO: { 3: 742380 }, // فعال‌سازی روی اکانت - فقط ۲ ماه (Hot offer) VIP: { 2: 1836000 }, }, // Apple Music APPLE: { ECO: { 1: 580760, 3: 1200000 }, VIP: { 1: 580760, 3: 1200000 }, // فعلاً همون قیمت }, }; function formatToman(n) { try { return Number(n).toLocaleString("fa-IR"); } catch { return String(n); } } function orderId() { return (Date.now().toString(36) + Math.random().toString(36).slice(2, 6)).toUpperCase(); } function signedAmount(base, tag) { return base + tag; // base + 3-digit tag } function tagFromOrderId(oid) { return (parseInt(oid.slice(-3), 36) % 1000 + 1000) % 1000; // 0..999 } async function tg(method, env, body) { const res = await fetch(`https://api.telegram.org/bot${env.BOT_TOKEN}/${method}`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), }); return res.json(); } function kbMain() { return { inline_keyboard: [[ { text: "🎧 Spotify", callback_data: "P|SPOTIFY" }, { text: "🍎 Apple Music", callback_data: "P|APPLE" }, ]], }; } function kbPlan(product) { return { inline_keyboard: [ [{ text: "💸 اقتصادی (کد/اکانت جدید)", callback_data: `PL|${product}|ECO` }], [{ text: "⚡ VIP (فعال‌سازی روی اکانت)", callback_data: `PL|${product}|VIP` }], [{ text: "⬅️ برگشت", callback_data: "BACK|MAIN" }], ], }; } function availableMonths(product, plan) { const obj = BASE_PRICES?.[product]?.[plan] || {}; return Object.keys(obj) .map((k) => parseInt(k, 10)) .filter((m) => obj[m] > 0) .sort((a, b) => a - b); } function kbMonths(product, plan) { const months = availableMonths(product, plan); const rows = []; // دکمه‌ها دو تا دو تا کنار هم for (let i = 0; i < months.length; i += 2) { const row = []; row.push({ text: `${months[i]} ماهه`, callback_data: `M|${product}|${plan}|${months[i]}` }); if (months[i + 1]) row.push({ text: `${months[i + 1]} ماهه`, callback_data: `M|${product}|${plan}|${months[i + 1]}` }); rows.push(row); } rows.push([{ text: "⬅️ برگشت", callback_data: `BACK|PLAN|${product}` }]); return { inline_keyboard: rows }; } function kbAdmin(oid) { return { inline_keyboard: [ [ { text: "✅ Approve", callback_data: `A|APPROVE|${oid}` }, { text: "❌ Reject", callback_data: `A|REJECT|${oid}` }, ], [{ text: "🎟 Delivered", callback_data: `A|DELIVERED|${oid}` }], ], }; } async function getState(env, chatId) { const raw = await env.KV.get(`state:${chatId}`); return raw ? JSON.parse(raw) : { step: "MAIN" }; } async function setState(env, chatId, state) { await env.KV.put(`state:${chatId}`, JSON.stringify(state), { expirationTtl: 60 * 60 * 6 }); } async function getOrder(env, oid) { const raw = await env.KV.get(`order:${oid}`); return raw ? JSON.parse(raw) : null; } async function setOrder(env, oid, order) { await env.KV.put(`order:${oid}`, JSON.stringify(order), { expirationTtl: 60 * 60 * 24 * 7 }); } async function handleUpdate(update, env) { // ===== Messages ===== if (update.message) { const msg = update.message; const chatId = msg.chat.id; if (msg.text && msg.text.startsWith("/chatid")) { await tg("sendMessage", env, { chat_id: chatId, text: `Chat ID: \`${chatId}\``, parse_mode: "Markdown", }); return; } if (msg.text && msg.text.startsWith("/start")) { await setState(env, chatId, { step: "MAIN" }); await tg("sendMessage", env, { chat_id: chatId, text: `سلام ✨ به ${BRAND} خوش اومدی.\nچی می‌خوای سفارش بدی؟`, reply_markup: kbMain(), }); return; } // Receipt photo if (msg.photo && msg.photo.length) { const state = await getState(env, chatId); if (!state.orderId) { await tg("sendMessage", env, { chat_id: chatId, text: "اول /start رو بزن و سفارش بساز ✅" }); return; } const order = await getOrder(env, state.orderId); if (!order) { await tg("sendMessage", env, { chat_id: chatId, text: "سفارش پیدا نشد. /start ✅" }); return; } const fileId = msg.photo[msg.photo.length - 1].file_id; order.receipt_file_id = fileId; order.status = "RECEIPT"; await setOrder(env, order.order_id, order); await tg("sendMessage", env, { chat_id: chatId, text: "✅ رسید دریافت شد. داریم بررسی می‌کنیم و نتیجه رو اعلام می‌کنیم.", }); const adminChatId = parseInt(env.ADMIN_CHAT_ID || "0", 10); if (!adminChatId) { await tg("sendMessage", env, { chat_id: chatId, text: "⚠️ هنوز ADMIN_CHAT_ID تنظیم نشده. ربات رو داخل گروه ops اضافه کن و اونجا /chatid بزن.", }); return; } await tg("sendPhoto", env, { chat_id: adminChatId, photo: fileId, caption: `🧾 Receipt\nOrder: #${order.order_id}\nUser: @${order.username} (id:${order.user_id})\n` + `Product: ${order.product}\nPlan: ${order.plan}\nMonths: ${order.months}\nAmount: ${formatToman(order.amount)}\nStatus: ${order.status}`, reply_markup: kbAdmin(order.order_id), }); return; } if (msg.text) { await tg("sendMessage", env, { chat_id: chatId, text: "برای شروع /start رو بزن ✅" }); } return; } // ===== Buttons ===== if (update.callback_query) { const cq = update.callback_query; const data = cq.data || ""; const message = cq.message; const chatId = message.chat.id; await tg("answerCallbackQuery", env, { callback_query_id: cq.id }); // Admin actions (only in admin group) if (data.startsWith("A|")) { const adminChatId = parseInt(env.ADMIN_CHAT_ID || "0", 10); if (!adminChatId || chatId !== adminChatId) return; const [, action, oid] = data.split("|"); const order = await getOrder(env, oid); if (!order) return; if (action === "APPROVE") { order.status = "APPROVED"; await setOrder(env, order.order_id, order); await tg("sendMessage", env, { chat_id: order.user_id, text: "✅ پرداخت تایید شد. نوبت‌دهی انجام میشه و تحویل برات انجام می‌دیم ⚡️", }); } else if (action === "REJECT") { order.status = "REJECTED"; await setOrder(env, order.order_id, order); await tg("sendMessage", env, { chat_id: order.user_id, text: "❌ رسید تایید نشد. لطفاً یک عکس واضح‌تر از رسید بفرست.", }); } else if (action === "DELIVERED") { order.status = "DELIVERED"; await setOrder(env, order.order_id, order); await tg("sendMessage", env, { chat_id: order.user_id, text: "🎉 انجام شد. اگر نیاز به راهنما داشتی همینجا پیام بده ⚡️", }); } return; } // User flow if (data === "BACK|MAIN") { await setState(env, chatId, { step: "MAIN" }); await tg("editMessageText", env, { chat_id: chatId, message_id: message.message_id, text: "چی می‌خوای سفارش بدی؟", reply_markup: kbMain(), }); return; } if (data.startsWith("P|")) { const [, product] = data.split("|"); await setState(env, chatId, { step: "PLAN", product }); await tg("editMessageText", env, { chat_id: chatId, message_id: message.message_id, text: "حالا پلن رو انتخاب کن:", reply_markup: kbPlan(product), }); return; } if (data.startsWith("BACK|PLAN|")) { const product = data.split("|")[2]; await setState(env, chatId, { step: "PLAN", product }); await tg("editMessageText", env, { chat_id: chatId, message_id: message.message_id, text: "پلن رو انتخاب کن:", reply_markup: kbPlan(product), }); return; } if (data.startsWith("PL|")) { const [, product, plan] = data.split("|"); const months = availableMonths(product, plan); if (!months.length) { await tg("sendMessage", env, { chat_id: chatId, text: "فعلاً این پلن موجود نیست." }); return; } await setState(env, chatId, { step: "MONTHS", product, plan }); await tg("editMessageText", env, { chat_id: chatId, message_id: message.message_id, text: "مدت اشتراک رو انتخاب کن:", reply_markup: kbMonths(product, plan), }); return; } if (data.startsWith("M|")) { const [, product, plan, monthsStr] = data.split("|"); const months = parseInt(monthsStr, 10); const base = (BASE_PRICES?.[product]?.[plan]?.[months]) ?? 0; if (!base) { await tg("sendMessage", env, { chat_id: chatId, text: "این مدت فعلاً موجود نیست. /start ✅" }); return; } const oid = orderId(); const tag = tagFromOrderId(oid); const amount = signedAmount(base, tag); const order = { order_id: oid, user_id: cq.from.id, username: cq.from.username || cq.from.first_name || "user", product, plan, months, amount, status: "PAYMENT_PENDING", }; await setOrder(env, oid, order); await setState(env, chatId, { step: "WAIT_RECEIPT", orderId: oid }); await tg("editMessageText", env, { chat_id: chatId, message_id: message.message_id, text: `✅ سفارش #${oid} ثبت شد.\n\n` + `مبلغ پرداختی (دقیق): ${formatToman(amount)} تومان\n` + `*لطفاً دقیق همین مبلغ رو واریز کن.*\n\n` + `💳 کارت‌به‌کارت به:\n${CARD_NUMBER}\n` + `به نام: ${CARD_NAME}\n\n` + `📸 بعد از واریز، اسکرین‌شات رسید رو همینجا بفرست.\n` + `⏱️ تحویل طبق نوبت‌دهی انجام میشه.`, parse_mode: "Markdown", }); return; } } }