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:
@ -25,7 +25,8 @@ model User {
|
|||||||
organization Organization? @relation(fields: [organizationId], references: [id])
|
organization Organization? @relation(fields: [organizationId], references: [id])
|
||||||
|
|
||||||
// === НОВЫЕ СВЯЗИ С ПРИЕМКОЙ ПОСТАВОК V2 ===
|
// === НОВЫЕ СВЯЗИ С ПРИЕМКОЙ ПОСТАВОК V2 ===
|
||||||
fulfillmentSupplyOrdersReceived FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersReceiver")
|
fulfillmentSupplyOrdersReceived FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersReceiver")
|
||||||
|
sellerSupplyOrdersReceived SellerConsumableSupplyOrder[] @relation("SellerSupplyOrdersReceiver")
|
||||||
|
|
||||||
@@map("users")
|
@@map("users")
|
||||||
}
|
}
|
||||||
@ -126,9 +127,18 @@ model Organization {
|
|||||||
|
|
||||||
// === НОВЫЕ СВЯЗИ С ПОСТАВКАМИ V2 ===
|
// === НОВЫЕ СВЯЗИ С ПОСТАВКАМИ V2 ===
|
||||||
// Поставки расходников ФФ
|
// Поставки расходников ФФ
|
||||||
fulfillmentSupplyOrdersAsFulfillment FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersFulfillment")
|
fulfillmentSupplyOrdersAsFulfillment FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersFulfillment")
|
||||||
fulfillmentSupplyOrdersAsSupplier FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersSupplier")
|
fulfillmentSupplyOrdersAsSupplier FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersSupplier")
|
||||||
fulfillmentSupplyOrdersAsLogistics FulfillmentConsumableSupplyOrder[] @relation("FFSupplyOrdersLogistics")
|
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([referralCode])
|
||||||
@@index([referredById])
|
@@index([referredById])
|
||||||
@ -294,7 +304,11 @@ model Product {
|
|||||||
supplyOrderItems SupplyOrderItem[]
|
supplyOrderItems SupplyOrderItem[]
|
||||||
|
|
||||||
// === НОВЫЕ СВЯЗИ С ПОСТАВКАМИ V2 ===
|
// === НОВЫЕ СВЯЗИ С ПОСТАВКАМИ V2 ===
|
||||||
fulfillmentSupplyItems FulfillmentConsumableSupplyItem[] @relation("FFSupplyItems")
|
fulfillmentSupplyItems FulfillmentConsumableSupplyItem[] @relation("FFSupplyItems")
|
||||||
|
sellerSupplyItems SellerConsumableSupplyItem[] @relation("SellerSupplyItems")
|
||||||
|
|
||||||
|
// === НОВЫЕ СВЯЗИ СО СКЛАДСКИМИ ОСТАТКАМИ V2 ===
|
||||||
|
inventoryRecords FulfillmentConsumableInventory[] @relation("InventoryProducts")
|
||||||
|
|
||||||
@@unique([organizationId, article])
|
@@unique([organizationId, article])
|
||||||
@@map("products")
|
@@map("products")
|
||||||
@ -751,89 +765,231 @@ enum SecurityAlertSeverity {
|
|||||||
|
|
||||||
// Новый enum для статусов поставок v2
|
// Новый enum для статусов поставок v2
|
||||||
enum SupplyOrderStatusV2 {
|
enum SupplyOrderStatusV2 {
|
||||||
PENDING // Ожидает одобрения поставщика
|
PENDING // Ожидает одобрения поставщика
|
||||||
SUPPLIER_APPROVED // Одобрено поставщиком
|
SUPPLIER_APPROVED // Одобрено поставщиком
|
||||||
LOGISTICS_CONFIRMED // Логистика подтверждена
|
LOGISTICS_CONFIRMED // Логистика подтверждена
|
||||||
SHIPPED // Отгружено поставщиком
|
SHIPPED // Отгружено поставщиком
|
||||||
IN_TRANSIT // В пути
|
IN_TRANSIT // В пути
|
||||||
DELIVERED // Доставлено и принято
|
DELIVERED // Доставлено и принято
|
||||||
CANCELLED // Отменено
|
CANCELLED // Отменено
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5-статусная система для поставок расходников селлера
|
||||||
|
enum SellerSupplyOrderStatus {
|
||||||
|
PENDING // Ожидает одобрения поставщика
|
||||||
|
APPROVED // Одобрено поставщиком
|
||||||
|
SHIPPED // Отгружено
|
||||||
|
DELIVERED // Доставлено
|
||||||
|
COMPLETED // Завершено
|
||||||
|
CANCELLED // Отменено
|
||||||
}
|
}
|
||||||
|
|
||||||
// Модель для поставок расходников фулфилмента
|
// Модель для поставок расходников фулфилмента
|
||||||
model FulfillmentConsumableSupplyOrder {
|
model FulfillmentConsumableSupplyOrder {
|
||||||
// === БАЗОВЫЕ ПОЛЯ ===
|
// === БАЗОВЫЕ ПОЛЯ ===
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
status SupplyOrderStatusV2 @default(PENDING)
|
status SupplyOrderStatusV2 @default(PENDING)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
// === ДАННЫЕ ФФ (создатель) ===
|
// === ДАННЫЕ ФФ (создатель) ===
|
||||||
fulfillmentCenterId String // кто заказывает (FK: Organization)
|
fulfillmentCenterId String // кто заказывает (FK: Organization)
|
||||||
requestedDeliveryDate DateTime // когда нужно
|
requestedDeliveryDate DateTime // когда нужно
|
||||||
resalePricePerUnit Decimal? @db.Decimal(10, 2) // цена продажи селлерам
|
resalePricePerUnit Decimal? @db.Decimal(10, 2) // цена продажи селлерам
|
||||||
minStockLevel Int? // минимальный остаток
|
minStockLevel Int? // минимальный остаток
|
||||||
notes String? // заметки ФФ
|
notes String? // заметки ФФ
|
||||||
|
|
||||||
// === ДАННЫЕ ПОСТАВЩИКА ===
|
// === ДАННЫЕ ПОСТАВЩИКА ===
|
||||||
supplierId String? // кто поставляет (FK: Organization)
|
supplierId String? // кто поставляет (FK: Organization)
|
||||||
supplierApprovedAt DateTime? // когда одобрил
|
supplierApprovedAt DateTime? // когда одобрил
|
||||||
packagesCount Int? // количество грузомест
|
packagesCount Int? // количество грузомест
|
||||||
estimatedVolume Decimal? @db.Decimal(8, 3) // объем груза в м³
|
estimatedVolume Decimal? @db.Decimal(8, 3) // объем груза в м³
|
||||||
supplierContractId String? // номер договора
|
supplierContractId String? // номер договора
|
||||||
supplierNotes String? // заметки поставщика
|
supplierNotes String? // заметки поставщика
|
||||||
|
|
||||||
// === ДАННЫЕ ЛОГИСТИКИ ===
|
// === ДАННЫЕ ЛОГИСТИКИ ===
|
||||||
logisticsPartnerId String? // кто везет (FK: Organization)
|
logisticsPartnerId String? // кто везет (FK: Organization)
|
||||||
estimatedDeliveryDate DateTime? // план доставки
|
estimatedDeliveryDate DateTime? // план доставки
|
||||||
routeId String? // маршрут (FK: LogisticsRoute)
|
routeId String? // маршрут (FK: LogisticsRoute)
|
||||||
logisticsCost Decimal? @db.Decimal(10, 2) // стоимость доставки
|
logisticsCost Decimal? @db.Decimal(10, 2) // стоимость доставки
|
||||||
logisticsNotes String? // заметки логистики
|
logisticsNotes String? // заметки логистики
|
||||||
|
|
||||||
// === ДАННЫЕ ОТГРУЗКИ ===
|
// === ДАННЫЕ ОТГРУЗКИ ===
|
||||||
shippedAt DateTime? // факт отгрузки
|
shippedAt DateTime? // факт отгрузки
|
||||||
trackingNumber String? // номер отслеживания
|
trackingNumber String? // номер отслеживания
|
||||||
|
|
||||||
// === ДАННЫЕ ПРИЕМКИ ===
|
// === ДАННЫЕ ПРИЕМКИ ===
|
||||||
receivedAt DateTime? // факт приемки
|
receivedAt DateTime? // факт приемки
|
||||||
receivedById String? // кто принял (FK: User)
|
receivedById String? // кто принял (FK: User)
|
||||||
actualQuantity Int? // принято количество
|
actualQuantity Int? // принято количество
|
||||||
defectQuantity Int? // брак
|
defectQuantity Int? // брак
|
||||||
receiptNotes String? // заметки приемки
|
receiptNotes String? // заметки приемки
|
||||||
|
|
||||||
// === СВЯЗИ ===
|
// === СВЯЗИ ===
|
||||||
fulfillmentCenter Organization @relation("FFSupplyOrdersFulfillment", fields: [fulfillmentCenterId], references: [id])
|
fulfillmentCenter Organization @relation("FFSupplyOrdersFulfillment", fields: [fulfillmentCenterId], references: [id])
|
||||||
supplier Organization? @relation("FFSupplyOrdersSupplier", fields: [supplierId], references: [id])
|
supplier Organization? @relation("FFSupplyOrdersSupplier", fields: [supplierId], references: [id])
|
||||||
logisticsPartner Organization? @relation("FFSupplyOrdersLogistics", fields: [logisticsPartnerId], references: [id])
|
logisticsPartner Organization? @relation("FFSupplyOrdersLogistics", fields: [logisticsPartnerId], references: [id])
|
||||||
receivedBy User? @relation("FFSupplyOrdersReceiver", fields: [receivedById], references: [id])
|
receivedBy User? @relation("FFSupplyOrdersReceiver", fields: [receivedById], references: [id])
|
||||||
items FulfillmentConsumableSupplyItem[]
|
items FulfillmentConsumableSupplyItem[]
|
||||||
|
|
||||||
@@map("fulfillment_consumable_supply_orders")
|
@@map("fulfillment_consumable_supply_orders")
|
||||||
}
|
}
|
||||||
|
|
||||||
model FulfillmentConsumableSupplyItem {
|
model FulfillmentConsumableSupplyItem {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
supplyOrderId String // связь с поставкой
|
supplyOrderId String // связь с поставкой
|
||||||
productId String // какой расходник (FK: Product)
|
productId String // какой расходник (FK: Product)
|
||||||
|
|
||||||
// === КОЛИЧЕСТВА ===
|
// === КОЛИЧЕСТВА ===
|
||||||
requestedQuantity Int // запросили
|
requestedQuantity Int // запросили
|
||||||
approvedQuantity Int? // поставщик одобрил
|
approvedQuantity Int? // поставщик одобрил
|
||||||
shippedQuantity Int? // отгрузили
|
shippedQuantity Int? // отгрузили
|
||||||
receivedQuantity Int? // приняли
|
receivedQuantity Int? // приняли
|
||||||
defectQuantity Int? @default(0) // брак
|
defectQuantity Int? @default(0) // брак
|
||||||
|
|
||||||
// === ЦЕНЫ ===
|
// === ЦЕНЫ ===
|
||||||
unitPrice Decimal @db.Decimal(10, 2) // цена за единицу от поставщика
|
unitPrice Decimal @db.Decimal(10, 2) // цена за единицу от поставщика
|
||||||
totalPrice Decimal @db.Decimal(12, 2) // общая стоимость
|
totalPrice Decimal @db.Decimal(12, 2) // общая стоимость
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
// === СВЯЗИ ===
|
// === СВЯЗИ ===
|
||||||
supplyOrder FulfillmentConsumableSupplyOrder @relation(fields: [supplyOrderId], references: [id], onDelete: Cascade)
|
supplyOrder FulfillmentConsumableSupplyOrder @relation(fields: [supplyOrderId], references: [id], onDelete: Cascade)
|
||||||
product Product @relation("FFSupplyItems", fields: [productId], references: [id])
|
product Product @relation("FFSupplyItems", fields: [productId], references: [id])
|
||||||
|
|
||||||
@@unique([supplyOrderId, productId])
|
@@unique([supplyOrderId, productId])
|
||||||
@@map("fulfillment_consumable_supply_items")
|
@@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")
|
||||||
|
}
|
||||||
|
@ -35,6 +35,7 @@ import {
|
|||||||
GET_MY_EMPLOYEES,
|
GET_MY_EMPLOYEES,
|
||||||
GET_LOGISTICS_PARTNERS,
|
GET_LOGISTICS_PARTNERS,
|
||||||
} from '@/graphql/queries'
|
} from '@/graphql/queries'
|
||||||
|
import { GET_INCOMING_SELLER_SUPPLIES } from '@/graphql/queries/seller-consumables-v2'
|
||||||
import { useAuth } from '@/hooks/useAuth'
|
import { useAuth } from '@/hooks/useAuth'
|
||||||
|
|
||||||
interface SupplyOrder {
|
interface SupplyOrder {
|
||||||
@ -146,21 +147,31 @@ export function FulfillmentConsumablesOrdersTab() {
|
|||||||
console.error('LOGISTICS ERROR:', logisticsError)
|
console.error('LOGISTICS ERROR:', logisticsError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Загружаем заказы поставок
|
// Загружаем заказы поставок из старой системы
|
||||||
const { data, loading, error, refetch } = useQuery(GET_SUPPLY_ORDERS)
|
const { data, loading, error, refetch } = useQuery(GET_SUPPLY_ORDERS)
|
||||||
|
|
||||||
|
// Загружаем селлерские поставки из новой системы
|
||||||
|
const {
|
||||||
|
data: sellerData,
|
||||||
|
loading: sellerLoading,
|
||||||
|
error: sellerError,
|
||||||
|
refetch: refetchSellerSupplies,
|
||||||
|
} = useQuery(GET_INCOMING_SELLER_SUPPLIES)
|
||||||
|
|
||||||
// Мутация для приемки поставки фулфилментом
|
// Мутация для приемки поставки фулфилментом
|
||||||
const [fulfillmentReceiveOrder, { loading: receiving }] = useMutation(FULFILLMENT_RECEIVE_ORDER, {
|
const [fulfillmentReceiveOrder, { loading: receiving }] = useMutation(FULFILLMENT_RECEIVE_ORDER, {
|
||||||
onCompleted: (data) => {
|
onCompleted: (data) => {
|
||||||
if (data.fulfillmentReceiveOrder.success) {
|
if (data.fulfillmentReceiveOrder.success) {
|
||||||
toast.success(data.fulfillmentReceiveOrder.message)
|
toast.success(data.fulfillmentReceiveOrder.message)
|
||||||
refetch() // Обновляем список заказов
|
refetch() // Обновляем старые заказы поставок
|
||||||
|
refetchSellerSupplies() // Обновляем селлерские поставки
|
||||||
} else {
|
} else {
|
||||||
toast.error(data.fulfillmentReceiveOrder.message)
|
toast.error(data.fulfillmentReceiveOrder.message)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
refetchQueries: [
|
refetchQueries: [
|
||||||
{ query: GET_SUPPLY_ORDERS }, // Обновляем заказы поставок
|
{ query: GET_SUPPLY_ORDERS }, // Обновляем заказы поставок
|
||||||
|
{ query: GET_INCOMING_SELLER_SUPPLIES }, // Обновляем селлерские поставки
|
||||||
{ query: GET_MY_SUPPLIES }, // Обновляем склад фулфилмента (расходники фулфилмента)
|
{ query: GET_MY_SUPPLIES }, // Обновляем склад фулфилмента (расходники фулфилмента)
|
||||||
{ query: GET_WAREHOUSE_PRODUCTS }, // Обновляем товары склада
|
{ query: GET_WAREHOUSE_PRODUCTS }, // Обновляем товары склада
|
||||||
{ query: GET_PENDING_SUPPLIES_COUNT }, // Обновляем счетчики уведомлений
|
{ query: GET_PENDING_SUPPLIES_COUNT }, // Обновляем счетчики уведомлений
|
||||||
@ -176,7 +187,8 @@ export function FulfillmentConsumablesOrdersTab() {
|
|||||||
onCompleted: (data) => {
|
onCompleted: (data) => {
|
||||||
if (data.assignLogisticsToSupply.success) {
|
if (data.assignLogisticsToSupply.success) {
|
||||||
toast.success('Логистика и ответственный назначены успешно')
|
toast.success('Логистика и ответственный назначены успешно')
|
||||||
refetch() // Обновляем список заказов
|
refetch() // Обновляем старые заказы поставок
|
||||||
|
refetchSellerSupplies() // Обновляем селлерские поставки
|
||||||
// Сбрасываем состояние назначения
|
// Сбрасываем состояние назначения
|
||||||
setAssigningOrders((prev) => {
|
setAssigningOrders((prev) => {
|
||||||
const newSet = new Set(prev)
|
const newSet = new Set(prev)
|
||||||
@ -187,7 +199,10 @@ export function FulfillmentConsumablesOrdersTab() {
|
|||||||
toast.error(data.assignLogisticsToSupply.message || 'Ошибка при назначении логистики')
|
toast.error(data.assignLogisticsToSupply.message || 'Ошибка при назначении логистики')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
refetchQueries: [{ query: GET_SUPPLY_ORDERS }],
|
refetchQueries: [
|
||||||
|
{ query: GET_SUPPLY_ORDERS },
|
||||||
|
{ query: GET_INCOMING_SELLER_SUPPLIES },
|
||||||
|
],
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
console.error('Error assigning logistics:', error)
|
console.error('Error assigning logistics:', error)
|
||||||
toast.error('Ошибка при назначении логистики')
|
toast.error('Ошибка при назначении логистики')
|
||||||
@ -204,37 +219,93 @@ export function FulfillmentConsumablesOrdersTab() {
|
|||||||
setExpandedOrders(newExpanded)
|
setExpandedOrders(newExpanded)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Получаем данные заказов поставок
|
// Получаем данные заказов поставок из старой системы
|
||||||
const supplyOrders: SupplyOrder[] = data?.supplyOrders || []
|
const supplyOrders: SupplyOrder[] = data?.supplyOrders || []
|
||||||
|
|
||||||
// Фильтруем заказы для фулфилмента (ТОЛЬКО расходники фулфилмента)
|
// Получаем селлерские поставки и конвертируем их в формат SupplyOrder
|
||||||
|
const sellerSupplies = sellerData?.incomingSellerSupplies || []
|
||||||
|
const convertedSellerSupplies: SupplyOrder[] = sellerSupplies.map((supply: any) => ({
|
||||||
|
id: supply.id,
|
||||||
|
partnerId: supply.supplierId || supply.supplier?.id,
|
||||||
|
deliveryDate: supply.requestedDeliveryDate,
|
||||||
|
status: supply.status === 'DELIVERED' ? 'DELIVERED' :
|
||||||
|
supply.status === 'SHIPPED' ? 'SHIPPED' :
|
||||||
|
supply.status === 'APPROVED' ? 'SUPPLIER_APPROVED' :
|
||||||
|
'PENDING',
|
||||||
|
totalAmount: supply.totalCostWithDelivery || supply.items?.reduce((sum: number, item: any) =>
|
||||||
|
sum + (item.unitPrice * item.requestedQuantity), 0) || 0,
|
||||||
|
totalItems: supply.items?.reduce((sum: number, item: any) => sum + item.requestedQuantity, 0) || 0,
|
||||||
|
createdAt: supply.createdAt,
|
||||||
|
consumableType: 'SELLER_CONSUMABLES',
|
||||||
|
fulfillmentCenter: supply.fulfillmentCenter,
|
||||||
|
organization: supply.seller, // Селлер-создатель
|
||||||
|
partner: supply.supplier, // Поставщик
|
||||||
|
logisticsPartner: supply.logisticsPartner,
|
||||||
|
items: supply.items?.map((item: any) => ({
|
||||||
|
id: item.id,
|
||||||
|
quantity: item.requestedQuantity,
|
||||||
|
price: item.unitPrice,
|
||||||
|
totalPrice: item.totalPrice || (item.unitPrice * item.requestedQuantity),
|
||||||
|
product: {
|
||||||
|
id: item.product?.id,
|
||||||
|
name: item.product?.name || 'Товар',
|
||||||
|
article: item.product?.article || '',
|
||||||
|
description: item.product?.description,
|
||||||
|
price: item.product?.price,
|
||||||
|
quantity: item.product?.quantity,
|
||||||
|
images: item.product?.images,
|
||||||
|
mainImage: item.product?.mainImage,
|
||||||
|
category: item.product?.category,
|
||||||
|
},
|
||||||
|
})) || [],
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Объединяем старые поставки и селлерские поставки
|
||||||
|
const allSupplyOrders = [...supplyOrders, ...convertedSellerSupplies]
|
||||||
|
|
||||||
|
// Фильтруем заказы для фулфилмента (расходники фулфилмента + селлеров)
|
||||||
const fulfillmentOrders = supplyOrders.filter((order) => {
|
const fulfillmentOrders = supplyOrders.filter((order) => {
|
||||||
// Показываем только заказы созданные САМИМ фулфилментом для своих расходников
|
// Получатель должен быть наш фулфилмент-центр
|
||||||
const isCreatedBySelf = order.organization?.id === user?.organization?.id
|
|
||||||
// И получатель тоже мы (фулфилмент заказывает расходники для себя)
|
|
||||||
const isRecipient = order.fulfillmentCenter?.id === user?.organization?.id
|
const isRecipient = order.fulfillmentCenter?.id === user?.organization?.id
|
||||||
// И статус не PENDING и не CANCELLED (одобренные поставщиком заявки)
|
// И статус не PENDING и не CANCELLED (одобренные поставщиком заявки)
|
||||||
const isApproved = order.status !== 'CANCELLED' && order.status !== 'PENDING'
|
const isApproved = order.status !== 'CANCELLED' && order.status !== 'PENDING'
|
||||||
// ✅ КРИТИЧНОЕ ИСПРАВЛЕНИЕ: Показывать только расходники ФУЛФИЛМЕНТА (НЕ селлеров и НЕ товары)
|
|
||||||
|
// ✅ ИСПРАВЛЕНИЕ: Показывать ОБА типа расходников - фулфилмент и селлер
|
||||||
const isFulfillmentConsumables = order.consumableType === 'FULFILLMENT_CONSUMABLES'
|
const isFulfillmentConsumables = order.consumableType === 'FULFILLMENT_CONSUMABLES'
|
||||||
|
const isSellerConsumables = order.consumableType === 'SELLER_CONSUMABLES'
|
||||||
|
const isAnyConsumables = isFulfillmentConsumables || isSellerConsumables
|
||||||
|
|
||||||
// Проверяем, что это НЕ товары (товары содержат услуги в рецептуре)
|
// Проверяем, что это НЕ товары (товары содержат услуги в рецептуре)
|
||||||
const hasServices = order.items?.some(item => item.recipe?.services && item.recipe.services.length > 0)
|
const hasServices = order.items?.some(item => item.recipe?.services && item.recipe.services.length > 0)
|
||||||
const isConsumablesOnly = isFulfillmentConsumables && !hasServices
|
const isConsumablesOnly = isAnyConsumables && !hasServices
|
||||||
|
|
||||||
console.warn('🔍 Фильтрация расходников фулфилмента:', {
|
// Дополнительная проверка для селлерских поставок
|
||||||
|
const isCreatedBySelf = order.organization?.id === user?.organization?.id
|
||||||
|
const isFromSeller = order.organization?.type === 'SELLER'
|
||||||
|
|
||||||
|
// Логика фильтрации:
|
||||||
|
// 1. Свои поставки фулфилмента (созданные нами)
|
||||||
|
// 2. Поставки от селлеров (созданные селлерами для нас)
|
||||||
|
const shouldShow = isRecipient && isApproved && isConsumablesOnly && (isCreatedBySelf || isFromSeller)
|
||||||
|
|
||||||
|
console.warn('🔍 Фильтрация расходников фулфилмента + селлеров:', {
|
||||||
orderId: order.id.slice(-8),
|
orderId: order.id.slice(-8),
|
||||||
isRecipient,
|
isRecipient,
|
||||||
isCreatedBySelf,
|
|
||||||
isApproved,
|
isApproved,
|
||||||
isFulfillmentConsumables,
|
isFulfillmentConsumables,
|
||||||
|
isSellerConsumables,
|
||||||
|
isAnyConsumables,
|
||||||
hasServices,
|
hasServices,
|
||||||
isConsumablesOnly,
|
isConsumablesOnly,
|
||||||
|
isCreatedBySelf,
|
||||||
|
isFromSeller,
|
||||||
consumableType: order.consumableType,
|
consumableType: order.consumableType,
|
||||||
|
organizationType: order.organization?.type,
|
||||||
itemsWithServices: order.items?.filter(item => item.recipe?.services && item.recipe.services.length > 0).length || 0,
|
itemsWithServices: order.items?.filter(item => item.recipe?.services && item.recipe.services.length > 0).length || 0,
|
||||||
finalResult: isRecipient && isCreatedBySelf && isApproved && isConsumablesOnly,
|
finalResult: shouldShow,
|
||||||
})
|
})
|
||||||
|
|
||||||
return isRecipient && isCreatedBySelf && isApproved && isConsumablesOnly
|
return shouldShow
|
||||||
})
|
})
|
||||||
|
|
||||||
// Генерируем порядковые номера для заказов
|
// Генерируем порядковые номера для заказов
|
||||||
@ -422,7 +493,7 @@ export function FulfillmentConsumablesOrdersTab() {
|
|||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs">Одобрено</p>
|
<p className="text-white/60 text-xs">Одобрено</p>
|
||||||
<p className="text-sm font-bold text-white">
|
<p className="text-sm font-bold text-white">
|
||||||
{fulfillmentOrders.filter((order) => order.status === 'SUPPLIER_APPROVED').length}
|
{(fulfillmentOrders || []).filter((order) => order.status === 'SUPPLIER_APPROVED').length}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -436,7 +507,7 @@ export function FulfillmentConsumablesOrdersTab() {
|
|||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs">Подтверждено</p>
|
<p className="text-white/60 text-xs">Подтверждено</p>
|
||||||
<p className="text-sm font-bold text-white">
|
<p className="text-sm font-bold text-white">
|
||||||
{fulfillmentOrders.filter((order) => order.status === 'CONFIRMED').length}
|
{(fulfillmentOrders || []).filter((order) => order.status === 'CONFIRMED').length}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -450,7 +521,7 @@ export function FulfillmentConsumablesOrdersTab() {
|
|||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs">В пути</p>
|
<p className="text-white/60 text-xs">В пути</p>
|
||||||
<p className="text-sm font-bold text-white">
|
<p className="text-sm font-bold text-white">
|
||||||
{fulfillmentOrders.filter((order) => order.status === 'IN_TRANSIT').length}
|
{(fulfillmentOrders || []).filter((order) => order.status === 'IN_TRANSIT').length}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -464,7 +535,7 @@ export function FulfillmentConsumablesOrdersTab() {
|
|||||||
<div>
|
<div>
|
||||||
<p className="text-white/60 text-xs">Доставлено</p>
|
<p className="text-white/60 text-xs">Доставлено</p>
|
||||||
<p className="text-sm font-bold text-white">
|
<p className="text-sm font-bold text-white">
|
||||||
{fulfillmentOrders.filter((order) => order.status === 'DELIVERED').length}
|
{(fulfillmentOrders || []).filter((order) => order.status === 'DELIVERED').length}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -505,28 +576,30 @@ export function FulfillmentConsumablesOrdersTab() {
|
|||||||
<span className="text-white font-semibold text-sm">{order.number}</span>
|
<span className="text-white font-semibold text-sm">{order.number}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Селлер */}
|
{/* Заказчик (селлер или фулфилмент) */}
|
||||||
<div className="flex items-center space-x-2 min-w-0">
|
<div className="flex items-center space-x-2 min-w-0">
|
||||||
<div className="flex flex-col items-center">
|
<div className="flex flex-col items-center">
|
||||||
<Store className="h-3 w-3 text-blue-400 mb-0.5" />
|
<Store className="h-3 w-3 text-blue-400 mb-0.5" />
|
||||||
<span className="text-blue-400 text-xs font-medium leading-none">Селлер</span>
|
<span className="text-blue-400 text-xs font-medium leading-none">
|
||||||
|
{order.consumableType === 'SELLER_CONSUMABLES' ? 'Селлер' : 'Заказчик'}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-1.5">
|
<div className="flex items-center space-x-1.5">
|
||||||
<Avatar className="w-7 h-7 flex-shrink-0">
|
<Avatar className="w-7 h-7 flex-shrink-0">
|
||||||
<AvatarFallback className="bg-blue-500 text-white text-xs">
|
<AvatarFallback className="bg-blue-500 text-white text-xs">
|
||||||
{getInitials(order.partner.name || order.partner.fullName)}
|
{getInitials(order.organization?.name || order.organization?.fullName || 'Н/Д')}
|
||||||
</AvatarFallback>
|
</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<h3 className="text-white font-medium text-sm truncate max-w-[120px]">
|
<h3 className="text-white font-medium text-sm truncate max-w-[120px]">
|
||||||
{order.partner.name || order.partner.fullName}
|
{order.organization?.name || order.organization?.fullName || 'Не указано'}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-white/60 text-xs">{order.partner.inn}</p>
|
<p className="text-white/60 text-xs">{order.organization?.type || 'Н/Д'}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Поставщик (фулфилмент-центр) */}
|
{/* Поставщик */}
|
||||||
<div className="hidden xl:flex items-center space-x-2 min-w-0">
|
<div className="hidden xl:flex items-center space-x-2 min-w-0">
|
||||||
<div className="flex flex-col items-center">
|
<div className="flex flex-col items-center">
|
||||||
<Building className="h-3 w-3 text-green-400 mb-0.5" />
|
<Building className="h-3 w-3 text-green-400 mb-0.5" />
|
||||||
@ -535,14 +608,14 @@ export function FulfillmentConsumablesOrdersTab() {
|
|||||||
<div className="flex items-center space-x-1.5">
|
<div className="flex items-center space-x-1.5">
|
||||||
<Avatar className="w-7 h-7 flex-shrink-0">
|
<Avatar className="w-7 h-7 flex-shrink-0">
|
||||||
<AvatarFallback className="bg-green-500 text-white text-xs">
|
<AvatarFallback className="bg-green-500 text-white text-xs">
|
||||||
{getInitials(user?.organization?.name || 'ФФ')}
|
{getInitials(order.partner.name || order.partner.fullName)}
|
||||||
</AvatarFallback>
|
</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<h3 className="text-white font-medium text-sm truncate max-w-[100px]">
|
<h3 className="text-white font-medium text-sm truncate max-w-[100px]">
|
||||||
{user?.organization?.name || 'ФФ-центр'}
|
{order.partner.name || order.partner.fullName}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-white/60 text-xs">Наш ФФ</p>
|
<p className="text-white/60 text-xs">{order.partner.inn}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -596,12 +669,12 @@ export function FulfillmentConsumablesOrdersTab() {
|
|||||||
<div className="flex items-center space-x-1.5">
|
<div className="flex items-center space-x-1.5">
|
||||||
<Avatar className="w-6 h-6 flex-shrink-0">
|
<Avatar className="w-6 h-6 flex-shrink-0">
|
||||||
<AvatarFallback className="bg-green-500 text-white text-xs">
|
<AvatarFallback className="bg-green-500 text-white text-xs">
|
||||||
{getInitials(user?.organization?.name || 'ФФ')}
|
{getInitials(order.partner.name || order.partner.fullName)}
|
||||||
</AvatarFallback>
|
</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<h3 className="text-white font-medium text-sm truncate">
|
<h3 className="text-white font-medium text-sm truncate">
|
||||||
{user?.organization?.name || 'Фулфилмент-центр'}
|
{order.partner.name || order.partner.fullName}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -719,13 +792,41 @@ export function FulfillmentConsumablesOrdersTab() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Информация о заказчике */}
|
||||||
|
<div className="mb-3">
|
||||||
|
<h4 className="text-white font-semibold mb-1.5 flex items-center text-sm">
|
||||||
|
<Store className="h-4 w-4 mr-1.5 text-blue-400" />
|
||||||
|
Информация о {order.consumableType === 'SELLER_CONSUMABLES' ? 'селлере' : 'заказчике'}
|
||||||
|
</h4>
|
||||||
|
<div className="bg-white/5 rounded p-2 space-y-1.5">
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Building className="h-3 w-3 text-white/60 flex-shrink-0" />
|
||||||
|
<span className="text-white/80 text-sm font-medium">
|
||||||
|
{order.organization?.name || order.organization?.fullName || 'Не указано'}
|
||||||
|
</span>
|
||||||
|
<span className="text-white/60 text-xs">
|
||||||
|
({order.organization?.type || 'Н/Д'})
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Информация о поставщике */}
|
{/* Информация о поставщике */}
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<h4 className="text-white font-semibold mb-1.5 flex items-center text-sm">
|
<h4 className="text-white font-semibold mb-1.5 flex items-center text-sm">
|
||||||
<Building className="h-4 w-4 mr-1.5 text-blue-400" />
|
<Building className="h-4 w-4 mr-1.5 text-green-400" />
|
||||||
Информация о селлере
|
Информация о поставщике
|
||||||
</h4>
|
</h4>
|
||||||
<div className="bg-white/5 rounded p-2 space-y-1.5">
|
<div className="bg-white/5 rounded p-2 space-y-1.5">
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Building className="h-3 w-3 text-white/60 flex-shrink-0" />
|
||||||
|
<span className="text-white/80 text-sm font-medium">
|
||||||
|
{order.partner.name || order.partner.fullName}
|
||||||
|
</span>
|
||||||
|
<span className="text-white/60 text-xs">
|
||||||
|
ИНН: {order.partner.inn}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
{order.partner.address && (
|
{order.partner.address && (
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<MapPin className="h-3 w-3 text-white/60 flex-shrink-0" />
|
<MapPin className="h-3 w-3 text-white/60 flex-shrink-0" />
|
||||||
@ -751,23 +852,23 @@ export function FulfillmentConsumablesOrdersTab() {
|
|||||||
<div>
|
<div>
|
||||||
<h4 className="text-white font-semibold mb-1.5 flex items-center text-sm">
|
<h4 className="text-white font-semibold mb-1.5 flex items-center text-sm">
|
||||||
<Package className="h-4 w-4 mr-1.5 text-green-400" />
|
<Package className="h-4 w-4 mr-1.5 text-green-400" />
|
||||||
Товары ({order.items.length})
|
Товары ({order.items?.length || 0})
|
||||||
</h4>
|
</h4>
|
||||||
<div className="space-y-1.5">
|
<div className="space-y-1.5">
|
||||||
{order.items.map((item) => (
|
{order.items?.map((item) => (
|
||||||
<div key={item.id} className="bg-white/5 rounded p-2 flex items-center justify-between">
|
<div key={item.id} className="bg-white/5 rounded p-2 flex items-center justify-between">
|
||||||
<div className="flex items-center space-x-2 flex-1 min-w-0">
|
<div className="flex items-center space-x-2 flex-1 min-w-0">
|
||||||
{item.product.mainImage && (
|
{item.product?.mainImage && (
|
||||||
<img
|
<img
|
||||||
src={item.product.mainImage}
|
src={item.product.mainImage}
|
||||||
alt={item.product.name}
|
alt={item.product?.name || 'Товар'}
|
||||||
className="w-8 h-8 rounded object-cover flex-shrink-0"
|
className="w-8 h-8 rounded object-cover flex-shrink-0"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<h5 className="text-white font-medium text-sm truncate">{item.product.name}</h5>
|
<h5 className="text-white font-medium text-sm truncate">{item.product?.name || 'Без названия'}</h5>
|
||||||
<p className="text-white/60 text-xs">{item.product.article}</p>
|
<p className="text-white/60 text-xs">{item.product?.article || 'Без артикула'}</p>
|
||||||
{item.product.category && (
|
{item.product?.category?.name && (
|
||||||
<Badge
|
<Badge
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
className="bg-blue-500/20 text-blue-300 text-xs mt-0.5 px-1.5 py-0.5"
|
className="bg-blue-500/20 text-blue-300 text-xs mt-0.5 px-1.5 py-0.5"
|
||||||
|
@ -1155,6 +1155,10 @@ export const GET_SUPPLY_ORDERS = gql`
|
|||||||
name
|
name
|
||||||
article
|
article
|
||||||
description
|
description
|
||||||
|
price
|
||||||
|
quantity
|
||||||
|
images
|
||||||
|
mainImage
|
||||||
category {
|
category {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
|
@ -3,12 +3,13 @@ import { JSONScalar, DateTimeScalar } from '../scalars'
|
|||||||
|
|
||||||
import { authResolvers } from './auth'
|
import { authResolvers } from './auth'
|
||||||
import { employeeResolvers } from './employees'
|
import { employeeResolvers } from './employees'
|
||||||
|
import { fulfillmentConsumableV2Queries, fulfillmentConsumableV2Mutations } from './fulfillment-consumables-v2'
|
||||||
import { logisticsResolvers } from './logistics'
|
import { logisticsResolvers } from './logistics'
|
||||||
import { referralResolvers } from './referrals'
|
import { referralResolvers } from './referrals'
|
||||||
import { integrateSecurityWithExistingResolvers } from './secure-integration'
|
import { integrateSecurityWithExistingResolvers } from './secure-integration'
|
||||||
import { secureSuppliesResolvers } from './secure-supplies'
|
import { secureSuppliesResolvers } from './secure-supplies'
|
||||||
|
import { sellerConsumableQueries, sellerConsumableMutations } from './seller-consumables'
|
||||||
import { suppliesResolvers } from './supplies'
|
import { suppliesResolvers } from './supplies'
|
||||||
import { fulfillmentConsumableV2Queries, fulfillmentConsumableV2Mutations } from './fulfillment-consumables-v2'
|
|
||||||
|
|
||||||
// Типы для резолверов
|
// Типы для резолверов
|
||||||
interface ResolverObject {
|
interface ResolverObject {
|
||||||
@ -111,6 +112,12 @@ const mergedResolvers = mergeResolvers(
|
|||||||
Query: fulfillmentConsumableV2Queries,
|
Query: fulfillmentConsumableV2Queries,
|
||||||
Mutation: fulfillmentConsumableV2Mutations,
|
Mutation: fulfillmentConsumableV2Mutations,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// НОВЫЕ резолверы для системы поставок селлера
|
||||||
|
{
|
||||||
|
Query: sellerConsumableQueries,
|
||||||
|
Mutation: sellerConsumableMutations,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
// Применяем middleware безопасности ко всем резолверам
|
// Применяем middleware безопасности ко всем резолверам
|
||||||
|
Reference in New Issue
Block a user