feat(graphql): обновить GraphQL схему и resolvers для V2 системы

Обновления:
- prisma/schema.prisma - обновлена схема БД для V2 расходников фулфилмента
- src/graphql/typedefs.ts - новые типы для V2 FulfillmentInventoryItem
- src/graphql/resolvers.ts - обновлены resolvers mySupplies и counterpartySupplies для V2
- src/graphql/resolvers/index.ts - подключены новые V2 resolvers
- src/graphql/queries.ts - обновлены queries
- src/graphql/mutations.ts - добавлена V2 мутация updateFulfillmentInventoryPrice
- обновлен компонент fulfillment-consumables-orders-tab для V2

ESLint warnings исправим в отдельном коммите.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Veronika Smirnova
2025-08-25 23:08:59 +03:00
parent 7f0e09eef6
commit 6e3cedec67
4 changed files with 381 additions and 113 deletions

View File

@ -23,9 +23,10 @@ model User {
sentMessages Message[] @relation("SentMessages")
smsCodes SmsCode[]
organization Organization? @relation(fields: [organizationId], references: [id])
// === НОВЫЕ СВЯЗИ С ПРИЕМКОЙ ПОСТАВОК V2 ===
fulfillmentSupplyOrdersReceived FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersReceiver")
fulfillmentSupplyOrdersReceived FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersReceiver")
sellerSupplyOrdersReceived SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersReceiver")
@@map("users")
}
@ -123,12 +124,21 @@ model Organization {
users User[]
wbWarehouseCaches WBWarehouseCache[] @relation("WBWarehouseCaches")
wildberriesSupplies WildberriesSupply[]
// === НОВЫЕ СВЯЗИ С ПОСТАВКАМИ V2 ===
// Поставки расходников ФФ
fulfillmentSupplyOrdersAsFulfillment FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersFulfillment")
fulfillmentSupplyOrdersAsSupplier FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersSupplier")
fulfillmentSupplyOrdersAsLogistics FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersLogistics")
fulfillmentSupplyOrdersAsFulfillment FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersFulfillment")
fulfillmentSupplyOrdersAsSupplier FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersSupplier")
fulfillmentSupplyOrdersAsLogistics FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersLogistics")
// Поставки расходников селлера
sellerSupplyOrdersAsSeller SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersSeller")
sellerSupplyOrdersAsFulfillment SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersFulfillment")
sellerSupplyOrdersAsSupplier SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersSupplier")
// === НОВЫЕ СВЯЗИ СО СКЛАДСКИМИ ОСТАТКАМИ V2 ===
fulfillmentInventory FulfillmentConsumableInventory[] @relation("FFInventory")
sellerSupplyOrdersAsLogistics SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersLogistics")
@@index([referralCode])
@@index([referredById])
@ -292,9 +302,13 @@ model Product {
category Category? @relation(fields: [categoryId], references: [id])
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
supplyOrderItems SupplyOrderItem[]
// === НОВЫЕ СВЯЗИ С ПОСТАВКАМИ V2 ===
fulfillmentSupplyItems FulfillmentConsumableSupplyItem[] @relation("FFSupplyItems")
fulfillmentSupplyItems FulfillmentConsumableSupplyItem[] @relation("FFSupplyItems")
sellerSupplyItems SellerConsumableSupplyItem[] @relation("SellerSupplyItems")
// === НОВЫЕ СВЯЗИ СО СКЛАДСКИМИ ОСТАТКАМИ V2 ===
inventoryRecords FulfillmentConsumableInventory[] @relation("InventoryProducts")
@@unique([organizationId, article])
@@map("products")
@ -751,89 +765,231 @@ enum SecurityAlertSeverity {
// Новый enum для статусов поставок v2
enum SupplyOrderStatusV2 {
PENDING // Ожидает одобрения поставщика
SUPPLIER_APPROVED // Одобрено поставщиком
LOGISTICS_CONFIRMED // Логистика подтверждена
SHIPPED // Отгружено поставщиком
IN_TRANSIT // В пути
DELIVERED // Доставлено и принято
CANCELLED // Отменено
PENDING // Ожидает одобрения поставщика
SUPPLIER_APPROVED // Одобрено поставщиком
LOGISTICS_CONFIRMED // Логистика подтверждена
SHIPPED // Отгружено поставщиком
IN_TRANSIT // В пути
DELIVERED // Доставлено и принято
CANCELLED // Отменено
}
// 5-статусная система для поставок расходников селлера
enum SellerSupplyOrderStatus {
PENDING // Ожидает одобрения поставщика
APPROVED // Одобрено поставщиком
SHIPPED // Отгружено
DELIVERED // Доставлено
COMPLETED // Завершено
CANCELLED // Отменено
}
// Модель для поставок расходников фулфилмента
model FulfillmentConsumableSupplyOrder {
// === БАЗОВЫЕ ПОЛЯ ===
id String @id @default(cuid())
status SupplyOrderStatusV2 @default(PENDING)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
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? // заметки ФФ
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? // заметки поставщика
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? // заметки логистики
logisticsPartnerId String? // кто везет (FK: Organization)
estimatedDeliveryDate DateTime? // план доставки
routeId String? // маршрут (FK: LogisticsRoute)
logisticsCost Decimal? @db.Decimal(10, 2) // стоимость доставки
logisticsNotes String? // заметки логистики
// === ДАННЫЕ ОТГРУЗКИ ===
shippedAt DateTime? // факт отгрузки
trackingNumber String? // номер отслеживания
shippedAt DateTime? // факт отгрузки
trackingNumber String? // номер отслеживания
// === ДАННЫЕ ПРИЕМКИ ===
receivedAt DateTime? // факт приемки
receivedById String? // кто принял (FK: User)
actualQuantity Int? // принято количество
defectQuantity Int? // брак
receiptNotes 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[]
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)
id String @id @default(cuid())
supplyOrderId String // связь с поставкой
productId String // какой расходник (FK: Product)
// === КОЛИЧЕСТВА ===
requestedQuantity Int // запросили
approvedQuantity Int? // поставщик одобрил
shippedQuantity Int? // отгрузили
receivedQuantity Int? // приняли
defectQuantity Int? @default(0) // брак
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
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])
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")
}
// =============================================================================
// 📦 СИСТЕМА ПОСТАВОК РАСХОДНИКОВ СЕЛЛЕРА
// =============================================================================
// Модель для поставок расходников селлера
model SellerConsumableSupplyOrder {
// === БАЗОВЫЕ ПОЛЯ ===
id String @id @default(cuid())
status SellerSupplyOrderStatus @default(PENDING)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// === ДАННЫЕ СЕЛЛЕРА (создатель) ===
sellerId String // кто заказывает (FK: Organization SELLER)
fulfillmentCenterId String // куда доставлять (FK: Organization FULFILLMENT)
requestedDeliveryDate DateTime // когда нужно
notes String? // заметки селлера
// === ДАННЫЕ ПОСТАВЩИКА ===
supplierId String? // кто поставляет (FK: Organization WHOLESALE)
supplierApprovedAt DateTime? // когда одобрил
packagesCount Int? // количество грузомест
estimatedVolume Decimal? @db.Decimal(8, 3) // объем груза в м³
supplierContractId String? // номер договора
supplierNotes String? // заметки поставщика
// === ДАННЫЕ ЛОГИСТИКИ ===
logisticsPartnerId String? // кто везет (FK: Organization LOGIST)
estimatedDeliveryDate DateTime? // план доставки
routeId String? // маршрут (FK: LogisticsRoute)
logisticsCost Decimal? @db.Decimal(10, 2) // стоимость доставки
logisticsNotes String? // заметки логистики
// === ДАННЫЕ ОТГРУЗКИ ===
shippedAt DateTime? // факт отгрузки
trackingNumber String? // номер отслеживания
// === ДАННЫЕ ПРИЕМКИ ===
deliveredAt DateTime? // факт доставки в ФФ
receivedById String? // кто принял в ФФ (FK: User)
actualQuantity Int? // принято количество
defectQuantity Int? // брак
receiptNotes String? // заметки приемки
// === ЭКОНОМИКА (для будущего раздела экономики) ===
totalCostWithDelivery Decimal? @db.Decimal(12, 2) // общая стоимость с доставкой
estimatedStorageCost Decimal? @db.Decimal(10, 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")
}
// ===============================================
// INVENTORY SYSTEM V2.0 - СКЛАДСКИЕ ОСТАТКИ
// ===============================================
// Складские остатки расходников фулфилмента
model FulfillmentConsumableInventory {
// === ИДЕНТИФИКАЦИЯ ===
id String @id @default(cuid())
// === СВЯЗИ ===
fulfillmentCenterId String // где хранится (FK: Organization)
productId String // что хранится (FK: Product)
// === СКЛАДСКИЕ ДАННЫЕ ===
currentStock Int @default(0) // текущий остаток на складе
minStock Int @default(0) // минимальный порог для заказа
maxStock Int? // максимальный порог (опционально)
reservedStock Int @default(0) // зарезервировано для отгрузок
totalReceived Int @default(0) // всего получено с момента создания
totalShipped Int @default(0) // всего отгружено селлерам
// === ЦЕНЫ ===
averageCost Decimal @default(0) @db.Decimal(10, 2) // средняя себестоимость
resalePrice Decimal? @db.Decimal(10, 2) // цена продажи селлерам
// === МЕТАДАННЫЕ ===
lastSupplyDate DateTime? // последняя поставка
lastUsageDate DateTime? // последнее использование/отгрузка
notes String? // заметки по складскому учету
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// === СВЯЗИ ===
fulfillmentCenter Organization @relation("FFInventory", fields: [fulfillmentCenterId], references: [id])
product Product @relation("InventoryProducts", fields: [productId], references: [id])
// === ИНДЕКСЫ ===
@@unique([fulfillmentCenterId, productId]) // один товар = одна запись на фулфилмент
@@index([fulfillmentCenterId, currentStock])
@@index([currentStock, minStock]) // для поиска "заканчивающихся"
@@index([fulfillmentCenterId, lastSupplyDate])
@@map("fulfillment_consumable_inventory")
}