xync-db 0.5.5.dev82__tar.gz → 0.6.0__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.
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/PKG-INFO +1 -1
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/enums.py +3 -4
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/CLAUDE.md +2 -2
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/models/0001_initial.py +44 -6
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/models/0003_seed.py +6 -3
- xync_db-0.6.0/src/xync_db/migrations/models/seed/a_city_seed.py +23 -0
- xync_db-0.6.0/src/xync_db/migrations/models/seed/cities.json +337 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/models/CLAUDE.md +6 -4
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/models/__init__.py +16 -5
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/.gitignore +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/README.md +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/pyproject.toml +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/__init__.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/config.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/exceptions.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/graph.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/i18n.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/login_store.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/logo.png +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/__init__.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/models/0002_triggers.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/models/__init__.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/models/seed/__init__.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/models/seed/a_actor_seed.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/models/seed/a_bin_seed.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/models/seed/a_country_seed.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/models/seed/a_tg_seed.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/models/seed/b_htx_seed.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/models/seed/c_net_seed.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/models/seed/countries.json +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/models/seed/ranges.csv +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/migrations/models/seed/xync_files.sql +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/py.typed +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/shared.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/typs/__init__.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/typs/db/__init__.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/typs/db/actor.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/typs/db/ad.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/typs/db/common.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/typs/db/cred.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/typs/db/order.py +0 -0
- {xync_db-0.5.5.dev82 → xync_db-0.6.0}/src/xync_db/typs/db/pm.py +0 -0
|
@@ -202,12 +202,12 @@ class Boundary(IntEnum):
|
|
|
202
202
|
class SbpStrict(IntEnum):
|
|
203
203
|
sbp = 1
|
|
204
204
|
card = 2
|
|
205
|
+
atm_qr = 3 # наличные через банкомат по QR-коду: «отправляю в чат фото qr-кода с банкомата»
|
|
205
206
|
|
|
206
207
|
|
|
207
|
-
class
|
|
208
|
+
class PartyType(IntEnum): # чей счёт в платеже: и from_party, и to_party у CondParsed
|
|
208
209
|
fst = 0
|
|
209
210
|
fam = 1
|
|
210
|
-
lk = 2
|
|
211
211
|
trd = 3
|
|
212
212
|
|
|
213
213
|
|
|
@@ -221,7 +221,6 @@ class Slip(IntEnum):
|
|
|
221
221
|
class AbuserType(IntEnum):
|
|
222
222
|
rating = 1 # рейтинг: жмет "Оплачено" сразу, "Отмена" по апелляции
|
|
223
223
|
fake = 2 # реклама
|
|
224
|
-
cash = 3 # типа кэш обменник, но хз
|
|
225
224
|
long = 4 # ждать дольше 15 мин (оплату/отпуск)
|
|
226
225
|
add_vrf = 5 # сверх чека — видео из лк/выписка и т.п.
|
|
227
226
|
fee = 6 # доплата/комиссия сверх суммы ордера
|
|
@@ -248,7 +247,7 @@ class GeminiRes(IntEnum): # исход запроса к Gemini (`GeminiReq`)
|
|
|
248
247
|
minute = 1 # прочие 429 (…PerMinute…, отказ без квоты): ключ на минуту мимо этой модели
|
|
249
248
|
day = 2 # 429 …PerDay…: ключ выбыл по этой модели до сброса квоты (`GeminiKey.pick`)
|
|
250
249
|
bad_key = 4 # 401/403/API_KEY_INVALID: ключ выбыл по всем моделям на сутки
|
|
251
|
-
fail = 5 # прочие сбои (таймаут; 5xx — перегружена модель: условие — к следующей)
|
|
250
|
+
fail = 5 # прочие сбои (таймаут; 499 — оборван, один повтор; 5xx — перегружена модель: условие — к следующей)
|
|
252
251
|
|
|
253
252
|
|
|
254
253
|
class ExStatus(IntEnum):
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
`user_new`.
|
|
12
12
|
3. **`0003_seed`** — засев по зависимостям: файлы PM-логотипов → `a_actor_seed` (биржи, 56 базовых валют, монеты,
|
|
13
13
|
XyncPay, эл. кошельки, origin user id=0) → `a_tg_seed` (DC/App, `pm_rep`) → `a_country_seed` (страны+валюты
|
|
14
|
-
из `seed/countries.json`) → `
|
|
15
|
-
HTX) → `c_net_seed` (web3-сети).
|
|
14
|
+
из `seed/countries.json`) → `a_city_seed` (города из `seed/cities.json`) → `a_bin_seed` (BIN/банки из
|
|
15
|
+
`seed/ranges.csv`) → `b_htx_seed` (валюты/монеты/пары HTX) → `c_net_seed` (web3-сети).
|
|
16
16
|
|
|
17
17
|
Засев, зависящий от Pm (`set_pms` с логотипами, `refine_pms`), — в `xync-script`, не здесь: миграции не
|
|
18
18
|
импортируют `pyro_client`.
|
|
@@ -25,11 +25,11 @@ from xync_db.enums import (
|
|
|
25
25
|
ExStatus,
|
|
26
26
|
ExType,
|
|
27
27
|
FileType,
|
|
28
|
-
FromParty,
|
|
29
28
|
GeminiModel,
|
|
30
29
|
GeminiRes,
|
|
31
30
|
HotStatus,
|
|
32
31
|
OrderStatus,
|
|
32
|
+
PartyType,
|
|
33
33
|
PersonStatus,
|
|
34
34
|
PmType,
|
|
35
35
|
SbpStrict,
|
|
@@ -228,6 +228,26 @@ class Migration(migrations.Migration):
|
|
|
228
228
|
options={"table": "country", "app": "models", "pk_attr": "id"},
|
|
229
229
|
bases=["Country"],
|
|
230
230
|
),
|
|
231
|
+
ops.CreateModel(
|
|
232
|
+
name="City",
|
|
233
|
+
fields=[
|
|
234
|
+
("id", fields.IntField(generated=True, primary_key=True, unique=True, db_index=True)),
|
|
235
|
+
("name", fields.CharField(unique=True, max_length=63)),
|
|
236
|
+
(
|
|
237
|
+
"country",
|
|
238
|
+
fields.ForeignKeyField(
|
|
239
|
+
"models.Country",
|
|
240
|
+
source_field="country_id",
|
|
241
|
+
db_constraint=True,
|
|
242
|
+
to_field="id",
|
|
243
|
+
related_name="cities",
|
|
244
|
+
on_delete=OnDelete.CASCADE,
|
|
245
|
+
),
|
|
246
|
+
),
|
|
247
|
+
],
|
|
248
|
+
options={"table": "city", "app": "models", "pk_attr": "id"},
|
|
249
|
+
bases=["Model"],
|
|
250
|
+
),
|
|
231
251
|
ops.CreateModel(
|
|
232
252
|
name="Dc",
|
|
233
253
|
fields=[
|
|
@@ -712,15 +732,16 @@ class Migration(migrations.Migration):
|
|
|
712
732
|
(
|
|
713
733
|
"from_party",
|
|
714
734
|
fields.IntEnumField(
|
|
715
|
-
null=True, description="fst: 0\nfam: 1\
|
|
735
|
+
null=True, description="fst: 0\nfam: 1\ntrd: 3", enum_type=PartyType, generated=False
|
|
716
736
|
),
|
|
717
737
|
),
|
|
718
738
|
(
|
|
719
739
|
"to_party",
|
|
720
740
|
fields.IntEnumField(
|
|
721
|
-
null=True, description="fst: 0\nfam: 1\
|
|
741
|
+
null=True, description="fst: 0\nfam: 1\ntrd: 3", enum_type=PartyType, generated=False
|
|
722
742
|
),
|
|
723
743
|
),
|
|
744
|
+
("lk", fields.BooleanField(null=True)),
|
|
724
745
|
("ppo", UInt1Field(null=True)),
|
|
725
746
|
(
|
|
726
747
|
"slip",
|
|
@@ -732,16 +753,31 @@ class Migration(migrations.Migration):
|
|
|
732
753
|
"abuser",
|
|
733
754
|
fields.IntEnumField(
|
|
734
755
|
null=True,
|
|
735
|
-
description="rating: 1\nfake: 2\
|
|
756
|
+
description="rating: 1\nfake: 2\nlong: 4\nadd_vrf: 5\nfee: 6\nrate: 7",
|
|
736
757
|
enum_type=AbuserType,
|
|
737
758
|
generated=False,
|
|
738
759
|
),
|
|
739
760
|
),
|
|
761
|
+
(
|
|
762
|
+
"cash_city",
|
|
763
|
+
fields.ForeignKeyField(
|
|
764
|
+
"models.City",
|
|
765
|
+
source_field="cash_city_id",
|
|
766
|
+
null=True,
|
|
767
|
+
db_constraint=True,
|
|
768
|
+
to_field="id",
|
|
769
|
+
related_name="conds",
|
|
770
|
+
on_delete=OnDelete.SET_NULL,
|
|
771
|
+
),
|
|
772
|
+
),
|
|
740
773
|
("slavic", fields.BooleanField(null=True)),
|
|
741
774
|
(
|
|
742
775
|
"cred",
|
|
743
776
|
fields.IntEnumField(
|
|
744
|
-
null=True,
|
|
777
|
+
null=True,
|
|
778
|
+
description="no_llc: 1\nrus_num: 2\nforeign: 3",
|
|
779
|
+
enum_type=CredType,
|
|
780
|
+
generated=False,
|
|
745
781
|
),
|
|
746
782
|
),
|
|
747
783
|
("mtl_like", fields.BooleanField(null=True)),
|
|
@@ -749,7 +785,9 @@ class Migration(migrations.Migration):
|
|
|
749
785
|
("bank_side", fields.BooleanField(null=True)),
|
|
750
786
|
(
|
|
751
787
|
"sbp_strict",
|
|
752
|
-
fields.IntEnumField(
|
|
788
|
+
fields.IntEnumField(
|
|
789
|
+
null=True, description="sbp: 1\ncard: 2\natm_qr: 3", enum_type=SbpStrict, generated=False
|
|
790
|
+
),
|
|
753
791
|
),
|
|
754
792
|
("contact", fields.CharField(null=True, max_length=127)),
|
|
755
793
|
("is_intermediary", fields.BooleanField(null=True)),
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
2. a_actor_seed — биржи, 56 базовых валют, монеты, XyncPay PM, эл. кошельки ЮMoney/ЦУПИС/Pyypl/Alipay (Bank+Pm+RUB), origin user
|
|
8
8
|
3. a_tg_seed — Telegram DC/App, нормализация имён PM (`pm_rep`)
|
|
9
9
|
4. a_country_seed — ВСЕ страны + их валюты из mledoze (`seed/countries.json`), ДО биржевых
|
|
10
|
-
5.
|
|
11
|
-
6.
|
|
12
|
-
7.
|
|
10
|
+
5. a_city_seed — города из `seed/cities.json`, ПОСЛЕ стран (линк по alpha-2)
|
|
11
|
+
6. a_bin_seed — BIN-диапазоны + банки из binlist/data (`seed/ranges.csv`), ПОСЛЕ стран (линк по alpha-2)
|
|
12
|
+
7. b_htx_seed — HTX-специфика: валюты (CurEx), монеты, пары
|
|
13
|
+
8. c_net_seed — web3-сети (Net) + недостающие нативные монеты
|
|
13
14
|
|
|
14
15
|
NB (D-09): PM-зависимый засев (`set_pms` + `refine_pms`) живёт в `packages/xync-script`, НЕ здесь —
|
|
15
16
|
он тянет `pyro_client` (FileClient), а миграции не должны импортировать `pyro_client`.
|
|
@@ -24,6 +25,7 @@ from tortoise.migrations.operations import RunPython
|
|
|
24
25
|
from xync_db.migrations.models.seed import (
|
|
25
26
|
a_actor_seed,
|
|
26
27
|
a_bin_seed,
|
|
28
|
+
a_city_seed,
|
|
27
29
|
a_country_seed,
|
|
28
30
|
a_tg_seed,
|
|
29
31
|
b_htx_seed,
|
|
@@ -42,6 +44,7 @@ async def seed(apps, schema_editor):
|
|
|
42
44
|
sql = await a_actor_seed.actor_seed(db)
|
|
43
45
|
sql += await a_tg_seed.tg_seed(db)
|
|
44
46
|
sql += await a_country_seed.country_seed(db) # страны+валюты из mledoze, ДО биржевых сидеров
|
|
47
|
+
sql += await a_city_seed.city_seed(db) # города из sky, ПОСЛЕ стран (линк по alpha-2)
|
|
45
48
|
sql += await a_bin_seed.bin_seed(db) # BIN-диапазоны+банки из binlist/data, ПОСЛЕ стран (линк по alpha-2)
|
|
46
49
|
sql += await b_htx_seed.htx_seed(db)
|
|
47
50
|
sql += await c_net_seed.net_seed(db)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Сидер городов — ПОСЛЕ стран (`a_country_seed`, линк по alpha-2).
|
|
2
|
+
|
|
3
|
+
Данные — статический `cities.json` рядом: `{alpha-2: [имя, …]}` (выгружен из `sky.city`). Идемпотентен:
|
|
4
|
+
заводит только имена, которых ещё нет.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from tortoise import BaseDBAsyncClient
|
|
11
|
+
|
|
12
|
+
from xync_db.models import City, Country
|
|
13
|
+
|
|
14
|
+
DATA = Path(__file__).with_name("cities.json")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def city_seed(_: BaseDBAsyncClient) -> str:
|
|
18
|
+
data: dict[str, list[str]] = json.loads(DATA.read_text(encoding="utf-8"))
|
|
19
|
+
have = set(await City.all().values_list("name", flat=True))
|
|
20
|
+
for short, names in data.items():
|
|
21
|
+
country = await Country.get(short=short)
|
|
22
|
+
await City.bulk_create([City(name=n, country=country) for n in names if n not in have])
|
|
23
|
+
return "select 1;"
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
{
|
|
2
|
+
"RU": [
|
|
3
|
+
"Abakan",
|
|
4
|
+
"Achayvajam",
|
|
5
|
+
"Achinsk",
|
|
6
|
+
"Adamovka",
|
|
7
|
+
"Adler/Sochi",
|
|
8
|
+
"Agzu",
|
|
9
|
+
"Ajan",
|
|
10
|
+
"Ajanka",
|
|
11
|
+
"Aldan",
|
|
12
|
+
"Amderma",
|
|
13
|
+
"Amgu",
|
|
14
|
+
"Amurzet",
|
|
15
|
+
"Anadyr",
|
|
16
|
+
"Anapa",
|
|
17
|
+
"Apuka",
|
|
18
|
+
"Arkhangelsk",
|
|
19
|
+
"Arkhyz",
|
|
20
|
+
"Astrakhan",
|
|
21
|
+
"Bajkit",
|
|
22
|
+
"Balakovo",
|
|
23
|
+
"Barnaul",
|
|
24
|
+
"Batagay",
|
|
25
|
+
"Batagay-Alyta",
|
|
26
|
+
"Belaya Gora",
|
|
27
|
+
"Belgorod",
|
|
28
|
+
"Belokurikha",
|
|
29
|
+
"Beloreck",
|
|
30
|
+
"Beloyarsky",
|
|
31
|
+
"Berezovo",
|
|
32
|
+
"Beringovskiy",
|
|
33
|
+
"Blagoveschensk",
|
|
34
|
+
"Bodaybo",
|
|
35
|
+
"Bogorodskoye",
|
|
36
|
+
"Boguchany",
|
|
37
|
+
"Bolshoy Larjak",
|
|
38
|
+
"Bor",
|
|
39
|
+
"Bovanenkovo",
|
|
40
|
+
"Bratsk",
|
|
41
|
+
"Bryansk",
|
|
42
|
+
"Bugulma",
|
|
43
|
+
"Buguruslan",
|
|
44
|
+
"Burnyj",
|
|
45
|
+
"Bylino",
|
|
46
|
+
"Chara",
|
|
47
|
+
"Cheboksary",
|
|
48
|
+
"Chegdomyn",
|
|
49
|
+
"Chekhlomej",
|
|
50
|
+
"Chelyabinsk",
|
|
51
|
+
"Chemdalsk",
|
|
52
|
+
"Cherepovets",
|
|
53
|
+
"Cherskiy",
|
|
54
|
+
"Chirinda",
|
|
55
|
+
"Chita",
|
|
56
|
+
"Chkalovsky",
|
|
57
|
+
"Chokurdah",
|
|
58
|
+
"Chumikan",
|
|
59
|
+
"Dalnegorsk",
|
|
60
|
+
"Dalnerechensk",
|
|
61
|
+
"Deputatsky",
|
|
62
|
+
"Dikson",
|
|
63
|
+
"Dombay",
|
|
64
|
+
"Edinka",
|
|
65
|
+
"Egvekinot",
|
|
66
|
+
"Ekonda",
|
|
67
|
+
"Elbrus",
|
|
68
|
+
"Elista",
|
|
69
|
+
"Eniseysk",
|
|
70
|
+
"Erbogachen",
|
|
71
|
+
"Essentuki",
|
|
72
|
+
"Essey",
|
|
73
|
+
"Evensk",
|
|
74
|
+
"Gelendzik",
|
|
75
|
+
"Glade Cheget",
|
|
76
|
+
"Gorno-Altaysk",
|
|
77
|
+
"Groznyy",
|
|
78
|
+
"Hatanga",
|
|
79
|
+
"Igarka",
|
|
80
|
+
"Igrim",
|
|
81
|
+
"Inta",
|
|
82
|
+
"Irkutsk",
|
|
83
|
+
"Iturup",
|
|
84
|
+
"Iturup Island",
|
|
85
|
+
"Ivanovo",
|
|
86
|
+
"Izhevsk",
|
|
87
|
+
"Jukta",
|
|
88
|
+
"Kaliningrad",
|
|
89
|
+
"Kaluga",
|
|
90
|
+
"Kamenskoe",
|
|
91
|
+
"Kavalerovo",
|
|
92
|
+
"Kazachinskoye",
|
|
93
|
+
"Kazan",
|
|
94
|
+
"Kedrovy",
|
|
95
|
+
"Kemerovo",
|
|
96
|
+
"Keperveyem",
|
|
97
|
+
"Khabarovsk",
|
|
98
|
+
"Khailino",
|
|
99
|
+
"Khanty-Mansiysk",
|
|
100
|
+
"Kharuta",
|
|
101
|
+
"Kherpuchi",
|
|
102
|
+
"Khonu",
|
|
103
|
+
"Khuzhir",
|
|
104
|
+
"Kirensk",
|
|
105
|
+
"Kirov",
|
|
106
|
+
"Kirovsk",
|
|
107
|
+
"Kislokan",
|
|
108
|
+
"Kislovodsk",
|
|
109
|
+
"Kodinsk",
|
|
110
|
+
"Kogalym",
|
|
111
|
+
"Kolekjegan",
|
|
112
|
+
"Komsomolsk Na Amure",
|
|
113
|
+
"Korliki",
|
|
114
|
+
"Koslan",
|
|
115
|
+
"Kostroma",
|
|
116
|
+
"Kotlas",
|
|
117
|
+
"Krabozavodskoye",
|
|
118
|
+
"Krasnodar",
|
|
119
|
+
"Krasnojarsk",
|
|
120
|
+
"Krasnokamensk",
|
|
121
|
+
"Krasnoselkup",
|
|
122
|
+
"Krasny Kut",
|
|
123
|
+
"Krasnyiy Chikoy",
|
|
124
|
+
"Kujumba",
|
|
125
|
+
"Kunashir Island",
|
|
126
|
+
"Kurgan",
|
|
127
|
+
"Kursk",
|
|
128
|
+
"Kuskurgul",
|
|
129
|
+
"Kuzmovka",
|
|
130
|
+
"Kyra",
|
|
131
|
+
"Kyzyl",
|
|
132
|
+
"Laitamak",
|
|
133
|
+
"Larjak",
|
|
134
|
+
"Lensk",
|
|
135
|
+
"Leshukonskoye",
|
|
136
|
+
"Lipetsk",
|
|
137
|
+
"Magadan",
|
|
138
|
+
"Magan",
|
|
139
|
+
"Magas",
|
|
140
|
+
"Magdagachi",
|
|
141
|
+
"Magnitogorsk",
|
|
142
|
+
"Makhachkala",
|
|
143
|
+
"Mama",
|
|
144
|
+
"Manily",
|
|
145
|
+
"Markovo",
|
|
146
|
+
"Maximovka",
|
|
147
|
+
"Mezen",
|
|
148
|
+
"Mineralnye Vody",
|
|
149
|
+
"Miriuga",
|
|
150
|
+
"Mirnyj",
|
|
151
|
+
"Moscow",
|
|
152
|
+
"Motygino",
|
|
153
|
+
"Murmansk",
|
|
154
|
+
"Muzhi",
|
|
155
|
+
"Mys-Kamenny",
|
|
156
|
+
"Naberezhnye Chelny",
|
|
157
|
+
"Nadym",
|
|
158
|
+
"Nalchik",
|
|
159
|
+
"Naryan-Mar",
|
|
160
|
+
"Neftekamsk",
|
|
161
|
+
"Nefteyugansk",
|
|
162
|
+
"Nelkan",
|
|
163
|
+
"Neryungri",
|
|
164
|
+
"Nikolaevsk-na-Amure",
|
|
165
|
+
"Nikolskoe",
|
|
166
|
+
"Nizhneangarsk",
|
|
167
|
+
"Nizhnevartovsk",
|
|
168
|
+
"Nizhniy Novgorod",
|
|
169
|
+
"Nogliki",
|
|
170
|
+
"Nojabrxsk",
|
|
171
|
+
"Noril'sk",
|
|
172
|
+
"Novgorod",
|
|
173
|
+
"Novokurovka",
|
|
174
|
+
"Novokuznetsk",
|
|
175
|
+
"Novorossijsk",
|
|
176
|
+
"Novosibirsk",
|
|
177
|
+
"Novyj Urengoj",
|
|
178
|
+
"Nyagan",
|
|
179
|
+
"Nyurba",
|
|
180
|
+
"Okha",
|
|
181
|
+
"Okhotsk",
|
|
182
|
+
"Oktiabrskij",
|
|
183
|
+
"Olenyok",
|
|
184
|
+
"Olokminsk",
|
|
185
|
+
"Omolon",
|
|
186
|
+
"Omsk",
|
|
187
|
+
"Omsukchan",
|
|
188
|
+
"Orel",
|
|
189
|
+
"Orenburg",
|
|
190
|
+
"Orsk",
|
|
191
|
+
"Osharovo",
|
|
192
|
+
"Ossora",
|
|
193
|
+
"Ozernaya",
|
|
194
|
+
"Pakhachi",
|
|
195
|
+
"Palana",
|
|
196
|
+
"Pechora",
|
|
197
|
+
"Penza",
|
|
198
|
+
"Perm",
|
|
199
|
+
"Petropavlovsk-Kamchatsky",
|
|
200
|
+
"Petrozavodsk",
|
|
201
|
+
"Pevek",
|
|
202
|
+
"Plastun",
|
|
203
|
+
"Pobeda",
|
|
204
|
+
"Podvolochnoe",
|
|
205
|
+
"Pokur",
|
|
206
|
+
"Poligus",
|
|
207
|
+
"Poliny Osipenko",
|
|
208
|
+
"Poronaisk",
|
|
209
|
+
"Preobrazheniye",
|
|
210
|
+
"Provideniya",
|
|
211
|
+
"Pskov",
|
|
212
|
+
"Pug-Jug",
|
|
213
|
+
"Raduzhnyi",
|
|
214
|
+
"Romantik",
|
|
215
|
+
"Rostov",
|
|
216
|
+
"Ryazan",
|
|
217
|
+
"Rybinsk",
|
|
218
|
+
"Sabetta",
|
|
219
|
+
"Saint Petersburg",
|
|
220
|
+
"Salekhard",
|
|
221
|
+
"Samara",
|
|
222
|
+
"Samarga",
|
|
223
|
+
"Sangar",
|
|
224
|
+
"Saransk",
|
|
225
|
+
"Saratov",
|
|
226
|
+
"Saskylakh",
|
|
227
|
+
"Severo-Eniseyskiy",
|
|
228
|
+
"Severo-Kurilsk",
|
|
229
|
+
"Seymchan",
|
|
230
|
+
"Shakhtyorsk",
|
|
231
|
+
"Sheregesh",
|
|
232
|
+
"Shushenskoe",
|
|
233
|
+
"Sinegorye",
|
|
234
|
+
"Slautnoe",
|
|
235
|
+
"Smirnykh",
|
|
236
|
+
"Smolensk",
|
|
237
|
+
"Sobolevo",
|
|
238
|
+
"Solovetsky",
|
|
239
|
+
"Sosnovy Bor",
|
|
240
|
+
"Sovetskaya Gavan",
|
|
241
|
+
"Sovetsky",
|
|
242
|
+
"Srednekolymsk",
|
|
243
|
+
"Srednie Pakhachi",
|
|
244
|
+
"Stary Oskol",
|
|
245
|
+
"Stavropol",
|
|
246
|
+
"Strelka-Chunya",
|
|
247
|
+
"Strezhevoy",
|
|
248
|
+
"Sulomay",
|
|
249
|
+
"Suntar",
|
|
250
|
+
"Surgut",
|
|
251
|
+
"Surinda",
|
|
252
|
+
"Susuman",
|
|
253
|
+
"Svetlaya",
|
|
254
|
+
"Svetlogorsk",
|
|
255
|
+
"Svetly",
|
|
256
|
+
"Syktyvkar",
|
|
257
|
+
"Taganrog",
|
|
258
|
+
"Taksimo",
|
|
259
|
+
"Talakan",
|
|
260
|
+
"Talovka",
|
|
261
|
+
"Tambov",
|
|
262
|
+
"Tarko-Sale",
|
|
263
|
+
"Terney",
|
|
264
|
+
"Tigil",
|
|
265
|
+
"Tiksi",
|
|
266
|
+
"Tilichiki",
|
|
267
|
+
"Tobolsk",
|
|
268
|
+
"Tolka",
|
|
269
|
+
"Tomsk",
|
|
270
|
+
"Troitsko-Pechorsk",
|
|
271
|
+
"Tugur",
|
|
272
|
+
"Tula",
|
|
273
|
+
"Tura",
|
|
274
|
+
"Turukhansk",
|
|
275
|
+
"Tutonchany",
|
|
276
|
+
"Tver",
|
|
277
|
+
"Tynda",
|
|
278
|
+
"Tyumen",
|
|
279
|
+
"Uchami",
|
|
280
|
+
"Udachnyj",
|
|
281
|
+
"Udskoe",
|
|
282
|
+
"Ufa",
|
|
283
|
+
"Ukhta",
|
|
284
|
+
"Ulan-Ude",
|
|
285
|
+
"Ulyanovsk",
|
|
286
|
+
"Uraj",
|
|
287
|
+
"Urengoy",
|
|
288
|
+
"Usinsk",
|
|
289
|
+
"Ust'-Koksa",
|
|
290
|
+
"Ust-Ilimsk",
|
|
291
|
+
"Ust-Kamchatsk",
|
|
292
|
+
"Ust-Khayryuzovo",
|
|
293
|
+
"Ust-Kolikjegan",
|
|
294
|
+
"Ust-Kuiga",
|
|
295
|
+
"Ust-Kut",
|
|
296
|
+
"Ust-Maya",
|
|
297
|
+
"Ust-Nera",
|
|
298
|
+
"Ust-Omchug",
|
|
299
|
+
"Ust-Tsilma",
|
|
300
|
+
"Vagay",
|
|
301
|
+
"Vampugolsk",
|
|
302
|
+
"Vanavara",
|
|
303
|
+
"Varandey",
|
|
304
|
+
"Velikij Ustyug",
|
|
305
|
+
"Velikiye Luki",
|
|
306
|
+
"Verhnevilyuisk",
|
|
307
|
+
"Vershinskie",
|
|
308
|
+
"Vilyuisk",
|
|
309
|
+
"Vladikavkaz",
|
|
310
|
+
"Vladimir",
|
|
311
|
+
"Vladivostok",
|
|
312
|
+
"Volgodonsk",
|
|
313
|
+
"Volgograd",
|
|
314
|
+
"Vologda",
|
|
315
|
+
"Vorkuta",
|
|
316
|
+
"Voronezh",
|
|
317
|
+
"Vuktyl",
|
|
318
|
+
"Yagodnoe",
|
|
319
|
+
"Yakutsk",
|
|
320
|
+
"Yamburg",
|
|
321
|
+
"Yaroslavl",
|
|
322
|
+
"Yartsevo",
|
|
323
|
+
"Yekaterinburg",
|
|
324
|
+
"Yeysk",
|
|
325
|
+
"Yoshkar-Ola",
|
|
326
|
+
"Yuzhno-Sakhalinsk",
|
|
327
|
+
"Zaliv Lavrentija",
|
|
328
|
+
"Zeja",
|
|
329
|
+
"Zheleznogorsk",
|
|
330
|
+
"Zheleznovodsk",
|
|
331
|
+
"Zhigansk",
|
|
332
|
+
"Zonalnoye",
|
|
333
|
+
"Zyryanka",
|
|
334
|
+
"azau",
|
|
335
|
+
"terskol"
|
|
336
|
+
]
|
|
337
|
+
}
|
|
@@ -75,14 +75,16 @@ Re-exported models from `x_auth`: `Username`, `Proxy`, `Dc`, `Fcm`, `App`, `Sess
|
|
|
75
75
|
`Cond` -> `CondParsed`, `Synonym`, `CondSim`, `CondPrompt`
|
|
76
76
|
|
|
77
77
|
- `Cond.raw_txt` = текст условия (до 4095); условие — одной стороны, без объяв не живёт (D-18)
|
|
78
|
-
- `CondParsed` = structured parse result: `from_party` / `to_party` (`
|
|
79
|
-
покупателя), `
|
|
80
|
-
|
|
78
|
+
- `CondParsed` = structured parse result: `from_party` / `to_party` (`PartyType`: с чьего / на чей счёт идёт платёж
|
|
79
|
+
покупателя), `lk` (лк банка на руках: True — требование к тейкеру, False — есть у мейкера), `cash_city` (`City`
|
|
80
|
+
кэш-обменника / встречи), `ppo`, `slip` (`Slip`) — требует/шлёт понятно из направления объявы, abuse flags,
|
|
81
|
+
`is_intermediary` (мейкер-посредник «треугол»), linked bank `Pm`s
|
|
81
82
|
— все поля nullable, дефолт `None` (= «в условии не сказано»; никаких `*.no`-заглушек). Единый writer
|
|
82
83
|
`CondParsed.upsert(cond_id, bank_ids=None, **fields)` (бот-разметка /cond и разбор нейронками, D-19); ответ админа
|
|
83
84
|
на «сохранить разбор?» — эмиттер `CondParsed.answer(cond_id, remark=None)` → pg-канал `cond_ai_answer`
|
|
84
85
|
`[cond_id, remark]` (null — «да», текст — «нет» с замечанием, "" — «нет», замечание пишется, true — «🔄»: объяву
|
|
85
|
-
условия заново с биржи — реальный exid замаскированного мейкера + свежий `raw_txt`, затем вопрос
|
|
86
|
+
условия заново с биржи — реальный exid замаскированного мейкера + свежий `raw_txt`, затем вопрос заново; false —
|
|
87
|
+
«другая модель»: разбор следующей по кругу моделью, затем вопрос заново); возвращает, слушает
|
|
86
88
|
ли канал хоть один прогон (pg_stat_activity) — иначе ответ пропал бы молча
|
|
87
89
|
- `CondPrompt` = версии промпта разбора: системного промпта Gemini и (`is_jev`) вопросов JEV JSON-ом — у каждого
|
|
88
90
|
действует последняя (`id` max); пишет только `CondAi` (засев исходной + правки Claude по замечаниям админа, `cond` —
|
|
@@ -82,13 +82,13 @@ from xync_db.enums import (
|
|
|
82
82
|
ExAction,
|
|
83
83
|
ExStatus,
|
|
84
84
|
ExType,
|
|
85
|
-
FromParty,
|
|
86
85
|
GeminiModel,
|
|
87
86
|
GeminiRes,
|
|
88
87
|
HotStatus,
|
|
89
88
|
LinkType,
|
|
90
89
|
OrderErr,
|
|
91
90
|
OrderStatus,
|
|
91
|
+
PartyType,
|
|
92
92
|
PersonStatus,
|
|
93
93
|
PmType,
|
|
94
94
|
SbpStrict,
|
|
@@ -128,6 +128,12 @@ class Country(BaseCountry):
|
|
|
128
128
|
# fiats: BackwardFKRelation[Fiat]
|
|
129
129
|
|
|
130
130
|
|
|
131
|
+
class City(Model):
|
|
132
|
+
id: int = IntField(True)
|
|
133
|
+
name: str = CharField(63, unique=True)
|
|
134
|
+
country: ForeignKeyRelation[Country] = ForeignKeyField("models.Country", "cities", on_update=CASCADE)
|
|
135
|
+
|
|
136
|
+
|
|
131
137
|
class Cur(Model):
|
|
132
138
|
id = UInt1Field(True)
|
|
133
139
|
ticker: str = CharField(3, unique=True)
|
|
@@ -1464,11 +1470,15 @@ class Pm(Model):
|
|
|
1464
1470
|
class CondParsed(Model, TsTrait):
|
|
1465
1471
|
cond: OneToOneNullableRelation[Cond] = OneToOneField("models.Cond", "parsed", on_update=CASCADE, null=True)
|
|
1466
1472
|
cond_id: int | None # new
|
|
1467
|
-
from_party:
|
|
1468
|
-
to_party:
|
|
1473
|
+
from_party: PartyType | None = IntEnumField(PartyType, null=True) # с чьего счёта платят
|
|
1474
|
+
to_party: PartyType | None = IntEnumField(PartyType, null=True) # на чей счёт платят
|
|
1475
|
+
lk: bool | None = BooleanField(null=True) # лк на руках: True — требует от тейкера, False — есть у мейкера
|
|
1469
1476
|
ppo: int = UInt1Field(null=True) # Payments per order
|
|
1470
1477
|
slip: Slip = IntEnumField(Slip, null=True)
|
|
1471
1478
|
abuser: AbuserType | None = IntEnumField(AbuserType, null=True)
|
|
1479
|
+
cash_city: ForeignKeyNullableRelation[City] = ForeignKeyField(
|
|
1480
|
+
"models.City", "conds", on_update=CASCADE, on_delete=SET_NULL, null=True
|
|
1481
|
+
) # кэш-обменник / встреча за наличные в этом городе
|
|
1472
1482
|
slavic: bool = BooleanField(null=True)
|
|
1473
1483
|
cred: CredType | None = IntEnumField(
|
|
1474
1484
|
CredType, null=True
|
|
@@ -1501,7 +1511,8 @@ class CondParsed(Model, TsTrait):
|
|
|
1501
1511
|
async def answer(cls, cond_id: int, remark: str | bool | None = None) -> bool:
|
|
1502
1512
|
"""Ответ админа на вопрос «сохранить разбор Gemini?» (бот, routers/cond): `remark` None — «да», текст —
|
|
1503
1513
|
«нет» с замечанием, что не так (по нему Claude правит промпт — `CondAi.fix`), "" — «нет», замечание пишется,
|
|
1504
|
-
True — «🔄»: объяву условия заново с биржи (реальный exid мейкера, свежий текст), затем вопрос
|
|
1514
|
+
True — «🔄»: объяву условия заново с биржи (реальный exid мейкера, свежий текст), затем вопрос заново, False —
|
|
1515
|
+
«другая модель»: разбор следующей моделью (`CondAi.reparse`), затем вопрос заново.
|
|
1505
1516
|
Ждёт его прогон lens.parse_conds_admin в ДРУГОМ процессе (скрипт/крон), а ответ ловит бот api — поэтому через
|
|
1506
1517
|
pg_notify, как Agent.confirm_trade; на «да» разбор пишет сам ждущий (у него распарсенные поля).
|
|
1507
1518
|
→ ждёт ли кто-то: без слушателя pg_notify молча пропадает (прогон упал/закончился) — бот скажет это админу.
|
|
@@ -2036,7 +2047,7 @@ class Cred(Model):
|
|
|
2036
2047
|
def repr(self):
|
|
2037
2048
|
xtr = f" ({self.extra})" if self.extra else ""
|
|
2038
2049
|
name = f", имя: {self.name}" if self.name else ""
|
|
2039
|
-
return f"
|
|
2050
|
+
return f"{self.detail}{name}{xtr}"
|
|
2040
2051
|
|
|
2041
2052
|
_UNSET: ClassVar = object() # sentinel: «поле не передано» (отличаем от явного None, который НУЛЯЕТ)
|
|
2042
2053
|
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|