├── 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 | 
23 | 
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 |
--------------------------------------------------------------------------------