diff --git a/prisma/schema.prisma b/prisma/schema.prisma index b449e14..ad3cfdd 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -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") +} diff --git a/src/components/fulfillment-supplies/fulfillment-supplies/fulfillment-consumables-orders-tab.tsx b/src/components/fulfillment-supplies/fulfillment-supplies/fulfillment-consumables-orders-tab.tsx index 9a17407..c4fb2be 100644 --- a/src/components/fulfillment-supplies/fulfillment-supplies/fulfillment-consumables-orders-tab.tsx +++ b/src/components/fulfillment-supplies/fulfillment-supplies/fulfillment-consumables-orders-tab.tsx @@ -35,6 +35,7 @@ import { GET_MY_EMPLOYEES, GET_LOGISTICS_PARTNERS, } from '@/graphql/queries' +import { GET_INCOMING_SELLER_SUPPLIES } from '@/graphql/queries/seller-consumables-v2' import { useAuth } from '@/hooks/useAuth' interface SupplyOrder { @@ -146,21 +147,31 @@ export function FulfillmentConsumablesOrdersTab() { console.error('LOGISTICS ERROR:', logisticsError) } - // Загружаем заказы поставок + // Загружаем заказы поставок из старой системы 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, { onCompleted: (data) => { if (data.fulfillmentReceiveOrder.success) { toast.success(data.fulfillmentReceiveOrder.message) - refetch() // Обновляем список заказов + refetch() // Обновляем старые заказы поставок + refetchSellerSupplies() // Обновляем селлерские поставки } else { toast.error(data.fulfillmentReceiveOrder.message) } }, refetchQueries: [ { query: GET_SUPPLY_ORDERS }, // Обновляем заказы поставок + { query: GET_INCOMING_SELLER_SUPPLIES }, // Обновляем селлерские поставки { query: GET_MY_SUPPLIES }, // Обновляем склад фулфилмента (расходники фулфилмента) { query: GET_WAREHOUSE_PRODUCTS }, // Обновляем товары склада { query: GET_PENDING_SUPPLIES_COUNT }, // Обновляем счетчики уведомлений @@ -176,7 +187,8 @@ export function FulfillmentConsumablesOrdersTab() { onCompleted: (data) => { if (data.assignLogisticsToSupply.success) { toast.success('Логистика и ответственный назначены успешно') - refetch() // Обновляем список заказов + refetch() // Обновляем старые заказы поставок + refetchSellerSupplies() // Обновляем селлерские поставки // Сбрасываем состояние назначения setAssigningOrders((prev) => { const newSet = new Set(prev) @@ -187,7 +199,10 @@ export function FulfillmentConsumablesOrdersTab() { toast.error(data.assignLogisticsToSupply.message || 'Ошибка при назначении логистики') } }, - refetchQueries: [{ query: GET_SUPPLY_ORDERS }], + refetchQueries: [ + { query: GET_SUPPLY_ORDERS }, + { query: GET_INCOMING_SELLER_SUPPLIES }, + ], onError: (error) => { console.error('Error assigning logistics:', error) toast.error('Ошибка при назначении логистики') @@ -204,37 +219,93 @@ export function FulfillmentConsumablesOrdersTab() { setExpandedOrders(newExpanded) } - // Получаем данные заказов поставок + // Получаем данные заказов поставок из старой системы 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 isCreatedBySelf = order.organization?.id === user?.organization?.id - // И получатель тоже мы (фулфилмент заказывает расходники для себя) + // Получатель должен быть наш фулфилмент-центр const isRecipient = order.fulfillmentCenter?.id === user?.organization?.id // И статус не PENDING и не CANCELLED (одобренные поставщиком заявки) const isApproved = order.status !== 'CANCELLED' && order.status !== 'PENDING' - // ✅ КРИТИЧНОЕ ИСПРАВЛЕНИЕ: Показывать только расходники ФУЛФИЛМЕНТА (НЕ селлеров и НЕ товары) + + // ✅ ИСПРАВЛЕНИЕ: Показывать ОБА типа расходников - фулфилмент и селлер 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 isConsumablesOnly = isFulfillmentConsumables && !hasServices + const isConsumablesOnly = isAnyConsumables && !hasServices + + // Дополнительная проверка для селлерских поставок + 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('🔍 Фильтрация расходников фулфилмента:', { + console.warn('🔍 Фильтрация расходников фулфилмента + селлеров:', { orderId: order.id.slice(-8), isRecipient, - isCreatedBySelf, isApproved, isFulfillmentConsumables, + isSellerConsumables, + isAnyConsumables, hasServices, isConsumablesOnly, + isCreatedBySelf, + isFromSeller, consumableType: order.consumableType, + organizationType: order.organization?.type, 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() {

Одобрено

- {fulfillmentOrders.filter((order) => order.status === 'SUPPLIER_APPROVED').length} + {(fulfillmentOrders || []).filter((order) => order.status === 'SUPPLIER_APPROVED').length}

@@ -436,7 +507,7 @@ export function FulfillmentConsumablesOrdersTab() {

Подтверждено

- {fulfillmentOrders.filter((order) => order.status === 'CONFIRMED').length} + {(fulfillmentOrders || []).filter((order) => order.status === 'CONFIRMED').length}

@@ -450,7 +521,7 @@ export function FulfillmentConsumablesOrdersTab() {

В пути

- {fulfillmentOrders.filter((order) => order.status === 'IN_TRANSIT').length} + {(fulfillmentOrders || []).filter((order) => order.status === 'IN_TRANSIT').length}

@@ -464,7 +535,7 @@ export function FulfillmentConsumablesOrdersTab() {

Доставлено

- {fulfillmentOrders.filter((order) => order.status === 'DELIVERED').length} + {(fulfillmentOrders || []).filter((order) => order.status === 'DELIVERED').length}

@@ -505,28 +576,30 @@ export function FulfillmentConsumablesOrdersTab() { {order.number} - {/* Селлер */} + {/* Заказчик (селлер или фулфилмент) */}
- Селлер + + {order.consumableType === 'SELLER_CONSUMABLES' ? 'Селлер' : 'Заказчик'} +
- {getInitials(order.partner.name || order.partner.fullName)} + {getInitials(order.organization?.name || order.organization?.fullName || 'Н/Д')}

- {order.partner.name || order.partner.fullName} + {order.organization?.name || order.organization?.fullName || 'Не указано'}

-

{order.partner.inn}

+

{order.organization?.type || 'Н/Д'}

- {/* Поставщик (фулфилмент-центр) */} + {/* Поставщик */}
@@ -535,14 +608,14 @@ export function FulfillmentConsumablesOrdersTab() {
- {getInitials(user?.organization?.name || 'ФФ')} + {getInitials(order.partner.name || order.partner.fullName)}

- {user?.organization?.name || 'ФФ-центр'} + {order.partner.name || order.partner.fullName}

-

Наш ФФ

+

{order.partner.inn}

@@ -596,12 +669,12 @@ export function FulfillmentConsumablesOrdersTab() {
- {getInitials(user?.organization?.name || 'ФФ')} + {getInitials(order.partner.name || order.partner.fullName)}

- {user?.organization?.name || 'Фулфилмент-центр'} + {order.partner.name || order.partner.fullName}

@@ -719,13 +792,41 @@ export function FulfillmentConsumablesOrdersTab() {
+ {/* Информация о заказчике */} +
+

+ + Информация о {order.consumableType === 'SELLER_CONSUMABLES' ? 'селлере' : 'заказчике'} +

+
+
+ + + {order.organization?.name || order.organization?.fullName || 'Не указано'} + + + ({order.organization?.type || 'Н/Д'}) + +
+
+
+ {/* Информация о поставщике */}

- - Информация о селлере + + Информация о поставщике

+
+ + + {order.partner.name || order.partner.fullName} + + + ИНН: {order.partner.inn} + +
{order.partner.address && (
@@ -751,23 +852,23 @@ export function FulfillmentConsumablesOrdersTab() {

- Товары ({order.items.length}) + Товары ({order.items?.length || 0})

- {order.items.map((item) => ( + {order.items?.map((item) => (
- {item.product.mainImage && ( + {item.product?.mainImage && ( {item.product.name} )}
-
{item.product.name}
-

{item.product.article}

- {item.product.category && ( +
{item.product?.name || 'Без названия'}
+

{item.product?.article || 'Без артикула'}

+ {item.product?.category?.name && (