xync-bot 0.3.24.dev9__tar.gz → 0.3.24.dev12__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of xync-bot might be problematic. Click here for more details.
- {xync_bot-0.3.24.dev9/xync_bot.egg-info → xync_bot-0.3.24.dev12}/PKG-INFO +1 -1
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot/__init__.py +1 -1
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot/routers/pay/cd.py +1 -0
- xync_bot-0.3.24.dev12/xync_bot/routers/pay/dep.py +290 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot/routers/pay/handler.py +21 -47
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot/routers/pay/window.py +89 -52
- xync_bot-0.3.24.dev12/xync_bot/typs.py +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12/xync_bot.egg-info}/PKG-INFO +1 -1
- xync_bot-0.3.24.dev9/xync_bot/routers/__init__.py +0 -98
- xync_bot-0.3.24.dev9/xync_bot/routers/pay/dep.py +0 -122
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/.env.dist +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/.gitignore +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/.pre-commit-config.yaml +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/makefile +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/pyproject.toml +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/setup.cfg +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/test_main.http +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot/loader.py +0 -0
- /xync_bot-0.3.24.dev9/xync_bot/typs.py → /xync_bot-0.3.24.dev12/xync_bot/routers/__init__.py +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot/routers/cond/__init__.py +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot/routers/cond/func.py +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot/routers/main.py +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot/routers/order.py +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot/routers/photo.py +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot/routers/vpn.py +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot/routers/xicon.png +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot/shared.py +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot.egg-info/SOURCES.txt +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot.egg-info/dependency_links.txt +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot.egg-info/requires.txt +0 -0
- {xync_bot-0.3.24.dev9 → xync_bot-0.3.24.dev12}/xync_bot.egg-info/top_level.txt +0 -0
|
@@ -5,8 +5,8 @@ from PGram import Bot
|
|
|
5
5
|
from aiogram.client.default import DefaultBotProperties
|
|
6
6
|
from x_model import init_db
|
|
7
7
|
|
|
8
|
-
from xync_bot.routers import Store
|
|
9
8
|
from xync_bot.routers.cond import cr as cr
|
|
9
|
+
from xync_bot.routers.pay.dep import Store
|
|
10
10
|
|
|
11
11
|
# from xync_bot.routers.main import mr
|
|
12
12
|
from xync_bot.routers.pay.handler import pay as pay
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from asyncio import gather
|
|
3
|
+
from enum import IntEnum
|
|
4
|
+
|
|
5
|
+
from aiogram.exceptions import TelegramBadRequest
|
|
6
|
+
from aiogram.fsm.state import StatesGroup, State
|
|
7
|
+
from aiogram.types import Message, InlineKeyboardMarkup
|
|
8
|
+
from pyrogram.types import CallbackQuery
|
|
9
|
+
from tortoise.functions import Min
|
|
10
|
+
from x_auth.enums import Role
|
|
11
|
+
from x_model.func import ArrayAgg
|
|
12
|
+
from xync_schema import models
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Report(StatesGroup):
|
|
16
|
+
text = State()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class CredState(StatesGroup):
|
|
20
|
+
detail = State()
|
|
21
|
+
name = State()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class PaymentState(StatesGroup):
|
|
25
|
+
amount = State()
|
|
26
|
+
timer = State()
|
|
27
|
+
timer_active = State()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ActionType(IntEnum):
|
|
31
|
+
"""Цель (назначение) платежа (target)"""
|
|
32
|
+
|
|
33
|
+
sent = 1 # Отправил
|
|
34
|
+
received = 2 # Получил
|
|
35
|
+
not_received = 3 # Не получил
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class PayStep(IntEnum):
|
|
39
|
+
"""Цель (назначение) платежа (target)"""
|
|
40
|
+
|
|
41
|
+
t_type = 1 # Выбор типа
|
|
42
|
+
t_cur = 2 # Выбор валюты
|
|
43
|
+
t_coin = 3 # Выбор монеты
|
|
44
|
+
t_pm = 4 # Выбор платежки
|
|
45
|
+
t_ex = 5 # Выбор биржи
|
|
46
|
+
t_cred_dtl = 6 # Ввод номера карты
|
|
47
|
+
t_cred_name = 7 # Ввод имени
|
|
48
|
+
# t_addr = 8 # todo: позже добавим: Выбор/ввод крипто кошелька
|
|
49
|
+
t_amount = 9 # Ввод суммы
|
|
50
|
+
""" Источник платежа (source) """
|
|
51
|
+
s_type = 10 # Выбор типа
|
|
52
|
+
s_cur = 11 # Выбор типа
|
|
53
|
+
s_pm = 12 # Выбор типа
|
|
54
|
+
s_coin = 13 # Выбор типа
|
|
55
|
+
s_ex = 14 # Выбор типа
|
|
56
|
+
ppo = 15 # Выбор возможности разбивки платежа
|
|
57
|
+
urgency = 16 # Выбор срочности получения платежа
|
|
58
|
+
pending_send = 17 # Ожидание отправки (если мы платим фиатом)
|
|
59
|
+
pending_confirm = 18 # Ожидание пока на той стороне подтвердят получение нашего фиата (если мы платим фиатом)
|
|
60
|
+
pending_receive = 19 # Ожидание поступления (если мы получаем фиат)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
flags = {
|
|
64
|
+
"RUB": "🇷🇺",
|
|
65
|
+
"THB": "🇹🇭",
|
|
66
|
+
"IDR": "🇮🇩",
|
|
67
|
+
"TRY": "🇹🇷",
|
|
68
|
+
"GEL": "🇬🇪",
|
|
69
|
+
"VND": "🇻🇳",
|
|
70
|
+
"AED": "🇦🇪",
|
|
71
|
+
"AMD": "🇦🇲",
|
|
72
|
+
"AZN": "🇦🇿",
|
|
73
|
+
"CNY": "🇨🇳",
|
|
74
|
+
"EUR": "🇪🇺",
|
|
75
|
+
"HKD": "🇭🇰",
|
|
76
|
+
"INR": "🇮🇳",
|
|
77
|
+
"PHP": "🇵🇭",
|
|
78
|
+
"USD": "🇺🇸",
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class SingleStore(type):
|
|
83
|
+
_store = None
|
|
84
|
+
|
|
85
|
+
async def __call__(cls):
|
|
86
|
+
if not cls._store:
|
|
87
|
+
cls._store = super(SingleStore, cls).__call__()
|
|
88
|
+
cls._store.coins = {k: v for k, v in await models.Coin.all().order_by("ticker").values_list("id", "ticker")}
|
|
89
|
+
curs = {c.id: c for c in await models.Cur.filter(ticker__in=flags.keys()).order_by("ticker")}
|
|
90
|
+
cls._store.curs = curs
|
|
91
|
+
cls._store.exs = {k: v for k, v in await models.Ex.all().values_list("id", "name")}
|
|
92
|
+
cls._store.pmcurs = {
|
|
93
|
+
k: v
|
|
94
|
+
for k, v in await models.Pmex.filter(pm__pmcurs__cur_id__in=cls._store.curs.keys())
|
|
95
|
+
.annotate(sname=Min("name"))
|
|
96
|
+
.group_by("pm__pmcurs__id")
|
|
97
|
+
.values_list("pm__pmcurs__id", "sname")
|
|
98
|
+
}
|
|
99
|
+
cls._store.coinexs = {
|
|
100
|
+
c.id: [ex.ex_id for ex in c.coinexs] for c in await models.Coin.all().prefetch_related("coinexs")
|
|
101
|
+
}
|
|
102
|
+
cls._store.curpms = {
|
|
103
|
+
cur_id: ids
|
|
104
|
+
for cur_id, ids in await models.Pmcur.filter(cur_id__in=curs.keys())
|
|
105
|
+
.annotate(ids=ArrayAgg("id"))
|
|
106
|
+
.group_by("cur_id")
|
|
107
|
+
.values_list("cur_id", "ids")
|
|
108
|
+
}
|
|
109
|
+
cls._store.curpms = {
|
|
110
|
+
cur_id: ids
|
|
111
|
+
for cur_id, ids in await models.Pmcur.filter(cur_id__in=curs.keys())
|
|
112
|
+
.annotate(ids=ArrayAgg("id"))
|
|
113
|
+
.group_by("cur_id")
|
|
114
|
+
.values_list("cur_id", "ids")
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return cls._store
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class Store:
|
|
121
|
+
class Global(metaclass=SingleStore):
|
|
122
|
+
coins: dict[int, str] # id:ticker
|
|
123
|
+
curs: dict[int, models.Cur] # id:Cur
|
|
124
|
+
exs: dict[int, str] # id:name
|
|
125
|
+
coinexs: dict[int, list[int]] # id:[ex_ids]
|
|
126
|
+
pmcurs: dict[int, str] # pmcur_id:name
|
|
127
|
+
curpms: dict[int, list[int]] # id:[pmcur_ids]
|
|
128
|
+
|
|
129
|
+
class Permanent:
|
|
130
|
+
msg_id: int = None
|
|
131
|
+
user: models.User = None
|
|
132
|
+
actors: dict[int, int] = None # key=ex_id
|
|
133
|
+
creds: dict[int, models.Cred] = None # key=cred_id
|
|
134
|
+
cur_creds: dict[int, list[int]] = None # pmcur_id:[cred_ids]
|
|
135
|
+
|
|
136
|
+
class Current:
|
|
137
|
+
is_target: bool = True
|
|
138
|
+
is_fiat: bool = None
|
|
139
|
+
msg_to_del: Message = None
|
|
140
|
+
|
|
141
|
+
class Payment:
|
|
142
|
+
t_cur_id: int = None
|
|
143
|
+
s_cur_id: int = None
|
|
144
|
+
t_coin_id: int = None
|
|
145
|
+
s_coin_id: int = None
|
|
146
|
+
t_pmcur_id: int = None
|
|
147
|
+
s_pmcur_id: int = None
|
|
148
|
+
t_ex_id: int = None
|
|
149
|
+
s_ex_id: int = None
|
|
150
|
+
amount: int | float = None
|
|
151
|
+
ppo: int = 1
|
|
152
|
+
addr_id: int = None
|
|
153
|
+
cred_dtl: str = None
|
|
154
|
+
cred_id: int = None
|
|
155
|
+
urg: int = 5
|
|
156
|
+
pr_id: int = None
|
|
157
|
+
|
|
158
|
+
glob: Global
|
|
159
|
+
perm: Permanent = Permanent()
|
|
160
|
+
pay: Payment = Payment()
|
|
161
|
+
curr: Current = Current()
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
async def fill_creds(person_id: int) -> tuple[dict[int, models.Cred], dict[int, list[int]]]:
|
|
165
|
+
cq = models.Cred.filter(person_id=person_id)
|
|
166
|
+
creds = {c.id: c for c in await cq}
|
|
167
|
+
cur_creds = {
|
|
168
|
+
pci: ids
|
|
169
|
+
for pci, ids in await cq.annotate(ids=ArrayAgg("id")).group_by("pmcur_id").values_list("pmcur_id", "ids")
|
|
170
|
+
}
|
|
171
|
+
return creds, cur_creds
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
async def fill_actors(person_id: int) -> dict[int, int]:
|
|
175
|
+
ex_actors = {
|
|
176
|
+
# todo: check len(ids) == 1
|
|
177
|
+
exi: ids[0]
|
|
178
|
+
for exi, ids in await models.Actor.filter(person_id=person_id)
|
|
179
|
+
.annotate(ids=ArrayAgg("id"))
|
|
180
|
+
.group_by("ex_id")
|
|
181
|
+
.values_list("ex_id", "ids")
|
|
182
|
+
}
|
|
183
|
+
return ex_actors
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
async def edit(msg: Message, txt: str, rm: InlineKeyboardMarkup):
|
|
187
|
+
await gather(msg.edit_text(txt), msg.edit_reply_markup(reply_markup=rm))
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
async def ans(cbq: CallbackQuery, txt: str = None):
|
|
191
|
+
await cbq.answer(txt, cache_time=0)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
async def dlt(msg: Message):
|
|
195
|
+
await msg.delete()
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
async def edt(msg: Message, txt: str, rm: InlineKeyboardMarkup):
|
|
199
|
+
if msg.message_id == msg.bot.store.perm.msg_id:
|
|
200
|
+
await msg.edit_text(txt, reply_markup=rm)
|
|
201
|
+
else: # окно вызвано в ответ на текст, а не кнопку
|
|
202
|
+
try:
|
|
203
|
+
await msg.bot.edit_message_text(
|
|
204
|
+
txt, chat_id=msg.chat.id, message_id=msg.bot.store.perm.msg_id, reply_markup=rm
|
|
205
|
+
)
|
|
206
|
+
except TelegramBadRequest as e:
|
|
207
|
+
print(msg.bot.store.perm.msg_id, e)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
async def xync_have_coin_amount(store: Store) -> bool:
|
|
211
|
+
assets = await models.Asset.filter(
|
|
212
|
+
addr__coin_id=store.pay.t_coin_id, addr__ex_id=store.pay.t_ex_id, addr__actor__user__role__in=Role.ADMIN
|
|
213
|
+
)
|
|
214
|
+
return store.pay.amount <= sum(a.free for a in assets)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
async def client_have_coin_amount(store: Store) -> bool:
|
|
218
|
+
assets = await models.Asset.filter(addr__coin_id=store.pay.t_coin_id, addr__actor_id__in=store.perm.actors.values())
|
|
219
|
+
return store.pay.amount <= sum(a.free for a in assets)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
async def need_ppo(store: Store):
|
|
223
|
+
cur_id = getattr(store.pay, ("t" if store.curr.is_target else "s") + "_cur_id")
|
|
224
|
+
usd_amount = store.pay.amount * store.glob.curs[cur_id].rate
|
|
225
|
+
if usd_amount < 50:
|
|
226
|
+
return 0
|
|
227
|
+
elif usd_amount > 100:
|
|
228
|
+
return 2
|
|
229
|
+
else:
|
|
230
|
+
return 1
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
async def client_target_repr(store: Store) -> tuple[models.Addr | models.Cred, str]:
|
|
234
|
+
if store.pay.t_ex_id:
|
|
235
|
+
addr_to = (
|
|
236
|
+
await models.Addr.filter(
|
|
237
|
+
actor__ex_id=store.pay.t_ex_id, coin_id=store.pay.t_coin_id, actor__user=store.perm.user
|
|
238
|
+
)
|
|
239
|
+
.prefetch_related("actor")
|
|
240
|
+
.first()
|
|
241
|
+
)
|
|
242
|
+
ex, coin = store.glob.exs[store.pay.s_ex_id], store.glob.coins[store.pay.s_coin_id]
|
|
243
|
+
if not addr_to:
|
|
244
|
+
logging.error(f"No {coin} addr in {ex} for user: {store.perm.user.username_id}")
|
|
245
|
+
return addr_to, f"{coin} на {ex} по id: `{addr_to.actor.exid}`"
|
|
246
|
+
# иначе: реквизиты для фиата
|
|
247
|
+
cur, pm = store.glob.curs[store.pay.t_cur_id], store.glob.pmcurs[store.pay.t_pmcur_id]
|
|
248
|
+
cred = store.perm.creds[store.pay.cred_id]
|
|
249
|
+
return cred, f"{cur.ticker} на {pm} по номеру: {cred.repr()}"
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
async def get_merch_target(store: Store) -> tuple[models.Addr | models.Cred, str]:
|
|
253
|
+
if store.pay.s_ex_id:
|
|
254
|
+
addr_in = (
|
|
255
|
+
await models.Addr.filter(
|
|
256
|
+
actor__ex_id=store.pay.s_ex_id, coin_id=store.pay.s_coin_id, actor__user__role__gte=Role.ADMIN
|
|
257
|
+
)
|
|
258
|
+
.prefetch_related("actor")
|
|
259
|
+
.first()
|
|
260
|
+
)
|
|
261
|
+
ex, coin = store.glob.exs[store.pay.s_ex_id], store.glob.coins[store.pay.s_coin_id]
|
|
262
|
+
if not addr_in:
|
|
263
|
+
logging.error(f"No {coin} addr in {ex}")
|
|
264
|
+
return addr_in, f"{coin} на {ex} по id: `{addr_in.actor.exid}`"
|
|
265
|
+
# иначе: реквизиты для фиатной оплаты
|
|
266
|
+
s_pmcur = await models.Pmcur.get(id=store.pay.s_pmcur_id).prefetch_related("pm__grp")
|
|
267
|
+
cred = await models.Cred.filter(
|
|
268
|
+
**({"pmcur__pm__grp": s_pmcur.pm.grp} if s_pmcur.pm.grp else {"pmcur_id": store.pay.s_pmcur_id}),
|
|
269
|
+
person__user__role__gte=Role.ADMIN,
|
|
270
|
+
).first() # todo: order by fiat.target-fiat.amount
|
|
271
|
+
cur, pm = store.glob.curs[store.pay.s_cur_id], store.glob.pmcurs[store.pay.s_pmcur_id]
|
|
272
|
+
if not cred:
|
|
273
|
+
logging.error(f"No {cur.ticker} cred for {pm}")
|
|
274
|
+
return cred, f"{cur.ticker} на {pm} по номеру: {cred.repr()}"
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def fmt_sec(sec: int):
|
|
278
|
+
days = sec // (24 * 3600)
|
|
279
|
+
sec %= 24 * 3600
|
|
280
|
+
hours = sec // 3600
|
|
281
|
+
sec %= 3600
|
|
282
|
+
minutes = sec // 60
|
|
283
|
+
sec %= 60
|
|
284
|
+
|
|
285
|
+
if days > 0:
|
|
286
|
+
return f"{days}д {hours:02d}:{minutes:02d}:{sec:02d}"
|
|
287
|
+
elif hours > 0:
|
|
288
|
+
return f"{hours:02d}:{minutes:02d}:{sec:02d}"
|
|
289
|
+
else:
|
|
290
|
+
return f"{minutes:02d}:{sec:02d}"
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
from asyncio import
|
|
2
|
-
from datetime import
|
|
1
|
+
from asyncio import gather
|
|
2
|
+
from datetime import datetime
|
|
3
3
|
|
|
4
4
|
import PGram
|
|
5
5
|
from aiogram import Router, F
|
|
6
6
|
from aiogram.filters import Command
|
|
7
7
|
from aiogram.types import Message, CallbackQuery
|
|
8
8
|
from aiogram.fsm.context import FSMContext
|
|
9
|
-
from xync_bot.routers.pay.dep import fill_creds, fill_actors, dlt, ans
|
|
9
|
+
from xync_bot.routers.pay.dep import fill_creds, fill_actors, dlt, ans, Store
|
|
10
10
|
from xync_schema import models
|
|
11
11
|
|
|
12
|
-
from xync_bot import Store
|
|
13
12
|
from xync_bot.routers.pay import cd, dep, window
|
|
14
13
|
|
|
15
14
|
pay = Router()
|
|
@@ -23,6 +22,7 @@ async def h_start(msg: Message):
|
|
|
23
22
|
await gather(window.type_select(msg), dlt(msg))
|
|
24
23
|
store.perm.user = await models.User.get(username_id=msg.from_user.id)
|
|
25
24
|
store.perm.creds, store.perm.cur_creds = await fill_creds(store.perm.user.person_id)
|
|
25
|
+
store.perm.actors = await fill_actors(store.perm.user.person_id)
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
@pay.callback_query(cd.MoneyType.filter(F.is_fiat))
|
|
@@ -36,9 +36,7 @@ async def h_got_fiat_type(query: CallbackQuery, bot: PGram):
|
|
|
36
36
|
async def h_got_crypto_type(query: CallbackQuery, bot: PGram):
|
|
37
37
|
"""Step 2c: Select coin"""
|
|
38
38
|
bot.store.curr.is_fiat = False
|
|
39
|
-
(
|
|
40
|
-
fill_actors(bot.store.perm.user.person_id), window.coin_select(query.message), ans(query, "Понял, крипта")
|
|
41
|
-
)
|
|
39
|
+
await gather(window.coin_select(query.message), ans(query, "Понял, крипта"))
|
|
42
40
|
|
|
43
41
|
|
|
44
42
|
@pay.callback_query(cd.Coin.filter())
|
|
@@ -91,7 +89,8 @@ async def h_got_cred_name(msg: Message, state: FSMContext):
|
|
|
91
89
|
person_id=store.perm.user.person_id,
|
|
92
90
|
pmcur_id=store.pay.t_pmcur_id,
|
|
93
91
|
)
|
|
94
|
-
|
|
92
|
+
store.pay.cred_id = cred.id
|
|
93
|
+
store.perm.creds[cred.id] = cred
|
|
95
94
|
await gather(window.amount(msg), dlt(msg), state.set_state(dep.PaymentState.amount))
|
|
96
95
|
|
|
97
96
|
|
|
@@ -101,11 +100,15 @@ async def h_got_ex(query: CallbackQuery, callback_data: cd.Ex, state: FSMContext
|
|
|
101
100
|
store: Store = query.message.bot.store
|
|
102
101
|
ist = store.curr.is_target
|
|
103
102
|
setattr(store.pay, ("t" if ist else "s") + "_ex_id", callback_data.id)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
103
|
+
if ist:
|
|
104
|
+
await window.amount(query.message)
|
|
105
|
+
actor_id = store.perm.actors[store.pay.t_ex_id]
|
|
106
|
+
addr = await models.Addr.get(coin_id=store.pay.t_coin_id, actor_id=actor_id)
|
|
107
|
+
store.pay.addr_id = addr.id
|
|
108
|
+
else:
|
|
109
|
+
await window.set_ppo(query.message)
|
|
110
|
+
await ans(query, f"Биржа {store.glob.exs[callback_data.id]} выбрана")
|
|
111
|
+
await state.set_state(dep.PaymentState.amount)
|
|
109
112
|
|
|
110
113
|
|
|
111
114
|
@pay.message(dep.PaymentState.amount)
|
|
@@ -129,7 +132,7 @@ async def h_got_source_pm(query: CallbackQuery, callback_data: cd.Pm):
|
|
|
129
132
|
store.pay.s_pmcur_id = callback_data.pmcur_id
|
|
130
133
|
await gather(
|
|
131
134
|
window.set_ppo(query.message),
|
|
132
|
-
ans(query, store.glob.
|
|
135
|
+
ans(query, store.glob.pmcurs[callback_data.pmcur_id]),
|
|
133
136
|
)
|
|
134
137
|
|
|
135
138
|
|
|
@@ -140,39 +143,10 @@ async def h_got_ppo(query: CallbackQuery, callback_data: cd.Ppo):
|
|
|
140
143
|
|
|
141
144
|
|
|
142
145
|
@pay.callback_query(cd.Time.filter())
|
|
143
|
-
async def
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if ex_id := (store.pay.t_ex_id or store.pay.s_ex_id):
|
|
149
|
-
actor_id = store.perm.ex_actors[ex_id]
|
|
150
|
-
if not (addr_id := store.pay.addr_id):
|
|
151
|
-
coin_id = store.pay.t_coin_id or store.pay.s_coin_id
|
|
152
|
-
addr_id = await models.Addr.get(coin_id=coin_id, actor_id=actor_id).values_list("id", flat=True)
|
|
153
|
-
store.pay.addr_id = addr_id
|
|
154
|
-
else:
|
|
155
|
-
addr_id = None
|
|
156
|
-
pr_data = dict(
|
|
157
|
-
pay_until=pay_until,
|
|
158
|
-
amount=store.pay.amount,
|
|
159
|
-
parts=store.pay.ppo,
|
|
160
|
-
payed_at=None,
|
|
161
|
-
addr_id=addr_id,
|
|
162
|
-
cred_id=store.pay.cred_id,
|
|
163
|
-
user=store.perm.user,
|
|
164
|
-
)
|
|
165
|
-
(pay_req, _), *__ = await gather(
|
|
166
|
-
models.PayReq.update_or_create(**pr_data), ans(query, None), state.set_state(dep.PaymentState.timer)
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
await state.update_data(
|
|
170
|
-
timer=callback_data.minutes,
|
|
171
|
-
timer_active=True,
|
|
172
|
-
pay_until=pay_until,
|
|
173
|
-
pay_req_id=pay_req.id,
|
|
174
|
-
)
|
|
175
|
-
create_task(window.run_timer(query.message, state))
|
|
146
|
+
async def h_got_urgency(query: CallbackQuery, callback_data: cd.Time):
|
|
147
|
+
query.message.bot.store.pay.urg = callback_data.minutes
|
|
148
|
+
await window.create_payreq(query.message)
|
|
149
|
+
await ans(query, f"Ok {callback_data.minutes} min.")
|
|
176
150
|
|
|
177
151
|
|
|
178
152
|
# ACTIONS
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
from asyncio import sleep
|
|
2
|
+
from datetime import datetime, timedelta
|
|
2
3
|
|
|
3
4
|
from aiogram.fsm.context import FSMContext
|
|
4
5
|
from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton
|
|
5
6
|
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
|
6
|
-
from
|
|
7
|
+
from xync_schema import models
|
|
8
|
+
|
|
9
|
+
from xync_bot.routers.pay.dep import (
|
|
10
|
+
edt,
|
|
11
|
+
need_ppo,
|
|
12
|
+
Store,
|
|
13
|
+
get_merch_target,
|
|
14
|
+
fmt_sec,
|
|
15
|
+
client_have_coin_amount,
|
|
16
|
+
client_target_repr,
|
|
17
|
+
)
|
|
7
18
|
|
|
8
|
-
from xync_bot import Store
|
|
9
19
|
from xync_bot.routers.pay import cd, dep
|
|
10
20
|
|
|
11
21
|
|
|
@@ -25,7 +35,16 @@ async def type_select(msg: Message):
|
|
|
25
35
|
]
|
|
26
36
|
]
|
|
27
37
|
)
|
|
28
|
-
|
|
38
|
+
if store.curr.is_target:
|
|
39
|
+
txt = "Что нужно?"
|
|
40
|
+
else:
|
|
41
|
+
if store.pay.t_coin_id:
|
|
42
|
+
inf = f"{store.glob.coins[store.pay.t_coin_id]} на {store.glob.exs[store.pay.t_ex_id]}:{store.pay.addr_id}"
|
|
43
|
+
else:
|
|
44
|
+
cur = store.glob.curs[store.pay.t_cur_id].ticker
|
|
45
|
+
cred: models.Cred = store.perm.creds[store.pay.cred_id]
|
|
46
|
+
inf = f"{cur} на {store.glob.pmcurs[store.pay.t_pmcur_id]}: {cred.repr()}"
|
|
47
|
+
txt = f"Нужен платеж: {store.pay.amount} {inf}\nЧем будете платить?"
|
|
29
48
|
if store.perm.msg_id:
|
|
30
49
|
await edt(msg, txt, rm)
|
|
31
50
|
else:
|
|
@@ -37,8 +56,8 @@ async def cur_select(msg: Message):
|
|
|
37
56
|
"""Common using cur func"""
|
|
38
57
|
builder = InlineKeyboardBuilder()
|
|
39
58
|
ist: bool = msg.bot.store.curr.is_target
|
|
40
|
-
for cur_id,
|
|
41
|
-
builder.button(text=ticker + dep.flags[ticker], callback_data=cd.Cur(id=cur_id, is_target=ist))
|
|
59
|
+
for cur_id, cur in msg.bot.store.glob.curs.items():
|
|
60
|
+
builder.button(text=cur.ticker + dep.flags[cur.ticker], callback_data=cd.Cur(id=cur_id, is_target=ist))
|
|
42
61
|
builder.button(text="Назад к выбору типа", callback_data=cd.PayNav(to=cd.PayStep.t_type))
|
|
43
62
|
builder.adjust(3, 3, 3, 3, 3, 1)
|
|
44
63
|
sfx = "ую нужно" if ist else "ой платишь"
|
|
@@ -82,7 +101,7 @@ async def pm(msg: Message):
|
|
|
82
101
|
cur_id = getattr(store.pay, ("t" if ist else "s") + "_cur_id")
|
|
83
102
|
builder = InlineKeyboardBuilder()
|
|
84
103
|
for pmcur_id in store.glob.curpms[cur_id]:
|
|
85
|
-
builder.button(text=store.glob.
|
|
104
|
+
builder.button(text=store.glob.pmcurs[pmcur_id], callback_data=cd.Pm(pmcur_id=pmcur_id, is_target=ist))
|
|
86
105
|
builder.button(
|
|
87
106
|
text="Назад к выбору валюты", callback_data=cd.PayNav(to=cd.PayStep.t_cur if ist else cd.PayStep.s_cur)
|
|
88
107
|
)
|
|
@@ -99,10 +118,7 @@ async def fill_cred_dtl(msg: Message):
|
|
|
99
118
|
if cred_ids := store.perm.cur_creds.get(store.pay.t_pmcur_id):
|
|
100
119
|
for cred_id in cred_ids:
|
|
101
120
|
cred = store.perm.creds[cred_id]
|
|
102
|
-
|
|
103
|
-
if cred.extra:
|
|
104
|
-
txt += f" ({cred.extra})"
|
|
105
|
-
builder.button(text=txt, callback_data=cd.Cred(id=cred_id))
|
|
121
|
+
builder.button(text=cred.repr(), callback_data=cd.Cred(id=cred_id))
|
|
106
122
|
txt = "Выберите реквизиты куда нужно получить деньги, если в списке нет нужных, то\nв"
|
|
107
123
|
|
|
108
124
|
builder.button(text="Назад к выбору платежной системы", callback_data=cd.PayNav(to=cd.PayStep.t_pm))
|
|
@@ -110,7 +126,7 @@ async def fill_cred_dtl(msg: Message):
|
|
|
110
126
|
builder.adjust(2)
|
|
111
127
|
|
|
112
128
|
await msg.edit_text(
|
|
113
|
-
f"{txt}ведите номер для {store.glob.
|
|
129
|
+
f"{txt}ведите номер для {store.glob.pmcurs[store.pay.t_pmcur_id]}:", reply_markup=builder.as_markup()
|
|
114
130
|
)
|
|
115
131
|
|
|
116
132
|
|
|
@@ -121,9 +137,9 @@ async def fill_cred_name(msg: Message):
|
|
|
121
137
|
builder.adjust(2)
|
|
122
138
|
store: Store = msg.bot.store
|
|
123
139
|
cur = store.glob.curs[store.pay.t_cur_id]
|
|
124
|
-
payment = store.glob.
|
|
140
|
+
payment = store.glob.pmcurs[store.pay.t_pmcur_id]
|
|
125
141
|
detail = store.pay.cred_dtl
|
|
126
|
-
await edt(msg, f"{cur}:{payment}:{detail}: Введите имя получателя", builder.as_markup())
|
|
142
|
+
await edt(msg, f"{cur.ticker}:{payment}:{detail}: Введите имя получателя", builder.as_markup())
|
|
127
143
|
|
|
128
144
|
|
|
129
145
|
async def amount(msg: Message):
|
|
@@ -131,9 +147,9 @@ async def amount(msg: Message):
|
|
|
131
147
|
builder = InlineKeyboardBuilder()
|
|
132
148
|
store: Store = msg.bot.store
|
|
133
149
|
if store.curr.is_fiat:
|
|
134
|
-
cur_coin = store.glob.curs[store.pay.t_cur_id]
|
|
150
|
+
cur_coin = store.glob.curs[store.pay.t_cur_id].ticker
|
|
135
151
|
builder.button(text="Назад к вводу имени", callback_data=cd.PayNav(to=cd.PayStep.t_cred_name))
|
|
136
|
-
t_name = store.glob.
|
|
152
|
+
t_name = store.glob.pmcurs[store.pay.t_pmcur_id]
|
|
137
153
|
else:
|
|
138
154
|
cur_coin = store.glob.coins[store.pay.t_coin_id]
|
|
139
155
|
builder.button(text="Назад к выбору биржи", callback_data=cd.PayNav(to=cd.PayStep.t_ex))
|
|
@@ -146,55 +162,76 @@ async def amount(msg: Message):
|
|
|
146
162
|
|
|
147
163
|
|
|
148
164
|
async def set_ppo(msg: Message):
|
|
165
|
+
store: Store = msg.bot.store
|
|
166
|
+
ist = store.curr.is_target
|
|
167
|
+
if nppo := await need_ppo(store):
|
|
168
|
+
builder = InlineKeyboardBuilder()
|
|
169
|
+
builder.button(text="Нет", callback_data=cd.Ppo(num=1, is_target=ist)).button(
|
|
170
|
+
text="Да", callback_data=cd.Ppo(num=2, is_target=ist)
|
|
171
|
+
)
|
|
172
|
+
if nppo > 1:
|
|
173
|
+
builder.button(text="Да хоть 3мя", callback_data=cd.Ppo(num=3, is_target=ist))
|
|
174
|
+
builder.adjust(2)
|
|
175
|
+
await edt(msg, f"2мя платежами сможете {'принять' if ist else 'отравить'}?", builder.as_markup())
|
|
176
|
+
elif ist:
|
|
177
|
+
store.curr.is_target = False
|
|
178
|
+
await type_select(msg)
|
|
179
|
+
else:
|
|
180
|
+
await set_urgency(msg)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
async def set_urgency(msg: Message):
|
|
184
|
+
store: Store = msg.bot.store
|
|
185
|
+
if not store.curr.is_fiat or await client_have_coin_amount(store):
|
|
186
|
+
return await create_payreq(msg) # next
|
|
187
|
+
builder = InlineKeyboardBuilder()
|
|
188
|
+
(
|
|
189
|
+
builder.button(text="1 мин", callback_data=cd.Time(minutes=1))
|
|
190
|
+
.button(text="5 мин", callback_data=cd.Time(minutes=5))
|
|
191
|
+
.button(text="30 мин", callback_data=cd.Time(minutes=30))
|
|
192
|
+
.button(text="3 часа", callback_data=cd.Time(minutes=180))
|
|
193
|
+
.button(text="сутки", callback_data=cd.Time(minutes=60 * 24))
|
|
194
|
+
.button(text="Назад к выбору платежной\nсистемы для отправки", callback_data=cd.PayNav(to=cd.PayStep.s_pm))
|
|
195
|
+
.button(text="Домой", callback_data=cd.PayNav(to=cd.PayStep.t_type))
|
|
196
|
+
.adjust(2, 2, 1, 1, 1)
|
|
197
|
+
)
|
|
198
|
+
return await edt(msg, "Сколько можешь ждать?", builder.as_markup())
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
async def create_payreq(msg: Message):
|
|
202
|
+
store: Store = msg.bot.store
|
|
203
|
+
pay_req, _ = await models.PayReq.update_or_create(
|
|
204
|
+
{"pay_until": datetime.now() + timedelta(minutes=store.pay.urg)},
|
|
205
|
+
amount=store.pay.amount,
|
|
206
|
+
parts=store.pay.ppo,
|
|
207
|
+
addr_id=store.pay.addr_id,
|
|
208
|
+
cred_id=store.pay.cred_id,
|
|
209
|
+
user=store.perm.user,
|
|
210
|
+
)
|
|
211
|
+
store.pay.pr_id = pay_req.id
|
|
212
|
+
inp, txt = await get_merch_target(store)
|
|
213
|
+
ccred, ctxt = await client_target_repr(store)
|
|
214
|
+
txt += f"\nИ получите {store.pay.amount} {ctxt} в течение {fmt_sec(store.pay.urg * 60)}"
|
|
215
|
+
if store.pay.ppo > 1:
|
|
216
|
+
txt += f" максимум {store.pay.ppo} платежами"
|
|
149
217
|
rm = InlineKeyboardMarkup(
|
|
150
218
|
inline_keyboard=[
|
|
151
|
-
[
|
|
152
|
-
InlineKeyboardButton(text="Нет", callback_data="ppo:1"),
|
|
153
|
-
InlineKeyboardButton(text="Да", callback_data="ppo:2"),
|
|
154
|
-
],
|
|
155
|
-
[InlineKeyboardButton(text="Да хоть на 3", callback_data="ppo:3")],
|
|
219
|
+
[InlineKeyboardButton(text="Отправил", callback_data=cd.Action(act=cd.ActionType.sent).pack())],
|
|
156
220
|
]
|
|
157
221
|
)
|
|
158
|
-
await msg
|
|
222
|
+
await edt(msg, f"Отправьте {100500} " + txt, rm) # todo: get rate
|
|
159
223
|
|
|
160
|
-
|
|
161
|
-
async def set_urgency(msg: Message):
|
|
162
|
-
builder = InlineKeyboardBuilder()
|
|
163
|
-
builder.button(text="1 мин", callback_data=cd.Time(minutes=1))
|
|
164
|
-
builder.button(text="5 мин", callback_data=cd.Time(minutes=5))
|
|
165
|
-
builder.button(text="30 мин", callback_data=cd.Time(minutes=30))
|
|
166
|
-
builder.button(text="3 часа", callback_data=cd.Time(minutes=180))
|
|
167
|
-
builder.button(text="сутки", callback_data=cd.Time(minutes=60 * 24))
|
|
168
|
-
builder.button(text="Назад к вводу платежей", callback_data=cd.PayNav(to=cd.PayStep.t_pm))
|
|
169
|
-
builder.button(text="Домой", callback_data=cd.PayNav(to=cd.PayStep.t_type))
|
|
170
|
-
builder.adjust(2, 2, 1, 1, 1)
|
|
171
|
-
await msg.edit_text("Сколько можешь ждать?", reply_markup=builder.as_markup())
|
|
224
|
+
# create_task(window.run_timer(msg))В
|
|
172
225
|
|
|
173
226
|
|
|
174
227
|
async def run_timer(message, state: FSMContext):
|
|
175
228
|
builder = InlineKeyboardBuilder()
|
|
176
229
|
builder.button(text="Платеж получен", callback_data=cd.Action(act=cd.ActionType.received))
|
|
177
230
|
|
|
178
|
-
|
|
179
|
-
seconds = data * 60
|
|
180
|
-
|
|
181
|
-
def format(sec):
|
|
182
|
-
days = sec // (24 * 3600)
|
|
183
|
-
sec %= 24 * 3600
|
|
184
|
-
hours = sec // 3600
|
|
185
|
-
sec %= 3600
|
|
186
|
-
minutes = sec // 60
|
|
187
|
-
sec %= 60
|
|
188
|
-
|
|
189
|
-
if days > 0:
|
|
190
|
-
return f"{days}д {hours:02d}:{minutes:02d}:{sec:02d}"
|
|
191
|
-
elif hours > 0:
|
|
192
|
-
return f"{hours:02d}:{minutes:02d}:{sec:02d}"
|
|
193
|
-
else:
|
|
194
|
-
return f"{minutes:02d}:{sec:02d}"
|
|
231
|
+
seconds = await state.get_value("timer") * 60
|
|
195
232
|
|
|
196
233
|
try:
|
|
197
|
-
await message.edit_text(f"⏳ Осталось {
|
|
234
|
+
await message.edit_text(f"⏳ Осталось {fmt_sec(seconds)}", reply_markup=builder.as_markup())
|
|
198
235
|
except Exception:
|
|
199
236
|
return
|
|
200
237
|
|
|
@@ -202,7 +239,7 @@ async def run_timer(message, state: FSMContext):
|
|
|
202
239
|
await sleep(1)
|
|
203
240
|
seconds -= 1
|
|
204
241
|
try:
|
|
205
|
-
await message.edit_text(f"⏳ Осталось {
|
|
242
|
+
await message.edit_text(f"⏳ Осталось {fmt_sec(seconds)}", reply_markup=builder.as_markup())
|
|
206
243
|
await state.update_data(timer=seconds)
|
|
207
244
|
except Exception:
|
|
208
245
|
break
|
|
File without changes
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
from aiogram.types import Message
|
|
2
|
-
from tortoise.functions import Min
|
|
3
|
-
from x_model.func import ArrayAgg
|
|
4
|
-
from xync_schema import models
|
|
5
|
-
|
|
6
|
-
from xync_bot.routers.pay.dep import flags
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class SingleStore(type):
|
|
10
|
-
_store = None
|
|
11
|
-
|
|
12
|
-
async def __call__(cls):
|
|
13
|
-
if not cls._store:
|
|
14
|
-
cls._store = super(SingleStore, cls).__call__()
|
|
15
|
-
cls._store.coins = {k: v for k, v in await models.Coin.all().order_by("ticker").values_list("id", "ticker")}
|
|
16
|
-
curs = {
|
|
17
|
-
k: v
|
|
18
|
-
for k, v in await models.Cur.filter(ticker__in=flags.keys())
|
|
19
|
-
.order_by("ticker")
|
|
20
|
-
.values_list("id", "ticker")
|
|
21
|
-
}
|
|
22
|
-
cls._store.curs = curs
|
|
23
|
-
cls._store.exs = {k: v for k, v in await models.Ex.all().values_list("id", "name")}
|
|
24
|
-
cls._store.pms = {
|
|
25
|
-
k: v
|
|
26
|
-
for k, v in await models.Pmex.filter(pm__pmcurs__cur_id__in=cls._store.curs.keys())
|
|
27
|
-
.annotate(sname=Min("name"))
|
|
28
|
-
.group_by("pm__pmcurs__id")
|
|
29
|
-
.values_list("pm__pmcurs__id", "sname")
|
|
30
|
-
}
|
|
31
|
-
cls._store.coinexs = {
|
|
32
|
-
c.id: [ex.ex_id for ex in c.coinexs] for c in await models.Coin.all().prefetch_related("coinexs")
|
|
33
|
-
}
|
|
34
|
-
cls._store.curpms = {
|
|
35
|
-
cur_id: ids
|
|
36
|
-
for cur_id, ids in await models.Pmcur.filter(cur_id__in=curs.keys())
|
|
37
|
-
.annotate(ids=ArrayAgg("id"))
|
|
38
|
-
.group_by("cur_id")
|
|
39
|
-
.values_list("cur_id", "ids")
|
|
40
|
-
}
|
|
41
|
-
cls._store.curpms = {
|
|
42
|
-
cur_id: ids
|
|
43
|
-
for cur_id, ids in await models.Pmcur.filter(cur_id__in=curs.keys())
|
|
44
|
-
.annotate(ids=ArrayAgg("id"))
|
|
45
|
-
.group_by("cur_id")
|
|
46
|
-
.values_list("cur_id", "ids")
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return cls._store
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class Store:
|
|
53
|
-
class Global(metaclass=SingleStore):
|
|
54
|
-
coins: dict[int, str] # id:ticker
|
|
55
|
-
curs: dict[int, str] # id:ticker
|
|
56
|
-
exs: dict[int, str] # id:name
|
|
57
|
-
coinexs: dict[int, list[int]] # id:[ex_ids]
|
|
58
|
-
pms: dict[int, str] # pmcur_id:name
|
|
59
|
-
curpms: dict[int, list[int]] # id:[pmcur_ids]
|
|
60
|
-
|
|
61
|
-
class Permanent:
|
|
62
|
-
msg_id: int = None
|
|
63
|
-
user: models.User = None
|
|
64
|
-
actors: dict[int, models.Actor] = None # key=actor_id
|
|
65
|
-
ex_actors: dict[int, list[int]] = None # key=ex_id
|
|
66
|
-
creds: dict[int, models.Cred] = None # key=cred_id
|
|
67
|
-
cur_creds: dict[int, list[int]] = None # pmcur_id:[cred_ids]
|
|
68
|
-
|
|
69
|
-
class Current:
|
|
70
|
-
is_target: bool = True
|
|
71
|
-
is_fiat: bool = None
|
|
72
|
-
msg_to_del: Message = None
|
|
73
|
-
|
|
74
|
-
class Payment:
|
|
75
|
-
t_cur_id: int = None
|
|
76
|
-
s_cur_id: int = None
|
|
77
|
-
t_coin_id: int = None
|
|
78
|
-
s_coin_id: int = None
|
|
79
|
-
t_pmcur_id: int = None
|
|
80
|
-
s_pmcur_id: int = None
|
|
81
|
-
t_ex_id: int = None
|
|
82
|
-
s_ex_id: int = None
|
|
83
|
-
amount: int | float = None
|
|
84
|
-
ppo: int = None
|
|
85
|
-
addr_id: int = None
|
|
86
|
-
cred_dtl: str = None
|
|
87
|
-
cred_id: int = None
|
|
88
|
-
|
|
89
|
-
class Payreq:
|
|
90
|
-
id: int = None
|
|
91
|
-
created_at: int = None
|
|
92
|
-
payed_at: int = None
|
|
93
|
-
|
|
94
|
-
glob: Global
|
|
95
|
-
perm: Permanent = Permanent()
|
|
96
|
-
pay: Payment = Payment()
|
|
97
|
-
pr: Payreq = Payreq()
|
|
98
|
-
curr: Current = Current()
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
from asyncio import gather
|
|
2
|
-
from enum import IntEnum
|
|
3
|
-
|
|
4
|
-
from aiogram.exceptions import TelegramBadRequest
|
|
5
|
-
from aiogram.fsm.state import StatesGroup, State
|
|
6
|
-
from aiogram.types import Message, InlineKeyboardMarkup
|
|
7
|
-
from pyrogram.types import CallbackQuery
|
|
8
|
-
from x_model.func import ArrayAgg
|
|
9
|
-
from xync_schema import models
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class Report(StatesGroup):
|
|
13
|
-
text = State()
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class CredState(StatesGroup):
|
|
17
|
-
detail = State()
|
|
18
|
-
name = State()
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class PaymentState(StatesGroup):
|
|
22
|
-
amount = State()
|
|
23
|
-
timer = State()
|
|
24
|
-
timer_active = State()
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class ActionType(IntEnum):
|
|
28
|
-
"""Цель (назначение) платежа (target)"""
|
|
29
|
-
|
|
30
|
-
sent = 1 # Отправил
|
|
31
|
-
received = 2 # Получил
|
|
32
|
-
not_received = 3 # Не получил
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class PayStep(IntEnum):
|
|
36
|
-
"""Цель (назначение) платежа (target)"""
|
|
37
|
-
|
|
38
|
-
t_type = 1 # Выбор типа
|
|
39
|
-
t_cur = 2 # Выбор валюты
|
|
40
|
-
t_coin = 3 # Выбор монеты
|
|
41
|
-
t_pm = 4 # Выбор платежки
|
|
42
|
-
t_ex = 5 # Выбор биржи
|
|
43
|
-
t_cred_dtl = 6 # Ввод номера карты
|
|
44
|
-
t_cred_name = 7 # Ввод имени
|
|
45
|
-
# t_addr = 8 # todo: позже добавим: Выбор/ввод крипто кошелька
|
|
46
|
-
t_amount = 9 # Ввод суммы
|
|
47
|
-
""" Источник платежа (source) """
|
|
48
|
-
s_type = 10 # Выбор типа
|
|
49
|
-
s_cur = 11 # Выбор типа
|
|
50
|
-
s_pm = 12 # Выбор типа
|
|
51
|
-
s_coin = 13 # Выбор типа
|
|
52
|
-
s_ex = 14 # Выбор типа
|
|
53
|
-
ppo = 15 # Выбор возможности разбивки платежа
|
|
54
|
-
urgency = 16 # Выбор срочности получения платежа
|
|
55
|
-
pending_send = 17 # Ожидание отправки (если мы платим фиатом)
|
|
56
|
-
pending_confirm = 18 # Ожидание пока на той стороне подтвердят получение нашего фиата (если мы платим фиатом)
|
|
57
|
-
pending_receive = 19 # Ожидание поступления (если мы получаем фиат)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
flags = {
|
|
61
|
-
"RUB": "🇷🇺",
|
|
62
|
-
"THB": "🇹🇭",
|
|
63
|
-
"IDR": "🇮🇩",
|
|
64
|
-
"TRY": "🇹🇷",
|
|
65
|
-
"GEL": "🇬🇪",
|
|
66
|
-
"VND": "🇻🇳",
|
|
67
|
-
"AED": "🇦🇪",
|
|
68
|
-
"AMD": "🇦🇲",
|
|
69
|
-
"AZN": "🇦🇿",
|
|
70
|
-
"CNY": "🇨🇳",
|
|
71
|
-
"EUR": "🇪🇺",
|
|
72
|
-
"HKD": "🇭🇰",
|
|
73
|
-
"INR": "🇮🇳",
|
|
74
|
-
"PHP": "🇵🇭",
|
|
75
|
-
"USD": "🇺🇸",
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
async def fill_creds(person_id: int) -> tuple[dict[int, models.Cred], dict[int, list[int]]]:
|
|
80
|
-
cq = models.Cred.filter(person_id=person_id)
|
|
81
|
-
creds = {c.id: c for c in await cq}
|
|
82
|
-
cur_creds = {
|
|
83
|
-
pci: ids
|
|
84
|
-
for pci, ids in await cq.annotate(ids=ArrayAgg("id")).group_by("pmcur_id").values_list("pmcur_id", "ids")
|
|
85
|
-
}
|
|
86
|
-
return creds, cur_creds
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
async def fill_actors(person_id: int) -> tuple[dict[int, models.Actor], dict[int, list[int]]]:
|
|
90
|
-
aq = models.Actor.filter(person_id=person_id)
|
|
91
|
-
actors = {a.id: a for a in await aq}
|
|
92
|
-
ex_act_id = {
|
|
93
|
-
exi: ids[0]
|
|
94
|
-
for exi, ids in await aq.annotate(ids=ArrayAgg("id")) # todo: check len(ids) == 1
|
|
95
|
-
.group_by("ex_id")
|
|
96
|
-
.values_list("ex_id", "ids")
|
|
97
|
-
}
|
|
98
|
-
return actors, ex_act_id
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
async def edit(msg: Message, txt: str, rm: InlineKeyboardMarkup):
|
|
102
|
-
await gather(msg.edit_text(txt), msg.edit_reply_markup(reply_markup=rm))
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
async def ans(cbq: CallbackQuery, txt: str = None):
|
|
106
|
-
await cbq.answer(txt, cache_time=0)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
async def dlt(msg: Message):
|
|
110
|
-
await msg.delete()
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
async def edt(msg: Message, txt: str, rm: InlineKeyboardMarkup):
|
|
114
|
-
if msg.message_id == msg.bot.store.perm.msg_id:
|
|
115
|
-
await msg.edit_text(txt, reply_markup=rm)
|
|
116
|
-
else: # окно вызвано в ответ на текст, а не кнопку
|
|
117
|
-
try:
|
|
118
|
-
await msg.bot.edit_message_text(
|
|
119
|
-
txt, chat_id=msg.chat.id, message_id=msg.bot.store.perm.msg_id, reply_markup=rm
|
|
120
|
-
)
|
|
121
|
-
except TelegramBadRequest as e:
|
|
122
|
-
print(msg.bot.store.perm.msg_id, e)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/xync_bot-0.3.24.dev9/xync_bot/typs.py → /xync_bot-0.3.24.dev12/xync_bot/routers/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|