Files
sfera-new/docs/development/DATABASE_SCHEMA_V2.md
Veronika Smirnova 0e3ffc179c feat(fulfillment-supplies): миграция формы создания поставок расходников на v2 систему
- Обновлена форма создания поставок расходников фулфилмента для использования 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>
2025-08-25 07:52:46 +03:00

33 KiB
Raw Blame History

🗄️ СХЕМА БАЗЫ ДАННЫХ SFERA v2.0 - СИСТЕМА ПОСТАВОК

⚠️ ВАЖНО: Этот документ описывает НОВЫЕ таблицы для системы поставок v2.0. Существующие таблицы остаются без изменений для обратной совместимости.

📦 НОВЫЕ ТАБЛИЦЫ ПОСТАВОК НА ФУЛФИЛМЕНТ

1 FulfillmentConsumableSupplyOrder - Поставки расходников ФФ

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 - Поставки расходников селлеров

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 - Товарные поставки

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

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

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 - Статусы поставок НА фулфилмент

enum SupplyOrderStatusV2 {
  PENDING                 // Ожидает одобрения поставщика
  SUPPLIER_APPROVED       // Одобрено поставщиком  
  LOGISTICS_CONFIRMED     // Логистика подтверждена
  SHIPPED                 // Отгружено поставщиком
  IN_TRANSIT             // В пути
  DELIVERED              // Доставлено и принято
  CANCELLED              // Отменено
}

MarketplaceSupplyStatus - Статусы поставок НА маркетплейсы

enum MarketplaceSupplyStatus {
  PLANNED                // Запланирована
  PREPARED              // Подготовлена к отгрузке
  SHIPPED_TO_MARKETPLACE // Отгружена на маркетплейс
  ACCEPTED_BY_MARKETPLACE // Принята маркетплейсом
  CANCELLED             // Отменена
}

SellerConsumableAccessRights - Права доступа к расходникам селлеров

enum SellerConsumableAccessRights {
  SELLER_ONLY           // Только селлер может использовать
  SHARED_WITH_FF        // ФФ тоже может использовать (с разрешения)
}

🔄 ОБНОВЛЕНИЯ СУЩЕСТВУЮЩИХ ТАБЛИЦ

Product - Добавление новых связей

model Product {
  // ... существующие поля остаются без изменений
  
  // === НОВЫЕ СВЯЗИ С ПОСТАВКАМИ V2 ===
  fulfillmentSupplyItems      FulfillmentConsumableSupplyItem[]  @relation("FFSupplyItems")
  sellerSupplyItems           SellerConsumableSupplyItem[]       @relation("SellerSupplyItems")
  goodsSupplyItems            GoodsSupplyItem[]                  @relation("GoodsSupplyItems")
  ozonSupplyItems             OzonSupplyItem[]                   @relation("OzonSupplyItems")
  wildberriesSupplyItems      WildberriesSupplyItem[]           @relation("WBSupplyItems")
  
  // ... остальные поля остаются без изменений
}

Organization - Добавление новых связей

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 - Добавление новых связей

model User {
  // ... существующие поля остаются без изменений
  
  // === НОВЫЕ СВЯЗИ С ПРИЕМКОЙ ПОСТАВОК V2 ===
  fulfillmentSupplyOrdersReceived         FulfillmentConsumableSupplyOrder[]  @relation("FFSupplyOrdersReceiver")
  sellerSupplyOrdersReceived              SellerConsumableSupplyOrder[]       @relation("SellerSupplyOrdersReceiver")
  goodsSupplyOrdersReceived               GoodsSupplyOrder[]                  @relation("GoodsSupplyOrdersReceiver")
  
  // ... остальные поля остаются без изменений
}

🔍 ИНДЕКСЫ ДЛЯ ПРОИЗВОДИТЕЛЬНОСТИ

// Индексы для быстрого поиска поставок по статусу и организации
@@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: Создание новых таблиц

-- Создание таблиц параллельно с существующими
CREATE TABLE fulfillment_consumable_supply_orders (...);
CREATE TABLE fulfillment_consumable_supply_items (...);
-- и т.д.

Phase 2: Новые enum значения

-- Добавление новых enum без затрагивания старых
CREATE TYPE "SupplyOrderStatusV2" AS ENUM (...);
CREATE TYPE "MarketplaceSupplyStatus" AS ENUM (...);

Phase 3: Обновление связей (без удаления старых)

-- Добавление новых foreign key связей
ALTER TABLE "Product" ADD COLUMN ...;
ALTER TABLE "Organization" ADD COLUMN ...;

Phase 4: Данные миграции (только с одобрения)

-- Миграция данных из старых таблиц в новые
-- ТОЛЬКО после полного тестирования новой системы

⚠️ ВАЖНЫЕ ПРИНЦИПЫ

ОБРАТНАЯ СОВМЕСТИМОСТЬ

  • Все существующие таблицы остаются без изменений
  • Новые таблицы создаются параллельно
  • Старая система продолжает работать

🔒 БЕЗОПАСНОСТЬ ДАННЫХ

  • Каждый тип поставки изолирован в отдельной таблице
  • Связи защищены foreign key constraints
  • Каскадное удаление только для зависимых записей

📈 МАСШТАБИРУЕМОСТЬ

  • Легко добавлять новые типы поставок
  • Оптимизированные индексы для каждого use case
  • Независимые схемы для разных процессов

🛡️ ЦЕЛОСТНОСТЬ ДАННЫХ

  • Строгие ограничения на связи между таблицами
  • Валидация через enum значения
  • Уникальные индексы предотвращают дублирование

Следующий шаг: Создание Prisma миграций для FulfillmentConsumableSupplyOrder