Перейти к основному содержимому

Конвейер обработки документов

Назначение

Все документы WMS (33 типа) проходят через единый конвейер обработки при создании, обновлении и удалении. Конвейер гарантирует: валидацию, формирование движений по регистрам, ведение истории статусов и публикацию событий.

Ключевые классы

Базовые абстракции

КлассПакетРоль
BaseDocmodel.entity.documentАбстрактная JPA-сущность, базовый класс всех документов. Таблица wms_doc_base, наследование JOINED, дискриминатор по полю type
BaseDocItemmodel.entity.documentАбстрактная JPA-сущность позиций документов. Таблица wms_doc_base_item, наследование JOINED
BaseDocManager<D, S, ES>service.entity.documentАбстрактный менеджер документа. Содержит конвейер обработки
BaseDocItemManager<I, D, S, ES>service.entity.documentАбстрактный менеджер позиции документа
DocManagerservice.entityРеестр всех менеджеров. Универсальная точка входа save(document, modifiers)

Сервисы доступа к данным

КлассРоль
BaseDocEntityService<D, S, R>Сервис данных документа. save/delete заблокированы — бросают IllegalStateException. Сохранение только через менеджер
BaseDocItemEntityService<I, D, S, R>Аналогично для позиций
DocStatusHistoryEntityServiceСервис истории статусов

Поля BaseDoc

Основные поля, доступные у всех документов:

ПолеТипОписание
humanIdStringУникальный читаемый идентификатор (генерируется HumanIdGenerator)
externalIdStringВнешний идентификатор (из ERP или Merchant API)
dateLocalDateДата документа
statusStringСтрока, маппится на enum конкретного документа
merchantMerchantМерчант (мультитенантность)
warehouseWarehouseСклад
employeeEmployeeОтветственный сотрудник
workspaceWarehouseWorkspaceРабочее пространство
parentBaseDocСсылка на родительский документ
isDeletedBooleanМягкое удаление

Конвейер сохранения (BaseDocManager.saveInner)

save(document, modifiers)

├─ 1. beforeSave() — hook: подготовка перед сохранением
├─ 2. Фиксация изменений — извлечение карты изменённых полей из EntityChanges
├─ 3. validate() — валидация документа
├─ 4. validateItems() — валидация позиций
├─ 5. saveToDB() — первичное сохранение (flush для новых документов)
├─ 6. validateRelatedDocuments() — валидация связанных документов
├─ 7. updateAdditionalItems() — обновление доп. позиций (SkuItems и т.п.)
├─ 8. processMovements() — MovementManager: проводки по регистрам
├─ 9. additionalBusinessLogic() — hook: доп. бизнес-логика
├─ 10. processStatusHistory() — запись истории статуса + DocStatusChangedEvent
├─ 11. validateAfterProcessing() — финальная валидация
├─ 12. publishEvent() — BaseDocSavedEvent
├─ 13. afterAllSaved() — пост-обработка (пул серийных номеров)
└─ 14. Сохранение snapshot полей — changes.saveValues для следующего сравнения

Hook-методы для переопределения

МетодКогда переопределять
beforeSave()Подготовка данных, установка значений по умолчанию
validate()Бизнес-валидация документа
validateItems()Валидация позиций
validateRelatedDocuments()Проверка связанных документов
updateAdditionalItems()Обновление SkuItems, серийных номеров
additionalBusinessLogic()Основная бизнес-логика. Если возвращает true — повторное сохранение в БД
createDocSavedEvent()Создание типизированного события

Модификаторы обработки (ProcessingModifier)

Enum ProcessingModifier позволяет тонко управлять поведением конвейера:

МодификаторДействие
FORCE_MOVEMENTS_PROCESSINGПринудительная обработка движений
DISABLE_MOVEMENTS_PROCESSINGПропуск обработки движений
DISABLE_BUSINESS_LOGICПропуск additionalBusinessLogic
DISABLE_ADDITIONAL_ITEMS_UPDATEПропуск updateAdditionalItems
DISABLE_PUBLISH_EVENTПропуск публикации события
POSTPONE_RELATED_DOCS_VALIDATIONОтложенная валидация связанных документов

Взаимоисключающие модификаторы (FORCE + DISABLE для одного шага) вызывают IllegalArgumentException.

Массовое сохранение (saveAll)

При сохранении коллекции документов оптимизация:

  1. Все документы проходят через saveInner с DISABLE_MOVEMENTS_PROCESSING + DISABLE_PUBLISH_EVENT
  2. Движения обрабатываются одним вызовом movementManager.processDocument для всей коллекции
  3. События публикуются в конце

Защита от рекурсии

ThreadLocal<Map<D, Integer>> saveCounter — подсчёт вложенных вызовов save для одного документа. При превышении лимита (wms.docs.nested-save-limit) — DocumentProcessingException.

Транзакционность

Метод save оборачивает saveInner в TransactionTemplate с PROPAGATION_REQUIRED. При исключении транзакция маркируется для отката.

Автоматическая регистрация менеджеров

DocManager при старте приложения:

  1. Сканирует classpath пакета service.entity.document
  2. Находит все конкретные (не абстрактные) наследники BaseDocManager и BaseDocItemManager
  3. Строит маппинг Class → Manager
  4. Предоставляет save(document, modifiers) — делегирует нужному менеджеру по типу

Таблица типов документов

DocumentTypeКлассНазваниеНазначение
ADDITIONAL_PROCESSINGAdditionalProcessingDocДоп. обработкаМаркировка, стикеровка
BUNDLEBundleDocОбработанный наборРезультат сборки набора
BUNDLE_ORDERBundleOrderDocЗаказ на обработку набораЗаказ на сборку набора
BUNDLE_ORDER_BATCHBundleOrderBatchDocБатч наборовГруппа заказов на наборы
CHANGE_STOCKChangeStockDocИзменение остатковКорректировка остатков
INVENTORYInventoryDocИнвентаризацияУправляющий документ
INVENTORY_DISCREPANCYInventoryDiscrepancyDocКТОРасхождения
INVENTORY_FACTInventoryFactDocИнвентаризация, фактФактические данные
INVENTORY_PLANInventoryPlanDocИнвентаризация, планПлановые данные
LOADINGLoadingDocПогрузкаПогрузка в ТС
MOVEMENTMovementDocПеремещениеВнутрискладское перемещение
MOVEMENT_CONTROLMovementControlDocБлокировкаБлокировка операций
NON_CONFORMANCENonConformanceDocНесоответствияФиксация брака/потерь
ORDEROrderDocЗаказЗаказ на отгрузку
ORDER_BATCHOrderBatchDocБатчГруппа заказов
ORDER_PACKINGOrderPackingDocУпаковка заказаОбработка на рабочем месте
PACKAGING_UNITPackagingUnitDocГрузовое местоКоробка/паллет с товарами
PICKINGPickingDocОтборОтбор с хранения
PLACINGPlacingDocРазмещениеРазмещение на хранение
PRODUCT_QUALITY_LAB_CONTROLProductQualityLabControlDocЛабораторный контрольЛабораторная проверка
PRODUCT_QUALITY_VISUAL_CONTROLProductQualityVisualControlDocВизуальный контрольВизуальная проверка
RECEIPTReceiptDocПриходный ордерФактическая приёмка
REPLENISHMENTReplenishmentDocПодпиткаПополнение зон отбора
RETURNINGReturningDocВозвратПриёмка возвратов
RETURNING_ORDERReturningOrderDocВозврат заказаВозврат по заказу
SERIAL_NUMBER_GENERATIONSerialNumberGenerationDocЭмиссия серийных номеровГенерация серийных номеров
SKU_PACKAGING_UNPACKINGSkuPackagingUnpackingDocРаспаковкаРазбор заводских упаковок
SORTINGSortingDocСортировкаСортировка по заказам
SUPPLYSupplyDocПоставкаОжидаемая поставка
TRANSPORTATIONTransportationDocПеревозкаПеревозка груза
TRANSPORT_RUNTransportRunDocРейсРейс ТС
TRANSPORT_UNITTransportUnitDocТранспортное местоГруппа грузовых мест
UNLOADINGUnloadingDocРазгрузкаРазгрузка ТС
WORKFLOW_PLANWorkflowPlanDocПлан обработкиМаршрут контейнера

Иерархия документов

Документы связаны в дерево через поле parent:

SupplyDoc
└── ReceiptDoc
└── PlacingDoc

OrderBatchDoc
├── PickingDoc
├── SortingDoc
└── OrderDoc
└── OrderPackingDoc
└── PackagingUnitDoc
└── TransportUnitDoc
└── LoadingDoc

InventoryDoc
├── InventoryPlanDoc
└── InventoryFactDoc
└── InventoryDiscrepancyDoc

BundleOrderBatchDoc
└── BundleOrderDoc
└── BundleDoc

Кэширование: DocCacheWrapper (родитель) и DocChildrenCacheWrapper (дочерние) минимизируют запросы к БД.