xync-client 0.0.155__py3-none-any.whl → 0.0.162__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.
- xync_client/Abc/AdLoader.py +0 -294
- xync_client/Abc/Agent.py +326 -51
- xync_client/Abc/Ex.py +421 -12
- xync_client/Abc/Order.py +7 -14
- xync_client/Abc/xtype.py +35 -3
- xync_client/Bybit/InAgent.py +18 -447
- xync_client/Bybit/agent.py +531 -431
- xync_client/Bybit/etype/__init__.py +0 -0
- xync_client/Bybit/etype/ad.py +47 -34
- xync_client/Bybit/etype/order.py +34 -49
- xync_client/Bybit/ex.py +20 -46
- xync_client/Bybit/order.py +14 -12
- xync_client/Htx/agent.py +82 -40
- xync_client/Htx/etype/ad.py +22 -5
- xync_client/Htx/etype/order.py +194 -0
- xync_client/Htx/ex.py +16 -16
- xync_client/Mexc/agent.py +196 -13
- xync_client/Mexc/api.py +955 -336
- xync_client/Mexc/etype/ad.py +52 -1
- xync_client/Mexc/etype/order.py +131 -416
- xync_client/Mexc/ex.py +29 -19
- xync_client/Okx/1.py +14 -0
- xync_client/Okx/agent.py +39 -0
- xync_client/Okx/ex.py +8 -8
- xync_client/Pms/Payeer/agent.py +396 -0
- xync_client/Pms/Payeer/login.py +1 -63
- xync_client/Pms/Payeer/trade.py +58 -0
- xync_client/Pms/Volet/{__init__.py → agent.py} +1 -2
- xync_client/loader.py +1 -0
- {xync_client-0.0.155.dist-info → xync_client-0.0.162.dist-info}/METADATA +2 -1
- {xync_client-0.0.155.dist-info → xync_client-0.0.162.dist-info}/RECORD +33 -29
- xync_client/Pms/Payeer/__init__.py +0 -262
- xync_client/Pms/Payeer/api.py +0 -25
- {xync_client-0.0.155.dist-info → xync_client-0.0.162.dist-info}/WHEEL +0 -0
- {xync_client-0.0.155.dist-info → xync_client-0.0.162.dist-info}/top_level.txt +0 -0
xync_client/Bybit/InAgent.py
CHANGED
|
@@ -1,465 +1,36 @@
|
|
|
1
|
-
import
|
|
2
|
-
import logging
|
|
3
|
-
import re
|
|
4
|
-
import traceback
|
|
5
|
-
from datetime import datetime, timezone, timedelta
|
|
6
|
-
from uuid import uuid4
|
|
7
|
-
|
|
8
|
-
import websockets
|
|
9
|
-
from asyncio import run, sleep
|
|
10
|
-
from decimal import Decimal
|
|
11
|
-
|
|
1
|
+
from asyncio import create_task
|
|
12
2
|
from bybit_p2p import P2P
|
|
13
|
-
from playwright.async_api import async_playwright
|
|
14
|
-
from pydantic import ValidationError
|
|
15
3
|
from pyro_client.client.file import FileClient
|
|
16
|
-
from tortoise.exceptions import IntegrityError
|
|
17
|
-
from tortoise.timezone import now
|
|
18
|
-
from tortoise.transactions import in_transaction
|
|
19
4
|
from xync_bot import XyncBot
|
|
5
|
+
from xync_schema.models import Agent
|
|
6
|
+
|
|
7
|
+
from xync_client.Bybit.agent import AgentClient
|
|
20
8
|
from xync_client.Bybit.ex import ExClient
|
|
21
9
|
|
|
22
|
-
from xync_client.Abc.PmAgent import PmAgentClient
|
|
23
10
|
from xync_schema import models
|
|
24
|
-
from xync_schema.enums import UserStatus, OrderStatus
|
|
25
11
|
|
|
26
12
|
from xync_client.Bybit.etype.order import (
|
|
27
|
-
|
|
28
|
-
CountDown,
|
|
29
|
-
SellerCancelChange,
|
|
30
|
-
Read,
|
|
31
|
-
Receive,
|
|
32
|
-
OrderFull,
|
|
33
|
-
StatusApi,
|
|
13
|
+
OrderItem,
|
|
34
14
|
)
|
|
35
|
-
from xync_client.loader import NET_TOKEN, PAY_TOKEN
|
|
36
|
-
from xync_client.Abc.InAgent import BaseInAgentClient
|
|
37
15
|
|
|
38
16
|
|
|
39
|
-
class InAgentClient(
|
|
17
|
+
class InAgentClient(AgentClient):
|
|
40
18
|
actor: models.Actor
|
|
41
19
|
agent: models.Agent
|
|
42
20
|
api: P2P
|
|
43
21
|
ex_client: ExClient
|
|
44
|
-
pm_clients: dict[int, PmAgentClient]
|
|
45
|
-
|
|
46
|
-
async def start_listen(self):
|
|
47
|
-
t = await self.ott()
|
|
48
|
-
ts = int(float(t["time_now"]) * 1000)
|
|
49
|
-
await self.ws_prv(self.agent.auth["deviceId"], t["result"], ts)
|
|
50
|
-
|
|
51
|
-
# 3N: [T] - Уведомление об одобрении запроса на сделку
|
|
52
|
-
async def request_accepted_notify(self) -> int: ... # id
|
|
53
|
-
|
|
54
|
-
async def ws_prv(self, did: str, tok: str, ts: int):
|
|
55
|
-
u = f"wss://ws2.bybit.com/private?appid=bybit&os=web&deviceid={did}×tamp={ts}"
|
|
56
|
-
async with websockets.connect(u) as websocket:
|
|
57
|
-
auth_msg = json.dumps({"req_id": did, "op": "login", "args": [tok]})
|
|
58
|
-
await websocket.send(auth_msg)
|
|
59
|
-
|
|
60
|
-
sub_msg = json.dumps({"op": "subscribe", "args": ["FIAT_OTC_TOPIC", "FIAT_OTC_ONLINE_TOPIC"]})
|
|
61
|
-
await websocket.send(sub_msg)
|
|
62
|
-
sub_msg = json.dumps({"op": "input", "args": ["FIAT_OTC_TOPIC", '{"topic":"SUPER_DEAL"}']})
|
|
63
|
-
await websocket.send(sub_msg)
|
|
64
|
-
sub_msg = json.dumps({"op": "input", "args": ["FIAT_OTC_TOPIC", '{"topic":"OTC_ORDER_STATUS"}']})
|
|
65
|
-
await websocket.send(sub_msg)
|
|
66
|
-
sub_msg = json.dumps({"op": "input", "args": ["FIAT_OTC_TOPIC", '{"topic":"WEB_THREE_SELL"}']})
|
|
67
|
-
await websocket.send(sub_msg)
|
|
68
|
-
sub_msg = json.dumps({"op": "input", "args": ["FIAT_OTC_TOPIC", '{"topic":"APPEALED_CHANGE"}']})
|
|
69
|
-
await websocket.send(sub_msg)
|
|
70
|
-
|
|
71
|
-
sub_msg = json.dumps({"op": "subscribe", "args": ["fiat.cashier.order"]})
|
|
72
|
-
await websocket.send(sub_msg)
|
|
73
|
-
sub_msg = json.dumps({"op": "subscribe", "args": ["fiat.cashier.order-eftd-complete-privilege-event"]})
|
|
74
|
-
await websocket.send(sub_msg)
|
|
75
|
-
sub_msg = json.dumps({"op": "subscribe", "args": ["fiat.cashier.order-savings-product-event"]})
|
|
76
|
-
await websocket.send(sub_msg)
|
|
77
|
-
sub_msg = json.dumps({"op": "subscribe", "args": ["fiat.deal-core.order-savings-complete-event"]})
|
|
78
|
-
await websocket.send(sub_msg)
|
|
79
|
-
|
|
80
|
-
sub_msg = json.dumps({"op": "subscribe", "args": ["FIAT_OTC_TOPIC", "FIAT_OTC_ONLINE_TOPIC"]})
|
|
81
|
-
await websocket.send(sub_msg)
|
|
82
|
-
while resp := await websocket.recv():
|
|
83
|
-
if data := json.loads(resp):
|
|
84
|
-
upd, order_db = None, None
|
|
85
|
-
logging.info(f" {now().strftime('%H:%M:%S')} upd: {data.get('topic')}:{data.get('type')}")
|
|
86
|
-
match data.get("topic"):
|
|
87
|
-
case "OTC_ORDER_STATUS":
|
|
88
|
-
match data["type"]:
|
|
89
|
-
case "STATUS_CHANGE":
|
|
90
|
-
try:
|
|
91
|
-
upd = StatusChange.model_validate(data["data"])
|
|
92
|
-
except ValidationError as e:
|
|
93
|
-
logging.error(e)
|
|
94
|
-
logging.error(data["data"])
|
|
95
|
-
order = self.api.get_order_details(orderId=upd.id)
|
|
96
|
-
order = OrderFull.model_validate(order["result"])
|
|
97
|
-
order_db = await models.Order.get_or_none(
|
|
98
|
-
exid=order.id, ad__exid=order.itemId
|
|
99
|
-
) or await self.create_order(order)
|
|
100
|
-
match upd.status:
|
|
101
|
-
case StatusApi.created:
|
|
102
|
-
logging.info(f"Order {order.id} created at {order.createDate}")
|
|
103
|
-
# сразу уменьшаем доступный остаток монеты/валюты
|
|
104
|
-
await self.money_upd(order_db)
|
|
105
|
-
if upd.side: # я покупатель - ждем мою оплату
|
|
106
|
-
_dest = order.paymentTermList[0].accountNo
|
|
107
|
-
if not re.match(r"^([PpРр])\d{7,10}\b", _dest):
|
|
108
|
-
continue
|
|
109
|
-
await order_db.fetch_related("ad__pair_side__pair", "cred__pmcur__cur")
|
|
110
|
-
await self.send_payment(order_db)
|
|
111
|
-
case StatusApi.wait_for_buyer:
|
|
112
|
-
if upd.side == 0: # ждем когда покупатель оплатит
|
|
113
|
-
if not (pmacdx := await self.get_pma_by_cdex(order)):
|
|
114
|
-
continue
|
|
115
|
-
pma, cdx = pmacdx
|
|
116
|
-
am, tid = await pma.check_in(
|
|
117
|
-
Decimal(order.amount),
|
|
118
|
-
cdx.cred.pmcur.cur.ticker,
|
|
119
|
-
# todo: почему в московском час.поясе?
|
|
120
|
-
datetime.fromtimestamp(float(order.transferDate) / 1000),
|
|
121
|
-
)
|
|
122
|
-
if not tid:
|
|
123
|
-
logging.info(
|
|
124
|
-
f"Order {order.id} created at {order.createDate}, not paid yet"
|
|
125
|
-
)
|
|
126
|
-
continue
|
|
127
|
-
try:
|
|
128
|
-
t, is_new = await models.Transfer.update_or_create(
|
|
129
|
-
dict(
|
|
130
|
-
amount=int(float(order.amount) * 100),
|
|
131
|
-
order=order_db,
|
|
132
|
-
),
|
|
133
|
-
pmid=tid,
|
|
134
|
-
)
|
|
135
|
-
except IntegrityError as e:
|
|
136
|
-
logging.error(tid)
|
|
137
|
-
logging.error(order)
|
|
138
|
-
logging.exception(e)
|
|
139
|
-
|
|
140
|
-
if not is_new: # если по этому платежу уже отпущен другая продажа
|
|
141
|
-
continue
|
|
142
|
-
|
|
143
|
-
# если висят незавершенные продажи с такой же суммой
|
|
144
|
-
pos = (await self.get_orders_active(1))["result"]
|
|
145
|
-
pos = [
|
|
146
|
-
o
|
|
147
|
-
for o in pos.get("items", [])
|
|
148
|
-
if (
|
|
149
|
-
o["amount"] == order.amount
|
|
150
|
-
and o["id"] != upd.id
|
|
151
|
-
and int(order.createDate)
|
|
152
|
-
< int(o["createDate"]) + 15 * 60 * 1000
|
|
153
|
-
# get full_order from o, and cred or pm from full_order:
|
|
154
|
-
and self.api.get_order_details(orderId=o["id"])["result"][
|
|
155
|
-
"paymentTermList"
|
|
156
|
-
][0]["accountNo"]
|
|
157
|
-
== order.paymentTermList[0].accountNo
|
|
158
|
-
)
|
|
159
|
-
]
|
|
160
|
-
curex = await models.CurEx.get(
|
|
161
|
-
cur__ticker=order.currencyId, ex=self.ex_client.ex
|
|
162
|
-
)
|
|
163
|
-
pos_db = await models.Order.filter(
|
|
164
|
-
exid__not=order.id,
|
|
165
|
-
cred_id=order_db.cred_id,
|
|
166
|
-
amount=int(float(order.amount) * 10**curex.scale),
|
|
167
|
-
status__not_in=[OrderStatus.completed, OrderStatus.canceled],
|
|
168
|
-
created_at__gt=now() - timedelta(minutes=15),
|
|
169
|
-
)
|
|
170
|
-
if pos or pos_db:
|
|
171
|
-
await self.ex_client.bot.send(
|
|
172
|
-
f"[Duplicate amount!]"
|
|
173
|
-
f"(https://www.bybit.com/ru-RU/p2p/orderList/{order.id})",
|
|
174
|
-
self.actor.person.user.username_id,
|
|
175
|
-
)
|
|
176
|
-
logging.warning("Duplicate amount!")
|
|
177
|
-
continue
|
|
178
|
-
|
|
179
|
-
# !!! ОТПРАВЛЯЕМ ДЕНЬГИ !!!
|
|
180
|
-
self.api.release_assets(orderId=upd.id)
|
|
181
|
-
logging.info(
|
|
182
|
-
f"Order {order.id} created, paid before #{tid}:{am} at {order.createDate}, and RELEASED at {now()}"
|
|
183
|
-
)
|
|
184
|
-
elif upd.side == 1: # я покупатель - ждем мою оплату
|
|
185
|
-
continue # logging.warning(f"Order {order.id} PAID at {now()}: {int_am}")
|
|
186
|
-
else:
|
|
187
|
-
...
|
|
188
|
-
# todo: check is always canceling
|
|
189
|
-
# await order_db.update_from_dict({"status": OrderStatus.canceled}).save()
|
|
190
|
-
# logging.info(f"Order {order.id} canceled at {datetime.now()}")
|
|
191
|
-
|
|
192
|
-
case StatusApi.wait_for_seller:
|
|
193
|
-
if order_db.status == OrderStatus.paid:
|
|
194
|
-
continue
|
|
195
|
-
await order_db.update_from_dict(
|
|
196
|
-
{
|
|
197
|
-
"status": OrderStatus.paid,
|
|
198
|
-
"payed_at": datetime.fromtimestamp(
|
|
199
|
-
float(order.transferDate) / 1000
|
|
200
|
-
),
|
|
201
|
-
}
|
|
202
|
-
).save()
|
|
203
|
-
logging.info(f"Order {order.id} payed at {order_db.payed_at}")
|
|
204
|
-
|
|
205
|
-
case StatusApi.appealed:
|
|
206
|
-
# todo: appealed by WHO? щас наугад стоит by_seller
|
|
207
|
-
await order_db.update_from_dict(
|
|
208
|
-
{
|
|
209
|
-
"status": OrderStatus.appealed_by_seller,
|
|
210
|
-
"appealed_at": datetime.fromtimestamp(
|
|
211
|
-
float(order.updateDate) / 1000
|
|
212
|
-
),
|
|
213
|
-
}
|
|
214
|
-
).save()
|
|
215
|
-
logging.info(f"Order {order.id} appealed at {order_db.appealed_at}")
|
|
216
|
-
|
|
217
|
-
case StatusApi.canceled:
|
|
218
|
-
await order_db.update_from_dict({"status": OrderStatus.canceled}).save()
|
|
219
|
-
logging.info(f"Order {order.id} canceled at {datetime.now()}")
|
|
220
|
-
await self.money_upd(order_db)
|
|
221
|
-
|
|
222
|
-
case StatusApi.completed:
|
|
223
|
-
await order_db.update_from_dict(
|
|
224
|
-
{
|
|
225
|
-
"status": OrderStatus.completed,
|
|
226
|
-
"confirmed_at": datetime.fromtimestamp(
|
|
227
|
-
float(order.updateDate) / 1000
|
|
228
|
-
),
|
|
229
|
-
}
|
|
230
|
-
).save()
|
|
231
|
-
await self.money_upd(order_db)
|
|
232
|
-
|
|
233
|
-
case _:
|
|
234
|
-
logging.warning(f"Order {order.id} UNKNOWN STATUS {datetime.now()}")
|
|
235
|
-
case "COUNT_DOWN":
|
|
236
|
-
upd = CountDown.model_validate(data["data"])
|
|
237
|
-
case _:
|
|
238
|
-
self.listen(data)
|
|
239
|
-
case "OTC_USER_CHAT_MSG":
|
|
240
|
-
match data["type"]:
|
|
241
|
-
case "RECEIVE":
|
|
242
|
-
upd = Receive.model_validate(data["data"])
|
|
243
|
-
if order_db := await models.Order.get_or_none(
|
|
244
|
-
exid=upd.orderId, ad__maker__ex=self.actor.ex
|
|
245
|
-
).prefetch_related("ad__pair_side__pair", "cred__pmcur__cur"):
|
|
246
|
-
im_taker = order_db.taker_id == self.actor.id
|
|
247
|
-
im_buyer = order_db.ad.pair_side.is_sell == im_taker
|
|
248
|
-
if order_db.ad.auto_msg != upd.message and upd.roleType == "user":
|
|
249
|
-
msg, _ = await models.Msg.update_or_create(
|
|
250
|
-
{
|
|
251
|
-
"to_maker": upd.userId == self.actor.exid and im_taker,
|
|
252
|
-
"sent_at": datetime.fromtimestamp(float(upd.createDate) / 1000),
|
|
253
|
-
},
|
|
254
|
-
txt=upd.message,
|
|
255
|
-
order=order_db,
|
|
256
|
-
)
|
|
257
|
-
if not upd.message:
|
|
258
|
-
...
|
|
259
|
-
if im_buyer and (g := re.match(r"^[PpРр]\d{7,10}\b", upd.message)):
|
|
260
|
-
if not order_db.cred.detail.startswith(dest := g.group()):
|
|
261
|
-
order_db.cred.detail = dest
|
|
262
|
-
await order_db.save()
|
|
263
|
-
await self.send_payment(order_db)
|
|
264
|
-
case "READ":
|
|
265
|
-
upd = Read.model_validate(data["data"])
|
|
266
|
-
# if upd.status not in (StatusWs.created, StatusWs.canceled, 10, StatusWs.completed):
|
|
267
|
-
if upd.orderStatus in (
|
|
268
|
-
StatusApi.wait_for_buyer,
|
|
269
|
-
): # todo: тут приходит ордер.статус=10, хотя покупатель еще не нажал оплачено
|
|
270
|
-
order = self.api.get_order_details(orderId=upd.orderId)["result"]
|
|
271
|
-
order = OrderFull.model_validate(order)
|
|
272
|
-
|
|
273
|
-
case "CLEAR":
|
|
274
|
-
continue
|
|
275
|
-
case _:
|
|
276
|
-
self.listen(data)
|
|
277
|
-
case "OTC_USER_CHAT_MSG_V2":
|
|
278
|
-
# match data["type"]:
|
|
279
|
-
# case "RECEIVE":
|
|
280
|
-
# upd = Receive.model_validate(data["data"])
|
|
281
|
-
# case "READ":
|
|
282
|
-
# upd = Read.model_validate(data["data"])
|
|
283
|
-
# case "CLEAR":
|
|
284
|
-
# pass
|
|
285
|
-
# case _:
|
|
286
|
-
# self.listen(data)
|
|
287
|
-
continue
|
|
288
|
-
case "SELLER_CANCEL_CHANGE":
|
|
289
|
-
upd = SellerCancelChange.model_validate(data["data"])
|
|
290
|
-
case None:
|
|
291
|
-
if not data.get("success"):
|
|
292
|
-
logging.error(data, "NOT SUCCESS!")
|
|
293
|
-
else:
|
|
294
|
-
continue # success login, subscribes, input
|
|
295
|
-
case _:
|
|
296
|
-
logging.warning(data, "UNKNOWN TOPIC")
|
|
297
|
-
if not upd:
|
|
298
|
-
logging.warning(data, "NOT PROCESSED UPDATE")
|
|
299
|
-
|
|
300
|
-
async def money_upd(self, odb: models.Order):
|
|
301
|
-
# обновляем остаток монеты
|
|
302
|
-
await odb.fetch_related("ad__pair_side__pair", "ad__my_ad__credexs__cred__fiat", "cred__pmcur", "transfer")
|
|
303
|
-
ass = await models.Asset.get(addr__coin_id=odb.ad.pair_side.pair.coin_id, addr__actor=self.actor)
|
|
304
|
-
# обновляем остаток валюты
|
|
305
|
-
im_maker = odb.ad.maker_id == self.actor.id
|
|
306
|
-
im_seller = odb.ad.pair_side.is_sell == im_maker
|
|
307
|
-
if im_maker:
|
|
308
|
-
if _fiats := [cx.cred.fiat for cx in odb.ad.my_ad.credexs if cx.cred.fiat]:
|
|
309
|
-
fiat = _fiats[0]
|
|
310
|
-
await fiat.fetch_related("cred__pmcur__pm")
|
|
311
|
-
else:
|
|
312
|
-
raise ValueError(odb, "No Fiat")
|
|
313
|
-
elif im_seller: # im taker
|
|
314
|
-
fltr = dict(cred__person_id=self.actor.person_id)
|
|
315
|
-
fltr |= (
|
|
316
|
-
{"cred__ovr_pm_id": odb.cred.ovr_pm_id, "cred__pmcur__cur_id": odb.cred.pmcur.cur_id}
|
|
317
|
-
if odb.cred.ovr_pm_id
|
|
318
|
-
else {"cred__pmcur_id": odb.cred.pmcur_id}
|
|
319
|
-
)
|
|
320
|
-
if not (fiat := await models.Fiat.get_or_none(**fltr).prefetch_related("cred__pmcur__pm")):
|
|
321
|
-
raise ValueError(odb, "No Fiat")
|
|
322
|
-
fee = round(odb.amount * (fiat.cred.pmcur.pm.fee or 0) * 0.0001)
|
|
323
|
-
# k = int(im_seller) * 2 - 1 # im_seller: 1, im_buyer: -1
|
|
324
|
-
if odb.status == OrderStatus.created:
|
|
325
|
-
if im_seller:
|
|
326
|
-
ass.free -= odb.quantity
|
|
327
|
-
ass.freeze += odb.quantity
|
|
328
|
-
else: # я покупатель
|
|
329
|
-
fiat.amount -= odb.amount + fee
|
|
330
|
-
elif odb.status == OrderStatus.completed:
|
|
331
|
-
if im_seller:
|
|
332
|
-
fiat.amount += odb.amount
|
|
333
|
-
else: # я покупатель
|
|
334
|
-
ass.free += odb.quantity
|
|
335
|
-
elif odb.status == OrderStatus.canceled:
|
|
336
|
-
if im_seller:
|
|
337
|
-
ass.free += odb.quantity
|
|
338
|
-
ass.freeze -= odb.quantity
|
|
339
|
-
else: # я покупатель
|
|
340
|
-
fiat.amount += odb.amount + fee
|
|
341
|
-
else:
|
|
342
|
-
logging.exception(odb.id, f"STATUS: {odb.status.name}")
|
|
343
|
-
await ass.save(update_fields=["free", "freeze"])
|
|
344
|
-
await fiat.save(update_fields=["amount"])
|
|
345
|
-
logging.info(f"Order #{odb.id} {odb.status.name}. Fiat: {fiat.amount}, Asset: {ass.free}")
|
|
346
|
-
|
|
347
|
-
async def send_payment(self, order_db: models.Order):
|
|
348
|
-
if order_db.status != OrderStatus.created:
|
|
349
|
-
return
|
|
350
|
-
fmt_am = round(order_db.amount * 10**-2, 2)
|
|
351
|
-
pma, cur = await self.get_pma_by_pmex(order_db)
|
|
352
|
-
async with in_transaction():
|
|
353
|
-
# отмечаем ордер на бирже "оплачен"
|
|
354
|
-
pmex = await models.PmEx.get(pm_id=order_db.cred.pmcur.pm_id, ex=self.actor.ex)
|
|
355
|
-
credex = await models.CredEx.get(cred=order_db.cred, ex=self.actor.ex)
|
|
356
|
-
self.api.mark_as_paid(
|
|
357
|
-
orderId=str(order_db.exid),
|
|
358
|
-
paymentType=pmex.exid, # pmex.exid
|
|
359
|
-
paymentId=str(credex.exid), # credex.exid
|
|
360
|
-
)
|
|
361
|
-
# проверяем не отправляли ли мы уже перевод по этому ордеру
|
|
362
|
-
if t := await models.Transfer.get_or_none(order=order_db, amount=order_db.amount):
|
|
363
|
-
await pma.bot.send(
|
|
364
|
-
f"Order# {order_db.exid}: Double send {fmt_am}{cur} to {order_db.cred.detail} #{t.pmid}!",
|
|
365
|
-
self.actor.person.user.username_id,
|
|
366
|
-
)
|
|
367
|
-
raise Exception(
|
|
368
|
-
f"Order# {order_db.exid}: Double send {fmt_am}{cur} to {order_db.cred.detail} #{t.pmid}!"
|
|
369
|
-
)
|
|
370
|
-
|
|
371
|
-
# ставим в бд статус "оплачен"
|
|
372
|
-
order_db.status = OrderStatus.paid
|
|
373
|
-
order_db.payed_at = datetime.now(timezone.utc)
|
|
374
|
-
await order_db.save()
|
|
375
|
-
# создаем перевод в бд
|
|
376
|
-
t = models.Transfer(order=order_db, amount=order_db.amount, updated_at=now())
|
|
377
|
-
# отправляем деньги
|
|
378
|
-
tid, img = await pma.send(t)
|
|
379
|
-
t.pmid = tid
|
|
380
|
-
await t.save()
|
|
381
|
-
await self.send_receipt(str(order_db.exid), tid) # отправляем продавцу чек
|
|
382
|
-
logging.info(f"Order {order_db.exid} PAID at {datetime.now()}: {fmt_am}!")
|
|
383
|
-
|
|
384
|
-
async def send_receipt(self, oexid: str, tid: int) -> tuple[PmAgentClient | None, models.CredEx] | None:
|
|
385
|
-
try:
|
|
386
|
-
if res := self.api.upload_chat_file(upload_file=f"tmp/{tid}.png").get("result"):
|
|
387
|
-
await sleep(0.5)
|
|
388
|
-
self.api.send_chat_message(orderId=oexid, contentType="pic", message=res["url"], msgUuid=uuid4().hex)
|
|
389
|
-
except Exception as e:
|
|
390
|
-
logging.error(e)
|
|
391
|
-
await sleep(0.5)
|
|
392
|
-
self.api.send_chat_message(orderId=oexid, contentType="str", message=f"#{tid}", msgUuid=uuid4().hex)
|
|
393
|
-
|
|
394
|
-
async def get_pma_by_cdex(self, order: OrderFull) -> tuple[PmAgentClient | None, models.CredEx] | None:
|
|
395
|
-
cdxs = await models.CredEx.filter(
|
|
396
|
-
ex=self.ex_client.ex,
|
|
397
|
-
exid__in=[ptl.id for ptl in order.paymentTermList],
|
|
398
|
-
cred__person=self.actor.person,
|
|
399
|
-
).prefetch_related("cred__pmcur__cur")
|
|
400
|
-
pmas = [pma for cdx in cdxs if (pma := self.pm_clients.get(cdx.cred.pmcur.pm_id))]
|
|
401
|
-
if not len(pmas):
|
|
402
|
-
# raise ValueError(order.paymentTermList, f"No pm_agents for {order.paymentTermList[0].paymentType}")
|
|
403
|
-
return None
|
|
404
|
-
elif len(pmas) > 1:
|
|
405
|
-
logging.error(order.paymentTermList, f">1 pm_agents for {cdxs[0].cred.pmcur.pm_id}")
|
|
406
|
-
else:
|
|
407
|
-
return pmas[0], cdxs[0]
|
|
408
|
-
|
|
409
|
-
async def get_pma_by_pmex(self, order_db: models.Order) -> tuple[PmAgentClient, str]:
|
|
410
|
-
pma = self.pm_clients.get(order_db.cred.pmcur.pm_id)
|
|
411
|
-
if pma:
|
|
412
|
-
return pma, order_db.cred.pmcur.cur.ticker
|
|
413
|
-
logging.error(f"No pm_agents for {order_db.cred.pmcur.pm_id}")
|
|
414
|
-
|
|
415
|
-
@staticmethod
|
|
416
|
-
def listen(data: dict | None):
|
|
417
|
-
# print(data)
|
|
418
|
-
...
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
async def main():
|
|
422
|
-
from x_model import init_db
|
|
423
|
-
from xync_client.loader import TORM
|
|
424
|
-
|
|
425
|
-
cn = await init_db(TORM, True)
|
|
426
|
-
logging.basicConfig(level=logging.INFO)
|
|
427
|
-
|
|
428
|
-
agent = (
|
|
429
|
-
await models.Agent.filter(
|
|
430
|
-
actor__ex_id=4,
|
|
431
|
-
status__in=[3],
|
|
432
|
-
auth__isnull=False,
|
|
433
|
-
actor__person__user__status=UserStatus.ACTIVE,
|
|
434
|
-
actor__person__user__pm_agents__pm_id=366,
|
|
435
|
-
actor__person_id=1,
|
|
436
|
-
)
|
|
437
|
-
.prefetch_related("actor__ex", "actor__person__user__gmail")
|
|
438
|
-
.first()
|
|
439
|
-
)
|
|
440
|
-
pm_agents = await models.PmAgent.filter(
|
|
441
|
-
active=True,
|
|
442
|
-
auth__isnull=False,
|
|
443
|
-
user__status=UserStatus.ACTIVE,
|
|
444
|
-
).prefetch_related("pm", "user__gmail")
|
|
445
|
-
|
|
446
|
-
bbot = XyncBot(PAY_TOKEN, cn)
|
|
447
22
|
|
|
448
|
-
|
|
449
|
-
b: FileClient
|
|
450
|
-
cl = InAgentClient(agent, b, bbot)
|
|
451
|
-
# await cl.agent_client.export_my_ads()
|
|
452
|
-
# payeer_cl = Client(actor.person.user.username_id)
|
|
453
|
-
for pma in pm_agents:
|
|
454
|
-
pcl: PmAgentClient = pma.client(bbot)
|
|
455
|
-
cl.pm_clients[pma.pm_id] = await pcl.start(await async_playwright().start(), False)
|
|
456
|
-
try:
|
|
457
|
-
_ = await cl.start_listen()
|
|
458
|
-
except Exception as e:
|
|
459
|
-
await b.send("😱Bybit InAgent CRASHED!!!😱", agent.actor.person.user.username_id)
|
|
460
|
-
await b.send(f"```\n{''.join(traceback.format_exception(e))}\n```", agent.actor.person.user.username_id)
|
|
461
|
-
await cl.close()
|
|
23
|
+
orders: dict[int, models.Order] = {}
|
|
462
24
|
|
|
25
|
+
def __init__(self, agent: Agent, ex_client: ExClient, fbot: FileClient, bbot: XyncBot, **kwargs):
|
|
26
|
+
super().__init__(agent, ex_client, fbot, bbot, **kwargs)
|
|
27
|
+
create_task(self.load_pending_orders())
|
|
463
28
|
|
|
464
|
-
|
|
465
|
-
|
|
29
|
+
async def load_pending_orders(self):
|
|
30
|
+
po: dict[int, OrderItem] = await self.get_pending_orders()
|
|
31
|
+
if isinstance(po, int): # если код ошибки вместо результата
|
|
32
|
+
raise ValueError(po)
|
|
33
|
+
self.orders = {o.exid: o for o in await models.Order.filter(exid__in=po.keys())}
|
|
34
|
+
for oid in po.keys() - self.orders.keys():
|
|
35
|
+
fo = self.api.get_order_details(orderId=oid)
|
|
36
|
+
self.orders[oid] = await self.create_order_db(fo)
|