# ТЗ: Модуль Склад Связанные документы: - [План реорганизации](plan.md) - [Карта нового меню](menu.md) - [Исходное ТЗ](source-tz.md) - [ТЗ: Каталог общий](tz-catalog-common.md) - [ТЗ: Запчасти](tz-spare-parts.md) ## 1. Назначение `Склад` — новый модуль для учета МАФ/позиций, которые есть на складе или заказаны. Модуль должен быть реализован полностью по образцу раздела `Запчасти`, с адаптацией под МАФ/позиции из `Каталог общий`. ## 2. Статус Статус модуля: **ядро реализовано и проверено; управление ценой добавлено в план как расширение**. Реализованы `Наличие`, `Заказы`, карточка позиции, бронирование, списание, отмена, история движений, импорт и постоянные права. PDF-экспорт ожидает согласованного шаблона. ## 3. Место в меню Целевое меню: ```text Склад ├── Наличие └── Заказы ``` Требования: - добавить верхний пункт `Склад`; - добавить пункты `Наличие` и `Заказы`; - рабочие страницы размещаются под префиксом маршрутов `stock`; - выбранный год в CRM не влияет на отображение и данные модуля; - техническое имя маршрутов, таблиц и прав модуля: `stock`. ## 4. Права доступа Требования из исходного ТЗ: | Подраздел | Доступ | |---|---| | Наличие | Видно всем пользователям | | Заказы | Видит только админ и помощник руководителя (`assistant_head`) | Реализованные права: - штатные авторизованные роли получают просмотр наличия, бронирование, списание и отмену; - просмотр и управление заказами, а также импорт доступны администратору и `assistant_head`; - роль `помощник руководителя` в системе соответствует `assistant_head`. ## 5. Подраздел `Наличие` Назначение: - отображать список МАФ/позиций, у которых есть наличие на складе. Правило вывода: - показывать МАФ, у которых есть хотя бы одна запись в подвкладке `Заказы`; - в итоговом списке основное внимание на позициях с остатком на складе больше 0. Колонки: | Колонка | Источник | |---|---| | Картинка | `Каталог общий` | | Артикул | `Каталог общий` | | Наименование | `Каталог общий` | | Характеристики | `Каталог общий` | | Ед. измерения | `Каталог общий` | | Кол-во в наличии | Подвкладка `Заказы` | | Забронировано | Функция бронирования | | Остаток фактический | Кол-во в наличии минус забронировано и списано | | Заказано | Сумма позиций со статусом `заказан` | | Примечание | Добавление или импорт | Функционал: - список наличия; - поиск и фильтры; - переход в карточку позиции по двойному клику; - экспорт в PDF всех позиций в наличии; - отображение фактического остатка; - отображение количества в бронях; - отображение заказанного количества. ## 6. Карточка позиции Карточка открывается из `Наличие` двойным кликом. Нередактируемые поля: - картинка; - артикул; - наименование; - характеристики; - единица измерения; - количество в наличии; - забронировано; - остаток фактический; - заказано; - примечание. Функционал карточки: - отображение остатков внизу карточки аналогично `Запчастям`; - список активных броней; - история бронирований и списаний; - кнопка `Забронировать`; - действие `Списать`; - действие `Отменить бронь`. ## 7. Бронирование Кнопка `Забронировать` открывает модальное окно. Поля: - менеджер из выпадающего списка; - количество; - примечание. Правила: - нельзя забронировать больше доступного остатка; - при попытке превышения показывать ошибку `Такого кол-ва нет в наличии`; - после бронирования запись появляется в списке `Забронировано`. Список `Забронировано`: - менеджер; - количество; - номер заказа или заказов; - примечание; - действие `Списать`; - действие `Отменить бронь`. ## 8. Списание Списание выполняется по активной брони. Правила: - количество списывается с соответствующих заказов; - сохраняется история, куда ушла позиция; - сохраняется история, из какого заказа списана позиция; - фиксируется пользователь и время операции; - после списания фактический остаток пересчитывается. ## 9. Отмена брони Правила: - отмена возвращает количество в доступный остаток; - история отмены сохраняется; - отмененная бронь не участвует в расчете активного забронированного количества. ## 10. Подраздел `Заказы` Назначение: - ручное добавление складских заказов; - импорт складских заказов; - источник данных для расчета наличия. Поля заказа: | Поле | Описание | |---|---| | Номер заказа | Вводится вручную | | Артикул | Артикул позиции из общего каталога | | Статус заказа | `на складе` / `заказан` / `отгружено` | | Кол-во заказано | Вводится вручную | | Остаток | Фактический остаток с учетом бронирований и списаний | | Примечание | Ручной ввод или импорт | | Дата добавления | Заполняется автоматически | Функционал: - список заказов; - создание заказа; - редактирование заказа; - импорт; - изменение статуса; - массовый перевод всех заказанных позиций с выбранным номером заказа в статус `на складе`; - связь с позицией общего каталога; - расчет остатка по заказу; - отображение активных броней. ### Цена позиции `Склад` является единственным владельцем актуальной цены позиции. Цена не должна дублироваться в `Каталог общий` или данных технического описания. Требования: - цена связана с позицией общего каталога по `common_catalog_item_id`; - актуальная цена отображается в списке наличия и карточке позиции склада; - изменение цены не изменяет справочные и технические данные позиции; - сохраняются история значений, дата изменения и пользователь; - права просмотра и редактирования цены проверяются отдельно на сервере; - техническое описание получает актуальную цену из склада при формировании DOCX; - цена из `to.stroyprofit.com` может быть использована только как начальное значение после подтверждения её назначения; - если цена зависит от складского заказа или партии, это хранится нормализованно и не заменяет историю общей цены без явно согласованного правила. ## 11. Экспорт Требования: - в `Наличие` должна быть кнопка `Экспорт`; - экспорт выполняется в PDF; - экспортируются все позиции в наличии; - PDF формируется по отдельному шаблону; - шаблон PDF нужно подготовить отдельно. ## 12. Связи | Модуль | Связь | Требование | |---|---|---| | Каталог общий | Источник картинки, артикула, наименования, характеристик, ед. изм. | Обязательная связь. | | Технич. описание | Использует актуальную цену при формировании DOCX | Цена хранится только в `Склад`; техописание её не дублирует. | | График отгрузок / График заказов | Данные об отгрузках | Уточнить после реализации графиков. | | Запчасти | Эталон логики | Использовать паттерны реализации. | ## 13. Модель данных Реализация использует следующие соответствия: | `Запчасти` | `Склад` | Таблица | |---|---|---| | `SparePart` | `CommonCatalogItem` | `common_catalog_items` | | `SparePartOrder` | `StockOrder` | `stock_orders` | | `Reservation` | `StockReservation` | `stock_reservations` | | `InventoryMovement` | `StockMovement` | `stock_movements` | Отдельная таблица остатков не создаётся: физическое наличие, активная бронь, доступный остаток и заказанное количество рассчитываются из заказов и броней. Заказ связан с общей позицией по `common_catalog_item_id`; при импорте позиция разрешается по уникальному артикулу общего каталога. Цена относится к складскому учёту позиции и должна храниться отдельно от технических характеристик. Финальная таблица цены проектируется после уточнения, является ли цена общей для позиции или относится к конкретному заказу/партии; в любом варианте изменение не должно уничтожать историю. ## 14. Отложенная функциональность - PDF-шаблон; - интеграция с графиком отгрузок; Ядро склада, финальная схема таблиц и постоянные permissions входят в текущую реализацию. ## 15. Этапы реализации - [x] Разобрать текущие модели и сервисы `Запчасти`. - [x] Составить карту соответствия сущностей `Запчасти` -> `Склад`. - [x] Согласовать имя модуля в маршрутах и таблицах. - [x] Спроектировать таблицы. - [x] Добавить модели. - [x] Реализовать `Заказы`. - [x] Реализовать `Наличие`. - [x] Реализовать карточку позиции. - [x] Реализовать бронирование. - [x] Реализовать списание. - [x] Реализовать отмену брони. - [x] Реализовать историю. - [x] Реализовать импорт. - [ ] Реализовать PDF-экспорт. - [x] Настроить права доступа. - [x] Покрыть расчеты остатков тестами. - [ ] Уточнить назначение и область действия цены. - [ ] Реализовать единый источник и историю цены в модуле `Склад`. - [ ] Добавить цену в список/карточку склада, права и интерфейс управления ценой. - [ ] Подключить чтение актуальной цены в экспорте техописаний. ## 16. Критерии приемки - В меню есть `Склад`. - Есть подвкладки `Наличие` и `Заказы`. - `Наличие` доступно всем пользователям. - `Заказы` доступны админу и помощнику руководителя. - `помощник руководителя` соответствует роли `assistant_head`. - Позиции берут справочные данные из `Каталог общий`. - Нельзя забронировать больше доступного остатка. - Списание уменьшает остаток соответствующего заказа. - Отмена брони возвращает доступный остаток. - История операций сохраняется. - PDF-экспорт формируется по шаблону после его согласования и передачи в проект. ## 17. Открытые вопросы - Какой точный PDF-шаблон нужен для экспорта? - Как будет выглядеть связь с графиком отгрузок/заказов? - Что означает цена из `to.stroyprofit.com`: отпускную, закупочную или иную цену? - Цена общая для позиции или зависит от складского заказа/партии?