xync-bot 0.3.24.dev12__py3-none-any.whl → 0.3.26__py3-none-any.whl
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/__main__.py +37 -0
- xync_bot/routers/__init__.py +41 -0
- xync_bot/routers/cond/__init__.py +1 -7
- xync_bot/routers/main/__init__.py +0 -0
- xync_bot/routers/{main.py → main/handler.py} +28 -60
- xync_bot/routers/pay/dep.py +0 -171
- xync_bot/routers/pay/handler.py +108 -105
- xync_bot/routers/pay/window.py +38 -52
- xync_bot/routers/send/__init__.py +117 -0
- xync_bot/shared.py +19 -0
- xync_bot/store.py +151 -0
- {xync_bot-0.3.24.dev12.dist-info → xync_bot-0.3.26.dist-info}/METADATA +1 -1
- xync_bot-0.3.26.dist-info/RECORD +23 -0
- xync_bot/__init__.py +0 -26
- xync_bot-0.3.24.dev12.dist-info/RECORD +0 -20
- {xync_bot-0.3.24.dev12.dist-info → xync_bot-0.3.26.dist-info}/WHEEL +0 -0
- {xync_bot-0.3.24.dev12.dist-info → xync_bot-0.3.26.dist-info}/top_level.txt +0 -0
xync_bot/__main__.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from asyncio import run
|
|
3
|
+
|
|
4
|
+
from PGram import Bot
|
|
5
|
+
from aiogram.client.default import DefaultBotProperties
|
|
6
|
+
from aiogram.enums import UpdateType
|
|
7
|
+
from x_model import init_db
|
|
8
|
+
|
|
9
|
+
from xync_bot.store import Store
|
|
10
|
+
from xync_bot.routers.main.handler import mr
|
|
11
|
+
from xync_bot.routers.cond import cr
|
|
12
|
+
from xync_bot.routers.pay.handler import pr
|
|
13
|
+
from xync_bot.routers import last
|
|
14
|
+
from xync_bot.routers.send import sd
|
|
15
|
+
|
|
16
|
+
au = [
|
|
17
|
+
UpdateType.MESSAGE,
|
|
18
|
+
UpdateType.CALLBACK_QUERY,
|
|
19
|
+
UpdateType.CHAT_MEMBER,
|
|
20
|
+
UpdateType.MY_CHAT_MEMBER,
|
|
21
|
+
] # , UpdateType.CHAT_JOIN_REQUEST
|
|
22
|
+
bot = Bot([sd, cr, pr, mr, last], Store(), au, default=DefaultBotProperties(parse_mode="HTML"))
|
|
23
|
+
|
|
24
|
+
if __name__ == "__main__":
|
|
25
|
+
from xync_bot.loader import TOKEN, TORM
|
|
26
|
+
|
|
27
|
+
logging.basicConfig(level=logging.INFO)
|
|
28
|
+
|
|
29
|
+
async def main() -> None:
|
|
30
|
+
cn = await init_db(TORM)
|
|
31
|
+
bot.dp.workflow_data["store"].glob = await Store.Global() # todo: refact store loading
|
|
32
|
+
await bot.start(
|
|
33
|
+
TOKEN,
|
|
34
|
+
cn,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
run(main())
|
xync_bot/routers/__init__.py
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from aiogram import Router, F
|
|
4
|
+
from aiogram.enums import ContentType
|
|
5
|
+
from aiogram.exceptions import TelegramBadRequest
|
|
6
|
+
from aiogram.types import Message
|
|
7
|
+
|
|
8
|
+
last = Router(name="last")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@last.message(
|
|
12
|
+
F.content_type.not_in(
|
|
13
|
+
{
|
|
14
|
+
ContentType.NEW_CHAT_MEMBERS,
|
|
15
|
+
# ContentType.LEFT_CHAT_MEMBER,
|
|
16
|
+
# ContentType.SUPERGROUP_CHAT_CREATED,
|
|
17
|
+
# ContentType.NEW_CHAT_PHOTO,
|
|
18
|
+
# ContentType.FORUM_TOPIC_CREATED,
|
|
19
|
+
# ContentType.FORUM_TOPIC_EDITED,
|
|
20
|
+
ContentType.FORUM_TOPIC_CLOSED,
|
|
21
|
+
# ContentType.GENERAL_FORUM_TOPIC_HIDDEN, # deletable
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
async def del_cbq(msg: Message):
|
|
26
|
+
try:
|
|
27
|
+
await msg.delete()
|
|
28
|
+
logging.info({"DELETED": msg.model_dump(exclude_none=True)})
|
|
29
|
+
except TelegramBadRequest:
|
|
30
|
+
logging.error({"NOT_DELETED": msg.model_dump(exclude_none=True)})
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@last.message()
|
|
34
|
+
async def all_rest(msg: Message):
|
|
35
|
+
logging.warning(
|
|
36
|
+
{
|
|
37
|
+
"NO_HANDLED": msg.model_dump(
|
|
38
|
+
exclude_none=True,
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
)
|
|
@@ -8,7 +8,7 @@ from xync_schema.enums import SynonymType
|
|
|
8
8
|
|
|
9
9
|
from xync_bot.routers.cond.func import wrap_cond, get_val, btns, rkm, ikm, SynTypeCd, CondCd
|
|
10
10
|
|
|
11
|
-
cr = Router()
|
|
11
|
+
cr = Router(name="cond")
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
@cr.message(Command("cond"))
|
|
@@ -89,9 +89,3 @@ async def got_action(cbq: CallbackQuery, callback_data: CondCd, state: FSMContex
|
|
|
89
89
|
await (await state.get_value("cmsg")).delete()
|
|
90
90
|
await show_cond(cbq.message, cond)
|
|
91
91
|
return await cbq.answer(callback_data.act)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
@cr.message()
|
|
95
|
-
async def unknown(msg: Message):
|
|
96
|
-
# user = await User.get(username_id=msg.from_user.id)
|
|
97
|
-
await msg.delete()
|
|
File without changes
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
3
|
from aiogram import Router, F
|
|
4
|
-
from aiogram.enums import ContentType
|
|
5
|
-
from aiogram.exceptions import TelegramBadRequest
|
|
6
4
|
from aiogram.filters import CommandStart, CommandObject, ChatMemberUpdatedFilter, JOIN_TRANSITION, LEAVE_TRANSITION
|
|
7
5
|
from aiogram.filters.callback_data import CallbackData
|
|
8
6
|
from aiogram.types import (
|
|
@@ -18,8 +16,9 @@ from aiogram.utils.deep_linking import create_start_link
|
|
|
18
16
|
from xync_schema import models
|
|
19
17
|
|
|
20
18
|
from xync_bot.shared import NavCallbackData
|
|
19
|
+
from xync_bot.store import Store
|
|
21
20
|
|
|
22
|
-
mr = Router()
|
|
21
|
+
mr = Router(name="main")
|
|
23
22
|
|
|
24
23
|
|
|
25
24
|
class RrCallbackData(CallbackData, prefix="reg_res"): # registration response
|
|
@@ -30,6 +29,7 @@ class RrCallbackData(CallbackData, prefix="reg_res"): # registration response
|
|
|
30
29
|
home_btns = InlineKeyboardMarkup(
|
|
31
30
|
inline_keyboard=[
|
|
32
31
|
[
|
|
32
|
+
InlineKeyboardButton(text="Transfer", callback_data=NavCallbackData(to="transfer").pack()),
|
|
33
33
|
InlineKeyboardButton(text="Invite", callback_data=NavCallbackData(to="ref_link").pack()),
|
|
34
34
|
InlineKeyboardButton(text="Get VPN", callback_data=NavCallbackData(to="get_vpn").pack()),
|
|
35
35
|
]
|
|
@@ -41,7 +41,7 @@ home_btns = InlineKeyboardMarkup(
|
|
|
41
41
|
async def start_handler(msg: Message, command: CommandObject):
|
|
42
42
|
me: User = msg.from_user
|
|
43
43
|
ref_id: int = command.args.isnumeric() and int(command.args)
|
|
44
|
-
user = await models.User.
|
|
44
|
+
user = await models.User.get(username_id=me.id, blocked=False)
|
|
45
45
|
rm = None
|
|
46
46
|
logging.info(msg, {"src": "start"})
|
|
47
47
|
if user:
|
|
@@ -66,6 +66,27 @@ async def start_handler(msg: Message, command: CommandObject):
|
|
|
66
66
|
return await msg.answer(rs, reply_markup=rm)
|
|
67
67
|
|
|
68
68
|
|
|
69
|
+
@mr.message(CommandStart(deep_link=True)) # attempt to reg by fake link
|
|
70
|
+
async def fraud_handler(msg: Message):
|
|
71
|
+
logging.warning(f"Start: {msg.from_user.id}. Msg: {msg}")
|
|
72
|
+
# todo: alert to admins! Fraud attempt!
|
|
73
|
+
await msg.answer("🤔")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@mr.message(CommandStart()) # обычный /start
|
|
77
|
+
async def home(msg: Message, store: Store):
|
|
78
|
+
me = msg.from_user
|
|
79
|
+
user, is_new = await models.User.tg_upsert(me, False)
|
|
80
|
+
|
|
81
|
+
rr = "сначала вы должны найти поручителя, и перейти по его реферальной ссылке.\nhttps://telegra.ph/XyncNet-02-13"
|
|
82
|
+
if is_new: # has ref and created now
|
|
83
|
+
await msg.answer(f"Здравствуйте {me.full_name}, что бы использовать возможности нашей сети, {rr}")
|
|
84
|
+
elif not user.ref_id:
|
|
85
|
+
await msg.answer(rr.capitalize())
|
|
86
|
+
else:
|
|
87
|
+
await msg.answer(f"{me.full_name}, не балуйтесь, вы и так уже активный участник👌🏼", reply_markup=home_btns)
|
|
88
|
+
|
|
89
|
+
|
|
69
90
|
@mr.callback_query(RrCallbackData.filter())
|
|
70
91
|
async def phrases_input_request(cb: CallbackQuery, callback_data: RrCallbackData) -> None:
|
|
71
92
|
protege = await models.User[callback_data.to]
|
|
@@ -83,27 +104,7 @@ async def phrases_input_request(cb: CallbackQuery, callback_data: RrCallbackData
|
|
|
83
104
|
await cb.message.edit_text(rs)
|
|
84
105
|
|
|
85
106
|
|
|
86
|
-
@mr.
|
|
87
|
-
async def fraud_handler(msg: Message):
|
|
88
|
-
logging.warning(f"Start: {msg.from_user.id}. Msg: {msg}")
|
|
89
|
-
# todo: alert to admins! Fraud attempt!
|
|
90
|
-
await msg.answer("🤔")
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@mr.message(CommandStart())
|
|
94
|
-
async def start_no_ref_handler(msg: Message):
|
|
95
|
-
me = msg.from_user
|
|
96
|
-
user, cr = await models.User.tg2in(me, False)
|
|
97
|
-
rr = "сначала вы должны найти поручителя, и перейти по его реферальной ссылке.\nhttps://telegra.ph/XyncNet-02-13"
|
|
98
|
-
if cr: # has ref and created now
|
|
99
|
-
await msg.answer(f"Здравствуйте {me.full_name}, что бы использовать возможности нашей сети, {rr}")
|
|
100
|
-
elif not user.ref_id:
|
|
101
|
-
await msg.answer(rr.capitalize())
|
|
102
|
-
else:
|
|
103
|
-
await msg.answer(f"{me.full_name}, не балуйтесь, вы и так уже активный участник👌🏼", reply_markup=home_btns)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
@mr.callback_query(NavCallbackData.filter(F.to == "ref_link"))
|
|
107
|
+
@mr.callback_query(NavCallbackData.filter(F.to.__eq__("ref_link")))
|
|
107
108
|
async def ref_link_handler(cbq: CallbackQuery):
|
|
108
109
|
me = cbq.from_user
|
|
109
110
|
if not (u := await models.User.get_or_none(id=me.id, blocked=False).prefetch_related("ref")):
|
|
@@ -118,7 +119,7 @@ async def ref_link_handler(cbq: CallbackQuery):
|
|
|
118
119
|
await cbq.answer("Wait for your protege request..")
|
|
119
120
|
|
|
120
121
|
|
|
121
|
-
@mr.my_chat_member(F.chat.type == "private") # my_chat_member is fired on
|
|
122
|
+
@mr.my_chat_member(F.chat.type == "private") # my_chat_member is fired on adding bot to any chat. filter for preventing
|
|
122
123
|
async def my_user_set_status(my_chat_member: ChatMemberUpdated):
|
|
123
124
|
logging.info({"my_chat_member": my_chat_member.model_dump(exclude_none=True)})
|
|
124
125
|
u: User = my_chat_member.from_user
|
|
@@ -128,7 +129,7 @@ async def my_user_set_status(my_chat_member: ChatMemberUpdated):
|
|
|
128
129
|
|
|
129
130
|
@mr.my_chat_member()
|
|
130
131
|
async def user_set_status(my_chat_member: ChatMemberUpdated):
|
|
131
|
-
if my_chat_member.new_chat_member.user.username == "XyncNetBot": # удалена
|
|
132
|
+
if my_chat_member.new_chat_member.user.username == "XyncNetBot": # удалена группа, где бот был добавлен админом
|
|
132
133
|
if forum := await models.Forum.get_or_none(id=my_chat_member.chat.id):
|
|
133
134
|
await forum.delete()
|
|
134
135
|
res = f"I {my_chat_member.new_chat_member.status} from {my_chat_member.chat.id}:{my_chat_member.chat.title}"
|
|
@@ -186,36 +187,3 @@ async def order_msg(msg: Message):
|
|
|
186
187
|
await models.Msg.create(tgid=msg.message_id, txt=msg.text, order_id=order.id, receiver=receiver)
|
|
187
188
|
logging.info(msg, {"src": "order_msg"})
|
|
188
189
|
return await msg.send_copy(receiver.forum, message_thread_id=rcv_topic)
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
@mr.message(
|
|
192
|
-
F.content_type.not_in(
|
|
193
|
-
{
|
|
194
|
-
ContentType.NEW_CHAT_MEMBERS,
|
|
195
|
-
# ContentType.LEFT_CHAT_MEMBER,
|
|
196
|
-
# ContentType.SUPERGROUP_CHAT_CREATED,
|
|
197
|
-
# ContentType.NEW_CHAT_PHOTO,
|
|
198
|
-
# ContentType.FORUM_TOPIC_CREATED,
|
|
199
|
-
# ContentType.FORUM_TOPIC_EDITED,
|
|
200
|
-
ContentType.FORUM_TOPIC_CLOSED,
|
|
201
|
-
# ContentType.GENERAL_FORUM_TOPIC_HIDDEN, # deletable
|
|
202
|
-
}
|
|
203
|
-
)
|
|
204
|
-
)
|
|
205
|
-
async def del_cbq(msg: Message):
|
|
206
|
-
try:
|
|
207
|
-
await msg.delete()
|
|
208
|
-
logging.info({"DELETED": msg.model_dump(exclude_none=True)})
|
|
209
|
-
except TelegramBadRequest:
|
|
210
|
-
logging.error({"NOT_DELETED": msg.model_dump(exclude_none=True)})
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
@mr.message()
|
|
214
|
-
async def all_rest(msg: Message):
|
|
215
|
-
logging.warning(
|
|
216
|
-
{
|
|
217
|
-
"NO_HANDLED": msg.model_dump(
|
|
218
|
-
exclude_none=True,
|
|
219
|
-
)
|
|
220
|
-
}
|
|
221
|
-
)
|
xync_bot/routers/pay/dep.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import logging
|
|
2
1
|
from asyncio import gather
|
|
3
2
|
from enum import IntEnum
|
|
4
3
|
|
|
@@ -6,8 +5,6 @@ from aiogram.exceptions import TelegramBadRequest
|
|
|
6
5
|
from aiogram.fsm.state import StatesGroup, State
|
|
7
6
|
from aiogram.types import Message, InlineKeyboardMarkup
|
|
8
7
|
from pyrogram.types import CallbackQuery
|
|
9
|
-
from tortoise.functions import Min
|
|
10
|
-
from x_auth.enums import Role
|
|
11
8
|
from x_model.func import ArrayAgg
|
|
12
9
|
from xync_schema import models
|
|
13
10
|
|
|
@@ -60,107 +57,6 @@ class PayStep(IntEnum):
|
|
|
60
57
|
pending_receive = 19 # Ожидание поступления (если мы получаем фиат)
|
|
61
58
|
|
|
62
59
|
|
|
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
60
|
async def fill_creds(person_id: int) -> tuple[dict[int, models.Cred], dict[int, list[int]]]:
|
|
165
61
|
cq = models.Cred.filter(person_id=person_id)
|
|
166
62
|
creds = {c.id: c for c in await cq}
|
|
@@ -207,73 +103,6 @@ async def edt(msg: Message, txt: str, rm: InlineKeyboardMarkup):
|
|
|
207
103
|
print(msg.bot.store.perm.msg_id, e)
|
|
208
104
|
|
|
209
105
|
|
|
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
106
|
def fmt_sec(sec: int):
|
|
278
107
|
days = sec // (24 * 3600)
|
|
279
108
|
sec %= 24 * 3600
|