
- Обновлена форма создания поставок расходников фулфилмента для использования 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>
600 lines
33 KiB
Markdown
600 lines
33 KiB
Markdown
# 🗄️ СХЕМА БАЗЫ ДАННЫХ SFERA v2.0 - СИСТЕМА ПОСТАВОК
|
||
|
||
> **⚠️ ВАЖНО:** Этот документ описывает НОВЫЕ таблицы для системы поставок v2.0. Существующие таблицы остаются без изменений для обратной совместимости.
|
||
|
||
## 📦 НОВЫЕ ТАБЛИЦЫ ПОСТАВОК НА ФУЛФИЛМЕНТ
|
||
|
||
### 1️⃣ **FulfillmentConsumableSupplyOrder - Поставки расходников ФФ**
|
||
|
||
```prisma
|
||
model FulfillmentConsumableSupplyOrder {
|
||
// === БАЗОВЫЕ ПОЛЯ ===
|
||
id String @id @default(cuid())
|
||
status SupplyOrderStatusV2 @default(PENDING)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
// === ДАННЫЕ ФФ (создатель) ===
|
||
fulfillmentCenterId String // кто заказывает (FK: Organization)
|
||
requestedDeliveryDate DateTime // когда нужно
|
||
resalePricePerUnit Decimal? @db.Decimal(10, 2) // цена продажи селлерам
|
||
minStockLevel Int? // минимальный остаток
|
||
notes String? // заметки ФФ
|
||
|
||
// === ДАННЫЕ ПОСТАВЩИКА ===
|
||
supplierId String? // кто поставляет (FK: Organization)
|
||
supplierApprovedAt DateTime? // когда одобрил
|
||
packagesCount Int? // количество грузомест
|
||
estimatedVolume Decimal? @db.Decimal(8, 3) // объем груза в м³
|
||
supplierContractId String? // номер договора
|
||
supplierNotes String? // заметки поставщика
|
||
|
||
// === ДАННЫЕ ЛОГИСТИКИ ===
|
||
logisticsPartnerId String? // кто везет (FK: Organization)
|
||
estimatedDeliveryDate DateTime? // план доставки
|
||
routeId String? // маршрут (FK: LogisticsRoute)
|
||
logisticsCost Decimal? @db.Decimal(10, 2) // стоимость доставки
|
||
logisticsNotes String? // заметки логистики
|
||
|
||
// === ДАННЫЕ ОТГРУЗКИ ===
|
||
shippedAt DateTime? // факт отгрузки
|
||
trackingNumber String? // номер отслеживания
|
||
|
||
// === ДАННЫЕ ПРИЕМКИ ===
|
||
receivedAt DateTime? // факт приемки
|
||
receivedById String? // кто принял (FK: User)
|
||
actualQuantity Int? // принято количество
|
||
defectQuantity Int? // брак
|
||
receiptNotes String? // заметки приемки
|
||
|
||
// === СВЯЗИ ===
|
||
fulfillmentCenter Organization @relation("FFSupplyOrdersFulfillment", fields: [fulfillmentCenterId], references: [id])
|
||
supplier Organization? @relation("FFSupplyOrdersSupplier", fields: [supplierId], references: [id])
|
||
logisticsPartner Organization? @relation("FFSupplyOrdersLogistics", fields: [logisticsPartnerId], references: [id])
|
||
receivedBy User? @relation("FFSupplyOrdersReceiver", fields: [receivedById], references: [id])
|
||
items FulfillmentConsumableSupplyItem[]
|
||
|
||
@@map("fulfillment_consumable_supply_orders")
|
||
}
|
||
|
||
model FulfillmentConsumableSupplyItem {
|
||
id String @id @default(cuid())
|
||
supplyOrderId String // связь с поставкой
|
||
productId String // какой расходник (FK: Product)
|
||
|
||
// === КОЛИЧЕСТВА ===
|
||
requestedQuantity Int // запросили
|
||
approvedQuantity Int? // поставщик одобрил
|
||
shippedQuantity Int? // отгрузили
|
||
receivedQuantity Int? // приняли
|
||
defectQuantity Int? @default(0) // брак
|
||
|
||
// === ЦЕНЫ ===
|
||
unitPrice Decimal @db.Decimal(10, 2) // цена за единицу от поставщика
|
||
totalPrice Decimal @db.Decimal(12, 2) // общая стоимость
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
// === СВЯЗИ ===
|
||
supplyOrder FulfillmentConsumableSupplyOrder @relation(fields: [supplyOrderId], references: [id], onDelete: Cascade)
|
||
product Product @relation("FFSupplyItems", fields: [productId], references: [id])
|
||
|
||
@@unique([supplyOrderId, productId])
|
||
@@map("fulfillment_consumable_supply_items")
|
||
}
|
||
```
|
||
|
||
### 2️⃣ **SellerConsumableSupplyOrder - Поставки расходников селлеров**
|
||
|
||
```prisma
|
||
model SellerConsumableSupplyOrder {
|
||
// === БАЗОВЫЕ ПОЛЯ ===
|
||
id String @id @default(cuid())
|
||
status SupplyOrderStatusV2 @default(PENDING)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
// === ДАННЫЕ СЕЛЛЕРА (создатель) ===
|
||
sellerId String // кто заказывает (FK: Organization)
|
||
fulfillmentCenterId String // где будет храниться (FK: Organization)
|
||
requestedDeliveryDate DateTime // когда нужно
|
||
notes String? // заметки селлера
|
||
|
||
// === ДАННЫЕ ПОСТАВЩИКА ===
|
||
supplierId String? // кто поставляет (FK: Organization)
|
||
supplierApprovedAt DateTime? // когда одобрил
|
||
packagesCount Int? // количество грузомест
|
||
estimatedVolume Decimal? @db.Decimal(8, 3) // объем груза в м³
|
||
supplierContractId String? // номер договора
|
||
supplierNotes String? // заметки поставщика
|
||
|
||
// === ДАННЫЕ ЛОГИСТИКИ ===
|
||
logisticsPartnerId String? // кто везет (FK: Organization)
|
||
estimatedDeliveryDate DateTime? // план доставки
|
||
routeId String? // маршрут (FK: LogisticsRoute)
|
||
logisticsCost Decimal? @db.Decimal(10, 2) // стоимость доставки
|
||
logisticsNotes String? // заметки логистики
|
||
|
||
// === ДАННЫЕ ОТГРУЗКИ ===
|
||
shippedAt DateTime? // факт отгрузки
|
||
trackingNumber String? // номер отслеживания
|
||
|
||
// === ДАННЫЕ ПРИЕМКИ ===
|
||
receivedAt DateTime? // факт приемки ФФ
|
||
receivedById String? // кто принял (FK: User)
|
||
actualQuantity Int? // принято количество
|
||
defectQuantity Int? // брак
|
||
receiptNotes String? // заметки приемки
|
||
|
||
// === УНИКАЛЬНЫЕ ПОЛЯ ДЛЯ РАСХОДНИКОВ СЕЛЛЕРОВ ===
|
||
storageTermMonths Int? // срок хранения в месяцах
|
||
accessRights SellerConsumableAccessRights @default(SELLER_ONLY)
|
||
storageCostPerMonth Decimal? @db.Decimal(8, 2) // стоимость хранения за месяц
|
||
|
||
// === СВЯЗИ ===
|
||
seller Organization @relation("SellerSupplyOrdersSeller", fields: [sellerId], references: [id])
|
||
fulfillmentCenter Organization @relation("SellerSupplyOrdersFulfillment", fields: [fulfillmentCenterId], references: [id])
|
||
supplier Organization? @relation("SellerSupplyOrdersSupplier", fields: [supplierId], references: [id])
|
||
logisticsPartner Organization? @relation("SellerSupplyOrdersLogistics", fields: [logisticsPartnerId], references: [id])
|
||
receivedBy User? @relation("SellerSupplyOrdersReceiver", fields: [receivedById], references: [id])
|
||
items SellerConsumableSupplyItem[]
|
||
|
||
@@map("seller_consumable_supply_orders")
|
||
}
|
||
|
||
model SellerConsumableSupplyItem {
|
||
id String @id @default(cuid())
|
||
supplyOrderId String // связь с поставкой
|
||
productId String // какой расходник селлера (FK: Product)
|
||
|
||
// === КОЛИЧЕСТВА ===
|
||
requestedQuantity Int // запросили
|
||
approvedQuantity Int? // поставщик одобрил
|
||
shippedQuantity Int? // отгрузили
|
||
receivedQuantity Int? // приняли
|
||
defectQuantity Int? @default(0) // брак
|
||
|
||
// === ЦЕНЫ (видит только селлер) ===
|
||
unitPrice Decimal @db.Decimal(10, 2) // цена за единицу от поставщика
|
||
totalPrice Decimal @db.Decimal(12, 2) // общая стоимость
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
// === СВЯЗИ ===
|
||
supplyOrder SellerConsumableSupplyOrder @relation(fields: [supplyOrderId], references: [id], onDelete: Cascade)
|
||
product Product @relation("SellerSupplyItems", fields: [productId], references: [id])
|
||
|
||
@@unique([supplyOrderId, productId])
|
||
@@map("seller_consumable_supply_items")
|
||
}
|
||
```
|
||
|
||
### 3️⃣ **GoodsSupplyOrder - Товарные поставки**
|
||
|
||
```prisma
|
||
model GoodsSupplyOrder {
|
||
// === БАЗОВЫЕ ПОЛЯ ===
|
||
id String @id @default(cuid())
|
||
status SupplyOrderStatusV2 @default(PENDING)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
// === ДАННЫЕ СЕЛЛЕРА (создатель) ===
|
||
sellerId String // кто заказывает (FK: Organization)
|
||
fulfillmentCenterId String // куда доставить (FK: Organization)
|
||
requestedDeliveryDate DateTime // когда нужно
|
||
notes String? // заметки селлера
|
||
|
||
// === ДАННЫЕ ПОСТАВЩИКА ===
|
||
supplierId String? // кто поставляет (FK: Organization)
|
||
supplierApprovedAt DateTime? // когда одобрил
|
||
packagesCount Int? // количество грузомест
|
||
estimatedVolume Decimal? @db.Decimal(8, 3) // объем груза в м³
|
||
supplierContractId String? // номер договора
|
||
supplierNotes String? // заметки поставщика
|
||
|
||
// === ДАННЫЕ ЛОГИСТИКИ ===
|
||
logisticsPartnerId String? // кто везет (FK: Organization)
|
||
estimatedDeliveryDate DateTime? // план доставки
|
||
routeId String? // маршрут (FK: LogisticsRoute)
|
||
logisticsCost Decimal? @db.Decimal(10, 2) // стоимость доставки
|
||
logisticsNotes String? // заметки логистики
|
||
|
||
// === ДАННЫЕ ОТГРУЗКИ ===
|
||
shippedAt DateTime? // факт отгрузки
|
||
trackingNumber String? // номер отслеживания
|
||
|
||
// === ДАННЫЕ ПРИЕМКИ ===
|
||
receivedAt DateTime? // факт приемки
|
||
receivedById String? // кто принял (FK: User)
|
||
actualQuantity Int? // принято количество
|
||
defectQuantity Int? // брак
|
||
receiptNotes String? // заметки приемки
|
||
|
||
// === УНИКАЛЬНЫЕ ПОЛЯ ДЛЯ ТОВАРОВ ===
|
||
hasRecipes Boolean @default(false) // есть ли рецептуры
|
||
totalServicesValue Decimal? @db.Decimal(12, 2) // общая стоимость услуг ФФ
|
||
|
||
// === СВЯЗИ ===
|
||
seller Organization @relation("GoodsSupplyOrdersSeller", fields: [sellerId], references: [id])
|
||
fulfillmentCenter Organization @relation("GoodsSupplyOrdersFulfillment", fields: [fulfillmentCenterId], references: [id])
|
||
supplier Organization? @relation("GoodsSupplyOrdersSupplier", fields: [supplierId], references: [id])
|
||
logisticsPartner Organization? @relation("GoodsSupplyOrdersLogistics", fields: [logisticsPartnerId], references: [id])
|
||
receivedBy User? @relation("GoodsSupplyOrdersReceiver", fields: [receivedById], references: [id])
|
||
items GoodsSupplyItem[]
|
||
|
||
@@map("goods_supply_orders")
|
||
}
|
||
|
||
model GoodsSupplyItem {
|
||
id String @id @default(cuid())
|
||
supplyOrderId String // связь с поставкой
|
||
productId String // какой товар (FK: Product)
|
||
|
||
// === КОЛИЧЕСТВА ===
|
||
requestedQuantity Int // запросили
|
||
approvedQuantity Int? // поставщик одобрил
|
||
shippedQuantity Int? // отгрузили
|
||
receivedQuantity Int? // приняли
|
||
defectQuantity Int? @default(0) // брак
|
||
|
||
// === ЦЕНЫ (видит только селлер) ===
|
||
unitPrice Decimal @db.Decimal(10, 2) // цена за единицу от поставщика
|
||
totalPrice Decimal @db.Decimal(12, 2) // общая стоимость
|
||
|
||
// === РЕЦЕПТУРА (JSON) ===
|
||
recipe Json? // полная рецептура в JSON
|
||
/*
|
||
recipe structure:
|
||
{
|
||
services: string[] // ID услуг ФФ
|
||
fulfillmentConsumables: string[] // ID расходников ФФ
|
||
sellerConsumables: string[] // ID расходников селлера
|
||
marketplaceCardId?: string // карточка товара
|
||
}
|
||
*/
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
// === СВЯЗИ ===
|
||
supplyOrder GoodsSupplyOrder @relation(fields: [supplyOrderId], references: [id], onDelete: Cascade)
|
||
product Product @relation("GoodsSupplyItems", fields: [productId], references: [id])
|
||
|
||
@@unique([supplyOrderId, productId])
|
||
@@map("goods_supply_items")
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🛒 ТАБЛИЦЫ ПОСТАВОК НА МАРКЕТПЛЕЙСЫ
|
||
|
||
### 4️⃣ **OzonSupplyOrder - Поставки на Ozon**
|
||
|
||
```prisma
|
||
model OzonSupplyOrder {
|
||
// === БАЗОВЫЕ ПОЛЯ ===
|
||
id String @id @default(cuid())
|
||
status MarketplaceSupplyStatus @default(PLANNED)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
// === ДАННЫЕ ФФ (создатель) ===
|
||
fulfillmentCenterId String // кто отгружает (FK: Organization)
|
||
plannedShipmentDate DateTime // план отгрузки
|
||
notes String? // заметки ФФ
|
||
|
||
// === СПЕЦИФИЧНЫЕ ПОЛЯ OZON ===
|
||
ozonWarehouseId String // склад Ozon
|
||
ozonSupplyId String? // ID поставки в системе Ozon
|
||
ozonPostingNumber String? // номер отправления Ozon
|
||
|
||
// === ДАННЫЕ ОТГРУЗКИ ===
|
||
preparedAt DateTime? // готово к отгрузке
|
||
shippedAt DateTime? // отгружено
|
||
trackingNumber String? // номер отслеживания
|
||
|
||
// === ДАННЫЕ ПРИЕМКИ МАРКЕТПЛЕЙСОМ ===
|
||
acceptedAt DateTime? // принято Ozon
|
||
acceptedQuantity Int? // принято количество
|
||
rejectedQuantity Int? // отклонено
|
||
rejectionReason String? // причина отклонения
|
||
|
||
// === СВЯЗИ ===
|
||
fulfillmentCenter Organization @relation("OzonSupplyOrders", fields: [fulfillmentCenterId], references: [id])
|
||
items OzonSupplyItem[]
|
||
|
||
@@map("ozon_supply_orders")
|
||
}
|
||
|
||
model OzonSupplyItem {
|
||
id String @id @default(cuid())
|
||
supplyOrderId String // связь с поставкой
|
||
productId String // какой готовый продукт (FK: Product)
|
||
|
||
// === КОЛИЧЕСТВА ===
|
||
plannedQuantity Int // планируется отгрузить
|
||
preparedQuantity Int? // подготовлено
|
||
shippedQuantity Int? // отгружено
|
||
acceptedQuantity Int? // принято Ozon
|
||
rejectedQuantity Int? @default(0) // отклонено
|
||
|
||
// === OZON СПЕЦИФИЧНЫЕ ПОЛЯ ===
|
||
ozonProductId String? // ID товара в Ozon
|
||
ozonSku String? // SKU в Ozon
|
||
ozonBarcode String? // штрихкод
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
// === СВЯЗИ ===
|
||
supplyOrder OzonSupplyOrder @relation(fields: [supplyOrderId], references: [id], onDelete: Cascade)
|
||
product Product @relation("OzonSupplyItems", fields: [productId], references: [id])
|
||
|
||
@@unique([supplyOrderId, productId])
|
||
@@map("ozon_supply_items")
|
||
}
|
||
```
|
||
|
||
### 5️⃣ **WildberriesSupplyOrder - Поставки на Wildberries**
|
||
|
||
```prisma
|
||
model WildberriesSupplyOrder {
|
||
// === БАЗОВЫЕ ПОЛЯ ===
|
||
id String @id @default(cuid())
|
||
status MarketplaceSupplyStatus @default(PLANNED)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
// === ДАННЫЕ ФФ (создатель) ===
|
||
fulfillmentCenterId String // кто отгружает (FK: Organization)
|
||
plannedShipmentDate DateTime // план отгрузки
|
||
notes String? // заметки ФФ
|
||
|
||
// === СПЕЦИФИЧНЫЕ ПОЛЯ WILDBERRIES ===
|
||
wbWarehouseId String // склад WB
|
||
wbSupplyId String? // ID поставки в системе WB
|
||
wbStickerId String? // ID стикера WB
|
||
|
||
// === ДАННЫЕ ОТГРУЗКИ ===
|
||
preparedAt DateTime? // готово к отгрузке
|
||
shippedAt DateTime? // отгружено
|
||
trackingNumber String? // номер отслеживания
|
||
|
||
// === ДАННЫЕ ПРИЕМКИ МАРКЕТПЛЕЙСОМ ===
|
||
acceptedAt DateTime? // принято WB
|
||
acceptedQuantity Int? // принято количество
|
||
rejectedQuantity Int? // отклонено
|
||
rejectionReason String? // причина отклонения
|
||
|
||
// === СВЯЗИ ===
|
||
fulfillmentCenter Organization @relation("WildberriesSupplyOrders", fields: [fulfillmentCenterId], references: [id])
|
||
items WildberriesSupplyItem[]
|
||
|
||
@@map("wildberries_supply_orders")
|
||
}
|
||
|
||
model WildberriesSupplyItem {
|
||
id String @id @default(cuid())
|
||
supplyOrderId String // связь с поставкой
|
||
productId String // какой готовый продукт (FK: Product)
|
||
|
||
// === КОЛИЧЕСТВА ===
|
||
plannedQuantity Int // планируется отгрузить
|
||
preparedQuantity Int? // подготовлено
|
||
shippedQuantity Int? // отгружено
|
||
acceptedQuantity Int? // принято WB
|
||
rejectedQuantity Int? @default(0) // отклонено
|
||
|
||
// === WB СПЕЦИФИЧНЫЕ ПОЛЯ ===
|
||
wbNmId String? // Номенклатура WB
|
||
wbSku String? // SKU в WB
|
||
wbBarcode String? // штрихкод
|
||
wbSize String? // размер для WB
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
// === СВЯЗИ ===
|
||
supplyOrder WildberriesSupplyOrder @relation(fields: [supplyOrderId], references: [id], onDelete: Cascade)
|
||
product Product @relation("WBSupplyItems", fields: [productId], references: [id])
|
||
|
||
@@unique([supplyOrderId, productId])
|
||
@@map("wildberries_supply_items")
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 НОВЫЕ ENUMS
|
||
|
||
### **SupplyOrderStatusV2 - Статусы поставок НА фулфилмент**
|
||
|
||
```prisma
|
||
enum SupplyOrderStatusV2 {
|
||
PENDING // Ожидает одобрения поставщика
|
||
SUPPLIER_APPROVED // Одобрено поставщиком
|
||
LOGISTICS_CONFIRMED // Логистика подтверждена
|
||
SHIPPED // Отгружено поставщиком
|
||
IN_TRANSIT // В пути
|
||
DELIVERED // Доставлено и принято
|
||
CANCELLED // Отменено
|
||
}
|
||
```
|
||
|
||
### **MarketplaceSupplyStatus - Статусы поставок НА маркетплейсы**
|
||
|
||
```prisma
|
||
enum MarketplaceSupplyStatus {
|
||
PLANNED // Запланирована
|
||
PREPARED // Подготовлена к отгрузке
|
||
SHIPPED_TO_MARKETPLACE // Отгружена на маркетплейс
|
||
ACCEPTED_BY_MARKETPLACE // Принята маркетплейсом
|
||
CANCELLED // Отменена
|
||
}
|
||
```
|
||
|
||
### **SellerConsumableAccessRights - Права доступа к расходникам селлеров**
|
||
|
||
```prisma
|
||
enum SellerConsumableAccessRights {
|
||
SELLER_ONLY // Только селлер может использовать
|
||
SHARED_WITH_FF // ФФ тоже может использовать (с разрешения)
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 ОБНОВЛЕНИЯ СУЩЕСТВУЮЩИХ ТАБЛИЦ
|
||
|
||
### **Product - Добавление новых связей**
|
||
|
||
```prisma
|
||
model Product {
|
||
// ... существующие поля остаются без изменений
|
||
|
||
// === НОВЫЕ СВЯЗИ С ПОСТАВКАМИ V2 ===
|
||
fulfillmentSupplyItems FulfillmentConsumableSupplyItem[] @relation("FFSupplyItems")
|
||
sellerSupplyItems SellerConsumableSupplyItem[] @relation("SellerSupplyItems")
|
||
goodsSupplyItems GoodsSupplyItem[] @relation("GoodsSupplyItems")
|
||
ozonSupplyItems OzonSupplyItem[] @relation("OzonSupplyItems")
|
||
wildberriesSupplyItems WildberriesSupplyItem[] @relation("WBSupplyItems")
|
||
|
||
// ... остальные поля остаются без изменений
|
||
}
|
||
```
|
||
|
||
### **Organization - Добавление новых связей**
|
||
|
||
```prisma
|
||
model Organization {
|
||
// ... существующие поля остаются без изменений
|
||
|
||
// === НОВЫЕ СВЯЗИ С ПОСТАВКАМИ V2 ===
|
||
// Поставки расходников ФФ
|
||
fulfillmentSupplyOrdersAsFulfillment FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersFulfillment")
|
||
fulfillmentSupplyOrdersAsSupplier FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersSupplier")
|
||
fulfillmentSupplyOrdersAsLogistics FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersLogistics")
|
||
|
||
// Поставки расходников селлеров
|
||
sellerSupplyOrdersAsSeller SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersSeller")
|
||
sellerSupplyOrdersAsFulfillment SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersFulfillment")
|
||
sellerSupplyOrdersAsSupplier SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersSupplier")
|
||
sellerSupplyOrdersAsLogistics SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersLogistics")
|
||
|
||
// Товарные поставки
|
||
goodsSupplyOrdersAsSeller GoodsSupplyOrder[] @relation("GoodsSupplyOrdersSeller")
|
||
goodsSupplyOrdersAsFulfillment GoodsSupplyOrder[] @relation("GoodsSupplyOrdersFulfillment")
|
||
goodsSupplyOrdersAsSupplier GoodsSupplyOrder[] @relation("GoodsSupplyOrdersSupplier")
|
||
goodsSupplyOrdersAsLogistics GoodsSupplyOrder[] @relation("GoodsSupplyOrdersLogistics")
|
||
|
||
// Поставки на маркетплейсы
|
||
ozonSupplyOrders OzonSupplyOrder[] @relation("OzonSupplyOrders")
|
||
wildberriesSupplyOrders WildberriesSupplyOrder[] @relation("WildberriesSupplyOrders")
|
||
|
||
// ... остальные поля остаются без изменений
|
||
}
|
||
```
|
||
|
||
### **User - Добавление новых связей**
|
||
|
||
```prisma
|
||
model User {
|
||
// ... существующие поля остаются без изменений
|
||
|
||
// === НОВЫЕ СВЯЗИ С ПРИЕМКОЙ ПОСТАВОК V2 ===
|
||
fulfillmentSupplyOrdersReceived FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersReceiver")
|
||
sellerSupplyOrdersReceived SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersReceiver")
|
||
goodsSupplyOrdersReceived GoodsSupplyOrder[] @relation("GoodsSupplyOrdersReceiver")
|
||
|
||
// ... остальные поля остаются без изменений
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔍 ИНДЕКСЫ ДЛЯ ПРОИЗВОДИТЕЛЬНОСТИ
|
||
|
||
```prisma
|
||
// Индексы для быстрого поиска поставок по статусу и организации
|
||
@@index([fulfillmentCenterId, status])
|
||
@@index([sellerId, status])
|
||
@@index([supplierId, status])
|
||
@@index([logisticsPartnerId, status])
|
||
|
||
// Индексы для поиска по датам
|
||
@@index([createdAt])
|
||
@@index([requestedDeliveryDate])
|
||
@@index([estimatedDeliveryDate])
|
||
|
||
// Индексы для отслеживания
|
||
@@index([trackingNumber])
|
||
@@index([supplierContractId])
|
||
|
||
// Маркетплейс-специфичные индексы
|
||
@@index([ozonSupplyId])
|
||
@@index([ozonProductId])
|
||
@@index([wbSupplyId])
|
||
@@index([wbNmId])
|
||
```
|
||
|
||
---
|
||
|
||
## 📋 ПЛАН МИГРАЦИИ
|
||
|
||
### **Phase 1: Создание новых таблиц**
|
||
```sql
|
||
-- Создание таблиц параллельно с существующими
|
||
CREATE TABLE fulfillment_consumable_supply_orders (...);
|
||
CREATE TABLE fulfillment_consumable_supply_items (...);
|
||
-- и т.д.
|
||
```
|
||
|
||
### **Phase 2: Новые enum значения**
|
||
```sql
|
||
-- Добавление новых enum без затрагивания старых
|
||
CREATE TYPE "SupplyOrderStatusV2" AS ENUM (...);
|
||
CREATE TYPE "MarketplaceSupplyStatus" AS ENUM (...);
|
||
```
|
||
|
||
### **Phase 3: Обновление связей (без удаления старых)**
|
||
```sql
|
||
-- Добавление новых foreign key связей
|
||
ALTER TABLE "Product" ADD COLUMN ...;
|
||
ALTER TABLE "Organization" ADD COLUMN ...;
|
||
```
|
||
|
||
### **Phase 4: Данные миграции (только с одобрения)**
|
||
```sql
|
||
-- Миграция данных из старых таблиц в новые
|
||
-- ТОЛЬКО после полного тестирования новой системы
|
||
```
|
||
|
||
---
|
||
|
||
## ⚠️ ВАЖНЫЕ ПРИНЦИПЫ
|
||
|
||
### ✅ **ОБРАТНАЯ СОВМЕСТИМОСТЬ**
|
||
- Все существующие таблицы остаются без изменений
|
||
- Новые таблицы создаются параллельно
|
||
- Старая система продолжает работать
|
||
|
||
### 🔒 **БЕЗОПАСНОСТЬ ДАННЫХ**
|
||
- Каждый тип поставки изолирован в отдельной таблице
|
||
- Связи защищены foreign key constraints
|
||
- Каскадное удаление только для зависимых записей
|
||
|
||
### 📈 **МАСШТАБИРУЕМОСТЬ**
|
||
- Легко добавлять новые типы поставок
|
||
- Оптимизированные индексы для каждого use case
|
||
- Независимые схемы для разных процессов
|
||
|
||
### 🛡️ **ЦЕЛОСТНОСТЬ ДАННЫХ**
|
||
- Строгие ограничения на связи между таблицами
|
||
- Валидация через enum значения
|
||
- Уникальные индексы предотвращают дублирование
|
||
|
||
**Следующий шаг:** Создание Prisma миграций для FulfillmentConsumableSupplyOrder |