4.6 KiB
Остатки счетов из Excel (Budget.xlsx)
Файл: ~/Downloads/Budget.xlsx
Лист: транзакции
Балансы совпадают с API после фиксов (2026-06-23).
| Счёт | Баланс | Валюта | Последняя операция |
|---|---|---|---|
| Нал RUB | 815 555.70 | RUB | 2025-05-16 (R6029, 60 000 deb) |
| Нал KGS | 1 794.00 | KGS | 2025-06-17 (R6042, deb) |
| Нал KZT | -22 820.00 | KZT | 2024-12-15 (R5505, deb) |
| Нал USD | 1.00 | USD | 2025-02-04 (R5976, deb) |
| Нал AED | 0.00 | AED | 2023-11-16 (R2335, deb) |
| Нал EUR | — | EUR | нет операций |
| Нал UZS | 18 000.35 | UZS | 2024-03-31 (R3337, deb) |
| Demir ИП | 192 308.54 | KGS | 2025-01-31 (R5943, deb) |
| Demir ИП USD | 284 842.96 | USD | 2026-05-29 (R6053, cred) |
| Demir KGS | 96 013.12 | KGS | 2025-01-31 (R5947, deb) |
| Demir USD | 3 394.29 | USD | 2025-01-31 (R5950, cred) |
| Тинькофф Black | 521 263.65 | RUB | 2025-01-31 (R5959, deb) |
| Тинькофф Кредитка | 7 170.17 | RUB | 2025-01-28 (R5901, deb) |
| Сбер | 266 905.98 | RUB | 2025-01-28 (R5898, deb) |
| Сбер Кредитка | 3 059.00 | RUB | 2025-01-31 (R5946, deb) |
| Альфа | 78 030.00 | RUB | 2025-01-28 (R5925, cred) |
| Альфа Кредитка | 0.50 | RUB | 2025-01-28 (R5924, deb) |
| ВТБ | 265 178.95 | RUB | 2025-01-27 (R5887, deb) |
| ВТБ Кредитка | 297 189.00 | RUB | 2025-01-31 (R5952, deb) |
| Райффайзен | — | RUB | нет операций |
Формула API
balance = incoming_transfer + incoming_income - outgoing + initial_balance
Где:
incoming_transfer—SUM(cross_rate * amount)где source IS NOT NULL (cross_rate конвертирует валюту source в валюту dest)incoming_income—SUM(amount)где source IS NULL (amount уже в валюте счёта, cross_rate — только для отчёта)outgoing—SUM(amount)(всегда в валюте счёта-источника)
Фиксы (2026-06-23)
1. incoming для income и transfer — разный расчёт
Было: incoming = SUM(COALESCE(cross_rate, 1.0) * amount) — cross_rate применялся ко всем включая income (где amount уже в валюте счёта). Для KGS-счетов с income-пополнениями (например "Конвертация USD по курсу 87") incoming умножался на 87, давая баланс ×87.
Стало: incoming разделён на две части:
incoming_transfer (source IS NOT NULL): cross_rate применяется (конвертирует валюту source→dest)incoming_income (source IS NULL): просто amount (cross_rate — только для отчётной валюты)
2. import_hash и on_conflict_do_nothing — удалены
Было: дедупликация по import_hash = SHA256(date|amount|source|dest|comment). В Excel есть 141 дублирующаяся строка с одинаковыми этими полями (реальные повторные списания). on_conflict_do_nothing молча пропускал их, но tx_count врал что импортировал.
Стало: обычный session.add(tx). Колонка import_hash и уникальный индекс дропнуты из таблицы. Функция _make_import_hash удалена.
3. Accounts — идемпотентность
Было: каждый запуск импорта создавал 20 новых аккаунтов (session.add). После нескольких запусков — 40+ аккаунтов с разными UUID, транзакции привязаны к разным наборам.
Стало: UPSERT — ищет существующий account по name + user_id, переиспользует.
4. UserSettings — UPSERT
Было: session.add(UserSettings(...)) — падало с UniqueViolation при повторном запуске.
Стало: pg_insert(...).on_conflict_do_update(...).
5. Нюанс Excel col I/L
Для некоторых строк Excel не кеширует вычисленные значения col I (остаток деб) — показывает None. Это не баг, а особенность data_only=True — если Excel не пересчитал формулы перед сохранением, кеш пуст. В таких случаях последний корректный баланс берётся из предыдущей строки минус amount.