# СИСТЕМА УПРАВЛЕНИЯ СКЛАДАМИ SFERA

## 🎯 ОБЗОР СИСТЕМЫ

Система управления складами SFERA обеспечивает полный цикл складских операций для различных типов хранилищ: Wildberries склады, общие склады организаций и фулфилмент-центры. Включает интеграцию с внешними API, управление товарами и расходниками, статистику и аналитику.

## 🏗️ АРХИТЕКТУРА СКЛАДСКОЙ СИСТЕМЫ

### Основные компоненты:

- **WBWarehouseDashboard** - интеграция со складами Wildberries
- **WarehouseDashboard** - общее управление складом организации
- **FulfillmentWarehouse** - специализированные складские операции фулфилмента
- **Интеграция с маркетплейсами** - синхронизация данных
- **Система кэширования** - оптимизация работы с внешними API

## 📦 1. WILDBERRIES СКЛАД (WBWarehouseDashboard)

### 1.1 Архитектура компонента

**Основано на коде:** `src/components/wb-warehouse/wb-warehouse-dashboard.tsx`

```typescript
export function WBWarehouseDashboard() {
  // Состояние данных WB Warehouse
  const [stocks, setStocks] = useState<WBStock[]>([])
  const [warehouses, setWarehouses] = useState<WBWarehouse[]>([])
  const [loading, setLoading] = useState(false)
  const [initialized, setInitialized] = useState(false)

  // Статистика
  const [totalProducts, setTotalProducts] = useState(0)
  const [totalStocks, setTotalStocks] = useState(0)
  const [totalReserved, setTotalReserved] = useState(0)
  const [totalFromClient, setTotalFromClient] = useState(0)
  const [activeWarehouses, setActiveWarehouses] = useState(0)

  // Analytics data
  const [analyticsData, setAnalyticsData] = useState<any[]>([])
}
```

### 1.2 Структура данных WB склада

#### 1.2.1 Товарная позиция (WBStock)

```typescript
interface WBStock {
  nmId: number // Номенклатурный номер WB
  vendorCode: string // Артикул поставщика
  title: string // Название товара
  brand: string // Бренд
  price: number // Цена
  stocks: Array<{
    // Остатки по складам
    warehouseId: number
    warehouseName: string
    quantity: number // Доступно для продажи
    quantityFull: number // Полное количество
    inWayToClient: number // В пути к клиенту
    inWayFromClient: number // Возвраты от клиентов
  }>
  totalQuantity: number // Общее количество
  totalReserved: number // Зарезервировано
  photos: any[] // Фотографии товара
  mediaFiles: any[] // Медиафайлы
  characteristics: any[] // Характеристики
  subjectName: string // Категория товара
  description: string // Описание
}
```

#### 1.2.2 Склад Wildberries (WBWarehouse)

```typescript
interface WBWarehouse {
  id: number // ID склада
  name: string // Название склада
  cargoType: number // Тип груза
  deliveryType: number // Тип доставки
}
```

### 1.3 Система аутентификации WB API

**Проверка API ключей:**

```typescript
// Проверка настройки API ключа
const hasWBApiKey = user?.organization?.apiKeys?.find((key) => key.marketplace === 'WILDBERRIES')?.isActive

// Извлечение токена доступа
const wbApiKey = user?.organization?.apiKeys?.find((key) => key.marketplace === 'WILDBERRIES')

const validationData = wbApiKey.validationData as Record<string, string>
const apiToken =
  validationData?.token || validationData?.apiKey || validationData?.key || (wbApiKey as { apiKey?: string }).apiKey
```

### 1.4 Алгоритм загрузки данных из WB API

**5-этапный процесс:**

#### Этап 1: Получение карточек товаров

```typescript
// 1. Получаем карточки товаров
const cards = await WildberriesService.getAllCards(apiToken).catch(() => [])
console.warn('WB Warehouse: Loaded cards:', cards.length)

const nmIds = cards.map((card) => card.nmID).filter((id) => id > 0)
console.warn('WB Warehouse: NM IDs to process:', nmIds.length)
```

#### Этап 2: Получение аналитики по товарам

```typescript
// 2. Получаем аналитику для каждого товара индивидуально
const analyticsResults = []
for (const nmId of nmIds) {
  try {
    const result = await wbService.getStocksReportByOffices({
      nmIds: [nmId],
      stockType: '',
    })
    analyticsResults.push({ nmId, data: result })
    await new Promise((resolve) => setTimeout(resolve, 1000)) // Rate limiting
  } catch (error) {
    console.error(`WB Warehouse: Error fetching analytics for nmId ${nmId}:`, error)
  }
}
```

#### Этап 3: Комбинирование данных

```typescript
// 3. Комбинируем данные
const combinedStocks = combineCardsWithIndividualAnalytics(cards, analyticsResults)

// Функция комбинирования
const combineCardsWithIndividualAnalytics = (cards: any[], analyticsResults: any[]): WBStock[] => {
  const stocksMap = new Map<number, WBStock>()

  // Создаем карту аналитических данных
  const analyticsMap = new Map()
  analyticsResults.forEach((result) => {
    analyticsMap.set(result.nmId, result.data)
  })

  cards.forEach((card) => {
    const stock: WBStock = {
      nmId: card.nmID,
      vendorCode: String(card.vendorCode || card.supplierVendorCode || ''),
      title: String(card.title || card.object || `Товар ${card.nmID}`),
      brand: String(card.brand || ''),
      // ... остальные поля
    }

    // Получаем аналитические данные для данного nmId
    const analytics = analyticsMap.get(card.nmID)
    if (analytics && analytics.data && analytics.data.regions) {
      analytics.data.regions.forEach((region: any) => {
        if (region.offices && Array.isArray(region.offices)) {
          region.offices.forEach((office: any) => {
            stock.stocks.push({
              warehouseId: office.officeID || 0,
              warehouseName: String(office.officeName || 'Неизвестный склад'),
              quantity: Number(office.metrics?.stockCount) || 0,
              quantityFull: Number(office.metrics?.stockCount) || 0,
              inWayToClient: Number(office.metrics?.toClientCount) || 0,
              inWayFromClient: Number(office.metrics?.fromClientCount) || 0,
            })
          })
        }
      })
    }

    // Подсчитываем общие показатели
    stock.totalQuantity = stock.stocks.reduce((sum, s) => sum + s.quantity, 0)
    stock.totalReserved = stock.stocks.reduce((sum, s) => sum + s.inWayToClient, 0)

    stocksMap.set(card.nmID, stock)
  })

  return Array.from(stocksMap.values())
}
```

#### Этап 4: Извлечение складов

```typescript
// 4. Извлекаем склады и обновляем статистику
const extractWarehousesFromStocks = (stocksData: WBStock[]): WBWarehouse[] => {
  const warehousesMap = new Map<number, WBWarehouse>()

  stocksData.forEach((item) => {
    item.stocks.forEach((stock) => {
      if (!warehousesMap.has(stock.warehouseId)) {
        warehousesMap.set(stock.warehouseId, {
          id: stock.warehouseId,
          name: stock.warehouseName,
          cargoType: 0,
          deliveryType: 0,
        })
      }
    })
  })

  return Array.from(warehousesMap.values())
}
```

#### Этап 5: Кэширование результата

```typescript
// 5. Сохраняем в кеш
await saveCache({
  variables: {
    input: {
      data: JSON.stringify({
        stocks: combinedStocks,
        warehouses: extractedWarehouses,
        analyticsData: analyticsData,
      }),
      totalProducts: stats.totalProducts,
      totalStocks: stats.totalStocks,
      totalReserved: stats.totalReserved,
    },
  },
})
```

### 1.5 Система кэширования WB данных

**Двухуровневая система:**

#### GraphQL Cache

```typescript
const {
  data: _cacheData,
  loading: cacheLoading,
  refetch: refetchCache,
} = useQuery(GET_WB_WAREHOUSE_DATA, {
  skip: !hasWBApiKey,
  fetchPolicy: 'cache-and-network',
})

const [saveCache] = useMutation(SAVE_WB_WAREHOUSE_CACHE)
```

#### Логика работы с кэшем

```typescript
const loadWarehouseData = async () => {
  // Сначала проверяем кэш
  try {
    const result = await refetchCache()
    const cacheResponse = result.data?.getWBWarehouseData

    if (cacheResponse?.success && cacheResponse?.fromCache && cacheResponse?.cache) {
      // Данные найдены в кэше
      loadWarehouseDataFromCache(cacheResponse.cache)
    } else {
      // Кеша нет или он устарел, загружаем из API
      await loadWarehouseDataFromAPI()
    }
  } catch (error) {
    console.error('WB Warehouse: Error checking cache:', error)
    await loadWarehouseDataFromAPI()
  }
}
```

### 1.6 Статистика WB склада

**Автоматически рассчитываемые метрики:**

```typescript
const updateStatistics = (stocksData: WBStock[], _warehousesData: WBWarehouse[]) => {
  // Общее количество товаров
  setTotalProducts(stocksData.length)

  // Общий остаток
  const totalStocksCount = stocksData.reduce((sum, item) => sum + item.totalQuantity, 0)
  setTotalStocks(totalStocksCount)

  // Зарезервировано
  const totalReservedCount = stocksData.reduce((sum, item) => sum + item.totalReserved, 0)
  setTotalReserved(totalReservedCount)

  // Возвраты от клиентов
  const totalFromClientCount = stocksData.reduce(
    (sum, item) => sum + item.stocks.reduce((stockSum, stock) => stockSum + stock.inWayFromClient, 0),
    0,
  )
  setTotalFromClient(totalFromClientCount)

  // Активные склады
  const warehousesWithStock = new Set(stocksData.flatMap((item) => item.stocks.map((s) => s.warehouseId)))
  setActiveWarehouses(warehousesWithStock.size)
}
```

### 1.7 Структура WB дашборда

**3 основные вкладки:**

```typescript
<Tabs value={activeTab} onValueChange={setActiveTab}>
  <TabsList className="grid grid-cols-3 w-full max-w-md mb-6">
    <TabsTrigger value="fulfillment">Склад фулфилмент</TabsTrigger>
    <TabsTrigger value="wildberries">Склад Wildberries</TabsTrigger>
    <TabsTrigger value="my-warehouse">Мой склад</TabsTrigger>
  </TabsList>

  <TabsContent value="fulfillment">
    <FulfillmentWarehouseTab />
  </TabsContent>

  <TabsContent value="wildberries">
    <WildberriesWarehouseTab
      stocks={stocks}
      warehouses={warehouses}
      loading={loading}
      // ... остальные props
    />
  </TabsContent>

  <TabsContent value="my-warehouse">
    <MyWarehouseTab />
  </TabsContent>
</Tabs>
```

## 🏪 2. ОБЩИЙ СКЛАД ОРГАНИЗАЦИИ (WarehouseDashboard)

### 2.1 Архитектура компонента

**Основано на коде:** `src/components/warehouse/warehouse-dashboard.tsx`

```typescript
export function WarehouseDashboard() {
  const [isDialogOpen, setIsDialogOpen] = useState(false)
  const [editingProduct, setEditingProduct] = useState<Product | null>(null)
  const [searchQuery, setSearchQuery] = useState('')
  const [viewMode, setViewMode] = useState<'cards' | 'table'>('cards')

  const { data, loading, error, refetch } = useQuery(GET_MY_PRODUCTS, {
    errorPolicy: 'all',
  })
}
```

### 2.2 Структура товарной позиции

**Интерфейс Product:**

```typescript
interface Product {
  id: string
  name: string // Название товара
  article: string // Артикул
  description: string // Описание
  price: number // Цена
  pricePerSet?: number // Цена за комплект
  quantity: number // Количество
  setQuantity?: number // Количество в комплекте
  ordered?: number // Заказано
  inTransit?: number // В пути
  stock?: number // На складе
  sold?: number // Продано
  type: 'PRODUCT' | 'CONSUMABLE' // Тип: товар или расходник
  category: { id: string; name: string } | null
  brand: string // Бренд
  color: string // Цвет
  size: string // Размер
  weight: number // Вес
  dimensions: string // Размеры
  material: string // Материал
  images: string[] // Изображения
  mainImage: string // Главное изображение
  isActive: boolean // Активность
  createdAt: string // Дата создания
  updatedAt: string // Дата обновления
  organization: { id: string; market?: string }
}
```

### 2.3 Система типов товаров

**2 основных типа:**

| Тип          | Значение  | Описание                   | Цвет бейджа                                    |
| ------------ | --------- | -------------------------- | ---------------------------------------------- |
| `PRODUCT`    | Товар     | Основной товар для продажи | Синий (`bg-blue-500/20 text-blue-300`)         |
| `CONSUMABLE` | Расходник | Вспомогательные материалы  | Оранжевый (`bg-orange-500/20 text-orange-300`) |

### 2.4 Интеграция с рынками

**Поддерживаемые рынки из кода:**

```typescript
const getMarketBadge = (market?: string) => {
  if (!market) return null

  const marketStyles = {
    sadovod: 'bg-green-500/20 text-green-300 border-green-500/30',
    'tyak-moscow': 'bg-blue-500/20 text-blue-300 border-blue-500/30',
  }

  const marketLabels = {
    sadovod: 'Садовод',
    'tyak-moscow': 'ТЯК Москва',
  }

  const style = marketStyles[market as keyof typeof marketStyles] ||
                'bg-gray-500/20 text-gray-300 border-gray-500/30'
  const label = marketLabels[market as keyof typeof marketLabels] || market

  return (
    <span className={`inline-flex items-center px-2 py-1 rounded text-xs font-medium border ${style}`}>
      {label}
    </span>
  )
}
```

**Цветовая кодировка рынков:**

- **Садовод** (`sadovod`): Зеленый
- **ТЯК Москва** (`tyak-moscow`): Синий
- **Неизвестный рынок**: Серый

### 2.5 Система остатков товаров

**Цветовая индикация количества:**

```typescript
<span className={`${
  (product.stock || product.quantity) === 0
    ? 'text-red-400'      // Нет в наличии
    : (product.stock || product.quantity) < 10
      ? 'text-yellow-400' // Мало (< 10 шт.)
      : 'text-green-400'  // Достаточно (≥ 10 шт.)
}`}>
  {product.stock || product.quantity || 0}
</span>
```

### 2.6 Режимы отображения товаров

**2 режима просмотра:**

#### Режим карточек (`cards`)

```typescript
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4">
  {filteredProducts.map((product) => (
    <ProductCard
      key={product.id}
      product={product}
      onEdit={handleEditProduct}
      onDelete={handleProductDeleted}
    />
  ))}
</div>
```

#### Режим таблицы (`table`)

```typescript
// 12-колоночная сетка
<div className="grid grid-cols-12 gap-4 p-4 text-white/60 text-sm font-medium border-b border-white/10">
  <div className="col-span-1">Фото</div>
  <div className="col-span-2">Название</div>
  <div className="col-span-1">Артикул</div>
  <div className="col-span-1">Тип</div>
  <div className="col-span-1">Рынок</div>
  <div className="col-span-1">Цена</div>
  <div className="col-span-1">Остаток</div>
  <div className="col-span-1">Заказано</div>
  <div className="col-span-1">В пути</div>
  <div className="col-span-1">Продано</div>
  <div className="col-span-1">Действия</div>
</div>
```

### 2.7 Функционал поиска и фильтрации

**Мультипоисковая система:**

```typescript
const filteredProducts = products.filter((product) => {
  const matchesSearch =
    !searchQuery ||
    product.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
    product.article.toLowerCase().includes(searchQuery.toLowerCase()) ||
    product.category?.name?.toLowerCase().includes(searchQuery.toLowerCase()) ||
    product.brand?.toLowerCase().includes(searchQuery.toLowerCase())

  return matchesSearch
})
```

**Поисковые поля:**

- Название товара
- Артикул
- Категория
- Бренд

### 2.8 Управление товарами

**CRUD операции:**

```typescript
// Создание товара
const handleCreateProduct = () => {
  setEditingProduct(null)
  setIsDialogOpen(true)
}

// Редактирование товара
const handleEditProduct = (product: Product) => {
  setEditingProduct(product)
  setIsDialogOpen(true)
}

// Сохранение товара
const handleProductSaved = () => {
  setIsDialogOpen(false)
  setEditingProduct(null)
  refetch() // Обновление списка
}

// Удаление товара
const handleProductDeleted = () => {
  refetch() // Обновление списка
}
```

### 2.9 Статистика общего склада

**Компонент WarehouseStatistics:**

```typescript
<Card className="bg-white/5 backdrop-blur border-white/10 p-4 mb-4">
  <WarehouseStatistics products={filteredProducts} />
</Card>
```

**Потенциальные метрики:**

- Общее количество товаров
- Общая стоимость склада
- Количество по типам (товары/расходники)
- Статистика по рынкам
- Товары с критически низкими остатками

## 🏭 3. ФУЛФИЛМЕНТ СКЛАД (FulfillmentWarehouse)

### 3.1 Модульная архитектура

**Основано на файлах:** `src/components/fulfillment-warehouse/`

```
fulfillment-warehouse/
├── fulfillment-warehouse-dashboard.tsx          // Главный компонент
├── fulfillment-warehouse-dashboard/            // Модульная структура
│   ├── blocks/                                 // Блоки функциональности
│   │   ├── StatCard.tsx                       // Карточка статистики
│   │   ├── StoreDataTableBlock.tsx           // Блок таблицы данных
│   │   ├── SummaryRowBlock.tsx               // Блок итогов
│   │   ├── TableHeadersBlock.tsx             // Заголовки таблиц
│   │   └── WarehouseStatsBlock.tsx           // Блок статистики склада
│   ├── components/                           // Переиспользуемые компоненты
│   │   ├── StatCard.tsx                      // Статистическая карточка
│   │   └── TableHeader.tsx                   // Заголовок таблицы
│   ├── hooks/                               // Специализированные хуки
│   ├── types/                               // Типы данных
│   ├── utils/                               // Утилиты
│   └── index.tsx                            // Главный экспорт
├── delivery-details.tsx                      // Детали доставки
├── supplies-stats.tsx                        // Статистика поставок
├── wb-return-claims.tsx                      // Претензии WB
├── supplies-list.tsx                         // Список поставок
├── supplies-grid.tsx                         // Сетка поставок
├── supply-card.tsx                          // Карточка поставки
├── supplies-header.tsx                       // Заголовок поставок
└── fulfillment-supplies-page.tsx             // Страница поставок фулфилмента
```

### 3.2 Специализированные функции

**17 компонентов фулфилмент склада:**

#### 3.2.1 Управление поставками

- **supplies-list.tsx** - список входящих поставок
- **supplies-grid.tsx** - сетчатое отображение поставок
- **supply-card.tsx** - карточка отдельной поставки
- **supplies-header.tsx** - заголовок и фильтры
- **supplies-stats.tsx** - статистика по поставкам

#### 3.2.2 Статистика и аналитика

- **StatCard.tsx** (2 версии) - карточки метрик
- **WarehouseStatsBlock.tsx** - блок статистики склада
- **SummaryRowBlock.tsx** - итоговые строки

#### 3.2.3 Специальные операции

- **wb-return-claims.tsx** - обработка возвратов WB
- **delivery-details.tsx** - детали доставки
- **StoreDataTableBlock.tsx** - управление данными магазинов

#### 3.2.4 UI компоненты

- **TableHeader.tsx** - заголовки таблиц
- **TableHeadersBlock.tsx** - блок заголовков

### 3.3 Интеграция с основным дашбордом

**Связь с WBWarehouseDashboard:**

```typescript
<TabsContent value="fulfillment" className="h-full mt-0 min-h-0">
  <FulfillmentWarehouseTab />
</TabsContent>
```

Фулфилмент склад интегрирован как одна из вкладок WB дашборда, обеспечивая единый интерфейс для всех типов складских операций.

## 🔗 4. ИНТЕГРАЦИЯ С ВНЕШНИМИ СИСТЕМАМИ

### 4.1 Wildberries Service

**Класс для работы с WB API:**

```typescript
import { WildberriesService } from '@/services/wildberries-service'

// Инициализация сервиса
const wbService = new WildberriesService(apiToken)

// Основные методы
- WildberriesService.getAllCards(apiToken)     // Получение карточек товаров
- wbService.getStocksReportByOffices({...})    // Аналитика по складам
```

**Rate Limiting:**

```typescript
// Задержка между запросами для соблюдения лимитов API
await new Promise((resolve) => setTimeout(resolve, 1000))
```

### 4.2 GraphQL интеграция

**Основные запросы и мутации:**

#### Запросы

```typescript
// Товары организации
GET_MY_PRODUCTS

// Данные WB склада
GET_WB_WAREHOUSE_DATA
```

#### Мутации

```typescript
// Сохранение кэша WB склада
SAVE_WB_WAREHOUSE_CACHE

// Операции с товарами (создание, обновление, удаление)
CREATE_PRODUCT
UPDATE_PRODUCT
DELETE_PRODUCT
```

### 4.3 Система событий

**Потенциальные события склада:**

- Изменение остатков товаров
- Поступление новых товаров
- Отгрузка товаров
- Возвраты от клиентов
- Обновление данных от внешних API

## 🎨 5. UI/UX ПАТТЕРНЫ СКЛАДОВ

### 5.1 Адаптивные сетки

**Responsive layouts для разных типов складов:**

```typescript
// Карточки товаров (WB и общий склад)
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5 gap-4">

// Таблица товаров (12-колоночная сетка)
<div className="grid grid-cols-12 gap-4">

// Статистика (4 карточки)
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
```

### 5.2 Состояния загрузки

**Паттерны loading states:**

```typescript
// Загрузка товаров
{loading ? (
  <div className="flex items-center justify-center h-full">
    <div className="text-center">
      <div className="animate-spin rounded-full h-16 w-16 border-4 border-white border-t-transparent mx-auto mb-4"></div>
      <p className="text-white/70">Загрузка товаров...</p>
    </div>
  </div>
) : (
  <ProductsList />
)}

// Инициализация WB склада
{!initialized ? (
  <div className="text-white">Инициализация склада...</div>
) : (
  <WarehouseContent />
)}
```

### 5.3 Пустые состояния

**Empty states для разных сценариев:**

```typescript
// Нет товаров
<div className="flex items-center justify-center h-full">
  <div className="text-center">
    <Package className="h-16 w-16 text-white/40 mx-auto mb-4" />
    <h3 className="text-lg font-medium text-white mb-2">
      {searchQuery ? 'Товары не найдены' : 'Склад пуст'}
    </h3>
    <p className="text-white/60 text-sm mb-4">
      {searchQuery ? 'Попробуйте изменить критерии поиска' : 'Добавьте ваш первый товар на склад'}
    </p>
  </div>
</div>

// Нет API ключа WB
{!hasWBApiKey && (
  <div className="text-center py-8">
    <h3 className="text-lg font-semibold text-white mb-2">API ключ не настроен</h3>
    <p className="text-white/60">Настройте интеграцию с Wildberries для работы со складом</p>
  </div>
)}
```

### 5.4 Модальные окна

**Dialog системы для управления товарами:**

```typescript
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
  <DialogContent className="glass-card !w-[90vw] !max-w-[90vw] max-h-[95vh]">
    <DialogHeader>
      <DialogTitle className="text-white">
        {editingProduct ? 'Редактировать товар/расходник' : 'Добавить товар/расходник'}
      </DialogTitle>
    </DialogHeader>
    <ProductForm
      product={editingProduct}
      onSave={handleProductSaved}
      onCancel={() => setIsDialogOpen(false)}
    />
  </DialogContent>
</Dialog>
```

## ⚡ 6. ПРОИЗВОДИТЕЛЬНОСТЬ И ОПТИМИЗАЦИЯ

### 6.1 Кэширование данных

**Многоуровневое кэширование WB:**

1. **React State** - локальное состояние компонента
2. **Apollo Cache** - GraphQL кэш
3. **Database Cache** - серверное кэширование
4. **Rate Limiting** - ограничение запросов к внешним API

### 6.2 Виртуализация больших списков

**Потенциальные оптимизации:**

- React Virtualized для больших списков товаров
- Pagination для табличного режима
- Lazy loading изображений товаров

### 6.3 Оптимизация запросов

**Стратегии загрузки:**

```typescript
// Параллельная загрузка данных
const [loadCards, loadAnalytics] = await Promise.allSettled([
  WildberriesService.getAllCards(apiToken),
  getAnalyticsData(nmIds),
])

// Batch операции для множественных обновлений
const batchUpdate = products.map((product) => updateProduct(product))
await Promise.all(batchUpdate)
```

## 📊 7. МЕТРИКИ И KPI СКЛАДОВ

### 7.1 Ключевые показатели WB склада

**Автоматически рассчитываемые метрики:**

- Общее количество товаров
- Общий остаток по всем складам
- Количество зарезервированных товаров
- Возвраты от клиентов
- Количество активных складов

### 7.2 Метрики общего склада

**Потенциальные KPI:**

- Оборачиваемость товаров
- Средняя стоимость единицы товара
- Доля товаров vs расходников
- Критически низкие остатки
- Время пополнения склада

### 7.3 Фулфилмент метрики

**Операционные показатели:**

- Скорость обработки поставок
- Эффективность сотрудников
- Качество упаковки
- Время отгрузки
- Уровень ошибок

## 🔒 8. БЕЗОПАСНОСТЬ И КОНТРОЛЬ ДОСТУПА

### 8.1 Проверка API ключей

```typescript
// Валидация ключей WB
if (!wbApiKey?.isActive) {
  toast.error('API ключ Wildberries не настроен')
  return
}

if (!apiToken) {
  toast.error('Токен API не найден')
  return
}
```

### 8.2 Фильтрация данных по организации

```typescript
// Безопасность на уровне запросов
const { data, loading, error } = useQuery(GET_MY_PRODUCTS, {
  variables: { organizationId: user?.organization?.id },
  errorPolicy: 'all',
})
```

### 8.3 Обработка ошибок

```typescript
// Graceful error handling
try {
  const result = await wbService.getStocksReportByOffices(params)
} catch (error) {
  console.error(`Error fetching analytics for nmId ${nmId}:`, error)
  // Продолжаем обработку других товаров
  continue
}
```

## 🔄 9. WORKFLOW СКЛАДСКИХ ОПЕРАЦИЙ

### 9.1 Стандартный процесс WB

```
1. Настройка API ключа WB
   ↓
2. Загрузка карточек товаров
   ↓
3. Получение аналитики по остаткам
   ↓
4. Комбинирование данных
   ↓
5. Кэширование результата
   ↓
6. Отображение в интерфейсе
```

### 9.2 Процесс управления общим складом

```
1. Добавление товара/расходника
   ↓
2. Указание характеристик и рынка
   ↓
3. Загрузка изображений
   ↓
4. Сохранение в базе данных
   ↓
5. Обновление статистики
   ↓
6. Отслеживание остатков
```

### 9.3 Фулфилмент операции

```
1. Получение поставки от поставщика
   ↓
2. Приемка и проверка товаров
   ↓
3. Размещение на складе
   ↓
4. Обработка заказов селлеров
   ↓
5. Упаковка и отгрузка
   ↓
6. Обновление остатков
```

## 📦 10. ДЕТАЛИЗАЦИЯ ВКЛАДОК WB СКЛАДА

### 10.1 Вкладка Wildberries (WildberriesWarehouseTab)

**Основано на коде:** `src/components/wb-warehouse/wildberries-warehouse-tab.tsx`

**Модульные компоненты:**

```typescript
// Импортируемые компоненты для вкладки WB
import { LoadingSkeleton } from './loading-skeleton' // Скелетоны загрузки
import { SearchBar } from './search-bar' // Поиск по товарам
import { StatsCards } from './stats-cards' // Карточки статистики
import { StockTableRow } from './stock-table-row' // Строка таблицы остатков
import { TableHeader } from './table-header' // Заголовок таблицы
```

**Структура WBStock (детализированная):**

```typescript
interface WBStock {
  nmId: number // Номенклатурный номер WB
  vendorCode: string // Артикул поставщика
  title: string // Название товара
  brand: string // Бренд
  price: number // Цена
  stocks: Array<{
    // Остатки по складам WB
    warehouseId: number // ID склада
    warehouseName: string // Название склада
    quantity: number // Доступно для продажи
    quantityFull: number // Полное количество
    inWayToClient: number // В пути к клиенту (зарезервировано)
    inWayFromClient: number // Возвраты от клиентов
  }>
  totalQuantity: number // Общее количество
  totalReserved: number // Общее зарезервировано
  photos: any[] // Фотографии
  mediaFiles: any[] // Медиафайлы
  characteristics: any[] // Характеристики
  subjectName: string // Категория
  description: string // Описание
}
```

**Props интерфейс WildberriesWarehouseTab:**

```typescript
interface WildberriesWarehouseTabProps {
  stocks: WBStock[] // Массив товаров WB
  warehouses: WBWarehouse[] // Склады WB
  loading: boolean // Состояние загрузки
  initialized: boolean // Флаг инициализации
  cacheLoading: boolean // Загрузка из кэша
  totalProducts: number // Общее количество товаров
  totalStocks: number // Общие остатки
  totalReserved: number // Зарезервировано
  totalFromClient: number // Возвраты от клиентов
  activeWarehouses: number // Активные склады
  analyticsData: any[] // Аналитические данные
  onRefresh: () => Promise<void> // Функция обновления
}
```

**Система поиска и фильтрации:**

```typescript
const filteredStocks = stocks.filter((item) => {
  if (!searchTerm) return true
  const search = searchTerm.toLowerCase()
  return (
    item.title.toLowerCase().includes(search) ||
    String(item.nmId).includes(search) ||
    item.brand.toLowerCase().includes(search) ||
    item.vendorCode.toLowerCase().includes(search)
  )
})
```

**Функциональные возможности:**

- Поиск товаров по номенклатуре или названию
- Статистические карточки с общими показателями
- Табличное отображение остатков по всем складам WB
- Аналитика по складам WB (до 6 блоков)
- Скелетоны загрузки для улучшения UX
- Функция обновления данных с обработкой ошибок

### 10.2 Вкладка Мой склад (MyWarehouseTab)

**Основано на коде:** `src/components/wb-warehouse/my-warehouse-tab.tsx`

**Структура товара собственного склада:**

```typescript
interface MyWarehouseItem {
  id: string // Уникальный ID
  sku: string // SKU товара
  name: string // Название
  category: string // Категория
  quantity: number // Количество
  price: number // Цена
  location: string // Местоположение на складе
  status: 'in_stock' | 'low_stock' | 'out_of_stock' // Статус остатков
  lastUpdated: string // Последнее обновление
}
```

**Статусы остатков:**

- **`in_stock`** - достаточно товара
- **`low_stock`** - мало товара (критические остатки)
- **`out_of_stock`** - товара нет

**Функции управления статусами:**

```typescript
const getStatusColor = (status: string) => {
  switch (status) {
    case 'in_stock':
      return 'text-green-400'
    case 'low_stock':
      return 'text-yellow-400'
    case 'out_of_stock':
      return 'text-red-400'
    default:
      return 'text-white/60'
  }
}

const getStatusText = (status: string) => {
  switch (status) {
    case 'in_stock':
      return 'В наличии'
    case 'low_stock':
      return 'Мало'
    case 'out_of_stock':
      return 'Нет в наличии'
    default:
      return 'Неизвестно'
  }
}
```

**Статистические расчеты:**

```typescript
const totalItems = items.length
const totalQuantity = items.reduce((sum, item) => sum + item.quantity, 0)
const totalValue = items.reduce((sum, item) => sum + item.quantity * item.price, 0)
const lowStockItems = items.filter((item) => item.status === 'low_stock' || item.status === 'out_of_stock').length
```

**Статистические карточки:**

- **"Общее кол-во товаров"** (Package, синий) - totalItems
- **"Общее количество"** (Warehouse, зеленый) - totalQuantity
- **"Общая стоимость"** (₽ символ, фиолетовый) - totalValue в рублях
- **"Требует внимания"** (⚠ символ, желтый) - lowStockItems

**UI компоненты:**

- Поиск по SKU и названию товара
- Кнопка добавления нового товара
- Карточки статистики по статусам остатков
- Таблица с местоположением товаров на складе
- 7-колоночная таблица: SKU, Название, Категория, Количество, Цена, Локация, Статус

### 10.3 Вкладка Фулфилмент (FulfillmentWarehouseTab)

**Основано на коде:** `src/components/wb-warehouse/fulfillment-warehouse-tab.tsx`

**Интеграция с основным модулем FulfillmentWarehouse:**

```typescript
// Использует 17+ компонентов из fulfillment-warehouse/
import { FulfillmentWarehouseDashboard } from '@/components/fulfillment-warehouse'
```

**Связь с фулфилмент операциями:**

- Приемка поставок от поставщиков
- Обработка товаров
- Упаковка и отгрузка на маркетплейсы
- Работа с возвратами
- Управление расходниками

### 10.4 Дополнительные UI компоненты

#### LoadingSkeleton

```typescript
// Анимированные скелетоны для loading состояний
// Улучшают воспринимаемую производительность
```

#### SearchBar

```typescript
// Универсальная строка поиска для всех типов складов
// Поддерживает поиск по различным полям
```

#### StatsCards

```typescript
// Карточки ключевых метрик склада
// Отображают общую статистику и тренды
```

#### StockTableRow

```typescript
// Строка таблицы остатков с подробной информацией
// Поддерживает различные форматы данных
```

#### TableHeader

```typescript
// Заголовок таблицы с сортировкой и фильтрацией
// Адаптивный дизайн для различных разрешений
```

## 🎯 ЗАКЛЮЧЕНИЕ

Система управления складами SFERA представляет собой комплексное решение для различных типов складских операций с глубокой интеграцией с внешними маркетплейсами и современным пользовательским интерфейсом.

Ключевые преимущества:

- **Полная интеграция с Wildberries** - синхронизация остатков и аналитики
- **Универсальное управление товарами** - товары и расходники в едином интерфейсе
- **Модульная архитектура фулфилмента** - 17+ специализированных компонентов
- **Многоуровневое кэширование** - оптимизация работы с внешними API
- **Адаптивный дизайн** - корректная работа на всех устройствах
- **Системы безопасности** - проверка доступа и валидация данных
- **Glass Morphism UI** - современный и привлекательный интерфейс
