diff --git a/personal/projects/budget-app/index.md b/personal/projects/budget-app/index.md index 040e904c..a070dcbf 100644 --- a/personal/projects/budget-app/index.md +++ b/personal/projects/budget-app/index.md @@ -455,30 +455,48 @@ API возвращает `t.date.isoformat()` → `2026-05-29T17:00:00`. Файлы: `frontend/src/pages/Transactions.vue`, `Accounts.vue`, `TaxRecords.vue` — каждая содержит `CURRENCY_SYMBOLS` маппинг и функцию `getCurrencySymbol`/`currencySymbol`. -### Страница быстрого ввода наличных +### БД: исправление типа кредиток + +Четыре кредитных счета были ошибочно импортированы как `type='debit'` вместо `type='credit'`. Исправлено вручную: +```sql +UPDATE account SET type = 'credit' WHERE name ILIKE '%кредитка%'; +``` +Затронуты: Альфа Кредитка, Сбер Кредитка, ВТБ Кредитка, Тинькофф Кредитка. +Модель `AccountType` поддерживает `credit` с самого начала — это была неточность импорта из Excel. + +### Страница быстрого ввода наличных — CashInput (2026-06-23) **Файл:** `frontend/src/pages/CashInput.vue` **Маршрут:** `/cash` +**Хедер:** скрыт на этой странице (App.vue проверяет `route.name === 'CashInput'`) -Одна страница с двумя режимами, переключаемыми сегмент-кнопкой: +Одна страница с двумя режимами, переключаемыми сегмент-кнопкой. **Режим «Расход» (по умолчанию):** -- Выбор наличного счёта (type=cash) — чипами, последний сохраняется в localStorage -- Поле суммы (крупное, центрированное) -- Чипы с топ-категориями наличных расходов (Grocery, Рестораны, Стройка, Быт/Техника, Дети, Отдых, Медицина, Авто, Транспорт/АЗС, Жена, Одежда, Кредиты, Квартплата, Аренда, Прочее) -- Кнопка «Другое» → раскрывающийся список всех остальных категорий по группам +- Выбор наличного счёта (type=cash) — чипами, последний сохраняется в `localStorage` под ключом `cash_last_account_id` +- Поле суммы (крупное, центрированное, автофокус) +- Чипы с топ-категориями наличных расходов (15 штук, по частоте из БД): + 🛒 Grocery, 🍣 Рестораны, 🛠️ Быт/Техника, 🧱 Стройка, 🧸 Дети, 🏖️ Отдых, 💊 Медицина, 🚙 Авто, ⛽️ Транспорт/АЗС, 👰‍♀️ Жена, 👚 Одежда, 💷 Кредиты, 📟 Квартплата/Связь, 🏢 Аренда, Прочее +- Без кнопки «Другое» — все уникальные категории уже в списке, других нет в БД - Опциональный комментарий - POST /api/transactions (source_account → NULL) **Режим «Обмен валюты»:** - Селекты счёт-источник / счёт-получатель (фильтр: другая валюта) -- Сумма (отдаю), Курс, Получу — три поля с двусторонним пересчётом: - - меняешь сумму → получу = сумма * курс - - меняешь курс → получу = сумма * курс - - меняешь получу → курс = получу / сумма +- Сумма (отдаю), Курс, Получу — три поля с двусторонним пересчётом (через `_updating` флаг для защиты от циклов): + - меняешь сумму → `получу = сумма * курс` + - меняешь курс → `получу = сумма * курс` + - меняешь получу → `курс = получу / сумма` - Комментарий (предзаполнен «Обмен валюты») - POST /api/transactions (source → dest с cross_rate) +**Технические детали и исправления, которые были сделаны:** +1. **Дата** — `new Date()` форматируется как `YYYY-MM-DDTHH:mm` (локальное время без TZ и миллисекунд). Через `localNow()` helper. Это критично: `new Date().toISOString()` даёт UTC c `Z`, что падает на бэкенде (`can't subtract offset-naive and offset-aware datetimes` — Pydantic парсит как offset-aware, а SQLAlchemy вставляет в `TIMESTAMP WITHOUT TIME ZONE`). +2. **Чипы — `type="button"`** — все `