new scheme

This commit is contained in:
2025-12-19 12:45:15 +03:00
parent 7343edec51
commit 91ff1642dc
13 changed files with 1243 additions and 176 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.idea
.vscode

View File

@@ -1,11 +1,76 @@
@startuml
'https://plantuml.com/sequence-diagram
autonumber
boundary LT_trigger
queue logistic_tracker.logistic_order_changes as kafka_lt
participant DDC
participant OMS_Order
queue touch.events as Touch
database db
loop
LT_trigger -> kafka_lt: Событие изменения лог заказа
DDC -> kafka_lt: Читает сообщение
end
alt customer_shipment.now > customer_shipment.before is False
DDC -> DDC: пропускает сообщение
else customer_shipment.now > customer_shipment.before is True
DDC -> OMS_Order: Ожидает подтверждение\nпереноса ДД от OMS через wf
alt Сигнал с подтверждением переноса ДД не пришло
DDC -> DDC: Прекращает ожидание события
else Сигнал с подтверждением переноса ДД пришло
OMS_Order -> DDC: Сигнал с подтверждением переноса ДД
DDC -> DDC: Проверяет что не было уведомлений\nпо заказу в течении этих суток
alt Было уведомление в последние сутки
DDC -> DDC: Пропускает данное изменение
else Не было уведомлений в последние сутки
DDC -> DDC: Проверяет заказ робота или клиента?
alt Заказ робота
DDC -> CRM: Отправка сообщения в топик CRM
DDC -> db: Записывает данные о поставленной задаче в БД
else Заказ клиента
DDC -> OMS_Order: Получить данные по заказу
OMS_Order -> DDC: Вернуть данные по заказу
DDC -> DDC: Подготовить данные для\nотправки в топик Touch
DDC -> Touch: Отправить нотификацию в топик Touch (b2c смс, b2b email)
DDC -> db: Записывает данные о нотификации клиента в БД
end
end
end
end
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response
Alice -> Bob: Another authentication Request
Alice <-- Bob: another authentication Response
@enduml
@startuml
start
:DDC читает топик LT;
if (customer_shipment.now > customer_shipment.before is False) then
:Пропускает сообщение;
kill
else
:DDC Ожидает подтверждение\nпереноса ДД от OMS через wf;
endif
if (Сигнал с подтверждением переноса ДД пришел?) then (нет)
:Прекращает ожидание события\nничего не делает;
kill
else (да)
if (Событие уведомления по заказу было в течении суток?) then (да)
:Пропускает событие;
kill
else (нет)
endif
if (Заказ назначен на менеджера?) then (да)
:Отправка сообщения в топик CRM;
:Записывает данные о поставленной задаче в БД;
else (нет (заказ робота))
:Отправить нотификацию в топик Touch (b2c смс, b2b email);
:Записывает данные о нотификации клиента в БД;
endif
stop
@enduml

63
oms/autobot.puml Normal file
View File

@@ -0,0 +1,63 @@
@startuml
participant "Топик сообщений" as Topic
participant "Сервис обработки" as Service
participant "База данных" as DB
participant "МСКБ API" as MSKB
participant "Bifrost API" as Bifrost
participant "CRM API" as CRM
participant "TOUCH API" as TOUCH
Topic -> Service: Сообщение с letter_guid,\ncontractor_guid,\ncontact_person_guid,\ncommodity_guid
activate Service
Service -> DB: Проверить заказ по autoBotLetterGuid=letter_guid
alt Заказ уже существует
Service --> Topic: Пропустить сообщение
deactivate Service
else Заказа нет
Service -> Service: Валидация contractor_guid
alt contractor_guid пустой
Service -> DB: Найти контрагента по contact_person_guid\nв последних заказах
alt Контрагент не найден
Service --> Topic: Завершить обработку
deactivate Service
else Найден contractor_guid
end
else несколько contractor_guid
Service -> DB: Найти последний завершенный заказ\nдля каждого contractor_guid
end
Service -> Service: Валидация contact_person_guid
alt contact_person_guid пустой
Service -> MSKB: /api/business/v2/physic/\nпоиск по letter_from
alt Не найдено
Service -> DB: Найти в последнем заказе\nпо contractor_guid
end
end
Service -> Service: Валидация commodity_guid
alt commodity_guid пустые
Service --> Topic: Завершить обработку
deactivate Service
end
Service -> DB: Найти последний завершенный заказ\nдля получения shipment данных
Service -> MSKB: /api/business/v2/juristic/search\nполучить GUID менеджера
Service -> Bifrost: bifrost.v1.ActiveDirectoryService/GetUserByID\nпроверить email менеджера
alt email != letter_to
Service --> Topic: Завершить обработку
deactivate Service
end
Service -> Service: Создать заказ
Service -> DB: createOrder
Service -> Service: Автооформление заказа (flowId=6)
Service -> DB: Обновить заказ\n(IsAutoBotOrder=true,\nautoBotLetterGuid=letter_guid)
Service -> CRM: Создать задачу менеджеру\n"Заказ не прошел АО..."
Service -> TOUCH: /api/v1/jsonapi/send-email-message\nОповестить менеджера
Service --> Topic: Обработка завершена
deactivate Service
end
@enduml

View File

@@ -42,3 +42,179 @@ workflow -> workflow: Проверяет наличие\nкрупногабар
end
end
@enduml
@startuml Редактирование заказа процесс
skinparam backgroundColor #FFFFFF
skinparam componentStyle rectangle
title Бизнес-процесс редактирования заказа
actor User as U
participant "Frontend ARM" as F
participant "Gateway" as G
participant "Workflow" as W
participant "Order" as OS
participant "History" as H
participant "WTIS" as WTIS
participant "MongoDB" as DB
== Инициация редактирования ==
U -> F: Клик на кнопку "Редактирование заказа"
activate F
F -> G: GET /orders/v1/{orderID}/start-correction
activate G
G -> W: ExecuteWorkflow(B2CGetEditableFieldsWorkflow)
activate W
== Workflow: Получение редактируемых полей ==
W -> OS: gRPC: GetOrder(orderID)
activate OS
OS -> DB: Поиск заказа
DB --> OS: Данные заказа
OS --> W: Order entity
deactivate OS
W -> H: gRPC: IsTransactionExist(orderID)
activate H
H -> H: Transaction Service\nIsTransactionExist()
H -> DB: Поиск открытой транзакции
DB --> H: TransactionID или null
H --> W: TransactionID или uuid.Nil
deactivate H
alt Транзакция не существует
W -> H: gRPC: StartTransaction(orderID, userID)
activate H
H -> H: Transaction Service\nStartTransaction()
H -> H: Создание новой транзакции\n(статус: Opened)
H -> DB: Сохранение транзакции
DB --> H: Подтверждение
H --> W: TransactionID
deactivate H
end
W -> W: Определение редактируемых полей\n(editorder.FieldsDispatcher)
W -> W: Activity: GetEditableFieldsFromWTIS(orderID)
W -> WTIS: API GET GetEditableFieldsFromWTIS(orderID)
activate WTIS
WTIS --> W: Права на редактирование атрибутов
deactivate WTIS
W -> W: Проверка прав пользователя\n(permissions)
W -> W: Формирование ответа\n(CorrectionAnswer)
W --> G: Результат workflow
deactivate W
G --> F: CorrectionAnswer\n(редактируемые поля)
deactivate G
F -> F: Показать уведомление\n"У вас есть 5 минут на редактирование"
F --> U: Интерфейс редактирования активирован
deactivate F
== Мониторинг транзакции ==
loop Каждые 30 секунд
F -> F: checkOrderHasTransaction()
F -> G: GET /orders/v1/{orderID}
G --> F: hasTransaction: boolean
alt hasTransaction = false
F -> F: Показать ошибку\n"Время на редактирование вышло"
F -> F: Перезагрузить страницу
end
end
== Завершение редактирования ==
U -> F: Клик "Сохранить" или "Отменить"
activate F
F -> G: GET /orders/v1/{orderID}/end-correction\n?typeCorrection=...&typeEndCorrection=...
activate G
G -> W: ExecuteWorkflow(B2CEndCorrectionsWorkflow)
activate W
== Workflow: Завершение редактирования ==
W -> W: Lock ресурса (mutex)\n(10 минут блокировка)
W -> OS: gRPC: GetOrder(orderID)
activate OS
OS -> DB: Поиск заказа
DB --> OS: Данные заказа
OS --> W: Order entity
deactivate OS
W -> W: Activity: IsTransactionExist(orderID)
W -> H: gRPC: IsTransactionExist(orderID)
activate H
H -> H: Transaction Service\nIsTransactionExist()
H -> DB: Поиск транзакции
DB --> H: TransactionID
H --> W: TransactionID
deactivate H
alt typeEndCorrection = "reject"
W -> W: Activity: EndTransaction(orderID, userID, true)
W -> H: gRPC: EndTransaction(orderID, userID, true)
activate H
H -> H: Transaction Service\nEndTransaction()
H -> H: Закрытие транзакции\n(статус: Rejected)
H -> DB: Обновление транзакции
DB --> H: Подтверждение
H --> W: Результат
deactivate H
W -> W: Unlock ресурса
W --> G: Успешная отмена
else typeEndCorrection = "success"
W -> W: ManualActionWorkflow.ExecuteAsChild()\n(синхронизация с WTIS)
W -> W: Activity: GetOrderByID(orderID)\n(обновленные данные)
W -> OS: gRPC: GetOrder(orderID)
activate OS
OS -> DB: Поиск заказа
DB --> OS: Обновленные данные заказа
OS --> W: Order entity
deactivate OS
W -> W: Activity: EndTransaction(orderID, userID, false)
W -> H: gRPC: EndTransaction(orderID, userID, false)
activate H
H -> H: Transaction Service\nEndTransaction()
H -> H: Закрытие транзакции\n(статус: Finished)
H -> DB: Обновление транзакции
H -> H: publishEvents()\n(публикация событий)
H --> W: Результат
deactivate H
W -> W: SaveOrderWithShipment()\n(сохранение изменений)
W -> OS: gRPC: UpsertOrderWithShipment(orderID)
activate OS
OS -> H: Transaction Service\nIsTransactionExist()
activate H
H -> DB: Поиск транзакции
DB --> H: TransactionID
H --> OS: TransactionID
deactivate H
OS -> DB: Сохранение заказа
DB --> OS: Подтверждение
OS --> W: Order entity
deactivate OS
W -> W: Unlock ресурса
W --> G: Успешное сохранение
end
deactivate W
G --> F: Результат завершения транзакции
deactivate G
F -> F: Обновление интерфейса
F --> U: Редактирование завершено
deactivate F
@enduml

View File

@@ -36,3 +36,108 @@ OMS --> ARM: answer
ARM --> user: Отображает корректировки по заданным условиям
@enduml
@startuml
scale 1000*1000
mainframe Взаимодействие с историей изменения заказа
actor Пользователь as user
participant ARM as ARM
participant Gateway as Gateway
participant History as History
participant Bifrost as Bifrost
autonumber
user -> ARM: Нажимает кнопку "История изменений"
ARM -> Gateway: REST GET /history/v1/order/{orderID}
Gateway -> History: gRPC GetChangesByOrderIDAndParameters()
History --> Gateway: EventsByOrderIDResponse
Gateway -> Bifrost: gRPC GetUsersByIDs() [для получения имен менеджеров]
Bifrost --> Gateway: UserInfo[]
Gateway --> ARM: Таблица истории изменений с именами менеджеров
ARM --> user: Рендерит модальное окно "История изменений"
user -> ARM: Нажимает кнопку "Подробнее" в корректировке
ARM -> Gateway: REST GET /history/v1/events?eventIDs=[eventID]
Gateway -> History: gRPC GetEventChangesByIDs()
History --> Gateway: EventChangesByIDResponse[]
Gateway -> Bifrost: gRPC GetUserByIDV2() [для получения имени менеджера]
Bifrost --> Gateway: UserInfo
Gateway --> ARM: Таблица истории изменений с именами менеджеров
ARM --> user: Отображает полную информацию о корректировке
user -> ARM: Выбирает фильтр по дате или по типу корректировки
ARM -> Gateway: REST GET /history/v1/order/{orderID}?eventCorrectionType=...&createdAts=...
Gateway -> History: gRPC GetChangesByOrderIDAndParameters() [с фильтрами]
History --> Gateway: EventsByOrderIDResponse
Gateway -> Bifrost: gRPC GetUsersByIDs() [для получения имен менеджеров]
Bifrost --> Gateway: UserInfo[]
Gateway --> ARM: Таблица истории изменений с именами менеджеров
ARM --> user: Отображает корректировки по заданным условиям
user -> ARM: Вводит идентификатор корректировки и нажимает Enter
ARM -> Gateway: REST GET /history/v1/events?eventIDs=[eventID]
Gateway -> History: gRPC GetEventChangesByIDs()
History --> Gateway: EventChangesByIDResponse[]
Gateway -> Bifrost: gRPC GetUserByIDV2() [для получения имени менеджера]
Bifrost --> Gateway: UserInfo
Gateway --> ARM: История изменений с именами менеджеров
ARM --> user: Отображает корректировки по заданным условиям
@enduml
@startuml
scale 1200*1200
mainframe Взаимодействие с историей изменения заказа
actor Пользователь as user
participant ARM as ARM
participant Gateway as Gateway
participant History as History
participant Bifrost as Bifrost
autonumber
user -> ARM: Нажимает кнопку "История изменений"
ARM -> Gateway: REST GET /history/v1/filters
Gateway -> History: gRPC GetTypesOfEvents()
History --> Gateway: AvailableActions (список типов событий)
Gateway --> ARM: HistoryFiltersList (eventCorrectionType[])
ARM -> Gateway: REST GET /history/v1/order/{orderID}
Gateway -> History: gRPC GetChangesByOrderIDAndParameters()
History --> Gateway: EventsByOrderIDResponse
Gateway -> Bifrost: gRPC GetUsersByIDs() [для получения имен менеджеров]
Bifrost --> Gateway: UserInfo[]
Gateway --> ARM: HistoryList (события с именами менеджеров)
ARM --> user: Рендерит модальное окно "История изменений" с фильтрами
user -> ARM: Нажимает кнопку "Подробнее" в корректировке
ARM -> Gateway: REST GET /history/v1/events?eventIDs=[eventID]
Gateway -> History: gRPC GetEventChangesByIDs()
History --> Gateway: EventChangesByIDResponse[]
Gateway -> Bifrost: gRPC GetUserByIDV2() [для получения имени менеджера]
Bifrost --> Gateway: UserInfo
Gateway --> ARM: HistoryEvent (с полными изменениями)
ARM --> user: Отображает полную информацию о корректировке
alt Первый тип поиска по дате и/или типу корректировки
user -> ARM: Выбирает фильтр по дате или по типу корректировки
ARM -> Gateway: REST GET /history/v1/order/{orderID}?eventCorrectionType=...&createdAts=...
Gateway -> History: gRPC GetChangesByOrderIDAndParameters() [с фильтрами]
History --> Gateway: EventsByOrderIDResponse
Gateway -> Bifrost: gRPC GetUsersByIDs() [для получения имен менеджеров]
Bifrost --> Gateway: UserInfo[]
Gateway --> ARM: HistoryList (отфильтрованные события)
ARM --> user: Отображает корректировки по заданным условиям
else Второй тип поиска по идентификатору корректировки
user -> ARM: Вводит идентификатор корректировки и нажимает Enter
ARM -> Gateway: REST GET /history/v1/events?eventIDs=[eventID]
Gateway -> History: gRPC GetEventChangesByIDs()
History --> Gateway: EventChangesByIDResponse[]
Gateway -> Bifrost: gRPC GetUserByIDV2() [для получения имени менеджера]
Bifrost --> Gateway: UserInfo
Gateway --> ARM: HistoryEvent (с полными изменениями)
ARM --> user: Отображает корректировки по заданным условиям
end
@enduml

View File

@@ -8,34 +8,64 @@
FontName Helvetica
FontColor black
FontSize 18
FontStyle bold
'FontStyle bold
}
arrow {
LineColor #000
LineThickness 3
LineStyle 2
LineThickness 1
LineStyle 5
}
highlight {
BackGroundColor #e5e5e5
FontColor black
}
}
' Здесь находятся расцветки изменений. Необходимо создать новый объект по образу .firstChange
' Здесь находятся расцветки изменений. Необходимо создать новый объект по образу .headerBlock
.headerBlock {
FontColor red
FontStyle bold
BackGroundColor grey
}
.firstChange {
FontColor blue
FontColor black
FontStyle bold
BackGroundColor Blue
}
</style>
' Здесь указываем какие атрибуты нужно подсвечивать в схеме
#highlight "order" / "Recipient" / "ID" <<firstChange>>
#highlight "order" / "Recipient" / "RecipientAddress" <<firstChange>>
#highlight "order" / "Recipient" / "RecipientPhone" <<firstChange>>
#highlight "order" / "Recipient" / "RecipientName" <<firstChange>>
'Пример другого цвета
#highlight "order" / "Shipment" / "shipmentFastDelivery" <<firstChange>>
' Заголовки (выделены красным и темно-серым для улучшения читаемости)
#highlight "order" / "Artifacts" / "Artifacts" <<headerBlock>>
#highlight "order" / "Artifacts" / "Artifacts" <<headerBlock>>
#highlight "order" / "B2CContractor" / "B2CContractor" <<headerBlock>>
#highlight "order" / "B2BContractor" / "B2BContractor" <<headerBlock>>
#highlight "order" / "Properties" / "Properties" <<headerBlock>>
#highlight "order" / "Supplies (array)" / "Supplies (array)" <<headerBlock>>
#highlight "order" / "Shipment" / "Shipment" <<headerBlock>>
#highlight "order" / "Shipment" / "ShipmentPickup" / "ShipmentPickup" <<headerBlock>>
#highlight "order" / "Shipment" / "ShipmentPickupFranchise" / "ShipmentPickupFranchise" <<headerBlock>>
#highlight "order" / "Shipment" / "ShipmentCourier" / "ShipmentCourier" <<headerBlock>>
#highlight "order" / "Shipment" / "shipmentTKCourier" / "shipmentTKCourier" <<headerBlock>>
#highlight "order" / "Shipment" / "ShipmentTKPickup" / "ShipmentTKPickup" <<headerBlock>>
#highlight "order" / "Shipment" / "shipmentFastDelivery" / "shipmentFastDelivery" <<headerBlock>>
#highlight "order" / "Shipment" / "Meta" / "Meta" <<headerBlock>>
#highlight "order" / "Contractor" / "Contractor" <<headerBlock>>
#highlight "order" / "Recipient" / "Recipient" <<headerBlock>>
#highlight "order" / "managerInfo" / "managerInfo" <<headerBlock>>
{
"order": {
"orderID": "uuid || Номер заказа",
"ID": "uuid || Номер заказа",
"ContractorID": "uuid || Идентификатор контрагента",
"RootOrder": "uuid || UUID корневого заказа",
"Number": "string || Номер заказа в формате ****-******-*****",
"ContractorType": "int || Тип КА",
"OrderStatus": "int || Идентификатор статуса заказа (от 0 до 7)",
"managerInfo": {
"managerInfo": "Блок информации о менеджере в заказе (ManagerInfo)",
"CreatedBy": "uuid || Идентификатор автора заказа из AD",
"CreatedFullName": "string || ФИО автора заказа",
"UpdatedBy": "uuid || Идентификатор последнего обновлявшего заказ",
@@ -44,12 +74,8 @@
"ManagerPhoneNumber": "string || Номер телефона менеджера",
"ManagerExtensionNumber": "string || Добавочный номер телефона менеджера"
},
"RootOrder": "uuid || UUID корневого заказа",
"Number": "string || Номер заказа в формате ****-******-*****",
"OrderStatus": "int || Идентификатор статуса заказа (от 0 до 7)",
"Contractor": {
"Type": "int || Тип контрагента.",
"B2CContractor": {
"B2CContractor": "Контрагент b2c (вложенный объект с атрибутами дальше по ветке)",
"Person": {
"ID": "uuid || Идентификатор (UUID) контрагента",
"FullName": "string || Полное ФИО КА",
@@ -58,9 +84,18 @@
}
},
"B2BContractor": {
"B2BContractor": "Блок контрагента B2b",
"ID": "uuid || Идентификатор (UUID) контрагента",
"Name": "string || Полное наименование КА",
"TIN": "string || Номер ИНН",
"edo": "boolean || Признак что КА работает по ЭДО",
"isPDZ": "boolean || false",
"paymentType": "integer || Признак оплаты, 1 - предоплата, 2 - постоплата",
"Agent": {
"ID": "uuid || Индентификатор агента заказа",
"OrderNumber": "string || Номер заказа в системе агента",
"ContractType": "integer || Тип договора к заказу, 1 - агентский, 2 - клиентский, 3 - торговый дом"
},
"ContactPersons (array)": {
"Person": {
"ID": "uuid || Идентификатор (UUID) контрагента",
@@ -75,6 +110,10 @@
"ID": "uuid || Идентификатор куратора",
"FullName": "string || ФИО куратора"
},
"KAM": {
"ID": "uuid || Идентификатор КАМа",
"FullName": "string || ФИО КАМа"
},
"Contract": {
"ID": "uuid || Идентификатор договора",
"Number": "string || Номер договора",
@@ -89,49 +128,18 @@
"OtherInformation": "string || Иные сведения"
}
}
}
},
"Recipient": {
"Recipient": "Блок грузополучателя (Deprecated) для поддержки старых заказов. Актуальный в shipment",
"ID": "uuid || Идентификатор (UUID) грузополучателя",
"RecipientName": "string || Имя грузополучателя заказа",
"RecipientPhone": "string || Номер телефона грузополучателя",
"RecipientAddress": "string || Адрес грузополучателя"
},
"Properties": {
"BasicTimestamps": {
"CreatedAt": "date-time || Дата и время создания заказа",
"UpdatedAt": "date-time || Дата и время последнего обновления заказа"
},
"OriginID": "int || Идентификатор источника заказа",
"SiteOrderDate": "date-time || Дата и время заказа выбранное на сайте",
"OrderComment": "string || Комментарий к заказу. Во wtis: primSklad",
"TtnNumber": "string || Номер ТТН",
"TtnDate": "string || Дата ТТН",
"IsPartialShipmentFromSite": "bool || Признак ЧО с сайта",
"PaymentAmount": "float || Сумма внесенной оплаты",
"BookingEndDates": "array || Массив с датами истечения бронирования заказа",
"IsPrepaymentRequired": "bool || Признак Необходима предоплата",
"RegionGUID": "uuid || Идентификатор (UUID) региона",
"RegionName": "string || Наименование региона",
"TypeOrderFromSite": "string || Тип заказа с сайта. normal / fast",
"Firma": "GUID фирмы отгружающей товар."
},
"Artifacts": {
"PartialShipment": "bool || Признак Частичная отгрузка",
"OrderMasterSystem": "string || Признак мастер-система по заказу",
"KkmDate": "string || Дата ККМ",
"KkmAmount": "float || Сумма оплаты через ККМ",
"PaymentKkm": "bool || Признак оплата через ККМ",
"PaymentCb": "bool || Признак оплата по счету",
"PaymentCard": "bool || Признак картой",
"IsEwalletPayment": "bool || Признак оплата с сайта",
"OrderStateWtis": "int || Состояние заказа из WTIS",
"AttbOplata": "int || Статус оплаты (0 - Не оплачено, 1 - Частичная оплата, 2 - Оплачено). || deprecated",
"OrderStatusWtis": "int || Статус заказа из WTIS",
"IsPromoEnabled": "bool || Признак, что сайт взаимодействует с МС Promo и берет распродажную инфу оттуда.",
"IsYandexEnabled": "bool || Признак, что адрес передается в новом формате для курьерки."
"RecipientAddress": "string || Адрес грузополучателя",
"isConsingeeApprove": "boolean || Признак подтверждения смены ГП"
},
"Items": "map[uuid.UUID]Item || Товары в заказе",
"Supplies (array)": {
"Supplies (array)": "Блок товарной части (supply)",
"ID": "uuid || Идентификатор поставки",
"ShipmentID": "uuid || Идентификатор шипмента",
"ProductID": "uuid || Идентификатор номенклатуры",
@@ -142,51 +150,190 @@
"Quantity": "int || Количество товара в доставке. Суммарное количество должно быть равно quantity в items",
"StatusItem": "int || Идентификатор статуса товара",
"Artifacts": {
"StatusItemWtis": "int || Клиентский статус товара из WTIS",
"Attb": "Состоние товара из WTIS",
"UUIDWtis": "uuid || UID товара из wtis",
"StatusItemWtis": "int || Статус товара из wtis",
"Attb": "int || Состояние товара во WTIS",
"AttbSklad": "int || Статус местонахождения товара (0 - Свободный, 1 - проверен)",
"AttbShipped": "int || Признак 'Товар доставлен' (0 - не доставлен, 1 - доставлен)",
"AttbReserve": "int || Атрибут резерва",
"FlagReturn": "bool || Признак Возврат товара. 1 - товар с вкладки Возвраты, 0 - для товаров с вкладки Товары.",
"FlagReturnedToSklad": "bool || Принят на склад",
"ReturnReason": "int || Причина возврата (1-sklad,2-kurier,3-manager,4-client)",
"AppendUser": "uuid || ID пользователя кто добавил поставку",
"ChangeUser": "uuid || ID пользователя кто последний изменил поставку"
"ChangeUser": "uuid || ID пользователя кто последний изменил поставку",
"OnHold": "bool || Флаг товар в процессе переноса",
"IsLargeSized": "bool || Флаг кгт (крупногабаритный товар)"
},
"DateCanDeliver": "date-time || Дата 'Сможем доставить'.",
"CreatedAt": "date-time || Дата создания поставки",
"UpdatedAt": "date-time || Дата последнего обновления поставки",
"Prices": {
"SupplyID": "uuid || Идентификатор поставки",
"DiscountPrice": "float || Сумма скидки",
"DiscountManualPrice": "float || Сумма скидки (ручная корректировка)",
"DiscountCategory": "string || Категория скидки",
"DiscountReason": "string || Причина скидки",
"DiscountType": "string || Тип скидки (manager, contractor)",
"DiscountManualType": "string || Тип ручной корректировки цены",
"DiscountManualTypeID": "uuid || Идентификатор типа ручной корректировки",
"Reason": "int || Причина скидки",
"InitialPrice": "float || Начальная цена",
"PurchasePrice": "float || Цена закупки",
"Price": "float || Цена товара",
"SalePrice": "float || Продажная цена",
"Discount": "float || Процент скидки",
"ClearanceSaleID": "uuid || Идентификатор распродажи",
"IsPromoCodeUsed": "bool || Флаг использования промокода",
"PromotionID": "int || Идентификатор акции из МС Promo",
"PromoCode": "string || Промокод в заказе",
"DiscountClearanceSale": "float || Сумма скидки от акции Промо",
"DiscountPromoCode": "float || Сумма скидки от промокода",
"DiscountClearance": "float || Процент скидки от акции/скидки",
"ExtraCost": "float || Цена доставки на единицу товара"
},
"IsRestored": "bool || Признак восстановления поставки.",
"IsAutoRestored": "bool || Признак автовосстановления поставки через sync",
"DeliveryDate": "date-time || Дата доставки"
},
"Supplies": "Supplies || поставки",
"Properties": {
"Properties": "Блок свойства заказа",
"BasicTimestamps": {
"CreatedAt": "date-time || Дата и время создания заказа",
"UpdatedAt": "date-time || Дата и время последнего обновления заказа"
},
"NumberSchemeBalance": "string || Номер схемы баланса",
"AccountingLine": "AccountingLine || Линия учета",
"OriginID": "int || Идентификатор источника заказа",
"SiteOrderDate": "date-time || Дата и время заказа выбранное на сайте",
"OrderComment": "string || Комментарий к заказу. Во wtis: primSklad",
"PrimSklad": "string || Примечание для менеджера",
"TtnNumber": "string || Номер ТТН",
"TtnDate": "string || Дата ТТН",
"Ttn": "string || Товарно-транспортная накладная (ТТН)",
"BillIsAutoOrdered": "bool || Признак 'Счет автоотправлен'",
"IsAutoReserved": "bool || Признак Заказ автооформлен",
"IsAutoBotOrder": "bool || Признак Заказ создан автоботом",
"IsPartialShipmentFromSite": "bool || Признак ЧО с сайта",
"IsLeasing": "bool || Признак оформления заказа в лизинг",
"PaymentAmount": "float || Сумма внесенной оплаты",
"PaymentPercentage": "int || процент оплаченности заказа",
"Prepayment": "float || Сумма внесенной предоплаты",
"ManagerGroup": "int || Группа менеджера",
"ManagerID": "uuid || Идентификатор (UUID) менеджера заказа",
"ManagerFullName": "string || ФИО менеджера заказа",
"ManagerPhoneNumber": "string || Телефон менеджера заказа",
"ManagerExtensionNumber": "string || Добавочный номер телефона менеджера",
"ConfirmationStatus": "ConfirmationStatus || Статус подтвержения заказа клиентом",
"BookingEndDates": "array || Массив с датами истечения бронирования заказа",
"PaymentDoc": "string || Наименование платежного документа",
"IsPrepaymentRequired": "bool || Признак 'Необходима предоплата'",
"RegionGUID": "uuid || Идентификатор (UUID) региона",
"RegionName": "string || Наименование региона",
"IsTest": "bool || Признак тестового заказа",
"ReasonForCancelingOrder": "int || Причина отмены заказа",
"TypeOrderFromSite": "string || Тип заказа с сайта. normal / fast",
"Firma": "GUID фирмы отгружающей товар.",
"FlowID": "int || Флоу заказа (аналог OriginID с доп логикой)",
"PriceFixing": {
"Number": "int || Порядковый номер фиксации",
"EndDate": "date-time || Дата окончания фиксации"
},
"b2gLaw": "string || Федеральный закон по которому отгружается заказ",
"b2gLawSite": "string || Федеральный закон выбранный пользователем на сайте",
"SalesChannelID": "int || Идентификатор канала продаж",
"SalesChannelName": "string || Наименование канала продаж",
"GroupManagerName": "string || Наименование группы менеджеров",
"IsAoSuccess": "bool || Флаг успешного автооформления",
"ReturnOrder": "bool || Признак возвратного заказа",
"VerificationCode": "bool || Признак подтверждения получения заказа по коду"
},
"Artifacts": {
"Artifacts": "Блок артефактов",
"UUIDWtis": "uuid || UUID заказа из wtis",
"PartialShipment": "bool || Признак Частичная отгрузка",
"Firma": "uuid || GUID фирмы отгружающей товар",
"RegionID": "int || Идентификатор региона из wtis",
"MainRegionID": "int || Идентификатор главного региона из wtis",
"BasketNumber": "string || Номер корзины клиента",
"OrderMasterSystem": "string || Признак мастер-система по заказу",
"StockMasterSystem": "StockMasterSystem || Мастер система по товародвижению",
"KkmDate": "string || Дата ККМ",
"KkmAmount": "float || Сумма оплаты через ККМ",
"PaymentKkm": "bool || Признак оплата через ККМ",
"PaymentCb": "bool || Признак оплата по счету",
"PaymentCard": "bool || Признак картой",
"IsEwalletPayment": "bool || Признак оплата с сайта",
"IsCredit": "bool || Признак кредитного заказа",
"OrderStateWtis": "int || Состояние заказа из WTIS",
"AttbOplata": "int || Статус оплаты (0 - Не оплачено, 1 - Частичная оплата, 2 - Оплачено). || deprecated",
"OrderStatusWtis": "int || Статус заказа из WTIS",
"IsPromoEnabled": "bool || Признак, что сайт взаимодействует с МС Promo и берет распродажную инфу оттуда.",
"IsYandexEnabled": "bool || Признак, что адрес передается в новом формате для курьерки."
},
"UpdateReason": "int || Причина обновления",
"Parts": "map[uuid.UUID]Part || Части заказа",
"HasTransaction": "bool || Признак наличия транзакции",
"IsNewVersion": "bool || Признак новой версии сущности",
"BaseShipmentID": "uuid || UUID доставки",
"DeliveryDate": "date-time || Дата доставки",
"Shipment": {
"Shipment": "Блок Доставка (Shipment)",
"Meta": {
"Meta": "Блок мета информации о доставке (Meta)",
"ID": "uuid || Идентификатор shipment",
"OrderID": "uuid || Идентификатор заказа",
"MethodID": "int || Идентификатор шипмента",
"Status": "int || Статус доставки",
"FSMStatus": "object || fsm для статуса",
"Artifacts": {
"DeliveryWith": "string || Начальный временной промежуток курьерской доставки",
"TrackingNumberID": "int || Deprecated",
"PartnerDeliverTo": "string || Deprecated",
"DestinationOfficeID": "int || Deprecated",
"Category": "int || Deprecated",
"DeliveryOn": "string || Верхняя граница часов доставки",
"DeliveryWay": "string || Тип доставки, через транспортную компанию",
"DeliveryType": "bool || 0 - обычная доставка 1 - доставка строительных материалов",
"DeliveryZone": "int || id зоны доставки строительных материалов",
"VeerouteExportDate": "date-time || Дата выгрузки в Veeroute",
"AddressID": "int || Идентификатор адреса доставки (внутренний от WTIS)",
"DeliveryDestinationType": "int || Тип отгрузки (1 - склад, 2 - курьер, 4 - ТК)"
},
"DeliveryDate": "date-time || Дата доставки",
"IsCustomDeliveryDate": "bool || Ручное изменение дата доставки",
"Services": {
"Settings": {
"SpreadExtraCost": "bool || Размазать стоимость доставки по товарам связанным с доставкой"
"SpreadExtraCost": "bool || Размазать стоимость доставки по товарам связанным с доставкой",
"IsShipmentPossible": "bool || Отгружать с ПДЗ",
"isPacking": "bool || Признак 'Упаковать заказ как на ТК'"
},
"LiftToFloor": {
"Price": "int || Цена услуги подъема на этаж",
"ElevatorStatus": "int || Статус лифта"
}
},
"CreatedAt": "date-time || Дата создания доставки",
"UpdatedAt": "date-time || Дата последнего обновления доставки"
"UpdatedAt": "date-time || Дата последнего обновления доставки",
"Recipient": {
"ID": "uuid || Идентификатор грузополучателя",
"RecipientName": "string || Имя грузополучателя",
"RecipientPhone": "string || Телефон грузополучателя",
"IsConsigneeApprove": "bool || Наличие подтверждения о смене ГП",
"InvoiceConsigneeAddress": "string || Доп адрес грузополучателя"
}
},
"ShipmentPickup": {
"ShipmentPickup": "Блок Самовывоз (ShipmentPickup)",
"OfficeGUID": "uuid || Идентификатор офиса"
},
"ShipmentPickupFranchise": {
"ShipmentPickupFranchise": "Блок Самовывоз франшиза (ShipmentPickupFranchise)",
"OfficeGUID": "uuid || UUID ТТ франшизы",
"FranchisePartnerID": "uuid || UUID партнера из МСКБ",
"FranchisePartnerName": "string || Наименование партнера из МСКБ"
},
"ShipmentCourier": {
"ShipmentCourier": "Блок Курьером (ShipmentCourier)",
"FactDeliveryBoy": "uuid || Идентификатор курьера который отдал заказ",
"FreeReason": "int || Причина бесплатной доставки",
"FiasID": "uuid || FIAS идентификатор адреса доставки",
@@ -194,9 +341,10 @@
"DeliveryAregGUID": "uuid || Идентификатор AREG адреса доставки",
"AddressTail": {
"AddressTailID": "uuid || Идентификатор хвоста адреса",
"Flat": "int || Номер квартиры",
"Entrance": "int || Подъезд",
"Floor": "int || Этаж",
"Postcode": "string || Почтовый индекс",
"Flat": "string || Кв./Офис",
"Entrance": "string || Подъезд",
"Floor": "string || Этаж",
"AddressComment": "string || Комментарий к адресу",
"ContactNumber": "string || Контактный номер в адресе доставки"
},
@@ -207,9 +355,14 @@
"DeliveryBoyName": "string || ФИО курьера в заказе",
"AddrDostav": "string || Адрес доставки",
"CourierDeliveryCost": "int || Стоимость доставки",
"CourierComment": "string || Комментарий для курьера"
"InitialCourierDeliveryCost": "int || Начальная цена доставки курьером",
"CourierComment": "string || Комментарий для курьера",
"DeliveryCategoryType": "int || Тип категории доставки",
"DeliveryCategoryName": "string || Название категории доставки",
"OfficeGUID": "uuid || Офис отгрузки курьеру"
},
"ShipmentTKPickup": {
"ShipmentTKPickup": "Блок ТК Самовывоз (ShipmentTKPickup)",
"TransportCompanyID": "uuid || Идентификатор транспортной компании",
"TransportCompanyCityID": "uuid || Идентификатор города ТК",
"TransportCompanyCityName": "string || Название города ТК",
@@ -217,9 +370,11 @@
"TransportCompanyTariffID": "uuid || Идентификатор тарифа ТК",
"TransportCompanyTariffName": "string || Наименование тарифа",
"CourierDeliveryCost": "int || Стоимость доставки",
"InitialCourierDeliveryCost": "int || Начальная цена доставки курьером",
"CourierComment": "string || Комментарий для курьера"
},
"shipmentTKCourier": {
"shipmentTKCourier": "Блок ТК Курьером (ShipmentTKCourier)",
"TransportCompanyID": "uuid || Идентификатор транспортной компании",
"TransportCompanyCityID": "uuid || Идентификатор города ТК",
"TransportCompanyCityName": "string || Название города ТК",
@@ -235,17 +390,47 @@
"DeliveryAregGUID": "uuid || Идентификатор AREG адреса доставки",
"AddressTail": {
"AddressTailID": "uuid || Идентификатор хвоста адреса",
"Flat": "int || Номер квартиры",
"Entrance": "int || Подъезд",
"Floor": "int || Этаж",
"PostCode": "string || Индекс адреса доставки",
"Flat": "string || Кв./Офис",
"Entrance": "string || Подъезд",
"Floor": "string || Этаж",
"AddressComment": "string || Комментарий к адресу",
"ContactNumber": "string || Контактный номер в адресе доставки"
},
"CourierDeliveryCost": "int || Стоимость доставки",
"InitialCourierDeliveryCost": "int || Начальная цена доставки курьером",
"DeliveryWay": "int || Тип доставки, через транспортную компанию",
"CourierComment": "string || Комментарий для курьера"
}
"CourierComment": "string || Комментарий для курьера",
"DeliveryCategoryType": "int || Тип категории доставки",
"DeliveryCategoryName": "string || Название категории доставки"
},
"shipmentFastDelivery": {
"shipmentFastDelivery": "Блок Быстрая доставка (ShipmentFastDelivery)",
"OfficeGUID": "uuid || Идентификатор офиса",
"FactDeliveryBoy": "uuid || Идентификатор курьера который отдал заказ",
"FreeReason": "int || Причина бесплатной доставки",
"FiasID": "uuid || FIAS идентификатор адреса доставки",
"IntervalGUID": "uuid || Идентификатор интервала курьерской доставки",
"DeliveryAregGUID": "uuid || Идентификатор AREG адреса доставки",
"AddressTail": {
"AddressTailID": "uuid || Идентификатор хвоста адреса",
"Flat": "string || Кв./Офис",
"Entrance": "string || Подъезд",
"Floor": "string || Этаж",
"AddressComment": "string || Комментарий к адресу",
"ContactNumber": "string || Контактный номер в адресе доставки"
},
"IntervalValue": "string || Значение интервала доставки",
"Latitude": "string || Широта адреса доставки",
"Longitude": "string || Долгота адреса доставки",
"CourierGUID": "uuid || Идентификатор курьера в заказе",
"DeliveryBoyName": "string || ФИО курьера в заказе",
"AddrDostav": "string || Адрес доставки",
"CourierDeliveryCost": "int || Стоимость доставки",
"CourierComment": "string || Комментарий для курьера",
"DeliveryDate": "date-time || Дата доставки"
}
}
}
}
@endjson

View File

@@ -0,0 +1,83 @@
@startuml
!theme plain
title Обработка товарных позиций при корректировке
start
:Получена корректировка заказа;
:Сравнить товары OMS и WTIS;
partition "Определить операции с товарами" {
:Товары для добавления;
note right: Есть в OMS, нет в WTIS
:Товары для удаления;
note right: Есть в WTIS, нет в OMS
:Товары для изменения;
note right: Есть в обоих, но с отличиями
}
partition "Обработать изменения товаров" {
if (Есть товары для изменения?) then (да)
:Для каждого товара проверить изменения;
if (Изменилось количество?) then (да)
if (Товар в резерве?) then (да)
:Создать копию с новым количеством;
:Удалить избыточную часть;
note right: Сложная логика split
else (нет)
:Изменить количество напрямую;
endif
endif
if (Изменилась цена?) then (да)
:Обновить цену и скидку;
endif
if (Изменился резерв?) then (да)
:Обновить дату резерва;
endif
endif
}
partition "Применить операции" {
if (Есть товары для добавления?) then (да)
:Создать новые товарные позиции;
endif
if (Есть товары для изменения?) then (да)
:Обновить существующие позиции;
endif
if (Есть товары для удаления?) then (да)
:Снять резерв с товаров;
:Установить статус "Удален";
:Удалить из заказа;
endif
}
partition "Обработать резервирование" {
if (Смена региона или ПВЗ?) then (да)
:Снять резерв со всех товаров;
note right: При смене региона/ПВЗ
endif
if (Есть товары для резервирования?) then (да)
:Зарезервировать товары;
note right: Из массива reserve
endif
if (Есть товары для снятия резерва?) then (да)
:Снять резерв с товаров;
note right: Из массива unreserve
endif
}
:Завершить обработку;
stop
@enduml

View File

@@ -0,0 +1,158 @@
@startuml
!theme plain
title Обработка корректировки заказа на WTIS
participant "Kafka" as Kafka
participant "Обработчик" as Handler
participant "Сервис синхронизации" as Service
participant "Сравнитель заказов" as Differ
participant "Создатель заказов" as Creator
participant "Резервирование" as Reserve
participant "База данных" as DB
== Получение корректировки ==
Kafka -> Handler: Сообщение корректировки
Handler -> Service: Обработать корректировку
== Поиск заказа ==
Service -> DB: Найти заказ по GUID
alt Заказ не найден
Service -> Creator: Создать новый заказ
else Заказ существует
Service -> Differ: Сравнить заказы OMS и WTIS
== Анализ изменений ==
Differ -> Differ: Сравнить поля заказа
note right: регион, ПВЗ, способ доставки,\nконтрагент, адрес, дата доставки
Differ -> Differ: Сравнить товарные позиции
note right: количество, цены, резерв
Differ --> Service: Список изменений
== Специальная обработка смены региона/ПВЗ ==
alt Смена региона или ПВЗ
Service -> Reserve: Снять резерв со всех товаров
note right: При смене региона/ПВЗ\nснимается весь резерв
end
== Применение изменений ==
Service -> Differ: Применить изменения к заказу
Service -> Creator: Сохранить заказ
== Обработка товаров ==
note over Service: **ДЕТАЛЬНАЯ СХЕМА:**\n"Обработка товарных позиций"
Service -> Service: Определить операции с товарами
note right: Товары для добавления,\nизменения, удаления
alt Есть товары для добавления
Service -> Creator: Добавить новые товары
end
alt Есть товары для изменения
Service -> Service: Обновить существующие товары
note right: **См. детальную схему:**\n- Изменение количества (split)\n- Изменение цен\n- Изменение резерва
end
alt Есть товары для удаления
Service -> Reserve: Снять резерв
Service -> Service: Удалить товары
note right: **См. детальную схему:**\nУстановка статуса "Удален"
end
end
== Резервирование товаров ==
note over Service: **ДЕТАЛЬНАЯ СХЕМА:**\n"Обработка товарных позиций"\n(блок "Резервирование")
alt Есть товары для резервирования
Service -> Reserve: Зарезервировать товары
note right: Из массива reserve
end
alt Есть товары для снятия резерва
Service -> Reserve: Снять резерв
note right: Из массива unreserve
end
== Завершение ==
Service -> Service: Обновить сайтовый заказ
Service -> Service: Отправить SMS клиенту
Service -> Service: Экспортировать в OMS
Service --> Handler: Результат обработки
Handler --> Kafka: Подтверждение
@enduml
@startuml
!theme plain
title Обработка корректировки заказа на WTIS
start
:Получение сообщения корректировки из Kafka oms.order.sync;
if (Заказ найден в БД?) then (нет)
:Создать новый заказ;
else (да)
:Сравнить заказы OMS и WTIS по атрибутам;
if (Смена региона или ПВЗ И есть товары для резерва?) then (да)
:Снять резерв с товаров из массива reserve;
else (нет)
endif
:Применить изменения к заказу;
:Сохранить заказ в БД;
:Определить операции с товарами;
if (Есть товары для добавления?) then (да)
:Добавить новые товары в заказ;
else (нет)
endif
if (Есть товары для изменения?) then (да)
:Обновить существующие товары;
if (Есть товары с уменьшением количества в резерве?) then (да)
:Создать копию товара с новым количеством;
:Удалить избыточную часть;
else (нет)
endif
else (нет)
endif
if (Есть товары для удаления?) then (да)
:Снять резерв с товаров;
:Установить статус "Удален";
:Удалить товары из заказа;
else (нет)
endif
:Установить скидки, контакты, адреса;
:Обновить дополнительные свойства заказа;
if (Есть товары для резервирования И не сайтовый заказ?) then (да)
:Зарезервировать товары из массива reserve;
else (нет)
endif
if (Есть товары для снятия резерва И не отмена заказа?) then (да)
:Снять резерв с товаров из массива unreserve;
else (нет)
endif
:Обновить заказ во wtis_doc_zayavki;
:Обновить заказ во wtis_doc_zayavki_site;
if (Не сайтовый заказ И активный И подтвержденный?) then (да)
:Отправить SMS клиенту с задержкой 10 минут;
else (нет)
endif
:Экспортировать данные обратно в OMS;
endif
:Подтверждение обработки в Kafka;
stop
@enduml

View File

@@ -0,0 +1,48 @@
@startuml Процесс создания и жизненный цикл заказа
state "Заказ не создан" as start
state "НОВЫЙ" as new_order
state "ЗАБРОНИРОВАН" as booked {
state "Таймер брони (3 дня)" as reserve_timer
}
state "Оформление..." as processing_payment
state "В РАБОТЕ" as in_progress
state "ОТМЕНЕН" as cancelled
state "Товар в закупке" as purchasing
start --> new_order : Создать заказ
new_order --> cancelled : Кнопка "Отменить заказ"\n(Ручная отмена)
new_order --> booked : Кнопка "Забронировать"\n(Синхронный запрос во Втис)
booked --> booked : **Успех:** Товары зарезервированы
booked --> new_order : Кнопка "Отменить бронирование"\n(Таймер брони продолжает идти)"
reserve_timer --> cancelled : Истек 3 дня\n(Автоотмена брони)
booked --> cancelled : Кнопка "Отменить заказ"\n(Ручная отмена)
new_order --> processing_payment : Кнопка "Оформить"
booked --> processing_payment : Кнопка "Оформить"
processing_payment --> in_progress : **Успех:** Товары доступны\nЗаказ передан в системы товародвижения
processing_payment --> purchasing : **Неудача:** Товара нет в наличии\n(Запуск процесса закупки)
purchasing --> in_progress : Товар закуплен
state in_progress {
state "Заказ выполняется" as active
state "Резерв продлен" as extended
active --> extended : Кнопка "Продлить резерв"\n(Правила: 1 раз если не оплачен,\n∞ раз (Ст. менеджер) если оплачен)
extended --> active
}
in_progress --> cancelled : Кнопка "Отменить заказ"
@enduml

BIN
plantuml.jar Normal file

Binary file not shown.

View File

@@ -1,11 +1,115 @@
@startuml
'https://plantuml.com/sequence-diagram
@startuml CompetitorProductMultipleSave
scale 0.8
actor Client
participant "API Endpoint" as API
participant "Validation" as Validation
participant "Database" as DB
participant "Kafka" as Kafka
participant "Logging" as Log
autonumber
Client -> API: POST /v1/ui/competitor-product/multiple-save\n{JSON request}
API -> Validation: Deserialize JSON to Protobuf
Alice -> Bob: Authentication Request
Bob --> Alice: Authentication Response
alt Deserialization error
Validation -> Log: ERROR "PRC-MATCH-1501 | <error>"
API -> Client: 400 Bad Request\n{error details}
return
end
Alice -> Bob: Another authentication Request
Alice <-- Bob: another authentication Response
group Type = CREATE (0)
Validation -> Validation: Check for IDs in CREATE mode
loop For each invalid object
Validation -> Log: WARN "PRC-MATCH-1502 | <warning>"
end
Validation -> Validation: Check for duplicates in request
loop For each duplicate
Validation -> Log: WARN "PRC-MATCH-1503 | <warning>"
end
Validation -> DB: Bulk SELECT by (competitor_id + sku)
alt DB error
DB -> Log: ERROR "PRC-MATCH-1504 | <error>"
API -> Client: 500 Server Error\n{error response}
end
loop For each existing record
Validation -> Log: WARN "PRC-MATCH-1505 | <warning>"
end
DB -> API: Return existing records
Validation -> Validation: Filter valid records
alt No valid records
API -> Client: 200 OK\n{empty response}
end
API -> DB: Bulk INSERT with RETURNING id
alt DB error
DB -> Log: ERROR "PRC-MATCH-1504 | <error>"
API -> Client: 500 Server Error\n{error response}
end
DB -> API: Return new IDs
end
group Type = UPDATE (1)
Validation -> Validation: Check for missing IDs
loop For each invalid object
Validation -> Log: WARN "PRC-MATCH-1502 | <warning>"
end
Validation -> Validation: Check for duplicate IDs
loop For each duplicate
Validation -> Log: WARN "PRC-MATCH-1503 | <warning>"
end
Validation -> DB: Bulk SELECT by IDs
alt DB error
DB -> Log: ERROR "PRC-MATCH-1504 | <error>"
API -> Client: 500 Server Error\n{error response}
return
end
loop For each not found ID
Validation -> Log: WARN "PRC-MATCH-1505 | <warning>"
end
Validation -> Validation: Validate status transitions
loop For each invalid transition
Validation -> Log: WARN "PRC-MATCH-1506 | <warning>"
end
alt No valid records
API -> Client: 200 OK\n{empty response}
return
end
API -> DB: Bulk UPDATE
alt DB error
DB -> Log: ERROR "PRC-MATCH-1504 | <error>"
API -> Client: 500 Server Error\n{error response}
return
end
end
API -> Kafka: Send to parsing.collector.out
alt Kafka error
Kafka -> Log: ERROR "PRC-MATCH-1507 | <error>"
API -> Client: 500 Server Error\n{error response}
return
end
API -> Kafka: Send to parsing.competitor_product_status.update
alt Kafka error
Kafka -> Log: ERROR "PRC-MATCH-1508 | <error>"
API -> Client: 500 Server Error\n{error response}
return
end
API -> Client: 200 OK\n{success response}
API -> Log: INFO "PRC-MATCH-1509 | <success>"
@enduml

View File

@@ -0,0 +1,78 @@
@startuml
actor Пользователь
participant "АРМ" as UI
participant "Gateway" as GW
participant "Scrooge\n(список причин)" as SCR
participant "Backend" as BE
participant "WorkFlow\nimportPriceSupplyToOrderWorkflow" as WF
participant "MongoDB" as ORD
participant "Productinfo\n(SKU в GUID)" as PI
participant "Scrooge\n(лимиты и скидки)" as LIM
participant "MS Product\n(названия товаров)" as PRD
autonumber
== Получение списка причин ==
Пользователь -> UI : нажимает «Импорт цен»
UI -> GW : GET /info/v1/discount-manual-types
GW -> SCR : вызов ручки получения типов
SCR --> GW : ответ 200 (список причин)
GW --> UI : ответ 200 (список причин)
UI -> UI : отображает список причин для выбора
Пользователь -> UI : выбирает причину
== Загрузка Excelфайла ==
Пользователь -> UI : прикрепляет Excel и нажимает «Загрузить»
UI -> GW : POST /orders/v1/{orderId}/products/import-price\n(file + manualType)
GW -> BE : перенаправляет запрос
== Парсинг Excel ==
BE -> BE : • парсинг\n• нормализация\n• базовая валидация
alt обнаружены бизнес‑ошибки при парсинге
BE -> BE : формирует ошибки\n(price_null, duplicate)
BE -> GW : ответ 200 + ошибки
GW -> UI : ответ 200 + ошибки
UI -> Пользователь : показывает список ошибок\nбизнес-ошибка "Товар не найден..."
end
BE -> WF : запускает WorkFlow (orderId, manualType, [{GUID/SKU, price}])
== WF — проверка товара ==
WF -> ORD : товар по GUID есть?
alt товар не найден
ORD --> WF : Ответ, что товар найден
WF -> PI : вызывает ConvertSkusToUids(SKU)\nhigh+low → GUID
PI --> WF : отдает GUID
WF -> ORD : повторная проверка по GUID
ORD --> WF : найден / нет
alt всё ещё не найден
WF -> WF : пропускает товар
end
end
== WF — проверка статусов ==
WF -> ORD : запрос статуса товара / заказа
ORD -> WF: ответ со статусом товара / заказа
alt статус недопустим
WF -> BE : бизнес‑ошибка «Корректировка недоступна…»
end
== WF — проверка цен ==
WF -> LIM : получает скидки по товарам
LIM --> WF : возможные скидки
WF -> WF : сравнивает цену из файла с минимальной доступной
alt цена ниже доступной
WF -> WF : устанавливает минимальную цену по правам
WF -> BE : бизнес‑ошибка «Цена ниже допустимой…»
end
== WF — обновление заказа ==
WF -> ORD : обновляет кучу полей с ценами и скидками\nлогирует корректировку цен
ORD --> WF : отдает результат выполнения скрипта
== Завершение ==
WF -> PRD : Отдает GUID товара
PRD --> WF : Получает SKU + Name товара
WF --> BE : отдает результат и ошибки
BE --> GW : ответ 200 + ошибки (если есть)
GW --> UI : ответ 200 + ошибки (если есть)
UI --> Пользователь : показывает ошибки (если есть)\nи обновленные цены
@enduml