Files
mkd/backend/HOW_REPORTS_WORK.md
2026-02-04 00:17:04 +05:00

136 lines
11 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Как работает обработка отчетов из 1С
## Оборотно-сальдовая ведомость по счету 20
### Распознавание файла
Файл `Оборотно_сальдовая_ведомость_по_счету_20_за_2025_г_ОООружба.csv` **автоматически распознается** как `balance_sheet` по ключевым словам в названии:
- "оборотн"
- "сальд"
- "ведомост"
### Формат CSV (схема колонок и чисел)
- **Разделитель**: точка с запятой (`;`).
- **Кодировка**: UTF-8 (при наличии BOM он автоматически убирается).
- **Строки 19**: метаданные и заголовки (организация, «Счет, Наименование счета», «Обороты за период», «Статьи затрат» и т.д.). Строка начала данных определяется автоматически (по подстроке «Обороты за период» / «Счет, Наименование» или по первой строке, где в колонке 0 есть текст, а в колонке 3 или 4 — число).
**Колонки (индексы 06):**
| Индекс | Содержимое |
|--------|------------|
| 0 | Наименование (адрес дома / номенклатурная группа / статья затрат) |
| 1, 2 | Сальдо на начало периода (Дебет, Кредит), часто пусто |
| **3** | **Обороты за период — Дебет** (источник расходов по счёту 20) |
| 4 | Обороты за период — Кредит |
| 5, 6 | Сальдо на конец периода (Дебет, Кредит) |
**Формат чисел**: пробел — разделитель тысяч, запятая — десятичный знак (например, `2 229,20`). Парсер удаляет пробелы и заменяет запятую на точку.
**Пример строки данных:**
`Булата Имашева 6/1;;;2 229,20;;2 229,20;` — адрес в колонке 0, оборот по дебету (расход) в колонке 3: 2 229,20.
### Куда сохраняются данные
1. **Таблица `financial_reports`**:
- Запись о загруженном файле
- Поля: `id`, `filename`, `file_type`, `uploaded_by`, `status`, `report_type`, `uploaded_at`
- Статус: `processing``completed` / `partial` / `failed`
2. **Таблица `building_financial_data`**:
- Финансовые данные по каждому дому
- Поля:
- `building_id` - ID дома из таблицы `buildings`
- `report_id` - ID отчета из `financial_reports`
- `period_start`, `period_end`, `period_type` - период (извлекается из названия файла)
- `total_income` - общий доход
- `total_expenses` - общие расходы
- `expenses_by_items` - JSONB с разбивкой по статьям: `{"Группа > Статья": сумма}`
- `balance` - баланс
- `metadata` - JSONB с полной структурой групп и статей
### Как извлекаются адреса
Функция `isBuildingAddress()` определяет адрес дома по следующим признакам:
- Содержит буквы (название улицы) И цифры (номер дома)
- Паттерны: `"6/1"`, `"Булата Имашева 6/1"`, `"Авроры 5/12"`
- НЕ является счетом (20, 20.01)
- НЕ является статьей затрат
**Важно**: Чтобы данные по адресу попали в отчёт, адрес из файла должен быть найден в системе. Поиск выполняется в таком порядке:
1. Таблица **`doma_address_mappings`** — по нормализованному адресу (LOWER, TRIM) ищется `building_id`. Это позволяет явно связать адрес из 1С/ОСВ (например, «Авроры 5/12», «Булата Имашева 6/1») с домом в системе.
2. Таблица **`buildings`** — по полному совпадению `data->'passport'->>'address'`, затем без учёта регистра и пробелов, затем по нормализованному адресу (без «ул.», «д.», запятых), затем по основной части адреса (ILIKE).
Если дом не найден ни одним способом, данные по этому адресу пропускаются и адрес добавляется в `error_log` отчета.
### Примеры адресов из файла
-**"Булата Имашева 6/1"** - распознается (есть цифры и буквы)
-**"Авроры 5/12"** - распознается (есть цифры и буквы)
- ⚠️ **"Зеленая Роща"** - НЕ распознается как адрес дома (нет цифр в первой колонке)
- Это может быть участок или комплекс, но не отдельный дом
- Если это участок, данные по нему не сохранятся в `building_financial_data`
### Структура данных в `expenses_by_items`
```json
{
"Административно-управленческие расходы > Набор персонала": 805.84,
"Административно-управленческие расходы > Налоги": 4416.06,
"Текущее обслуживание общедомового имущества > Ремонт кровли": 34000.00,
...
}
```
### Где посмотреть загруженные данные
1. **Список отчетов**: Вкладка "Отчеты" → "Загруженные отчеты"
2. **Детали отчета**: Клик на отчет → показывает дома, участки, детальную разбивку
3. **Данные по дому**: В паспорте дома → раздел "Финансы" → данные из `building_financial_data`
### Проблемы и решения
**Проблема**: "Дом не найден в базе"
- **Причина**: Адрес из файла не найден ни в `doma_address_mappings`, ни в таблице `buildings` (с учётом нормализации).
- **Решение**: Добавить запись в `doma_address_mappings` (адрес из ОСВ`building_id`), либо привести адрес дома в паспорте к формату из файла, либо добавить дом вручную.
**Проблема**: "Зеленая Роща" не распознается
- **Причина**: Нет цифр в первой колонке (это участок, а не дом)
- **Решение**: Если это участок, данные должны быть привязаны к конкретным домам внутри участка
---
## Оборотно-сальдовая ведомость по счёту 76.06 (лицевые счета жителей)
### Назначение
ОСВ по счёту 76.06 содержит **лицевые счета** (жители/собственники): в 1С колонка может называться «Контрагенты», по смыслу это лицевые счета с суммами (обороты, сальдо).
### Распознавание файла
- По названию файла: подстроки `"76"`, `"76.06"`, `"счету 76"` (без учёта регистра) — тип `balance_sheet_76`.
- По фронту: при выборе типа «ОСВ по счёту 76» передаётся `detailedReportType: 'balance_sheet_76'`.
### Формат CSV (схема колонок)
- Разделитель `;`, кодировка UTF-8, BOM убирается.
- Строки 18: метаданные, заголовки «Счет», «Контрагенты», «Дебет», «Кредит». Начало данных определяется автоматически (по «Обороты за период» / «Контрагенты» или по первой строке с числом в колонке 3/4).
- Колонки те же, что у ОСВ 20: 0 — наименование (лицевой счёт: код + ФИО (л/с) или просто ФИО/ИП/юрлицо); 1, 3, 4, 5, 6 — сальдо на начало, обороты дебет/кредит, сальдо на конец. Пропускаются строки с колонкой 0 = `76.06` или `Итого`.
### Куда сохраняются данные
1. **Таблица `financial_reports`**: запись с `report_type = 'balance_sheet_76'`.
2. **Таблица `report_76_rows`**: по одной строке на каждый лицевой счёт (report_id, row_index, account_label, account_ls, saldo_start_debet, turnover_debet, turnover_credit, saldo_end_debet, saldo_end_credit).
3. **Таблица `building_personal_account_mappings`** (сопоставление домов и лицевых счетов): привязка лицевого счёта к дому (building_id, account_ls, account_label, apartment). Используется для фильтра «ОСВ 76 по дому» и отображения данных 76 в карточке дома. Заполняется вручную или импортом.
### API
- `GET /api/finance/reports/:reportId/balance-sheet-76-rows` — строки отчёта (лицевые счета). Опциональный параметр `buildingId`: при указании возвращаются только строки, чей лицевой счёт привязан к этому дому в `building_personal_account_mappings`.
- `GET /api/finance/buildings/:buildingId/personal-accounts` — лицевые счета, привязанные к дому.
- `POST /api/finance/building-personal-account-mappings` — добавить/обновить привязку (body: building_id, account_ls, опционально account_label, apartment).
### Где посмотреть
1. **Список отчетов**: Финансы → Отчеты; фильтр «Лицевые счета (ОСВ 76)».
2. **Детали отчёта**: Клик на отчёт ОСВ 76 → таблица лицевых счетов (колонки: Лицевой счёт, Сальдо на начало, Обороты дебет/кредит, Сальдо на конец). При наличии маппинга можно добавить фильтр по дому.