Обновлены модели и компоненты для управления поставками и расходниками. Добавлены новые поля в модели SupplyOrder и соответствующие резолверы для поддержки логистики. Реализованы компоненты уведомлений для отображения статуса логистических заявок и поставок. Оптимизирован интерфейс для улучшения пользовательского опыта, добавлены логи для диагностики запросов. Обновлены GraphQL схемы и мутации для поддержки новых функциональных возможностей.

This commit is contained in:
Veronika Smirnova
2025-08-03 17:04:29 +03:00
parent a33adda9d7
commit 8407ca397c
34 changed files with 5382 additions and 1795 deletions

View File

@ -29,14 +29,14 @@ model User {
}
model Admin {
id String @id @default(cuid())
username String @unique
password String // Хеш пароля
email String? @unique
isActive Boolean @default(true)
id String @id @default(cuid())
username String @unique
password String // Хеш пароля
email String? @unique
isActive Boolean @default(true)
lastLogin DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("admins")
}
@ -104,14 +104,15 @@ model Organization {
users User[]
logistics Logistics[]
supplyOrders SupplyOrder[]
partnerSupplyOrders SupplyOrder[] @relation("SupplyOrderPartner")
fulfillmentSupplyOrders SupplyOrder[] @relation("SupplyOrderFulfillmentCenter")
logisticsSupplyOrders SupplyOrder[] @relation("SupplyOrderLogistics")
partnerSupplyOrders SupplyOrder[] @relation("SupplyOrderPartner")
fulfillmentSupplyOrders SupplyOrder[] @relation("SupplyOrderFulfillmentCenter")
logisticsSupplyOrders SupplyOrder[] @relation("SupplyOrderLogistics")
wildberriesSupplies WildberriesSupply[]
supplySuppliers SupplySupplier[] @relation("SupplySuppliers")
externalAds ExternalAd[] @relation("ExternalAds")
wbWarehouseCaches WBWarehouseCache[] @relation("WBWarehouseCaches")
sellerStatsCaches SellerStatsCache[] @relation("SellerStatsCaches")
supplySuppliers SupplySupplier[] @relation("SupplySuppliers")
externalAds ExternalAd[] @relation("ExternalAds")
wbWarehouseCaches WBWarehouseCache[] @relation("WBWarehouseCaches")
sellerStatsCaches SellerStatsCache[] @relation("SellerStatsCaches")
sellerSupplies Supply[] @relation("SellerSupplies")
@@map("organizations")
}
@ -198,24 +199,28 @@ model Service {
}
model Supply {
id String @id @default(cuid())
id String @id @default(cuid())
name String
description String?
price Decimal @db.Decimal(10, 2)
quantity Int @default(0)
unit String @default("шт")
category String @default("Расходники")
status String @default("planned") // planned, in-transit, delivered, in-stock
date DateTime @default(now())
supplier String @default("Не указан")
minStock Int @default(0)
currentStock Int @default(0)
usedStock Int @default(0) // Количество использованных расходников
price Decimal @db.Decimal(10, 2)
quantity Int @default(0)
unit String @default("шт")
category String @default("Расходники")
status String @default("planned") // planned, in-transit, delivered, in-stock
date DateTime @default(now())
supplier String @default("Не указан")
minStock Int @default(0)
currentStock Int @default(0)
usedStock Int @default(0) // Количество использованных расходников
imageUrl String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
type SupplyType @default(FULFILLMENT_CONSUMABLES) // Тип расходников
sellerOwnerId String? // ID селлера-владельца (для расходников селлеров)
sellerOwner Organization? @relation("SellerSupplies", fields: [sellerOwnerId], references: [id], onDelete: SetNull)
shopLocation String? // Местоположение в магазине фулфилмента
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
organizationId String
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
@@map("supplies")
}
@ -231,37 +236,37 @@ model Category {
}
model Product {
id String @id @default(cuid())
name String
article String
description String?
price Decimal @db.Decimal(12, 2)
pricePerSet Decimal? @db.Decimal(12, 2)
quantity Int @default(0)
setQuantity Int?
ordered Int?
inTransit Int?
stock Int?
sold Int?
type ProductType @default(PRODUCT)
categoryId String?
brand String?
color String?
size String?
weight Decimal? @db.Decimal(8, 3)
dimensions String?
material String?
images Json @default("[]")
mainImage String?
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
organizationId String
cartItems CartItem[]
favorites Favorites[]
id String @id @default(cuid())
name String
article String
description String?
price Decimal @db.Decimal(12, 2)
pricePerSet Decimal? @db.Decimal(12, 2)
quantity Int @default(0)
setQuantity Int?
ordered Int?
inTransit Int?
stock Int?
sold Int?
type ProductType @default(PRODUCT)
categoryId String?
brand String?
color String?
size String?
weight Decimal? @db.Decimal(8, 3)
dimensions String?
material String?
images Json @default("[]")
mainImage String?
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
organizationId String
cartItems CartItem[]
favorites Favorites[]
supplyOrderItems SupplyOrderItem[]
category Category? @relation(fields: [categoryId], references: [id])
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
category Category? @relation(fields: [categoryId], references: [id])
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
@@unique([organizationId, article])
@@map("products")
@ -355,41 +360,41 @@ model EmployeeSchedule {
}
model WildberriesSupply {
id String @id @default(cuid())
organizationId String
deliveryDate DateTime?
status WildberriesSupplyStatus @default(DRAFT)
totalAmount Decimal @db.Decimal(12, 2)
totalItems Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
cards WildberriesSupplyCard[]
id String @id @default(cuid())
organizationId String
deliveryDate DateTime?
status WildberriesSupplyStatus @default(DRAFT)
totalAmount Decimal @db.Decimal(12, 2)
totalItems Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
cards WildberriesSupplyCard[]
@@map("wildberries_supplies")
}
model WildberriesSupplyCard {
id String @id @default(cuid())
supplyId String
nmId String
vendorCode String
title String
brand String?
price Decimal @db.Decimal(12, 2)
discountedPrice Decimal? @db.Decimal(12, 2)
quantity Int
selectedQuantity Int
selectedMarket String?
selectedPlace String?
sellerName String?
sellerPhone String?
deliveryDate DateTime?
mediaFiles Json @default("[]")
selectedServices Json @default("[]")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
supply WildberriesSupply @relation(fields: [supplyId], references: [id], onDelete: Cascade)
id String @id @default(cuid())
supplyId String
nmId String
vendorCode String
title String
brand String?
price Decimal @db.Decimal(12, 2)
discountedPrice Decimal? @db.Decimal(12, 2)
quantity Int
selectedQuantity Int
selectedMarket String?
selectedPlace String?
sellerName String?
sellerPhone String?
deliveryDate DateTime?
mediaFiles Json @default("[]")
selectedServices Json @default("[]")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
supply WildberriesSupply @relation(fields: [supplyId], references: [id], onDelete: Cascade)
@@map("wildberries_supply_cards")
}
@ -459,6 +464,11 @@ enum ProductType {
CONSUMABLE
}
enum SupplyType {
FULFILLMENT_CONSUMABLES // Расходники фулфилмента (купленные фулфилментом для себя)
SELLER_CONSUMABLES // Расходники селлеров (принятые от селлеров для хранения)
}
model Logistics {
id String @id @default(cuid())
fromLocation String
@ -475,23 +485,23 @@ model Logistics {
}
model SupplyOrder {
id String @id @default(cuid())
partnerId String
deliveryDate DateTime
status SupplyOrderStatus @default(PENDING)
totalAmount Decimal @db.Decimal(12, 2)
totalItems Int
fulfillmentCenterId String?
logisticsPartnerId String
consumableType String? // Классификация расходников: FULFILLMENT_CONSUMABLES, SELLER_CONSUMABLES
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
organizationId String
items SupplyOrderItem[]
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
partner Organization @relation("SupplyOrderPartner", fields: [partnerId], references: [id])
fulfillmentCenter Organization? @relation("SupplyOrderFulfillmentCenter", fields: [fulfillmentCenterId], references: [id])
logisticsPartner Organization @relation("SupplyOrderLogistics", fields: [logisticsPartnerId], references: [id])
id String @id @default(cuid())
partnerId String
deliveryDate DateTime
status SupplyOrderStatus @default(PENDING)
totalAmount Decimal @db.Decimal(12, 2)
totalItems Int
fulfillmentCenterId String?
logisticsPartnerId String? // Опциональная логистика - может назначить фулфилмент
consumableType String? // Классификация расходников: FULFILLMENT_CONSUMABLES, SELLER_CONSUMABLES
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
organizationId String
items SupplyOrderItem[]
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
partner Organization @relation("SupplyOrderPartner", fields: [partnerId], references: [id])
fulfillmentCenter Organization? @relation("SupplyOrderFulfillmentCenter", fields: [fulfillmentCenterId], references: [id])
logisticsPartner Organization? @relation("SupplyOrderLogistics", fields: [logisticsPartnerId], references: [id])
@@map("supply_orders")
}
@ -531,13 +541,13 @@ model SupplySupplier {
model ExternalAd {
id String @id @default(cuid())
name String // Название рекламы
url String // URL рекламы
name String // Название рекламы
url String // URL рекламы
cost Decimal @db.Decimal(12, 2) // Стоимость
date DateTime // Дата рекламы
nmId String // ID товара Wildberries
date DateTime // Дата рекламы
nmId String // ID товара Wildberries
clicks Int @default(0) // Количество кликов
organizationId String // ID организации
organizationId String // ID организации
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
organization Organization @relation("ExternalAds", fields: [organizationId], references: [id], onDelete: Cascade)
@ -548,9 +558,9 @@ model ExternalAd {
model WBWarehouseCache {
id String @id @default(cuid())
organizationId String // ID организации
cacheDate DateTime // Дата кеширования (только дата, без времени)
data Json // Кешированные данные склада WB
organizationId String // ID организации
cacheDate DateTime // Дата кеширования (только дата, без времени)
data Json // Кешированные данные склада WB
totalProducts Int @default(0) // Общее количество товаров
totalStocks Int @default(0) // Общее количество остатков
totalReserved Int @default(0) // Общее количество в резерве
@ -564,30 +574,30 @@ model WBWarehouseCache {
}
model SellerStatsCache {
id String @id @default(cuid())
organizationId String // ID организации
cacheDate DateTime // Дата кеширования (только дата, без времени)
period String // Период статистики (week, month, quarter, custom)
dateFrom DateTime? // Дата начала периода (для custom)
dateTo DateTime? // Дата окончания периода (для custom)
id String @id @default(cuid())
organizationId String // ID организации
cacheDate DateTime // Дата кеширования (только дата, без времени)
period String // Период статистики (week, month, quarter, custom)
dateFrom DateTime? // Дата начала периода (для custom)
dateTo DateTime? // Дата окончания периода (для custom)
// Данные товаров
productsData Json? // Кешированные данные товаров
productsTotalSales Decimal? @db.Decimal(15, 2) // Общая сумма продаж товаров
productsTotalOrders Int? // Общее количество заказов товаров
productsCount Int? // Количество товаров
productsData Json? // Кешированные данные товаров
productsTotalSales Decimal? @db.Decimal(15, 2) // Общая сумма продаж товаров
productsTotalOrders Int? // Общее количество заказов товаров
productsCount Int? // Количество товаров
// Данные рекламы
advertisingData Json? // Кешированные данные рекламы
advertisingTotalCost Decimal? @db.Decimal(15, 2) // Общие расходы на рекламу
advertisingTotalViews Int? // Общие показы рекламы
advertisingTotalClicks Int? // Общие клики рекламы
advertisingData Json? // Кешированные данные рекламы
advertisingTotalCost Decimal? @db.Decimal(15, 2) // Общие расходы на рекламу
advertisingTotalViews Int? // Общие показы рекламы
advertisingTotalClicks Int? // Общие клики рекламы
// Метаданные
expiresAt DateTime // Время истечения кеша (24 часа)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
organization Organization @relation("SellerStatsCaches", fields: [organizationId], references: [id], onDelete: Cascade)
expiresAt DateTime // Время истечения кеша (24 часа)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
organization Organization @relation("SellerStatsCaches", fields: [organizationId], references: [id], onDelete: Cascade)
@@unique([organizationId, cacheDate, period, dateFrom, dateTo])
@@index([organizationId, cacheDate])