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:
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<ValCurs Date="17.09.2026" name="Foreign Currency Market">
|
||||
<Valute ID="R01235">
|
||||
<NumCode>840</NumCode>
|
||||
<CharCode>USD</CharCode>
|
||||
<Nominal>1</Nominal>
|
||||
<Name>Äîëëàð ÑØÀ</Name>
|
||||
<Value>92,1234</Value>
|
||||
<VunitRate>92,1234</VunitRate>
|
||||
</Valute>
|
||||
<Valute ID="R01820">
|
||||
<NumCode>392</NumCode>
|
||||
<CharCode>JPY</CharCode>
|
||||
<Nominal>100</Nominal>
|
||||
<Name>ßïîíñêèõ èåí</Name>
|
||||
<Value>61,5432</Value>
|
||||
<VunitRate>0,615432</VunitRate>
|
||||
</Valute>
|
||||
<Valute ID="R01239">
|
||||
<NumCode>978</NumCode>
|
||||
<CharCode>EUR</CharCode>
|
||||
<Nominal>1</Nominal>
|
||||
<Name>Åâðî</Name>
|
||||
<Value>101,4567</Value>
|
||||
<VunitRate>101,4567</VunitRate>
|
||||
</Valute>
|
||||
</ValCurs>
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<ValCurs ID="R01820" DateRange1="01.09.2026" DateRange2="03.09.2026" name="Foreign Currency Market Dynamic">
|
||||
<Record Date="01.09.2026" Id="R01820">
|
||||
<Nominal>100</Nominal>
|
||||
<Value>61,5432</Value>
|
||||
<VunitRate>0,615432</VunitRate>
|
||||
</Record>
|
||||
<Record Date="02.09.2026" Id="R01820">
|
||||
<Nominal>100</Nominal>
|
||||
<Value>62,0000</Value>
|
||||
<VunitRate>0,62</VunitRate>
|
||||
</Record>
|
||||
</ValCurs>
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<ValCurs ID="R01235" DateRange1="01.09.2026" DateRange2="03.09.2026" name="Foreign Currency Market Dynamic">
|
||||
<Record Date="01.09.2026" Id="R01235">
|
||||
<Nominal>1</Nominal>
|
||||
<Value>92,1234</Value>
|
||||
<VunitRate>92,1234</VunitRate>
|
||||
</Record>
|
||||
<Record Date="02.09.2026" Id="R01235">
|
||||
<Nominal>1</Nominal>
|
||||
<Value>92,5000</Value>
|
||||
<VunitRate>92,5</VunitRate>
|
||||
</Record>
|
||||
<Record Date="03.09.2026" Id="R01235">
|
||||
<Nominal>1</Nominal>
|
||||
<Value>93,0100</Value>
|
||||
<VunitRate>93,01</VunitRate>
|
||||
</Record>
|
||||
</ValCurs>
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"serverTimestamp": 1750000500,
|
||||
"deletion": []
|
||||
}
|
||||
+266
@@ -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": []
|
||||
}
|
||||
Reference in New Issue
Block a user