Merge pull request '[AURORA-2006] - Гудвилл (вкладка): мелкие дефекты после ревью' (#244) from fix/2006-goodwill into main
This commit is contained in:
commit
0547b8fcde
37
openspec/changes/goodwill-ui-errors/proposal.md
Normal file
37
openspec/changes/goodwill-ui-errors/proposal.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# Proposal
|
||||||
|
|
||||||
|
## Why
|
||||||
|
|
||||||
|
AURORA-2006 (PR arm-core #244): дефекты вкладки «Гудвилл», отложенные финальным ревью PR #220 (AURORA-1544).
|
||||||
|
- Ответы 409 и 404 на «Сохранить» не перечитывали таблицу: если версию забрал другой пользователь, экран оставался
|
||||||
|
редактируемым и каждое «Сохранить» снова получало 409; при 404 по исчезнувшей паре подсвечивалась доля строки.
|
||||||
|
- Стрелка раскрытия блока была привязана к номеру колонки: если скрыть «Учет в отчете» в «Настройке таблицы», стрелка
|
||||||
|
уезжала в другую колонку.
|
||||||
|
- После ошибки загрузки таблица писала «Вложений по 58.01 между компаниями периметра нет» вместо ошибки.
|
||||||
|
|
||||||
|
## What Changes
|
||||||
|
|
||||||
|
- 409 и 404 на «Сохранить» и на переключатель «Учитывать гудвилл в КФО» — уведомление с текстом сервера и перечитывание
|
||||||
|
таблицы, без подсветки строки; если после перечитывания `editable = false`, режим редактирования закрывается и
|
||||||
|
введённое сбрасывается. Так же, как в таблице корректировок (`errorOutcome`).
|
||||||
|
- Стрелка раскрытия блока — в колонке «Наименование дочерней организации», где бы она ни стояла; колонка скрыта — в первой
|
||||||
|
видимой.
|
||||||
|
- Ошибка загрузки — текст ошибки и кнопка «Повторить» вместо таблицы.
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
### Modified Capabilities
|
||||||
|
|
||||||
|
- `goodwill-ui` — «Таблица гудвилла»: стрелка блока и ошибка загрузки; «Редактирование таблицы гудвилла»: 409/404 при
|
||||||
|
сохранении; «Переключатель, фильтр и экспорт гудвилла»: 409/404 при переключении.
|
||||||
|
|
||||||
|
## Impact
|
||||||
|
|
||||||
|
Только фронт arm-core: `web/src/widgets/ConsolidationGoodwill/*`, `web/src/types/goodwill/goodwill.ts` (типы `Ref` и
|
||||||
|
причина «только чтение» — из `types/corrections.ts`), `web/src/hooks/useFullscreen.ts` (переименован из
|
||||||
|
`useFullScreen.tsx`). API, DBML, правила `05-domain-rules.md` не меняются.
|
||||||
|
|
||||||
|
## Non-goals
|
||||||
|
|
||||||
|
- Сверка предпросмотра P/G с ответом сервера на реальной паре 58.01 — проверка после выкладки (AURORA-2006, раздел
|
||||||
|
«Проверить после выкладки»), не код.
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
## MODIFIED Requirements
|
||||||
|
|
||||||
|
### Requirement: Таблица гудвилла
|
||||||
|
Вкладка `goodwill` страницы отчёта версии SHALL загружать таблицу одним запросом `GET /consolidations/versions/{id}/goodwill`
|
||||||
|
(контракт `../docs/dev/api-contract-goodwill.md`) и показывать блоки по ГО в порядке ответа: строка ГО, строки ДО, строка
|
||||||
|
«Всего» блока из `groups[].totals`, внизу «Итого по листу» из `totals`. Колонки — по макету `[31-03]`: «Учет в отчете»,
|
||||||
|
«Наименование дочерней организации», «Доля владения», «Фондовые вложения головной организации», «Доля участия головной
|
||||||
|
организации в уставном капитале», «Уставный капитал», «Гудвилл (+/-)», «Комментарий». Сумма `null` SHALL показываться
|
||||||
|
прочерком, ноль — нулём в выбранных единицах; итоги фронт MUST NOT считать сам. Стрелка раскрытия блока SHALL стоять в
|
||||||
|
колонке «Наименование дочерней организации» при любом наборе видимых колонок; если эта колонка скрыта — в первой видимой.
|
||||||
|
Если загрузка не удалась, вместо таблицы SHALL показываться текст ошибки (сообщение сервера или «Не удалось загрузить
|
||||||
|
таблицу гудвилла») и кнопка «Повторить»; сообщение «Вложений по 58.01 между компаниями периметра нет» MUST NOT
|
||||||
|
показываться при ошибке.
|
||||||
|
|
||||||
|
#### Scenario: Нулевой и нерассчитанный гудвилл
|
||||||
|
- **WHEN** у одной строки `goodwill_amount = "0.00"`, у другой `null`
|
||||||
|
- **THEN** первая показывает «0,00», вторая — «—»
|
||||||
|
|
||||||
|
#### Scenario: Строка «Нет вложений»
|
||||||
|
- **WHEN** у строки `has_investments = false`
|
||||||
|
- **THEN** строка серая, с меткой «Нет вложений», чекбокс недоступен, суммы — прочерки, сохранённые доля и комментарий видны
|
||||||
|
|
||||||
|
#### Scenario: Предупреждения
|
||||||
|
- **WHEN** у строки есть `warnings` (например, `CAPITAL_SOURCE_MISSING`)
|
||||||
|
- **THEN** рядом с названием ДО иконка предупреждения, по наведению — тексты `message`
|
||||||
|
|
||||||
|
#### Scenario: Стрелка блока при скрытой колонке
|
||||||
|
- **WHEN** в «Настройке таблицы» снята колонка «Учет в отчете»
|
||||||
|
- **THEN** стрелка раскрытия блока остаётся в колонке «Наименование дочерней организации»
|
||||||
|
|
||||||
|
#### Scenario: Ошибка загрузки
|
||||||
|
- **WHEN** `GET …/goodwill` отвечает ошибкой
|
||||||
|
- **THEN** вместо таблицы — текст ошибки и «Повторить»; «Повторить» запрашивает таблицу заново и при успехе показывает её
|
||||||
|
|
||||||
|
### Requirement: Редактирование таблицы гудвилла
|
||||||
|
Кнопка «Редактировать» SHALL быть доступна при `editable = true`; иначе — недоступна с подсказкой причины
|
||||||
|
(`read_only_reason`). В режиме редактирования (баннер «Доступны для редактирования столбцы «Доля владения» и
|
||||||
|
«Комментарий».») у действующих строк доступна галочка; у отмеченной действующей строки — поля доли и комментария, P и G
|
||||||
|
строки SHALL пересчитываться предварительно по введённой доле. Доля — 0–100, не больше двух знаков, запятая или точка;
|
||||||
|
ошибочная доля MUST NOT обрезаться или подменяться, а показывается ошибкой у поля. «Сохранить» SHALL быть недоступно,
|
||||||
|
пока у отмеченной действующей строки нет корректной доли или комментария. Групповой чекбокс блока SHALL отмечать и снимать
|
||||||
|
все действующие строки блока, включая скрытые фильтром, и показывать промежуточное состояние при частичном выборе.
|
||||||
|
«Отменить изменения» SHALL возвращать последнее сохранённое состояние. На ответ 409 (версия закрыта, блокировку забрали)
|
||||||
|
или 404 (пары уже нет) при «Сохранить» экран SHALL показать уведомление с текстом сервера и перечитать таблицу, строку
|
||||||
|
MUST NOT подсвечивать; если после перечитывания `editable = false`, режим редактирования SHALL закрыться, введённое —
|
||||||
|
сброситься.
|
||||||
|
|
||||||
|
#### Scenario: Сохранение набора
|
||||||
|
- **WHEN** аналитик отметил две строки, ввёл доли «80,5» и «100» и комментарии и нажал «Сохранить»
|
||||||
|
- **THEN** уходит один `PUT …/goodwill` только с изменёнными строками; ответ заменяет таблицу, режим редактирования закрывается
|
||||||
|
|
||||||
|
#### Scenario: Снятие галочки у строки без доли
|
||||||
|
- **WHEN** аналитик снимает галочку у строки, где доля не вводилась, и сохраняет
|
||||||
|
- **THEN** строка уходит с `ownership_share: null` и сохраняется без ошибки
|
||||||
|
|
||||||
|
#### Scenario: Ошибка строки от сервера
|
||||||
|
- **WHEN** сервер отвечает 422 `COMMENT_REQUIRED` с ключом пары
|
||||||
|
- **THEN** поле комментария этой строки подсвечено ошибкой, режим редактирования не закрыт, введённое не потеряно
|
||||||
|
|
||||||
|
#### Scenario: Лишние знаки доли
|
||||||
|
- **WHEN** аналитик вводит долю «80,123»
|
||||||
|
- **THEN** у поля ошибка «Число от 0 до 100, не больше двух знаков после запятой», значение в поле не меняется, «Сохранить» недоступно
|
||||||
|
|
||||||
|
#### Scenario: Версию забрал другой пользователь
|
||||||
|
- **WHEN** аналитик в режиме редактирования нажимает «Сохранить», сервер отвечает 409 `LOCKED_BY_OTHER`, перечитанная
|
||||||
|
таблица приходит с `editable = false`
|
||||||
|
- **THEN** уведомление с текстом сервера, режим редактирования закрыт, показаны сохранённые значения, «Редактировать»
|
||||||
|
недоступна с подсказкой «Консолидацию редактирует другой пользователь»
|
||||||
|
|
||||||
|
#### Scenario: Пары больше нет
|
||||||
|
- **WHEN** сервер отвечает на «Сохранить» 404 по паре, которой больше нет в версии
|
||||||
|
- **THEN** уведомление с текстом сервера, таблица перечитана, ни одна строка не подсвечена; правки этой пары в запрос
|
||||||
|
больше не попадают
|
||||||
|
|
||||||
|
### Requirement: Переключатель, фильтр и экспорт гудвилла
|
||||||
|
Панель вкладки SHALL содержать переключатель «Учитывать гудвилл в КФО» (`PUT …/goodwill-settings`, доступен при
|
||||||
|
`editable` вне режима редактирования) с подписью суммы `goodwill_in_kfo_amount` или «Гудвилл не учитывается в КФО»;
|
||||||
|
фильтр «Гудвилл»: «Все значения», «Положительные», «Отрицательные», «Нулевые» (нерассчитанный гудвилл — только во «Все
|
||||||
|
значения»); единицы и знаки после запятой; «Настройка таблицы»; «Экспорт» — `GET …/goodwill/export` с текущим фильтром
|
||||||
|
(`sign`); «На весь экран». На ответ 409 или 404 при переключении экран SHALL показать уведомление с текстом сервера и
|
||||||
|
перечитать таблицу.
|
||||||
|
|
||||||
|
#### Scenario: Экспорт с фильтром
|
||||||
|
- **WHEN** выбран фильтр «Положительные» и нажат «Экспорт»
|
||||||
|
- **THEN** запрос уходит с `sign=positive`
|
||||||
|
|
||||||
|
#### Scenario: Выключение гудвилла
|
||||||
|
- **WHEN** аналитик выключает переключатель
|
||||||
|
- **THEN** таблица перечитывается из ответа, под переключателем подпись «Гудвилл не учитывается в КФО», ручной ввод строк не меняется
|
||||||
|
|
||||||
|
#### Scenario: Переключатель после закрытия версии
|
||||||
|
- **WHEN** аналитик переключает «Учитывать гудвилл в КФО», а сервер отвечает 409 `VERSION_NOT_EDITABLE`
|
||||||
|
- **THEN** уведомление с текстом сервера, таблица перечитана, переключатель недоступен
|
||||||
9
openspec/changes/goodwill-ui-errors/tasks.md
Normal file
9
openspec/changes/goodwill-ui-errors/tasks.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Tasks
|
||||||
|
|
||||||
|
- [x] 1.1 arm-core `web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillContent` — 409/404 при «Сохранить» и при
|
||||||
|
переключателе: `errorOutcome`, перечитывание, выход из редактирования при `editable = false` (PR #244, автор)
|
||||||
|
- [x] 1.2 arm-core `web/src/widgets/ConsolidationGoodwill/ConsolidationGoodwillTable` — стрелка блока по ключу колонки
|
||||||
|
`name`; лишний CSS шахматки удалён (PR #244, автор)
|
||||||
|
- [x] 1.3 arm-core `web/` — ошибка загрузки с «Повторить»; `useFullscreen.ts`; типы из `types/corrections.ts` (PR #244, автор)
|
||||||
|
- [x] 1.4 Ревью: прогон в браузере на ГК «Пример» 2025 К3 — скрытие «Учет в отчете», 409 на `PUT …/goodwill` с
|
||||||
|
перечитыванием `editable = false`, 500 на `GET …/goodwill` и «Повторить» (ответы сервера подменены в Playwright)
|
||||||
@ -1,8 +1,5 @@
|
|||||||
/** DTO таблицы гудвилла — по `api/src/schemas/goodwill.py` и `../docs/dev/api-contract-goodwill.md`. Деньги и доля — строки. */
|
/** DTO таблицы гудвилла — по `api/src/schemas/goodwill.py` и `../docs/dev/api-contract-goodwill.md`. Деньги и доля — строки. */
|
||||||
export interface Ref {
|
import type { ReadOnlyReason, Ref } from '../corrections';
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GoodwillWarning {
|
export interface GoodwillWarning {
|
||||||
code: 'CAPITAL_SOURCE_MISSING' | 'CAPITAL_SOURCE_AMBIGUOUS' | 'OWNERSHIP_TOTAL_EXCEEDED' | string;
|
code: 'CAPITAL_SOURCE_MISSING' | 'CAPITAL_SOURCE_AMBIGUOUS' | 'OWNERSHIP_TOTAL_EXCEEDED' | string;
|
||||||
@ -42,13 +39,11 @@ export interface GoodwillGroup {
|
|||||||
totals: GoodwillTotals;
|
totals: GoodwillTotals;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GoodwillReadOnlyReason = 'VERSION_NOT_EDITABLE' | 'LOCK_REQUIRED' | 'LOCKED_BY_OTHER';
|
|
||||||
|
|
||||||
export interface GoodwillTableResponse {
|
export interface GoodwillTableResponse {
|
||||||
version_id: string;
|
version_id: string;
|
||||||
goodwill_enabled: boolean;
|
goodwill_enabled: boolean;
|
||||||
editable: boolean;
|
editable: boolean;
|
||||||
read_only_reason: GoodwillReadOnlyReason | null;
|
read_only_reason: ReadOnlyReason | null;
|
||||||
rows: GoodwillRow[];
|
rows: GoodwillRow[];
|
||||||
groups: GoodwillGroup[];
|
groups: GoodwillGroup[];
|
||||||
totals: GoodwillTotals;
|
totals: GoodwillTotals;
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
import { DownloadOutlined, EditOutlined, FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons';
|
import { DownloadOutlined, EditOutlined, FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons';
|
||||||
import { Alert, Button, ConfigProvider, Select, Space, Switch, Tooltip, Typography } from 'antd';
|
import { Alert, Button, ConfigProvider, Flex, Select, Space, Switch, Tooltip, Typography } from 'antd';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { ApiError } from '../../../api/client';
|
import { ApiError } from '../../../api/client';
|
||||||
import { ConsolidationFormatTableFilter } from '../../../components/ConsolidationFormatTableFilter/ConsolidationFormatTableFilter';
|
import { ConsolidationFormatTableFilter } from '../../../components/ConsolidationFormatTableFilter/ConsolidationFormatTableFilter';
|
||||||
import { type ColumnDef, ColumnSettings, useVisibleColumns } from '../../../components/GenericTable';
|
import { type ColumnDef, ColumnSettings, useVisibleColumns } from '../../../components/GenericTable';
|
||||||
import { useFullscreen } from '../../../hooks/useFullScreen';
|
import { useFullscreen } from '../../../hooks/useFullscreen';
|
||||||
import { exportGoodwillTable, fetchGoodwillTable, saveGoodwillRows, saveGoodwillSettings } from '../../../services/api/goodwill';
|
import { exportGoodwillTable, fetchGoodwillTable, saveGoodwillRows, saveGoodwillSettings } from '../../../services/api/goodwill';
|
||||||
import type { VersionCard } from '../../../types/consolidations/version_members';
|
import type { VersionCard } from '../../../types/consolidations/version_members';
|
||||||
import type { GoodwillEdit, GoodwillSign, GoodwillTableResponse } from '../../../types/goodwill/goodwill';
|
import type { GoodwillEdit, GoodwillSign, GoodwillTableResponse } from '../../../types/goodwill/goodwill';
|
||||||
import { saveBlob, xlsxFilename } from '../../../utils/download';
|
import { saveBlob, xlsxFilename } from '../../../utils/download';
|
||||||
import { changedRows, effectiveRow, matchesSign, parseShare, rowKey } from '../../../utils/goodwill';
|
import { changedRows, effectiveRow, matchesSign, parseShare, rowKey } from '../../../utils/goodwill';
|
||||||
import { useNotificationApi } from '../../../utils/useNotification';
|
import { useNotificationApi } from '../../../utils/useNotification';
|
||||||
import { readOnlyHint } from '../../CorrectionTable/readOnly';
|
import { errorOutcome, readOnlyHint } from '../../CorrectionTable/readOnly';
|
||||||
import { ConsolidationGoodwillTable } from '../ConsolidationGoodwillTable/ConsolidationGoodwillTable';
|
import { ConsolidationGoodwillTable } from '../ConsolidationGoodwillTable/ConsolidationGoodwillTable';
|
||||||
import { type GoodwillTreeRow, type RowIssues, formatMoney, getGoodwillColumns } from '../ConsolidationGoodwillTable/config';
|
import { type GoodwillTreeRow, type RowIssues, formatMoney, getGoodwillColumns } from '../ConsolidationGoodwillTable/config';
|
||||||
|
|
||||||
@ -45,6 +45,7 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => {
|
|||||||
|
|
||||||
const [data, setData] = useState<GoodwillTableResponse | null>(null);
|
const [data, setData] = useState<GoodwillTableResponse | null>(null);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [loadError, setLoadError] = useState<string | null>(null);
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const [settingsSaving, setSettingsSaving] = useState(false);
|
const [settingsSaving, setSettingsSaving] = useState(false);
|
||||||
const [decimals, setDecimals] = useState(2);
|
const [decimals, setDecimals] = useState(2);
|
||||||
@ -60,10 +61,14 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => {
|
|||||||
const loadData = useCallback(
|
const loadData = useCallback(
|
||||||
async (vId: string) => {
|
async (vId: string) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
setLoadError(null);
|
||||||
try {
|
try {
|
||||||
setData(await fetchGoodwillTable(vId));
|
setData(await fetchGoodwillTable(vId));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof ApiError) notification.error({ description: e.message });
|
const message = e instanceof ApiError ? e.message : 'Не удалось загрузить таблицу гудвилла';
|
||||||
|
setData(null);
|
||||||
|
setLoadError(message);
|
||||||
|
notification.error({ description: message });
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@ -158,6 +163,16 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => {
|
|||||||
setIsEditMode(false);
|
setIsEditMode(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// сервер закрыл правки (перечитали после 409, версию забрали или закрыли) — выходим из редактирования:
|
||||||
|
// иначе экран остаётся редактируемым и каждое «Сохранить» снова получает 409
|
||||||
|
useEffect(() => {
|
||||||
|
if (data && !data.editable) {
|
||||||
|
setEdits({});
|
||||||
|
setServerIssues({});
|
||||||
|
setIsEditMode(false);
|
||||||
|
}
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
if (!version_id || !data) return;
|
if (!version_id || !data) return;
|
||||||
if (pending.length === 0) {
|
if (pending.length === 0) {
|
||||||
@ -170,13 +185,21 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => {
|
|||||||
closeEditing();
|
closeEditing();
|
||||||
notification.success({ description: 'Изменения сохранены' });
|
notification.success({ description: 'Изменения сохранены' });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
// 409 (версию закрыли, блокировку забрали) и 404 (пары уже нет) — перечитываем
|
||||||
|
// таблицу, строку не подсвечиваем; правки в несуществующих парах при пересчёте cбрасываем
|
||||||
|
const out = errorOutcome(e, 'Не удалось сохранить изменения');
|
||||||
|
notification.error({ description: out.message });
|
||||||
|
if (out.reload) {
|
||||||
|
setServerIssues({});
|
||||||
|
loadData(version_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const detail = rowErrorDetail(e);
|
const detail = rowErrorDetail(e);
|
||||||
if (detail) {
|
if (detail) {
|
||||||
const key = `${detail.head_legal_entity_id}:${detail.subsidiary_legal_entity_id}`;
|
const key = `${detail.head_legal_entity_id}:${detail.subsidiary_legal_entity_id}`;
|
||||||
const field = ERROR_FIELD[detail.code ?? ''] ?? 'ownership_share';
|
const field = ERROR_FIELD[detail.code ?? ''] ?? 'ownership_share';
|
||||||
setServerIssues((prev) => ({ ...prev, [key]: { ...prev[key], [field]: detail.message } }));
|
setServerIssues((prev) => ({ ...prev, [key]: { ...prev[key], [field]: detail.message } }));
|
||||||
}
|
}
|
||||||
if (e instanceof ApiError) notification.error({ description: e.message });
|
|
||||||
} finally {
|
} finally {
|
||||||
setSaving(false);
|
setSaving(false);
|
||||||
}
|
}
|
||||||
@ -188,7 +211,9 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => {
|
|||||||
try {
|
try {
|
||||||
setData(await saveGoodwillSettings(version_id, { goodwill_enabled: enabled }));
|
setData(await saveGoodwillSettings(version_id, { goodwill_enabled: enabled }));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof ApiError) notification.error({ description: e.message });
|
const out = errorOutcome(e, 'Не удалось изменить настройку гудвилла');
|
||||||
|
notification.error({ description: out.message });
|
||||||
|
if (out.reload) loadData(version_id);
|
||||||
} finally {
|
} finally {
|
||||||
setSettingsSaving(false);
|
setSettingsSaving(false);
|
||||||
}
|
}
|
||||||
@ -229,91 +254,98 @@ export const GoodwillContent = ({ card }: { card: VersionCard | null }) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
{loadError && !loading ? (
|
||||||
ref={tableRef}
|
<Flex vertical align='center' gap={8} style={{ padding: 48 }}>
|
||||||
style={{
|
<span>{loadError}</span>
|
||||||
display: 'flex',
|
<Button onClick={() => version_id && loadData(version_id)}>Повторить</Button>
|
||||||
flexDirection: 'column',
|
</Flex>
|
||||||
height: isFullscreen ? '100vh' : 'auto',
|
) : (
|
||||||
padding: isFullscreen ? 16 : 0,
|
<div
|
||||||
backgroundColor: isFullscreen ? '#fff' : 'transparent',
|
ref={tableRef}
|
||||||
}}>
|
style={{
|
||||||
<ConsolidationGoodwillTable
|
display: 'flex',
|
||||||
data={data}
|
flexDirection: 'column',
|
||||||
rows={filteredRows}
|
height: isFullscreen ? '100vh' : 'auto',
|
||||||
columns={visibleColumns}
|
padding: isFullscreen ? 16 : 0,
|
||||||
loading={loading}
|
backgroundColor: isFullscreen ? '#fff' : 'transparent',
|
||||||
decimals={decimals}
|
}}>
|
||||||
units={units}
|
<ConsolidationGoodwillTable
|
||||||
isFullscreen={isFullscreen}
|
data={data}
|
||||||
toolbar={
|
rows={filteredRows}
|
||||||
<div
|
columns={visibleColumns}
|
||||||
style={{
|
loading={loading}
|
||||||
display: 'flex',
|
decimals={decimals}
|
||||||
justifyContent: 'space-between',
|
units={units}
|
||||||
alignItems: 'center',
|
isFullscreen={isFullscreen}
|
||||||
width: '100%',
|
toolbar={
|
||||||
flexWrap: 'wrap',
|
<div
|
||||||
gap: 16,
|
style={{
|
||||||
}}>
|
display: 'flex',
|
||||||
<div style={{ display: 'flex', alignItems: 'flex-start', flexWrap: 'wrap', gap: 16, flex: '1 1 auto' }}>
|
justifyContent: 'space-between',
|
||||||
<Space>
|
alignItems: 'center',
|
||||||
<Space orientation='vertical' size={0}>
|
width: '100%',
|
||||||
<span style={{ fontSize: 12, color: '#667085' }}>Гудвилл</span>
|
flexWrap: 'wrap',
|
||||||
<Select style={{ minWidth: 200 }} value={sign} options={SIGN_OPTIONS} onChange={setSign} variant='underlined' />
|
gap: 16,
|
||||||
</Space>
|
}}>
|
||||||
{sign !== 'all' ? <Button onClick={() => setSign('all')}>Сбросить фильтры</Button> : null}
|
<div style={{ display: 'flex', alignItems: 'flex-start', flexWrap: 'wrap', gap: 16, flex: '1 1 auto' }}>
|
||||||
</Space>
|
|
||||||
<div style={{ width: 1, height: 50, backgroundColor: '#e5e7eb' }} />
|
|
||||||
<ConsolidationFormatTableFilter
|
|
||||||
decimals={decimals}
|
|
||||||
units={units}
|
|
||||||
onDecimalsChange={setDecimals}
|
|
||||||
onUnitsChange={setUnits}
|
|
||||||
/>
|
|
||||||
<div style={{ width: 1, height: 50, backgroundColor: '#e5e7eb' }} />
|
|
||||||
<Space orientation='vertical' size={0}>
|
|
||||||
<Space>
|
<Space>
|
||||||
<Tooltip title={readOnly}>
|
<Space orientation='vertical' size={0}>
|
||||||
<Switch
|
<span style={{ fontSize: 12, color: '#667085' }}>Гудвилл</span>
|
||||||
checked={data?.goodwill_enabled ?? false}
|
<Select style={{ minWidth: 200 }} value={sign} options={SIGN_OPTIONS} onChange={setSign} variant='underlined' />
|
||||||
disabled={!data?.editable || isEditMode}
|
</Space>
|
||||||
loading={settingsSaving}
|
{sign !== 'all' ? <Button onClick={() => setSign('all')}>Сбросить фильтры</Button> : null}
|
||||||
onChange={handleSettings}
|
|
||||||
aria-label='Учитывать гудвилл в КФО'
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
<span>Учитывать гудвилл в КФО</span>
|
|
||||||
</Space>
|
</Space>
|
||||||
<Text type='secondary' style={{ fontSize: 12 }}>
|
<div style={{ width: 1, height: 50, backgroundColor: '#e5e7eb' }} />
|
||||||
{data?.goodwill_enabled
|
<ConsolidationFormatTableFilter
|
||||||
? `В КФО: ${formatMoney(data.totals.goodwill_in_kfo_amount, units, decimals)}`
|
decimals={decimals}
|
||||||
: 'Гудвилл не учитывается в КФО'}
|
units={units}
|
||||||
</Text>
|
onDecimalsChange={setDecimals}
|
||||||
</Space>
|
onUnitsChange={setUnits}
|
||||||
</div>
|
/>
|
||||||
<div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
|
<div style={{ width: 1, height: 50, backgroundColor: '#e5e7eb' }} />
|
||||||
<ColumnSettings defs={columnsConfig.columns} visibleKeys={visibleKeys} onChange={setVisibleKeys} />
|
<Space orientation='vertical' size={0}>
|
||||||
<Tooltip title={readOnly}>
|
<Space>
|
||||||
<Button
|
<Tooltip title={readOnly}>
|
||||||
type={isEditMode ? 'default' : 'primary'}
|
<Switch
|
||||||
icon={<EditOutlined />}
|
checked={data?.goodwill_enabled ?? false}
|
||||||
onClick={() => setIsEditMode(true)}
|
disabled={!data?.editable || isEditMode}
|
||||||
disabled={isEditMode || !data?.editable}>
|
loading={settingsSaving}
|
||||||
Редактировать
|
onChange={handleSettings}
|
||||||
|
aria-label='Учитывать гудвилл в КФО'
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<span>Учитывать гудвилл в КФО</span>
|
||||||
|
</Space>
|
||||||
|
<Text type='secondary' style={{ fontSize: 12 }}>
|
||||||
|
{data?.goodwill_enabled
|
||||||
|
? `В КФО: ${formatMoney(data.totals.goodwill_in_kfo_amount, units, decimals)}`
|
||||||
|
: 'Гудвилл не учитывается в КФО'}
|
||||||
|
</Text>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
|
||||||
|
<ColumnSettings defs={columnsConfig.columns} visibleKeys={visibleKeys} onChange={setVisibleKeys} />
|
||||||
|
<Tooltip title={readOnly}>
|
||||||
|
<Button
|
||||||
|
type={isEditMode ? 'default' : 'primary'}
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
onClick={() => setIsEditMode(true)}
|
||||||
|
disabled={isEditMode || !data?.editable}>
|
||||||
|
Редактировать
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
<Button loading={exportLoading} onClick={download} icon={<DownloadOutlined />}>
|
||||||
|
Экспорт
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
<Button onClick={toggleFullscreen} icon={isFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}>
|
||||||
<Button loading={exportLoading} onClick={download} icon={<DownloadOutlined />}>
|
{isFullscreen ? 'Свернуть' : 'На весь экран'}
|
||||||
Экспорт
|
</Button>
|
||||||
</Button>
|
</div>
|
||||||
<Button onClick={toggleFullscreen} icon={isFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}>
|
|
||||||
{isFullscreen ? 'Свернуть' : 'На весь экран'}
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,18 +1,8 @@
|
|||||||
.goodwillTable .empty-cell {
|
|
||||||
background-color: #f2f4f7;
|
|
||||||
}
|
|
||||||
.goodwillTable .ant-table-tbody > tr:hover > td.empty-cell {
|
|
||||||
background-color: #f2f4f7 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.goodwillTable .ant-table-summary {
|
.goodwillTable .ant-table-summary {
|
||||||
border-end-end-radius: 8px !important;
|
border-end-end-radius: 8px !important;
|
||||||
border-end-start-radius: 8px !important;
|
border-end-start-radius: 8px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.goodwillTable .ant-table-cell-fix {
|
|
||||||
background-color: #f8fafc !important;
|
|
||||||
}
|
|
||||||
.goodwillTable .resRow {
|
.goodwillTable .resRow {
|
||||||
background-color: #e6f4ea !important ;
|
background-color: #e6f4ea !important ;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,6 +57,10 @@ export const ConsolidationGoodwillTable: React.FC<ConsolidationGoodwillTableI> =
|
|||||||
isFullscreen = false,
|
isFullscreen = false,
|
||||||
}) => {
|
}) => {
|
||||||
const treeData = useMemo(() => buildTree(data, rows), [data, rows]);
|
const treeData = useMemo(() => buildTree(data, rows), [data, rows]);
|
||||||
|
const expandIconColumnIndex = Math.max(
|
||||||
|
0,
|
||||||
|
columns.findIndex((col) => col.key === 'name'),
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Table<GoodwillTreeRow>
|
<Table<GoodwillTreeRow>
|
||||||
@ -72,7 +76,7 @@ export const ConsolidationGoodwillTable: React.FC<ConsolidationGoodwillTableI> =
|
|||||||
bordered
|
bordered
|
||||||
title={() => toolbar}
|
title={() => toolbar}
|
||||||
key={treeData.map((g) => g.key).join('|')}
|
key={treeData.map((g) => g.key).join('|')}
|
||||||
expandable={{ defaultExpandAllRows: true, expandIconColumnIndex: 1 }}
|
expandable={{ defaultExpandAllRows: true, expandIconColumnIndex }}
|
||||||
summary={() => <ConsolidationGoodwillSummary totals={data?.totals ?? null} columns={columns} units={units} decimals={decimals} />}
|
summary={() => <ConsolidationGoodwillSummary totals={data?.totals ?? null} columns={columns} units={units} decimals={decimals} />}
|
||||||
rowClassName={rowClassName}
|
rowClassName={rowClassName}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user