
- Обновлена форма создания поставок расходников фулфилмента для использования 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>
487 lines
20 KiB
Markdown
487 lines
20 KiB
Markdown
# 🚚 АРХИТЕКТУРА СИСТЕМЫ ПОСТАВОК SFERA
|
||
|
||
## 🎯 ОБЗОР СИСТЕМЫ
|
||
|
||
Система поставок SFERA включает **5 типов поставок**, разделенных на две категории:
|
||
|
||
### 📦 **ПОСТАВКИ НА ФУЛФИЛМЕНТ (3 типа)**
|
||
1. **Товарные поставки** - товары селлера → склад ФФ
|
||
2. **Поставки расходников ФФ** - расходники ФФ → склад ФФ
|
||
3. **Поставки расходников селлеров** - расходники селлера → склад ФФ (на хранение)
|
||
|
||
### 🛒 **ПОСТАВКИ НА МАРКЕТПЛЕЙСЫ (2+ типов)**
|
||
4. **Поставки на Ozon** - готовые продукты со склада ФФ → Ozon
|
||
5. **Поставки на Wildberries** - готовые продукты со склада ФФ → Wildberries
|
||
|
||
---
|
||
|
||
## 📊 АРХИТЕКТУРА ДАННЫХ
|
||
|
||
### ✅ **ПРИНЦИП: ОТДЕЛЬНАЯ ТАБЛИЦА ДЛЯ КАЖДОГО ТИПА ПОСТАВКИ**
|
||
|
||
#### **Преимущества подхода:**
|
||
- 🎯 Четкое разделение ответственности
|
||
- 🔒 Упрощение системы безопасности
|
||
- 📈 Независимые схемы для разных процессов
|
||
- 🔧 Простота миграций и изменений
|
||
- 📝 Специфичные поля для каждого типа
|
||
|
||
### 🏗️ **СТРУКТУРА ТАБЛИЦ ПОСТАВОК НА ФУЛФИЛМЕНТ**
|
||
|
||
#### **1. GoodsSupplyOrder - Товарные поставки**
|
||
```typescript
|
||
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 - Поставки расходников ФФ**
|
||
```typescript
|
||
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 - Поставки расходников селлеров**
|
||
```typescript
|
||
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**
|
||
```typescript
|
||
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**
|
||
```typescript
|
||
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 АРХИТЕКТУРА
|
||
|
||
### 🎯 **ПРИНЦИП: ОТДЕЛЬНЫЕ ОПЕРАЦИИ ДЛЯ КАЖДОГО ТИПА**
|
||
|
||
#### **Поставки расходников ФФ:**
|
||
```graphql
|
||
# Queries
|
||
myFulfillmentConsumableSupplies: [FulfillmentConsumableSupplyOrder!]!
|
||
fulfillmentConsumableSupply(id: ID!): FulfillmentConsumableSupplyOrder
|
||
|
||
# Mutations
|
||
createFulfillmentConsumableSupply(input: CreateFulfillmentConsumableSupplyInput!): CreateSupplyResult!
|
||
updateFulfillmentConsumableSupply(id: ID!, input: UpdateFulfillmentConsumableSupplyInput!): UpdateSupplyResult!
|
||
```
|
||
|
||
#### **Поставки расходников селлеров:**
|
||
```graphql
|
||
# Queries
|
||
mySellerConsumableSupplies: [SellerConsumableSupplyOrder!]!
|
||
sellerConsumableSupply(id: ID!): SellerConsumableSupplyOrder
|
||
|
||
# Mutations
|
||
createSellerConsumableSupply(input: CreateSellerConsumableSupplyInput!): CreateSupplyResult!
|
||
updateSellerConsumableSupply(id: ID!, input: UpdateSellerConsumableSupplyInput!): UpdateSupplyResult!
|
||
```
|
||
|
||
#### **Товарные поставки:**
|
||
```graphql
|
||
# Queries
|
||
myGoodsSupplies: [GoodsSupplyOrder!]!
|
||
goodsSupply(id: ID!): GoodsSupplyOrder
|
||
|
||
# Mutations
|
||
createGoodsSupply(input: CreateGoodsSupplyInput!): CreateSupplyResult!
|
||
updateGoodsSupply(id: ID!, input: UpdateGoodsSupplyInput!): UpdateSupplyResult!
|
||
```
|
||
|
||
#### **Поставки на маркетплейсы (отдельная система):**
|
||
```graphql
|
||
# Queries
|
||
myOzonSupplies: [OzonSupplyOrder!]!
|
||
myWildberriesSupplies: [WildberriesSupplyOrder!]!
|
||
|
||
# Mutations
|
||
createOzonSupply(input: CreateOzonSupplyInput!): CreateMarketplaceSupplyResult!
|
||
createWildberriesSupply(input: CreateWildberriesSupplyInput!): CreateMarketplaceSupplyResult!
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 ПЛАН ПОЭТАПНОЙ МИГРАЦИИ
|
||
|
||
### ✅ **ПРИНЦИПЫ БЕЗОПАСНОЙ МИГРАЦИИ**
|
||
- 🛡️ Сохранение работоспособности существующей системы
|
||
- 🔄 Система откатов на каждом этапе
|
||
- 🧪 Тестирование каждого типа поставки отдельно
|
||
- 📝 Модульная архитектура
|
||
- ❌ **Удаление старого кода ТОЛЬКО после одобрения пользователя**
|
||
|
||
### **ЭТАП 1: FulfillmentConsumableSupplyOrder**
|
||
|
||
#### **1.1 Создание новой модели данных**
|
||
```typescript
|
||
// Новая таблица параллельно со старой
|
||
model FulfillmentConsumableSupplyOrder {
|
||
// ... вся структура
|
||
}
|
||
|
||
// Старая таблица остается для совместимости
|
||
model SupplyOrder {
|
||
// ... существующая структура
|
||
}
|
||
```
|
||
|
||
#### **1.2 GraphQL API**
|
||
```graphql
|
||
# Новые операции
|
||
createFulfillmentConsumableSupply()
|
||
myFulfillmentConsumableSupplies()
|
||
|
||
# Старые операции остаются работать
|
||
createSupplyOrder() # для других типов
|
||
mySupplyOrders() # для других типов
|
||
```
|
||
|
||
#### **1.3 Интерфейс**
|
||
- Форма `/fulfillment-supplies/create-consumables` → новая мутация
|
||
- Вкладка `/fulfillment-supplies/ff-consumables` → новый запрос
|
||
|
||
#### **1.4 Тестирование**
|
||
- ✅ Создание поставки расходников ФФ
|
||
- ✅ Отображение в интерфейсе
|
||
- ✅ Безопасность доступа
|
||
- ✅ Работа старой системы
|
||
|
||
### **ЭТАП 2: SellerConsumableSupplyOrder**
|
||
- Аналогично этапу 1
|
||
- Тестирование + интеграция
|
||
|
||
### **ЭТАП 3: GoodsSupplyOrder**
|
||
- Аналогично этапу 1
|
||
- Тестирование + интеграция
|
||
|
||
### **ЭТАП 4: Очистка (ТОЛЬКО после одобрения)**
|
||
- Миграция данных из старых таблиц
|
||
- Удаление старого кода
|
||
- Обновление документации
|
||
|
||
---
|
||
|
||
## 🎯 СТАТУСЫ ПОСТАВОК
|
||
|
||
### **SupplyOrderStatus (для поставок НА фулфилмент)**
|
||
```typescript
|
||
enum SupplyOrderStatus {
|
||
PENDING // Создана, ждет одобрения поставщика
|
||
SUPPLIER_APPROVED // Одобрена поставщиком
|
||
LOGISTICS_CONFIRMED // Логистика подтверждена
|
||
SHIPPED // Отгружена поставщиком
|
||
IN_TRANSIT // В пути
|
||
DELIVERED // Доставлена на склад ФФ
|
||
CANCELLED // Отменена
|
||
}
|
||
```
|
||
|
||
### **MarketplaceSupplyStatus (для поставок НА маркетплейсы)**
|
||
```typescript
|
||
enum MarketplaceSupplyStatus {
|
||
PLANNED // Запланирована
|
||
PREPARED // Подготовлена к отгрузке
|
||
SHIPPED_TO_MARKETPLACE // Отгружена на маркетплейс
|
||
ACCEPTED_BY_MARKETPLACE // Принята маркетплейсом
|
||
CANCELLED // Отменена
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 ИНТЕГРАЦИИ
|
||
|
||
### **Поставки НА фулфилмент:**
|
||
- 🏪 **DaData API** - валидация ИНН поставщиков
|
||
- 📱 **SMS Aero** - уведомления участникам
|
||
- ☁️ **AWS S3** - документы поставок
|
||
- 🚚 **Логистические партнеры** - трекинг доставки
|
||
|
||
### **Поставки НА маркетплейсы:**
|
||
- 🛒 **Ozon API** - создание поставок
|
||
- 🛍️ **Wildberries API** - создание поставок
|
||
- 📦 **Трекинг системы** - статусы доставки
|
||
- 💰 **Биллинг системы** - расчет комиссий
|
||
|
||
---
|
||
|
||
## 🔍 МОНИТОРИНГ И АУДИТ
|
||
|
||
### **Коммерческие данные:**
|
||
- 📊 Логирование доступа к ценам
|
||
- 🔐 Аудит прав доступа по ролям
|
||
- 📈 Метрики безопасности
|
||
- ⚠️ Алерты на подозрительную активность
|
||
|
||
### **Операционные метрики:**
|
||
- ⏱️ Время выполнения поставок
|
||
- 📦 Процент успешных доставок
|
||
- 🔄 SLA по статусам
|
||
- 📊 Аналитика по типам поставок
|
||
|
||
---
|
||
|
||
## ✅ ЗАКЛЮЧЕНИЕ
|
||
|
||
Новая архитектура системы поставок обеспечивает:
|
||
|
||
- 🎯 **Четкое разделение** типов поставок
|
||
- 🔒 **Надежную безопасность** коммерческих данных
|
||
- 📈 **Масштабируемость** для новых маркетплейсов
|
||
- 🔧 **Простоту развития** каждого типа независимо
|
||
- 🛡️ **Безопасную миграцию** без потери данных
|
||
|
||
**Следующий шаг:** Поэтапная реализация начиная с `FulfillmentConsumableSupplyOrder` |