spare_parts.md 6.0 KB

Ты — архитектор-разработчик ERP-системы с опытом проектирования складского и операционного учёта.

Задача: Перепроектировать логику учёта запчастей, резервирования и списания из рекламаций так, чтобы система была:

консистентной,

масштабируемой,

безопасной с точки зрения остатков,

без отрицательных физических остатков.

Упрощённые, временные и компромиссные решения не допускаются. Проектировать необходимо «как правильно».

  1. Архитектурные ограничения (обязательные)

Каталог запчастей — справочник, а не источник остатков.

В каталоге запрещено хранить:

фактические остатки,

зарезервированные остатки,

отрицательные значения.

Физические остатки не могут быть отрицательными ни при каких сценариях.

Любое изменение количества должно быть выражено через операции (движения).

Нехватка запчастей учитывается отдельной сущностью, а не минусами.

  1. Доменные сущности (обязательны к проектированию) 2.1. Part (Каталог запчастей)

Назначение: справочник.

Поля:

part_id / sku

цены и тарифы

нормативные коды

min_stock

метаданные

❌ Не хранит количества.

2.2. PartOrder (Заказ / партия)

Назначение: физическое поступление.

Поля:

order_id

part_id

ordered_qty

available_qty

with_documents (bool)

status (ordered / in_stock / issued)

Инвариант:

available_qty >= 0

2.3. InventoryMovement (Движение)

Назначение: единственный механизм изменения остатков.

Поля:

movement_id

part_id

qty

movement_type (receipt, reserve, issue, reserve_cancel)

source_type (order / reclamation)

source_id

with_documents

timestamp

Остатки рассчитываются агрегированием движений.

2.4. Reservation (логическая модель)

Реализуется через движения типа reserve.

Назначение:

уменьшение свободного остатка,

предотвращение двойного использования,

отделение резерва от физического списания.

2.5. Shortage (Дефицит)

Назначение: фиксация неудовлетворённой потребности.

Поля:

shortage_id

part_id

with_documents

required_qty

reserved_qty

missing_qty

reclamation_id

status (open / closed)

❗ Не влияет напрямую на физический остаток.

  1. Алгоритм: добавление детали в рекламацию

Пользователь выбирает part_id, количество и with_documents.

Система рассчитывает:

свободный остаток = физический остаток − активные резервы.

Выполняется:

резервирование доступного количества (reserve movement),

создание Shortage, если required_qty > free_qty.

Физический остаток не уменьшается.

  1. Алгоритм: списание (отгрузка)

Списание возможно только при наличии резерва.

При списании:

создаётся движение issue,

резерв закрывается или уменьшается.

Остаток партии уменьшается, но не уходит в минус.

  1. Алгоритм: закрытие дефицита

При создании PartOrder:

система ищет открытые Shortage по part_id + with_documents.

Поступившее количество:

резервируется под дефициты (FIFO / по дате),

уменьшает missing_qty.

При missing_qty = 0:

дефицит закрывается (status = closed).

  1. Контроль наличия (read-only представление)

Формируется автоматически, без ручного редактирования.

6.1. Критический уровень

Показывать все Shortage со статусом open.

6.2. Минимальный остаток

Показывать Part, для которых:

free_stock < min_stock

  1. Явные запреты (должны быть обеспечены кодом)

Запрещено:

хранить остатки в каталоге,

использовать отрицательные значения,

списывать детали напрямую из рекламации,

корректировать остатки без InventoryMovement.

  1. Ожидаемый результат от тебя

Нужно предоставить:

Схему сущностей и связей (ER / логическую модель).

Описание ключевых инвариантов и бизнес-ограничений.

Псевдокод или пошаговые алгоритмы:

резервирования,

списания,

закрытия дефицита.

Перечень существующих механизмов, которые должны быть удалены или переписаны.

Фокус на корректности модели и безопасности данных, а не на UI.