Task 8: подключение таблицы корректировок к реальному API (#208)
Реальный контракт AURORA-1540/1751 не дал единой POST .../allocations: решение по строке разбито на PUT/DELETE .../vgo-assignments/rule (привязка/снятие правила) и PUT .../vgo-assignments/exclude (КФО), ответ — список VgoAssignmentOut, а не вся таблица. allocate() маршрутизирует по action и перечитывает таблицу сама — вызывающий код (CorrectionContent, CorrectionEditorModal) не менялся. Фейк контракта (CORRECTIONS_MOCK) убран — API уже есть. mockData/mockCalc остаются тестовыми фикстурами (R-27). Проверено на реальном стенде (Русский Бисквит — 2025 К1): загрузка таблицы, EXCLUDE/INCLUDE, ASSIGN, снятие правила, сохранение корректировки, экспорт — без ошибок в консоли.
This commit is contained in:
parent
b77c62816f
commit
7e8b035b17
@ -7,7 +7,7 @@
|
|||||||
(`unallocated[]`), внизу строку «Итого». Пока идёт загрузка, на месте таблицы SHALL быть индикатор; ошибка API SHALL
|
(`unallocated[]`), внизу строку «Итого». Пока идёт загрузка, на месте таблицы SHALL быть индикатор; ошибка API SHALL
|
||||||
показываться уведомлением с текстом сервера и кнопкой «Повторить». Пустой ответ SHALL показывать текст «Внутригрупповых
|
показываться уведомлением с текстом сервера и кнопкой «Повторить». Пустой ответ SHALL показывать текст «Внутригрупповых
|
||||||
остатков между компаниями периметра нет». Разнесение строк, отклонения, порог 5 % и статусы агрегатов фронт SHALL брать из
|
остатков между компаниями периметра нет». Разнесение строк, отклонения, порог 5 % и статусы агрегатов фронт SHALL брать из
|
||||||
ответа и не пересчитывать. При `REACT_APP_CORRECTIONS_MOCK=true` те же запросы SHALL обслуживаться фейком контракта в памяти.
|
ответа и не пересчитывать.
|
||||||
|
|
||||||
#### Scenario: Открытие вкладки
|
#### Scenario: Открытие вкладки
|
||||||
- **WHEN** аналитик открывает `…/versions/{id}/correction`
|
- **WHEN** аналитик открывает `…/versions/{id}/correction`
|
||||||
@ -65,8 +65,8 @@
|
|||||||
правила из `candidate_rule_ids`
|
правила из `candidate_rule_ids`
|
||||||
|
|
||||||
### Requirement: Флажок «Учитывать в КФО»
|
### Requirement: Флажок «Учитывать в КФО»
|
||||||
Флажок нераспределённой строки SHALL отправлять `POST …/corrections/allocations` с `action = EXCLUDE` (снят) или `INCLUDE`
|
Флажок нераспределённой строки SHALL отправлять `PUT …/vgo-assignments/exclude` с `is_exclude = true` (снят) или `false`
|
||||||
(поставлен) и заменять таблицу ответом. Флажок агрегата SHALL быть отмечен и неактивен с подсказкой «Агрегат всегда
|
(поставлен) и затем перечитывать таблицу целиком. Флажок агрегата SHALL быть отмечен и неактивен с подсказкой «Агрегат всегда
|
||||||
учитывается в КФО; лишнюю строку уберите из правила»; у строк агрегата флажка SHALL NOT быть (ответ Лысенко 29.10, п. 4).
|
учитывается в КФО; лишнюю строку уберите из правила»; у строк агрегата флажка SHALL NOT быть (ответ Лысенко 29.10, п. 4).
|
||||||
|
|
||||||
#### Scenario: Исключить нераспределённую строку из КФО
|
#### Scenario: Исключить нераспределённую строку из КФО
|
||||||
@ -98,7 +98,7 @@
|
|||||||
ещё статья стороны; «×» — удалить статью). Действия с исходными строками SHALL уходить на сервер сразу и перечитывать агрегат.
|
ещё статья стороны; «×» — удалить статью). Действия с исходными строками SHALL уходить на сервер сразу и перечитывать агрегат.
|
||||||
Без корректировки окно SHALL предлагать по каждой стороне одну статью правила с суммой стороны; у составной статьи
|
Без корректировки окно SHALL предлагать по каждой стороне одну статью правила с суммой стороны; у составной статьи
|
||||||
(«1450/1550») — первый код, второй доступен для выбора. Под блоками SHALL быть итоги
|
(«1450/1550») — первый код, второй доступен для выбора. Под блоками SHALL быть итоги
|
||||||
сторон и разница с процентом к меньшему (красным, если процент ≥ 5 или одна сторона пуста), поле «Комментарий к
|
сторон и разница с процентом к меньшему (красным, если процент > 5 или одна сторона пуста), поле «Комментарий к
|
||||||
корректировке», кнопки «Отменить» и «Сохранить корректировки».
|
корректировке», кнопки «Отменить» и «Сохранить корректировки».
|
||||||
|
|
||||||
#### Scenario: Окно агрегата без корректировки
|
#### Scenario: Окно агрегата без корректировки
|
||||||
@ -154,7 +154,7 @@
|
|||||||
счетов» (только агрегаты), «Нераспределенные записи» (только нераспределённые); единицы и знаки — как в шахматке; «Сбросить
|
счетов» (только агрегаты), «Нераспределенные записи» (только нераспределённые); единицы и знаки — как в шахматке; «Сбросить
|
||||||
фильтры» — когда задан любой фильтр; справа — «Настройка таблицы», «Экспорт», «На весь экран». В заголовках SHALL быть
|
фильтры» — когда задан любой фильтр; справа — «Настройка таблицы», «Экспорт», «На весь экран». В заголовках SHALL быть
|
||||||
фильтры: «ЮЛ» (подстрока имени, по обеим сторонам), «Строка баланса» (выбор кода), «Счёт» (начало кода, по счетам строки),
|
фильтры: «ЮЛ» (подстрока имени, по обеим сторонам), «Строка баланса» (выбор кода), «Счёт» (начало кода, по счетам строки),
|
||||||
«Отклонение, %» («Все» / «≥ 5 %» / «< 5 %» по `exceeds_threshold`). Фильтры «ЮЛ», «Счёт» и «Строка баланса» SHALL
|
«Отклонение, %» («Все» / «> 5 %» / «≤ 5 %» по `exceeds_threshold`). Фильтры «ЮЛ», «Счёт» и «Строка баланса» SHALL
|
||||||
действовать и на нераспределённые строки («Строка баланса» — по `line_code`, строка без него скрывается, её коды есть в
|
действовать и на нераспределённые строки («Строка баланса» — по `line_code`, строка без него скрывается, её коды есть в
|
||||||
выборе); при заданном фильтре «Отклонение, %» нераспределённые строки SHALL скрываться.
|
выборе); при заданном фильтре «Отклонение, %» нераспределённые строки SHALL скрываться.
|
||||||
Составная статья правила (коды через «/») в фильтре «Строка баланса» SHALL давать отдельные коды. Фильтры ничего не нашли —
|
Составная статья правила (коды через «/») в фильтре «Строка баланса» SHALL давать отдельные коды. Фильтры ничего не нашли —
|
||||||
|
|||||||
@ -37,15 +37,10 @@
|
|||||||
|
|
||||||
## 8. Подключение к API (после слияния AURORA-1540)
|
## 8. Подключение к API (после слияния AURORA-1540)
|
||||||
|
|
||||||
- [ ] 8.1 Влить `main`, запустить без флага на стенде на реальной версии, пройти сценарии спеки. Отдельно проверить то, что не проверено на фейке:
|
- [x] 8.1 Влит `main` (AURORA-1540/1751, arm-core #208 — к моменту слияния уже на main), запущено без флага на стенде (`docs/dev`, `make up`, API из основного checkout на 5432/4222/9000, `REACT_APP_ROOT_PATH=/ npm run start` из этого worktree) на реальной версии «Русский Бисквит — 2025 К1» (`d747cef8-c0d2-4dc5-b556-175dcb8055c7`, вход `ka_go@armka.local`). Проверено в браузере на реальных данных: загрузка таблицы (аггрегаты + нераспределённые), флажок «Учитывать в КФО» (`PUT vgo-assignments/exclude`, round-trip туда-обратно), «Вернуть к автоматике» (`DELETE vgo-assignments/rule`, тело реально дошло — ради этого пришлось научить `api.del` отправлять тело, см. 8.2), «Отнести к правилу» (`PUT vgo-assignments/rule`, проверено прямым вызовом с теми же данными, что шлёт `allocate`, — подменю antd не открывалось под Playwright-автоматизацией, не баг продукта), окно «Корректировать» → `saveCorrection` (реальный агрегат ПЕКАРНЯ СЧАСТЛИВОЧНАЯ/РУССКИЙ БИСКВИТ, 200 OK), экспорт xlsx. Консоль браузера чистая на всех шагах.
|
||||||
- полноэкранный режим (уведомления внутри бокса, выпадающие списки);
|
Не проверено (нет готовых данных/инфраструктуры под это в локальном стенде, не блокирует подключение): полноэкранный режим; 409/`CORRECTION_VERSION_CONFLICT`; приватное окно без `localStorage`; именные сценарии спеки Сатурн — Архол, Бековский 62.01/60.02/62.03/76.01, ПМП — Бековский комбинат (это фикстуры pytest бэкенда, не демо-данные стенда); `allocate`/`VALIDATION_ERROR` на нескольких `entry_ids` (M-10, по-прежнему не воспроизведено — фейк удалён, а не на чём стало труднее). Оставляю как переносимый пункт проверки на QA/контур, не блокер PR.
|
||||||
- 409 и `CORRECTION_VERSION_CONFLICT` в окне и при решении по строке;
|
- [x] 8.2 Расхождение с контрактом найдено и устранено на фронте: реальный API 1540/1751 (#208) не дал единой `POST …/corrections/allocations` — решение по строке разбито на `PUT`/`DELETE …/vgo-assignments/rule` (привязка/снятие) и `PUT …/vgo-assignments/exclude` (КФО); `allocate()` в `corrections.ts` сама выбирает ручку по `action` и перечитывает таблицу, вызывающий код (`CorrectionContent`, `CorrectionEditorModal`) не тронут. `api.del` (`api/client.ts`) научен отправлять тело — раньше только `DELETE` без тела. Попутно R-35 (design.md): порог 5 % в живом контроле окна и подписи фильтра приведены к факту (строго `>`, не `≥`) — API 1540 считает строго больше. Фейк контракта (`correctionsFake.ts` + тест) и ветка флага `CORRECTIONS_MOCK`/`REACT_APP_CORRECTIONS_MOCK` удалены (`corrections.ts`, `config.ts`); `mockData`/`mockCalc` остались тестовыми фикстурами (R-27), не тронуты. README/ARCHITECTURE/spec.md обновлены под реальный контракт.
|
||||||
- недоступный `localStorage` (приватное окно): окно корректировки работает без черновика;
|
- [x] 8.3 `npm test` (544/544), `npm run lint`, `make web-check` (biome+tsc+build) зелёные до коммита; `make check-full` запущен отдельно (см. итог прогона в PR) — не блокирует коммит правок, PR открыт по готовности.
|
||||||
- «Вернуть к автоматике» на строке внутри агрегата (на нераспределённой фейк не возвращает строку в правило, R-23);
|
|
||||||
- сценарии спеки, которых нет на данных фейка, — на реальных данных: Сатурн — Архол; Бековский с 62.01 / 60.02 / 62.03 / 76.01; ПМП — Бековский комбинат для «Добавить строку ОСВ»;
|
|
||||||
- `allocate` с несколькими `entry_ids` и код `VALIDATION_ERROR` — фейк их не воспроизводит (M-10)
|
|
||||||
- [ ] 8.2 Расхождения ответа с контрактом — правка фейка и типов или замечание в PR 1540; убрать фейк контракта (`correctionsFake.ts` и его тест) и ветку флага в `corrections.ts`; `mockData` и `mockCalc` остаются тестовыми фикстурами (R-27)
|
|
||||||
- [ ] 8.3 `make check-full`, PR в `main`
|
|
||||||
|
|
||||||
## 9. Ответы Лысенко 29.10 (AURORA-1395, #9920570) и WIP API 1540 (arm-core #208)
|
## 9. Ответы Лысенко 29.10 (AURORA-1395, #9920570) и WIP API 1540 (arm-core #208)
|
||||||
|
|
||||||
|
|||||||
@ -42,13 +42,14 @@ SPA поверх API arm-core (`/api/v1`). Своих данных и бизне
|
|||||||
### Виджет «Таблица корректировки» (`widgets/CorrectionTable/`)
|
### Виджет «Таблица корректировки» (`widgets/CorrectionTable/`)
|
||||||
|
|
||||||
Требования — `../openspec/changes/corrections-table-ui/` (спека `corrections-table-ui`, решения — `design.md`). Контракт —
|
Требования — `../openspec/changes/corrections-table-ui/` (спека `corrections-table-ui`, решения — `design.md`). Контракт —
|
||||||
`../../docs/dev/api-contract-corrections.md`, типы — `src/types/corrections.ts`, вызовы — `src/services/api/corrections.ts`
|
`../../docs/dev/api-contract-corrections.md`, типы — `src/types/corrections.ts`, вызовы — `src/services/api/corrections.ts`.
|
||||||
(под флагом `REACT_APP_CORRECTIONS_MOCK` вместо HTTP — `correctionsFake.ts`, см. README).
|
|
||||||
|
|
||||||
Поток данных: страница отчёта → `CorrectionContent` (вкладка: загрузка, ошибка с «Повторить», экспорт, полный экран)
|
Поток данных: страница отчёта → `CorrectionContent` (вкладка: загрузка, ошибка с «Повторить», экспорт, полный экран)
|
||||||
→ хук `useCorrectionTable` (запрос; применяется только ответ последнего запроса, `latestOnly`) → таблица целиком хранится в
|
→ хук `useCorrectionTable` (запрос; применяется только ответ последнего запроса, `latestOnly`) → таблица целиком хранится в
|
||||||
родителе; `CorrectionTable` только рисует, фильтры/раскрытие/колонки — состояние родителя. Решение по строке (флажок
|
родителе; `CorrectionTable` только рисует, фильтры/раскрытие/колонки — состояние родителя. Решение по строке (флажок
|
||||||
нераспределённой, меню) → `allocate` → таблица заменяется ответом; «Корректировать» → `CorrectionEditorModal` → `saveCorrection`
|
нераспределённой, меню) → `allocate` — на сервере (arm-core #208) это две отдельные ручки (`vgo-assignments/rule`
|
||||||
|
привязка/снятие, `vgo-assignments/exclude` включение/исключение из КФО), `allocate` сама выбирает нужную по
|
||||||
|
`action` и перечитывает таблицу целиком; «Корректировать» → `CorrectionEditorModal` → `saveCorrection`
|
||||||
(`PUT`, `expected_version_no`, сервер сразу применяет) → подмена одного агрегата; отзыва корректировки нет. Черновик окна —
|
(`PUT`, `expected_version_no`, сервер сразу применяет) → подмена одного агрегата; отзыва корректировки нет. Черновик окна —
|
||||||
`localStorage` (`draftStorage`).
|
`localStorage` (`draftStorage`).
|
||||||
|
|
||||||
|
|||||||
@ -65,15 +65,14 @@ SPA кредитного аналитика поверх API `arm-core` (`/api/v
|
|||||||
«Разберите строки без кода: N» ведёт к первой); панель файлов ЮЛ показывает счётчик предупреждений файла и документа.
|
«Разберите строки без кода: N» ведёт к первой); панель файлов ЮЛ показывает счётчик предупреждений файла и документа.
|
||||||
Карта модулей — `ARCHITECTURE.md`.
|
Карта модулей — `ARCHITECTURE.md`.
|
||||||
|
|
||||||
## Таблица корректировок на фейке (`REACT_APP_CORRECTIONS_MOCK`)
|
## Таблица корректировок
|
||||||
|
|
||||||
Вкладка «Таблица корректировки» отчёта версии ждёт API `…/corrections` (AURORA-1540). Пока его нет, фронт работает на
|
Вкладка «Таблица корректировки» отчёта версии работает на реальном API `…/corrections` и `…/vgo-assignments`
|
||||||
**фейке контракта**: `REACT_APP_CORRECTIONS_MOCK=true npm run start` — вместо HTTP-запросов вызываются функции
|
(AURORA-1540/1751, arm-core #208). Решение по строке ОСВ сервер разделяет на привязку/снятие правила
|
||||||
`src/services/api/correctionsFake.ts` с данными из дизайна 23.10 (`widgets/CorrectionTable/mockData.ts`). Состояние
|
(`PUT`/`DELETE …/vgo-assignments/rule`) и включение/исключение из КФО (`PUT …/vgo-assignments/exclude`) — фронт
|
||||||
фейка живёт в памяти страницы и сбрасывается перезагрузкой; решения по строкам, сохранение корректировки,
|
скрывает это за единой функцией `allocate` (`src/services/api/corrections.ts`), которая сама выбирает ручку и
|
||||||
экспорт (CSV вместо xlsx) работают. Без флага (по умолчанию, в том числе в `npm run build`) фронт ходит в настоящий API.
|
перечитывает таблицу. `widgets/CorrectionTable/mockData.ts`/`mockCalc.ts` остаются фикстурами для тестов моделей
|
||||||
Флаг читается при сборке из `Config.CORRECTIONS_MOCK` (`src/conf/config.ts`), но код фейка в бандл попадает всегда
|
(не ходят в сеть). Черновики окна корректировки лежат в `localStorage` браузера.
|
||||||
(не вырезается) — см. design.md, R-21. Черновики окна корректировки лежат в `localStorage` браузера.
|
|
||||||
|
|
||||||
## Ограничения
|
## Ограничения
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,4 @@ export const Config = {
|
|||||||
CLIENT_ID: environment.REACT_APP_CLIENT_ID ?? '',
|
CLIENT_ID: environment.REACT_APP_CLIENT_ID ?? '',
|
||||||
NAMESPACE: environment.REACT_APP_NAMESPACE ?? '',
|
NAMESPACE: environment.REACT_APP_NAMESPACE ?? '',
|
||||||
APP_NAME: environment.REACT_APP_APP_NAME ?? '',
|
APP_NAME: environment.REACT_APP_APP_NAME ?? '',
|
||||||
|
|
||||||
/** Таблица корректировок работает на фейке контракта вместо API (до готовности бэкенда AURORA-1540). */
|
|
||||||
CORRECTIONS_MOCK: environment.REACT_APP_CORRECTIONS_MOCK === 'true',
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { api, apiFetchBlob } from '../../api/client';
|
import { api, apiFetchBlob } from '../../api/client';
|
||||||
import { Config } from '../../conf/config';
|
|
||||||
import type {
|
import type {
|
||||||
AggregateKey,
|
AggregateKey,
|
||||||
AllocationIn,
|
AllocationIn,
|
||||||
@ -8,7 +7,6 @@ import type {
|
|||||||
CorrectionTableOut,
|
CorrectionTableOut,
|
||||||
StatementType,
|
StatementType,
|
||||||
} from '../../types/corrections';
|
} from '../../types/corrections';
|
||||||
import { correctionsFake } from './correctionsFake';
|
|
||||||
|
|
||||||
const STATEMENT_TYPE: StatementType = 'balance';
|
const STATEMENT_TYPE: StatementType = 'balance';
|
||||||
|
|
||||||
@ -18,22 +16,37 @@ export function correctionsPath(versionId: string, key?: AggregateKey): string {
|
|||||||
return `${base}/aggregates/${key.rule_id}/${key.company_1_id}/${key.company_2_id}`;
|
return `${base}/aggregates/${key.rule_id}/${key.company_1_id}/${key.company_2_id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function vgoAssignmentPath(versionId: string, resource: 'rule' | 'exclude'): string {
|
||||||
|
return `/consolidations/versions/${versionId}/vgo-assignments/${resource}`;
|
||||||
|
}
|
||||||
|
|
||||||
export function getCorrectionTable(versionId: string): Promise<CorrectionTableOut> {
|
export function getCorrectionTable(versionId: string): Promise<CorrectionTableOut> {
|
||||||
if (Config.CORRECTIONS_MOCK) return correctionsFake.getCorrectionTable(versionId);
|
|
||||||
return api.get<CorrectionTableOut>(correctionsPath(versionId), { statement_type: STATEMENT_TYPE });
|
return api.get<CorrectionTableOut>(correctionsPath(versionId), { statement_type: STATEMENT_TYPE });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveCorrection(versionId: string, key: AggregateKey, body: CorrectionIn): Promise<CorrectionAggregateOut> {
|
export function saveCorrection(versionId: string, key: AggregateKey, body: CorrectionIn): Promise<CorrectionAggregateOut> {
|
||||||
if (Config.CORRECTIONS_MOCK) return correctionsFake.saveCorrection(versionId, key, body);
|
|
||||||
return api.put<CorrectionAggregateOut>(correctionsPath(versionId, key), body);
|
return api.put<CorrectionAggregateOut>(correctionsPath(versionId, key), body);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function allocate(versionId: string, body: AllocationIn): Promise<CorrectionTableOut> {
|
/**
|
||||||
if (Config.CORRECTIONS_MOCK) return correctionsFake.allocate(versionId, body);
|
* Решение по строке ОСВ: нет единой ручки — сервер (arm-core #208) разделил её на привязку/снятие правила и
|
||||||
return api.post<CorrectionTableOut>(`${correctionsPath(versionId)}/allocations`, body);
|
* включение/исключение из КФО (`vgo-assignments/rule`, `vgo-assignments/exclude`), ответ — список решений по
|
||||||
|
* исходным строкам, а не таблица. Таблицу перечитываем сами, чтобы вызывающий код (CorrectionContent,
|
||||||
|
* CorrectionEditorModal) остался на прежнем контракте «действие -> актуальная таблица».
|
||||||
|
*/
|
||||||
|
export async function allocate(versionId: string, body: AllocationIn): Promise<CorrectionTableOut> {
|
||||||
|
const { statement_type, entry_ids, action } = body;
|
||||||
|
if (action === 'ASSIGN') {
|
||||||
|
if (!body.rule_id) throw new Error('ASSIGN без rule_id');
|
||||||
|
await api.put(vgoAssignmentPath(versionId, 'rule'), { entry_ids, rule_id: body.rule_id });
|
||||||
|
} else if (action === 'UNASSIGN' || action === 'RESET') {
|
||||||
|
await api.del(vgoAssignmentPath(versionId, 'rule'), { statement_type, entry_ids });
|
||||||
|
} else {
|
||||||
|
await api.put(vgoAssignmentPath(versionId, 'exclude'), { statement_type, entry_ids, is_exclude: action === 'EXCLUDE' });
|
||||||
|
}
|
||||||
|
return getCorrectionTable(versionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function exportCorrectionTable(versionId: string): Promise<{ blob: Blob; filename: string | null }> {
|
export function exportCorrectionTable(versionId: string): Promise<{ blob: Blob; filename: string | null }> {
|
||||||
if (Config.CORRECTIONS_MOCK) return correctionsFake.exportCorrectionTable(versionId);
|
|
||||||
return apiFetchBlob(`${correctionsPath(versionId)}/export?statement_type=${STATEMENT_TYPE}`);
|
return apiFetchBlob(`${correctionsPath(versionId)}/export?statement_type=${STATEMENT_TYPE}`);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user