
- Обновлена форма создания поставок расходников фулфилмента для использования v2 GraphQL API - Заменена мутация CREATE_SUPPLY_ORDER на CREATE_FULFILLMENT_CONSUMABLE_SUPPLY - Обновлена структура input данных под новый формат v2 - Сделано поле логистики опциональным - Добавлено поле notes для комментариев к поставке - Обновлены refetchQueries на новые v2 запросы - Исправлены TypeScript ошибки в интерфейсах - Удалена дублирующая страница consumables-v2 - Сохранен оригинальный богатый UI интерфейс формы (819 строк) - Подтверждена работа с новой таблицей FulfillmentConsumableSupplyOrder Технические изменения: - src/components/fulfillment-supplies/create-fulfillment-consumables-supply-v2.tsx - основная форма - src/components/fulfillment-supplies/fulfillment-supplies-layout.tsx - обновлена навигация - Добавлены недостающие поля quantity и ordered в интерфейсы продуктов - Исправлены импорты и зависимости Результат: форма полностью интегрирована с v2 системой поставок, которая использует отдельные таблицы для каждого типа поставок согласно новой архитектуре. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
20 KiB
20 KiB
🚚 АРХИТЕКТУРА СИСТЕМЫ ПОСТАВОК SFERA
🎯 ОБЗОР СИСТЕМЫ
Система поставок SFERA включает 5 типов поставок, разделенных на две категории:
📦 ПОСТАВКИ НА ФУЛФИЛМЕНТ (3 типа)
- Товарные поставки - товары селлера → склад ФФ
- Поставки расходников ФФ - расходники ФФ → склад ФФ
- Поставки расходников селлеров - расходники селлера → склад ФФ (на хранение)
🛒 ПОСТАВКИ НА МАРКЕТПЛЕЙСЫ (2+ типов)
- Поставки на Ozon - готовые продукты со склада ФФ → Ozon
- Поставки на Wildberries - готовые продукты со склада ФФ → Wildberries
📊 АРХИТЕКТУРА ДАННЫХ
✅ ПРИНЦИП: ОТДЕЛЬНАЯ ТАБЛИЦА ДЛЯ КАЖДОГО ТИПА ПОСТАВКИ
Преимущества подхода:
- 🎯 Четкое разделение ответственности
- 🔒 Упрощение системы безопасности
- 📈 Независимые схемы для разных процессов
- 🔧 Простота миграций и изменений
- 📝 Специфичные поля для каждого типа
🏗️ СТРУКТУРА ТАБЛИЦ ПОСТАВОК НА ФУЛФИЛМЕНТ
1. GoodsSupplyOrder - Товарные поставки
interface GoodsSupplyOrder {
// === БАЗОВЫЕ ПОЛЯ ===
id: string
status: SupplyOrderStatus
createdAt: DateTime
updatedAt: DateTime
// === ДАННЫЕ СЕЛЛЕРА (создатель) ===
sellerId: string // кто заказывает
fulfillmentCenterId: string // куда доставить
requestedDeliveryDate: DateTime // когда нужно
// === ДАННЫЕ ПОСТАВЩИКА ===
supplierId: string // кто поставляет
supplierApprovedAt?: DateTime // когда одобрил
packagesCount?: number // количество грузомест
estimatedVolume?: number // объем груза
supplierContractId?: string // номер договора
// === ДАННЫЕ ЛОГИСТИКИ ===
logisticsPartnerId?: string // кто везет
estimatedDeliveryDate?: DateTime // план доставки
routeId?: string // маршрут
logisticsCost?: number // стоимость доставки
// === ДАННЫЕ ОТГРУЗКИ ===
shippedAt?: DateTime // факт отгрузки
// === ДАННЫЕ ПРИЕМКИ ===
receivedAt?: DateTime // факт приемки
receivedById?: string // кто принял (сотрудник ФФ)
actualQuantity?: number // принято количество
defectQuantity?: number // брак
// === УНИКАЛЬНЫЕ ПОЛЯ ДЛЯ ТОВАРОВ ===
hasRecipes: boolean // есть ли рецептуры
totalServicesValue?: number // стоимость услуг ФФ
// === СВЯЗИ ===
items: GoodsSupplyItem[]
}
interface GoodsSupplyItem {
id: string
supplyOrderId: string // связь с поставкой
productId: string // какой товар
requestedQuantity: number // запросили
approvedQuantity?: number // поставщик одобрил
shippedQuantity?: number // отгрузили
receivedQuantity?: number // приняли
defectQuantity?: number // брак
unitPrice: number // цена за единицу
totalPrice: number // общая стоимость
// === РЕЦЕПТУРА (JSON) ===
recipe?: {
services: string[] // ID услуг ФФ
fulfillmentConsumables: string[] // ID расходников ФФ
sellerConsumables: string[] // ID расходников селлера
marketplaceCardId?: string // карточка товара
}
}
2. FulfillmentConsumableSupplyOrder - Поставки расходников ФФ
interface FulfillmentConsumableSupplyOrder {
// === БАЗОВЫЕ ПОЛЯ ===
id: string
status: SupplyOrderStatus
createdAt: DateTime
updatedAt: DateTime
// === ДАННЫЕ ФФ (создатель) ===
fulfillmentCenterId: string // кто заказывает
requestedDeliveryDate: DateTime // когда нужно
// === ДАННЫЕ ПОСТАВЩИКА ===
supplierId: string // кто поставляет
supplierApprovedAt?: DateTime // когда одобрил
packagesCount?: number // количество грузомест
estimatedVolume?: number // объем груза
supplierContractId?: string // номер договора
// === ДАННЫЕ ЛОГИСТИКИ ===
logisticsPartnerId?: string // кто везет
estimatedDeliveryDate?: DateTime // план доставки
routeId?: string // маршрут
logisticsCost?: number // стоимость доставки
// === ДАННЫЕ ОТГРУЗКИ ===
shippedAt?: DateTime // факт отгрузки
// === ДАННЫЕ ПРИЕМКИ ===
receivedAt?: DateTime // факт приемки
receivedById?: string // кто принял (сотрудник ФФ)
actualQuantity?: number // принято количество
defectQuantity?: number // брак
// === УНИКАЛЬНЫЕ ПОЛЯ ДЛЯ РАСХОДНИКОВ ФФ ===
resalePricePerUnit?: number // цена продажи селлерам
minStockLevel?: number // складские лимиты
// === СВЯЗИ ===
items: FulfillmentConsumableSupplyItem[]
}
interface FulfillmentConsumableSupplyItem {
id: string
supplyOrderId: string // связь с поставкой
productId: string // какой расходник
requestedQuantity: number // запросили
approvedQuantity?: number // поставщик одобрил
shippedQuantity?: number // отгрузили
receivedQuantity?: number // приняли
defectQuantity?: number // брак
unitPrice: number // цена за единицу от поставщика
totalPrice: number // общая стоимость
}
3. SellerConsumableSupplyOrder - Поставки расходников селлеров
interface SellerConsumableSupplyOrder {
// === БАЗОВЫЕ ПОЛЯ ===
id: string
status: SupplyOrderStatus
createdAt: DateTime
updatedAt: DateTime
// === ДАННЫЕ СЕЛЛЕРА (создатель) ===
sellerId: string // кто заказывает
fulfillmentCenterId: string // где будет храниться
requestedDeliveryDate: DateTime // когда нужно
// === ДАННЫЕ ПОСТАВЩИКА ===
supplierId: string // кто поставляет
supplierApprovedAt?: DateTime // когда одобрил
packagesCount?: number // количество грузомест
estimatedVolume?: number // объем груза
supplierContractId?: string // номер договора
// === ДАННЫЕ ЛОГИСТИКИ ===
logisticsPartnerId?: string // кто везет
estimatedDeliveryDate?: DateTime // план доставки
routeId?: string // маршрут
logisticsCost?: number // стоимость доставки
// === ДАННЫЕ ОТГРУЗКИ ===
shippedAt?: DateTime // факт отгрузки
// === ДАННЫЕ ПРИЕМКИ ===
receivedAt?: DateTime // факт приемки ФФ
receivedById?: string // кто принял (сотрудник ФФ)
actualQuantity?: number // принято количество
defectQuantity?: number // брак
// === УНИКАЛЬНЫЕ ПОЛЯ ДЛЯ РАСХОДНИКОВ СЕЛЛЕРОВ ===
storageTermMonths?: number // срок хранения
accessRights: 'SELLER_ONLY' | 'SHARED_WITH_FF' // кто может использовать
storageCostPerMonth?: number // стоимость хранения
// === СВЯЗИ ===
items: SellerConsumableSupplyItem[]
}
interface SellerConsumableSupplyItem {
id: string
supplyOrderId: string // связь с поставкой
productId: string // какой расходник селлера
requestedQuantity: number // запросили
approvedQuantity?: number // поставщик одобрил
shippedQuantity?: number // отгрузили
receivedQuantity?: number // приняли
defectQuantity?: number // брак
unitPrice: number // цена за единицу
totalPrice: number // общая стоимость
}
🛒 СТРУКТУРА ТАБЛИЦ ПОСТАВОК НА МАРКЕТПЛЕЙСЫ
4. OzonSupplyOrder - Поставки на Ozon
interface OzonSupplyOrder {
// === БАЗОВЫЕ ПОЛЯ ===
id: string
status: MarketplaceSupplyStatus
createdAt: DateTime
updatedAt: DateTime
// === СПЕЦИФИЧНЫЕ ПОЛЯ OZON ===
ozonWarehouseId: string // склад Ozon
ozonSupplyId?: string // ID поставки в системе Ozon
// ... дополнительные поля для Ozon API
// === СВЯЗИ ===
items: OzonSupplyItem[]
}
5. WildberriesSupplyOrder - Поставки на Wildberries
interface WildberriesSupplyOrder {
// === БАЗОВЫЕ ПОЛЯ ===
id: string
status: MarketplaceSupplyStatus
createdAt: DateTime
updatedAt: DateTime
// === СПЕЦИФИЧНЫЕ ПОЛЯ WB ===
wbWarehouseId: string // склад WB
wbSupplyId?: string // ID поставки в системе WB
// ... дополнительные поля для WB API
// === СВЯЗИ ===
items: WildberriesSupplyItem[]
}
🔐 СИСТЕМА БЕЗОПАСНОСТИ
📋 ПРАВИЛА ДОСТУПА К ПОСТАВКАМ РАСХОДНИКОВ ФФ
Кто видит и что:
- ✅ ФФ (создатель): все детали + цены + остатки
- ✅ Поставщик: товары, количества, НЕ цены продажи ФФ
- ✅ Логистика: маршруты, объемы, НЕ коммерческие данные
- ❌ Селлеры: вообще не видят
📋 ПРАВИЛА ДОСТУПА К ПОСТАВКАМ РАСХОДНИКОВ СЕЛЛЕРОВ
Кто видит и что:
- ✅ Селлер (создатель): все свои детали + свои цены
- ✅ ФФ (хранитель): факт хранения + количества, НЕ закупочные цены селлера
- ✅ Поставщик: товары, количества для селлера
- ✅ Логистика: маршруты, объемы
- ❌ Другие селлеры: не видят чужие расходники
📋 ПРАВИЛА ДОСТУПА К ТОВАРНЫМ ПОСТАВКАМ
Кто видит и что:
- ✅ Селлер (создатель): все детали своих товаров + рецептуры
- ✅ ФФ (получатель): товары + рецептуры + услуги, НЕ закупочные цены селлера
- ✅ Поставщик: товары + количества, НЕ рецептуры и НЕ цены ФФ
- ✅ Логистика: маршруты + объемы, НЕ коммерческие данные
- ❌ Другие селлеры: не видят чужие поставки
🌐 URL-СТРУКТУРА ИНТЕРФЕЙСОВ
📦 ПОСТАВКИ НА ФУЛФИЛМЕНТ
/fulfillment-supplies/goods?status=new # Товар → Новые
/fulfillment-supplies/goods?status=receiving # Товар → Приёмка
/fulfillment-supplies/goods?status=accepted # Товар → Принято
/fulfillment-supplies/ff-consumables # Расходники фулфилмента
/fulfillment-supplies/seller-consumables # Расходники селлеров
/fulfillment-supplies/create-consumables # Создание поставки расходников ФФ
🛒 ПОСТАВКИ НА МАРКЕТПЛЕЙСЫ
/marketplace-supplies/ozon # Поставки на Ozon
/marketplace-supplies/wildberries # Поставки на Wildberries
/marketplace-supplies/create-ozon # Создание поставки на Ozon
/marketplace-supplies/create-wildberries # Создание поставки на WB
⚡ GRAPHQL API АРХИТЕКТУРА
🎯 ПРИНЦИП: ОТДЕЛЬНЫЕ ОПЕРАЦИИ ДЛЯ КАЖДОГО ТИПА
Поставки расходников ФФ:
# Queries
myFulfillmentConsumableSupplies: [FulfillmentConsumableSupplyOrder!]!
fulfillmentConsumableSupply(id: ID!): FulfillmentConsumableSupplyOrder
# Mutations
createFulfillmentConsumableSupply(input: CreateFulfillmentConsumableSupplyInput!): CreateSupplyResult!
updateFulfillmentConsumableSupply(id: ID!, input: UpdateFulfillmentConsumableSupplyInput!): UpdateSupplyResult!
Поставки расходников селлеров:
# Queries
mySellerConsumableSupplies: [SellerConsumableSupplyOrder!]!
sellerConsumableSupply(id: ID!): SellerConsumableSupplyOrder
# Mutations
createSellerConsumableSupply(input: CreateSellerConsumableSupplyInput!): CreateSupplyResult!
updateSellerConsumableSupply(id: ID!, input: UpdateSellerConsumableSupplyInput!): UpdateSupplyResult!
Товарные поставки:
# Queries
myGoodsSupplies: [GoodsSupplyOrder!]!
goodsSupply(id: ID!): GoodsSupplyOrder
# Mutations
createGoodsSupply(input: CreateGoodsSupplyInput!): CreateSupplyResult!
updateGoodsSupply(id: ID!, input: UpdateGoodsSupplyInput!): UpdateSupplyResult!
Поставки на маркетплейсы (отдельная система):
# Queries
myOzonSupplies: [OzonSupplyOrder!]!
myWildberriesSupplies: [WildberriesSupplyOrder!]!
# Mutations
createOzonSupply(input: CreateOzonSupplyInput!): CreateMarketplaceSupplyResult!
createWildberriesSupply(input: CreateWildberriesSupplyInput!): CreateMarketplaceSupplyResult!
🔄 ПЛАН ПОЭТАПНОЙ МИГРАЦИИ
✅ ПРИНЦИПЫ БЕЗОПАСНОЙ МИГРАЦИИ
- 🛡️ Сохранение работоспособности существующей системы
- 🔄 Система откатов на каждом этапе
- 🧪 Тестирование каждого типа поставки отдельно
- 📝 Модульная архитектура
- ❌ Удаление старого кода ТОЛЬКО после одобрения пользователя
ЭТАП 1: FulfillmentConsumableSupplyOrder
1.1 Создание новой модели данных
// Новая таблица параллельно со старой
model FulfillmentConsumableSupplyOrder {
// ... вся структура
}
// Старая таблица остается для совместимости
model SupplyOrder {
// ... существующая структура
}
1.2 GraphQL API
# Новые операции
createFulfillmentConsumableSupply()
myFulfillmentConsumableSupplies()
# Старые операции остаются работать
createSupplyOrder() # для других типов
mySupplyOrders() # для других типов
1.3 Интерфейс
- Форма
/fulfillment-supplies/create-consumables
→ новая мутация - Вкладка
/fulfillment-supplies/ff-consumables
→ новый запрос
1.4 Тестирование
- ✅ Создание поставки расходников ФФ
- ✅ Отображение в интерфейсе
- ✅ Безопасность доступа
- ✅ Работа старой системы
ЭТАП 2: SellerConsumableSupplyOrder
- Аналогично этапу 1
- Тестирование + интеграция
ЭТАП 3: GoodsSupplyOrder
- Аналогично этапу 1
- Тестирование + интеграция
ЭТАП 4: Очистка (ТОЛЬКО после одобрения)
- Миграция данных из старых таблиц
- Удаление старого кода
- Обновление документации
🎯 СТАТУСЫ ПОСТАВОК
SupplyOrderStatus (для поставок НА фулфилмент)
enum SupplyOrderStatus {
PENDING // Создана, ждет одобрения поставщика
SUPPLIER_APPROVED // Одобрена поставщиком
LOGISTICS_CONFIRMED // Логистика подтверждена
SHIPPED // Отгружена поставщиком
IN_TRANSIT // В пути
DELIVERED // Доставлена на склад ФФ
CANCELLED // Отменена
}
MarketplaceSupplyStatus (для поставок НА маркетплейсы)
enum MarketplaceSupplyStatus {
PLANNED // Запланирована
PREPARED // Подготовлена к отгрузке
SHIPPED_TO_MARKETPLACE // Отгружена на маркетплейс
ACCEPTED_BY_MARKETPLACE // Принята маркетплейсом
CANCELLED // Отменена
}
📊 ИНТЕГРАЦИИ
Поставки НА фулфилмент:
- 🏪 DaData API - валидация ИНН поставщиков
- 📱 SMS Aero - уведомления участникам
- ☁️ AWS S3 - документы поставок
- 🚚 Логистические партнеры - трекинг доставки
Поставки НА маркетплейсы:
- 🛒 Ozon API - создание поставок
- 🛍️ Wildberries API - создание поставок
- 📦 Трекинг системы - статусы доставки
- 💰 Биллинг системы - расчет комиссий
🔍 МОНИТОРИНГ И АУДИТ
Коммерческие данные:
- 📊 Логирование доступа к ценам
- 🔐 Аудит прав доступа по ролям
- 📈 Метрики безопасности
- ⚠️ Алерты на подозрительную активность
Операционные метрики:
- ⏱️ Время выполнения поставок
- 📦 Процент успешных доставок
- 🔄 SLA по статусам
- 📊 Аналитика по типам поставок
✅ ЗАКЛЮЧЕНИЕ
Новая архитектура системы поставок обеспечивает:
- 🎯 Четкое разделение типов поставок
- 🔒 Надежную безопасность коммерческих данных
- 📈 Масштабируемость для новых маркетплейсов
- 🔧 Простоту развития каждого типа независимо
- 🛡️ Безопасную миграцию без потери данных
Следующий шаг: Поэтапная реализация начиная с FulfillmentConsumableSupplyOrder