71 lines
4.6 KiB
Markdown
71 lines
4.6 KiB
Markdown
# Остатки счетов из 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.
|