feat(sources): контракт источников, worker и синк ZenMoney + ЦБ

Source.sync(ctx) -> SyncResult пишет только raw_* и возвращает курсор; локи,
журнал, ошибки и продвижение курсора берёт на себя worker/runner.

ZenMoney читается единственным доступным способом — POST /v8/diff/ по
serverTimestamp; токен живёт сутки, поэтому worker ротирует refresh_token через
source_credential. Маппер всегда пересобирает core из полных raw_*, так что
удаление в ZenMoney исчезает и у нас.

ЦБ ходит мимо прокси (trust_env=False) и отдаёт cp1251 с делением на Nominal.
Курсы только по рабочим дням — протяжку по календарю делает аналитика.

Планировщик — APScheduler в отдельном процессе, на источник advisory-лок
sync:<name>, чтобы ручной запуск не пересёкся с плановым.
This commit is contained in:
Dmitry
2026-09-18 13:43:49 +03:00
parent 3fc7a954b9
commit c55fe19e48
31 changed files with 3713 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
{
"serverTimestamp": 1750001000,
"account": [
{
"id": "aaaaaaaa-0000-0000-0000-000000000001",
"changed": 1750000900,
"user": 555,
"instrument": 2,
"type": "ccard",
"title": "Карта Т-Банк",
"syncID": ["4377"],
"balance": 24000.5,
"startBalance": 0,
"creditLimit": 100000,
"inBalance": true,
"savings": false,
"archive": false,
"enableCorrection": false,
"enableSMS": true
}
],
"deletion": [
{
"id": "dddddddd-0000-0000-0000-000000000006",
"object": "transaction",
"stamp": 1750000950,
"user": 555
}
]
}
+4
View File
@@ -0,0 +1,4 @@
{
"serverTimestamp": 1750000500,
"deletion": []
}
+266
View File
@@ -0,0 +1,266 @@
{
"serverTimestamp": 1750000000,
"instrument": [
{"id": 2, "title": "Российский рубль", "shortTitle": "RUB", "symbol": "₽", "rate": 1, "changed": 1700000000},
{"id": 1, "title": "Доллар США", "shortTitle": "USD", "symbol": "$", "rate": 92.5, "changed": 1700000000}
],
"company": [
{"id": 4711, "title": "Тинькофф", "changed": 1700000000}
],
"user": [
{"id": 555, "country": 1, "login": "ada", "currency": 2, "changed": 1700000000}
],
"account": [
{
"id": "aaaaaaaa-0000-0000-0000-000000000001",
"changed": 1749000000,
"user": 555,
"instrument": 2,
"type": "ccard",
"title": "Карта Тинькофф",
"syncID": ["4377"],
"balance": 25000.5,
"startBalance": 0,
"creditLimit": 100000,
"inBalance": true,
"savings": false,
"archive": false,
"enableCorrection": false,
"enableSMS": true
},
{
"id": "aaaaaaaa-0000-0000-0000-000000000002",
"changed": 1749000001,
"user": 555,
"instrument": 1,
"type": "cash",
"title": "Наличные USD",
"balance": 300.25,
"startBalance": 0,
"creditLimit": 0,
"inBalance": true,
"savings": false,
"archive": false,
"enableCorrection": false,
"enableSMS": false
},
{
"id": "aaaaaaaa-0000-0000-0000-000000000003",
"changed": 1749000002,
"user": 555,
"instrument": 2,
"type": "deposit",
"title": "Вклад",
"balance": 500000,
"startBalance": 400000,
"creditLimit": 0,
"inBalance": true,
"savings": true,
"archive": false,
"enableCorrection": false,
"enableSMS": false,
"capitalization": true,
"percent": 16.5,
"startDate": "2025-02-01",
"endDateOffset": 12,
"endDateOffsetInterval": "month",
"payoffStep": 1,
"payoffInterval": "month"
},
{
"id": "aaaaaaaa-0000-0000-0000-000000000009",
"changed": 1749000003,
"user": 555,
"instrument": 2,
"type": "debt",
"title": "Долги",
"balance": 0,
"startBalance": 0,
"creditLimit": 0,
"inBalance": false,
"savings": false,
"archive": false,
"enableCorrection": false,
"enableSMS": false
}
],
"tag": [
{
"id": "bbbbbbbb-0000-0000-0000-000000000001",
"changed": 1748000000,
"user": 555,
"title": "Еда",
"parent": null,
"icon": "food",
"color": 4294198070,
"showIncome": false,
"showOutcome": true,
"budgetIncome": false,
"budgetOutcome": true,
"required": false
},
{
"id": "bbbbbbbb-0000-0000-0000-000000000002",
"changed": 1748000001,
"user": 555,
"title": "Кафе",
"parent": "bbbbbbbb-0000-0000-0000-000000000001",
"icon": "cafe",
"color": null,
"showIncome": false,
"showOutcome": true,
"budgetIncome": false,
"budgetOutcome": true,
"required": false
},
{
"id": "bbbbbbbb-0000-0000-0000-000000000003",
"changed": 1748000002,
"user": 555,
"title": "Зарплата",
"parent": null,
"icon": null,
"color": null,
"showIncome": true,
"showOutcome": false,
"budgetIncome": true,
"budgetOutcome": false,
"required": false
}
],
"merchant": [
{"id": "cccccccc-0000-0000-0000-000000000001", "changed": 1748500000, "user": 555, "title": "Кофейня"}
],
"budget": [],
"reminder": [],
"reminderMarker": [],
"transaction": [
{
"id": "dddddddd-0000-0000-0000-000000000001",
"changed": 1749500000,
"created": 1749500000,
"user": 555,
"deleted": false,
"hold": false,
"income": 0,
"outcome": 350.4,
"incomeAccount": "aaaaaaaa-0000-0000-0000-000000000001",
"outcomeAccount": "aaaaaaaa-0000-0000-0000-000000000001",
"incomeInstrument": 2,
"outcomeInstrument": 2,
"tag": ["bbbbbbbb-0000-0000-0000-000000000002", "bbbbbbbb-0000-0000-0000-000000000001"],
"merchant": "cccccccc-0000-0000-0000-000000000001",
"payee": "COFFEE HOUSE",
"originalPayee": "COFFEE HOUSE MOSCOW",
"comment": "флэт уайт",
"date": "2025-09-01",
"mcc": 5812,
"latitude": 55.75,
"longitude": 37.61
},
{
"id": "dddddddd-0000-0000-0000-000000000002",
"changed": 1749500100,
"created": 1749500100,
"user": 555,
"deleted": false,
"hold": false,
"income": 180000,
"outcome": 0,
"incomeAccount": "aaaaaaaa-0000-0000-0000-000000000001",
"outcomeAccount": "aaaaaaaa-0000-0000-0000-000000000001",
"incomeInstrument": 2,
"outcomeInstrument": 2,
"tag": ["bbbbbbbb-0000-0000-0000-000000000003"],
"merchant": null,
"payee": null,
"originalPayee": null,
"comment": "зарплата за август",
"date": "2025-09-05",
"mcc": null
},
{
"id": "dddddddd-0000-0000-0000-000000000003",
"changed": 1749500200,
"created": 1749500200,
"user": 555,
"deleted": false,
"hold": false,
"income": 50000,
"outcome": 50000,
"incomeAccount": "aaaaaaaa-0000-0000-0000-000000000003",
"outcomeAccount": "aaaaaaaa-0000-0000-0000-000000000001",
"incomeInstrument": 2,
"outcomeInstrument": 2,
"tag": null,
"merchant": null,
"payee": null,
"comment": "на вклад",
"date": "2025-09-06",
"mcc": null
},
{
"id": "dddddddd-0000-0000-0000-000000000004",
"changed": 1749500300,
"created": 1749500300,
"user": 555,
"deleted": false,
"hold": false,
"income": 0,
"outcome": 19.99,
"incomeAccount": "aaaaaaaa-0000-0000-0000-000000000002",
"outcomeAccount": "aaaaaaaa-0000-0000-0000-000000000002",
"incomeInstrument": 1,
"outcomeInstrument": 1,
"opOutcome": 1850.5,
"opOutcomeInstrument": 2,
"tag": [],
"merchant": null,
"payee": "APPLE",
"comment": null,
"date": "2025-09-07",
"mcc": 5734
},
{
"id": "dddddddd-0000-0000-0000-000000000005",
"changed": 1749500400,
"created": 1749500400,
"user": 555,
"deleted": true,
"hold": false,
"income": 0,
"outcome": 999,
"incomeAccount": "aaaaaaaa-0000-0000-0000-000000000001",
"outcomeAccount": "aaaaaaaa-0000-0000-0000-000000000001",
"incomeInstrument": 2,
"outcomeInstrument": 2,
"tag": null,
"merchant": null,
"payee": "ОШИБКА",
"comment": null,
"date": "2025-09-08",
"mcc": null
},
{
"id": "dddddddd-0000-0000-0000-000000000006",
"changed": 1749500500,
"created": 1749500500,
"user": 555,
"deleted": false,
"hold": true,
"income": 0,
"outcome": 1200,
"incomeAccount": "aaaaaaaa-0000-0000-0000-000000000001",
"outcomeAccount": "aaaaaaaa-0000-0000-0000-000000000001",
"incomeInstrument": 2,
"outcomeInstrument": 2,
"tag": null,
"merchant": null,
"payee": "АЗС",
"comment": null,
"date": "2025-09-09",
"mcc": 5541
}
],
"deletion": []
}