├── requirements.txt ├── main.py ├── config.py ├── README.md └── cogs └── shop.py /requirements.txt: -------------------------------------------------------------------------------- 1 | disnake==2.7.0 2 | pyQiwiP2P==2.0.6 3 | asyncio==3.4.3 4 | colorama==0.4.6 5 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import disnake 2 | from disnake.ext import commands 3 | from config import token 4 | 5 | #В настройках бота на сайте включить все вкладки с INTENTS 6 | intents = disnake.Intents.all() 7 | bot = commands.Bot(command_prefix="s!", intents=intents, activity=disnake.Game(name="/start в ЛС")) 8 | 9 | #список когов 10 | cogs = ['shop'] 11 | 12 | #ивент готовности бота для подгрузок когов 13 | @bot.event 14 | async def on_ready(): 15 | for cog in cogs: 16 | bot.load_extension(f"cogs.{cog}") 17 | print('[Log]: Бот запущен!') 18 | 19 | #команда рестарт когов (s!reload) 20 | @bot.command() 21 | async def reload(inter): 22 | for cog in cogs: 23 | bot.reload_extension(f"cogs.{cog}") 24 | await inter.send('рестартнул коги') 25 | 26 | #запуск бота 27 | bot.run(token) 28 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | 2 | # _/_/_/ _/_/_/_/ _/ _/ _/ _/ 3 | # _/ _/ _/_/ _/ _/ _/_/ _/ 4 | # _/_/_/ _/ _/ _/_/_/ _/ _/ _/ _/ _/ 5 | # _/ _/ _/ _/ _/ _/ _/ _/ _/_/ 6 | #_/ _/ _/_/ _/ _/ _/ _/ _/ 7 | 8 | #токен бота 9 | token = '' 10 | 11 | #киви токен (https://p2p.qiwi.com/) 12 | qiwi_token = '' 13 | 14 | #администраторы с доступом к s!ashop 15 | admins_ids = [0, 0] 16 | 17 | #айди канала логов (туда все логи покупок и пополнений) 18 | logid = 0 19 | 20 | #айди роли покупателя (выдаётся после покупки) 21 | roleid = 0 22 | 23 | #айди вашего сервера 24 | guildid = 0 25 | 26 | #ссылка на изображение иконки в главном меню (/start) 27 | iconurl = 'https://media.discordapp.net/attachments/1063449709412356126/1065627669548503070/7510046.png' 28 | 29 | #ссылка на канал/сообщение/сервер вашей поддержки 30 | supporturl = 'https://discord.gg/TEuCA9EdmS' 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # ❗ НЕ АКТУАЛЬНО! 3 | С весны этого года компания QIWI перестала оффициально выдовать p2p api токены, если вы не обладатель такого токена полученного ранее или не смогли получить его другим путём - к сожалению использовать данный скрипт вы не сможете. 4 | 5 | # AutoShop 6 | Автоматический магазин с пополнением через QIWI для Discord 7 |
Developed by RoFliN | UPD: В данный момент автовыдача не поддерживается, данная автовыдача частично устарела и выход новых версий пока не намечается. 8 | 9 | ### 🖱️ Команды: 10 | 11 |
/start - Главное меню 12 |
s!ashop - Админ панель | Указать id администратора в config.py 13 |
s!reload - Рестарт когов 14 | ### 💠 Установка: 15 | 1. Установить необходимости requirements.txt 16 |
2. Заполнить файл config.py | Там всё расписано 17 |
3. Запустить main.py 18 |
4. Заполнять товары и радоваться жизни 19 |
ˣ Для работы необходимо на сайте бота (DISCORD/APLICATIONS) включить все вкладки INTENTS ˣ 20 | 21 | # 🌺 Скриншоты: 22 | ![/start](https://media.discordapp.net/attachments/1063449709412356126/1068530374482874428/image.png) 23 | ![s!ashop](https://media.discordapp.net/attachments/1063449709412356126/1068530344254521425/image.png) 24 | -------------------------------------------------------------------------------- /cogs/shop.py: -------------------------------------------------------------------------------- 1 | import disnake 2 | from disnake.ext import commands 3 | from disnake import TextInputStyle 4 | from config import qiwi_token, admins_ids, logid, roleid, guildid, iconurl, supporturl 5 | import sqlite3 6 | import random 7 | from pyqiwip2p import QiwiP2P 8 | import asyncio 9 | 10 | #подключение бд 11 | db = sqlite3.connect("db") 12 | cursor = db.cursor() 13 | 14 | #создание нужных таблиц если ещё не созданы 15 | cursor.execute("CREATE TABLE IF NOT EXISTS shop (id INT, name TEXT, price INT, tovar TEXT, status INT)") 16 | cursor.execute("CREATE TABLE IF NOT EXISTS users (id BIGINT, shopping INT, balance INT)") 17 | cursor.execute("CREATE TABLE IF NOT EXISTS checks (userid BIGINT, checkid VARCHAR, money INT)") 18 | cursor.execute("CREATE TABLE IF NOT EXISTS promocode (pc TEXT, value INT, count INT, userid BIGINT)") 19 | 20 | #подключение платёжной системы 21 | p2p = QiwiP2P(auth_key=qiwi_token) 22 | 23 | class ShopSystem(commands.Cog): 24 | def __init__(self, bot: commands.Bot): 25 | self.bot = bot 26 | 27 | #/start 28 | @commands.slash_command(description='Меню взаимодействий') 29 | async def start(self, inter): 30 | embed = disnake.Embed(title='Основное меню', description='Выберите категорию', color=disnake.Color.from_rgb(47,49,54)) 31 | embed.set_thumbnail(url=iconurl) #Тут картинку поставить 32 | await inter.response.send_message(embed=embed, components=[ 33 | disnake.ui.Button(label="Магазин", style=disnake.ButtonStyle.success, custom_id="bshop", emoji='🛍️'), 34 | disnake.ui.Button(label="Профиль", style=disnake.ButtonStyle.blurple, custom_id="bprofile", emoji='👥'), 35 | [disnake.ui.Button(label="Поддержка", style=disnake.ButtonStyle.primary, emoji='💤', url=supporturl)] 36 | ]) 37 | 38 | #/ashop 39 | @commands.command() 40 | async def ashop(self, inter): 41 | if inter.author.id in admins_ids: 42 | prods = cursor.execute("SELECT id, name, price FROM shop WHERE status = 0").fetchall() 43 | embed = disnake.Embed(title='Управление Магазином', description='Товары: ', color=disnake.Color.from_rgb(47,49,54)) 44 | for prod in prods: 45 | embed.add_field(name=prod[1], value=f'Цена: {prod[2]}₽ | ID: {prod[0]}', inline=False) 46 | await inter.send(embed=embed, components=[ 47 | disnake.ui.Button(label="Добавить товар", style=disnake.ButtonStyle.success, custom_id="sadd"), 48 | disnake.ui.Button(label="Удалить товар", style=disnake.ButtonStyle.danger, custom_id="sremove"), 49 | [disnake.ui.Button(label="Добавить промокод", style=disnake.ButtonStyle.success, custom_id="baddpc"), 50 | disnake.ui.Button(label="Выдать баланс", style=disnake.ButtonStyle.secondary, custom_id="setbal")]]) 51 | else: 52 | await inter.send("Ух, ну я думаю тебе это использовать не стоит! \n Хочешь купить бота? - RoFliN#0939") 53 | 54 | #остлеживание ивентов выпадающего списка 55 | @commands.Cog.listener() 56 | async def on_dropdown(self, inter: disnake.MessageInteraction): 57 | tovar = cursor.execute(f"SELECT id, price, tovar FROM shop WHERE name = '{inter.values[0]}' AND status = 0").fetchone() 58 | if tovar: 59 | user = cursor.execute(f"SELECT balance, shopping FROM users WHERE id = {inter.author.id}").fetchone() 60 | if user: 61 | if user[0] >= tovar[1]: 62 | embed = disnake.Embed(title='Вы точно хотите купить?', description=f'{inter.values[0]} за {tovar[1]}₽ \n У вас есть 1 минута на решение!', color=disnake.Color.from_rgb(47,49,54)) 63 | embed.set_footer(text='Проигнорируйте это сообщение если передумали') 64 | await inter.response.send_message(embed=embed, components=[ 65 | disnake.ui.Button(label='Подтвердить', style=disnake.ButtonStyle.success, custom_id='accept', emoji='✅') 66 | ], ephemeral=True) 67 | try: 68 | cursor.execute(f"UPDATE shop SET status = 1 WHERE id = {tovar[0]}") 69 | db.commit() 70 | interb = await self.bot.wait_for('button_click', timeout=60) 71 | balance = user[0] - tovar[1] 72 | shopi = user[1] + 1 73 | cursor.execute(f"UPDATE users SET balance = {balance}, shopping = {shopi} WHERE id = {inter.author.id}") 74 | cursor.execute(f"DELETE FROM shop WHERE id = {tovar[0]}") 75 | db.commit() 76 | await interb.send(tovar[2], ephemeral=True) 77 | log_channel = await self.bot.fetch_channel(logid) 78 | embed = disnake.Embed(title="Новая покупка", description=f"Покупатель: <@{inter.author.id}> \nТовар: {inter.values[0]}", color=disnake.Color.from_rgb(47,49,54)) 79 | await log_channel.send(embed=embed) 80 | guild = await self.bot.fetch_guild(guildid) 81 | role = guild.get_role(roleid) 82 | print(role, guild) 83 | await inter.author.add_roles(role) 84 | except: 85 | cursor.execute(f"UPDATE shop SET status = 0 WHERE id = {tovar[0]}") 86 | db.commit() 87 | return 88 | else: 89 | await inter.response.send_message('Вам нехватает денег, пополните счёт! | /start > профиль > пополнить', ephemeral=True) 90 | else: 91 | cursor.execute(f"INSERT INTO users (id, shopping, balance) VALUES ({inter.author.id}, 0, 0)") 92 | db.commit() 93 | await inter.response.send_message('Вам нехватает денег, пополните счёт! | /start > профиль > пополнить', ephemeral=True) 94 | else: 95 | await inter.response.send_message('Товар уже продан.', ephemeral=True) 96 | 97 | #остлеживание ивентов кнопок 98 | @commands.Cog.listener("on_button_click") 99 | async def menu_listener(self, inter: disnake.MessageInteraction): 100 | if inter.component.custom_id == "bshop": 101 | try: 102 | prods = cursor.execute("SELECT id, name, price FROM shop WHERE status = 0").fetchall() 103 | embed = disnake.Embed(title='Магазин', description='Доступные товары', color=disnake.Color.from_rgb(47,49,54)) 104 | names = [] 105 | for prod in prods: 106 | names.append(prod[1]) 107 | dev = [] 108 | options = [] 109 | for prod in prods: 110 | if names.count(f"{prod[1]}") > 1: 111 | embed.add_field(name=prod[1], value=f'Цена: {prod[2]}₽ | Кол-во: {names.count(f"{prod[1]}")}', inline=False) 112 | options.append(disnake.SelectOption( 113 | label=prod[1], description=f"Цена: {prod[2]}₽ | Кол-во: {names.count(f'{prod[1]}')}", emoji='🛒')) 114 | for i in range(names.count(f"{prod[1]}")): 115 | names.remove(prod[1]) 116 | dev.append(prod[1]) 117 | else: 118 | if prod[1] in dev: 119 | pass 120 | else: 121 | embed.add_field(name=prod[1], value=f'Цена: {prod[2]}₽ | Кол-во: 1', inline=False) 122 | options.append(disnake.SelectOption( 123 | label=prod[1], description=f"Цена: {prod[2]}₽ | Кол-во: 1", emoji='🛒')) 124 | await inter.response.send_message(embed=embed, ephemeral=True, components=[disnake.ui.Select(placeholder='Выберите товар', min_values=1, max_values=1, options=options)]) 125 | except: 126 | await inter.response.send_message(embed=embed, ephemeral=True) 127 | 128 | if inter.component.custom_id == 'baddpc': 129 | await inter.response.send_modal(title='Добавить промокод', custom_id='addpc', components=[ 130 | disnake.ui.TextInput( 131 | label="Промокод", 132 | placeholder="PROMOCODE", 133 | custom_id="pc", 134 | style=TextInputStyle.short 135 | ), 136 | disnake.ui.TextInput( 137 | label="Проценты", 138 | placeholder="000", 139 | custom_id="pcval", 140 | style=TextInputStyle.short 141 | ), 142 | disnake.ui.TextInput( 143 | label="Кол-во использований", 144 | placeholder="10", 145 | custom_id="pcount", 146 | style=TextInputStyle.short 147 | ) 148 | ]) 149 | 150 | if inter.component.custom_id == 'bprofile': 151 | user = cursor.execute(f"SELECT shopping, balance FROM users WHERE id = {inter.author.id}").fetchone() 152 | if not user: 153 | cursor.execute(f"INSERT INTO users (id, shopping, balance) VALUES ({inter.author.id}, 0, 0)") 154 | db.commit() 155 | user = cursor.execute(f"SELECT shopping, balance FROM users WHERE id = {inter.author.id}").fetchone() 156 | embed = disnake.Embed(title=f'Профиль - {inter.author}', description=f'\n **Баланс: {user[1]}₽** \n**Куплено товаров: {user[0]}**', color=disnake.Color.from_rgb(47,49,54)) 157 | embed.set_thumbnail(url=inter.author.avatar.url) 158 | await inter.response.send_message(embed=embed, ephemeral=True, components=[ 159 | disnake.ui.Button(label="Пополнить баланс", style=disnake.ButtonStyle.success, custom_id="addbal") 160 | ]) 161 | 162 | if inter.component.custom_id == 'addbal': 163 | await inter.response.send_modal(title='Пополнить баланс', custom_id='gencheck', components=[ 164 | disnake.ui.TextInput( 165 | label="Сумма", 166 | placeholder="Только целые числа!", 167 | required=True, 168 | custom_id="summa", 169 | style=TextInputStyle.short 170 | ), 171 | disnake.ui.TextInput( 172 | label="Промокод", 173 | placeholder="Необязательно", 174 | custom_id="promocode", 175 | required=False, 176 | style=TextInputStyle.short 177 | ) 178 | ]) 179 | if inter.component.custom_id == "sadd": 180 | await inter.response.send_modal(title='Добавить Товар', custom_id='addprod', components = [ 181 | disnake.ui.TextInput( 182 | label="Название", 183 | placeholder="Название товара", 184 | custom_id="name", 185 | style=TextInputStyle.short, 186 | ), 187 | disnake.ui.TextInput( 188 | label="Содержимое", 189 | placeholder="Содержимое товара", 190 | custom_id="tovar", 191 | style=TextInputStyle.paragraph, 192 | ), 193 | disnake.ui.TextInput( 194 | label="Цена", 195 | placeholder="Цена товара", 196 | custom_id="price", 197 | style=TextInputStyle.short, 198 | ), 199 | ]) 200 | if inter.component.custom_id == "sremove": 201 | await inter.response.send_modal(title='Удалить товар', custom_id='removeprod', components = [ 202 | disnake.ui.TextInput( 203 | label="ID", 204 | placeholder="ID Товара", 205 | custom_id="id", 206 | style=TextInputStyle.short, 207 | ) 208 | ]) 209 | if inter.component.custom_id == "setbal": 210 | await inter.response.send_modal(title="Выдать баланс", custom_id="msetbal", components=[ 211 | disnake.ui.TextInput( 212 | label="Айди участника", 213 | placeholder="000000000000000", 214 | custom_id="userid", 215 | style=TextInputStyle.short, 216 | ), 217 | disnake.ui.TextInput( 218 | label="Количество денег", 219 | placeholder="00000", 220 | custom_id="amount", 221 | style=TextInputStyle.short, 222 | ) 223 | ]) 224 | 225 | #отслеживание ивентов модальных окон 226 | @commands.Cog.listener() 227 | async def on_modal_submit(self, inter: disnake.ModalInteraction): 228 | if inter.custom_id == "addpc": 229 | cursor.execute(f"INSERT INTO promocode (pc, value, count, userid) VALUES ('{inter.text_values['pc']}', {inter.text_values['pcval']}, {inter.text_values['pcount']}, {inter.author.id})") 230 | db.commit() 231 | await inter.response.send_message(f"Добавлен промокод: {inter.text_values['pc']}") 232 | 233 | if inter.custom_id == "addprod": 234 | cursor.execute(f"INSERT INTO shop (id, name, price, tovar, status) VALUES ({random.randint(0, 999999)}, '{inter.text_values['name']}', {inter.text_values['price']}, '{inter.text_values['tovar']}', 0)") 235 | db.commit() 236 | await inter.response.send_message(f"Добавлен новый товар: {inter.text_values['name']}", ephemeral=True) 237 | if inter.custom_id == "removeprod": 238 | cursor.execute(f"DELETE FROM shop WHERE id = {inter.text_values['id']}") 239 | db.commit() 240 | await inter.response.send_message("Удалено", ephemeral=True) 241 | 242 | if inter.custom_id == "msetbal": 243 | try: 244 | bal = cursor.execute(f"SELECT balance FROM users WHERE id = {int(inter.text_values['userid'])}").fetchone() 245 | fullbal = int(bal[0]) + int(inter.text_values['amount']) 246 | cursor.execute(f"UPDATE users SET balance = {fullbal} WHERE id = {inter.text_values['userid']}") 247 | await inter.response.send_message(f"Выдал юзеру <@{inter.text_values['userid']}> {inter.text_values['amount']}Р") 248 | log_channel = await self.bot.fetch_channel(logid) 249 | embed = disnake.Embed(title="Выдан баланс", description=f"Пользователь: <@{inter.text_values['userid']}> \nСумма: {inter.text_values['amount']}₽ \n Админ: {inter.author.mention}", color=disnake.Color.from_rgb(47,49,54)) 250 | await log_channel.send(embed=embed) 251 | except: 252 | await inter.response.send_message(f"Похоже юзера нету в бд и он ещё не использовал бота") 253 | 254 | if inter.custom_id == "gencheck": 255 | try: 256 | summa = int(inter.text_values['summa']) 257 | summaop = int(inter.text_values['summa']) 258 | if inter.text_values['promocode'] != '': 259 | pc = cursor.execute(f"SELECT value, count FROM promocode WHERE pc = '{inter.text_values['promocode']}'").fetchone() 260 | if pc and pc[1] >= 1: 261 | bonus = summa * pc[0] / 100 262 | summa = int(round(summa + bonus)) 263 | pcount = pc[1] - 1 264 | if pcount <= 0: 265 | cursor.execute(f"DELETE FROM promocode WHERE pc = '{inter.text_values['promocode']}'") 266 | db.commit() 267 | else: 268 | cursor.execute(f"UPDATE promocode SET count = {pcount} WHERE pc = '{inter.text_values['promocode']}'") 269 | db.commit() 270 | else: 271 | pass 272 | 273 | comment = f'{inter.author.id}_{random.randint(10000, 99999)}' 274 | bill = p2p.bill(amount=summaop, lifetime=2, comment=comment) 275 | cursor.execute(f"INSERT INTO checks (userid, checkid, money) VALUES ({inter.author.id}, '{bill.bill_id}', {summa})") 276 | db.commit() 277 | embed = disnake.Embed(title='Оплата счёта', description=f'**Оплатите:** {summaop}₽ \n **Получите:** {summa}₽', color=disnake.Color.from_rgb(47,49,54)) 278 | await inter.response.send_message(embed=embed, ephemeral=True, components=[ 279 | disnake.ui.Button(label='Оплатить', style=disnake.ButtonStyle.success, url=bill.pay_url) 280 | ]) 281 | except: 282 | await inter.response.send_message("Ишак тупой вводи только целые числа в сумму! >:(") 283 | 284 | #проверка платежей каждую минуту 285 | async def checkoplata(bot): 286 | while True: 287 | await asyncio.sleep(30) 288 | oplats = cursor.execute("SELECT userid, checkid, money FROM checks").fetchall() 289 | for oplata in oplats: 290 | if str(p2p.check(bill_id=oplata[1]).status) == "PAID": 291 | user = cursor.execute(f"SELECT balance FROM users WHERE id = {oplata[0]}").fetchone() 292 | newbal = int(user[0]) + int(oplata[2]) 293 | cursor.execute(f"UPDATE users SET balance = {newbal} WHERE id = {oplata[0]}") 294 | cursor.execute(f"DELETE FROM checks WHERE checkid = '{oplata[1]}'") 295 | db.commit() 296 | log_channel = await bot.fetch_channel(logid) 297 | member = await bot.fetch_user(int(oplata[0])) 298 | await member.send(f"Ваш баланс пополнен на {oplata[2]} Рублей!") 299 | embed = disnake.Embed(title="Пополнен баланс", description=f"Пользователь: <@{oplata[0]}> \nСумма: {oplata[2]}", color=disnake.Color.from_rgb(47,49,54)) 300 | await log_channel.send(embed=embed) 301 | elif str(p2p.check(bill_id=oplata[1]).status) == "EXPIRED": 302 | cursor.execute(f"DELETE FROM checks WHERE checkid = '{oplata[1]}'") 303 | db.commit() 304 | 305 | def setup(bot: commands.Bot): 306 | bot.add_cog(ShopSystem(bot)) 307 | bot.loop.create_task(checkoplata(bot)) 308 | --------------------------------------------------------------------------------