# ДОМЕН ФУЛФИЛМЕНТ-ЦЕНТРОВ (FULFILLMENT)

## 🎯 РОЛЬ В ЭКОСИСТЕМЕ SFERA

**Фулфилмент-центр** - центральный узел логистической сети, обеспечивающий приемку, обработку, хранение и отправку товаров селлеров на маркетплейсы.

### КЛЮЧЕВЫЕ ФУНКЦИИ:

- ✅ Прием товаров от поставщиков
- ✅ Обработка и упаковка товаров селлеров
- ✅ Управление двумя типами расходников
- ✅ Интеграция с маркетплейсами (отправка)
- ✅ Контроль качества и складские операции

## 🏢 БИЗНЕС-МОДЕЛЬ ФУЛФИЛМЕНТА

### 1. ИСТОЧНИКИ ДОХОДА

```typescript
enum FulfillmentRevenueStreams {
  SERVICES_TO_SELLERS = "Услуги селлерам"        // Основной доход
  CONSUMABLES_TO_SELLERS = "Продажа расходников" // Дополнительный доход
  STORAGE_FEES = "Складские услуги"              // Регулярный доход
  PROCESSING_FEES = "Обработка заказов"          // За единицу
}
```

**Экономическая модель рецептур:**

- Селлер выбирает расходники ФФ → в кабинете селлера: расход
- В кабинете фулфилмента: доход от продажи расходников

### 2. ПАРТНЕРСКИЕ СВЯЗИ

```mermaid
graph TD
    A[FULFILLMENT] --> B[SELLER - Клиенты]
    A --> C[WHOLESALE - Поставщики расходников]
    A --> D[LOGIST - Доставка товаров]

    B --> E[Заказывают услуги]
    B --> F[Размещают товары на хранение]
    C --> G[Поставляют расходники]
    D --> H[Доставляют товары к ФФ]
```

## 📦 УПРАВЛЕНИЕ РАСХОДНИКАМИ (ДВОЙНАЯ СИСТЕМА V2)

> **ВАЖНО:** Система полностью переведена на V2 архитектуру с улучшенной синхронизацией данных

### FULFILLMENT_CONSUMABLES (Собственные расходники) - V2 СИСТЕМА

**Таблица БД:** `fulfillmentConsumableInventory`
**GraphQL Query:** `GET_MY_FULFILLMENT_SUPPLIES`

```typescript
interface FulfillmentConsumables {
  purpose: 'Операционные нужды фулфилмента'
  owner: 'FULFILLMENT'
  usage: 'Внутренние операции (упаковка, маркировка, и т.д.)'
  orderProcess: 'ФФ заказывает у поставщиков'

  // Примеры:
  items: [
    'Коробки для упаковки',
    'Скотч и пленка',
    'Этикетки и стикеры',
    'Пузырчатая пленка',
    'Инструменты и оборудование',
  ]
}
```

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

```graphql
# Получение собственных расходников ФФ
query GetMyFulfillmentSupplies {
  myFulfillmentSupplies {
    id
    name
    article
    price
    currentStock
    type # = FULFILLMENT_CONSUMABLES
  }
}
```

### SELLER_CONSUMABLES (Расходники селлеров на хранении)

```typescript
interface SellerConsumablesOnWarehouse {
  purpose: 'Расходники селлеров для их продуктов'
  owner: 'SELLER'
  storageLocation: 'Склад фулфилмента'
  usage: 'Компоненты рецептур продуктов селлера'

  // ФФ может видеть, но не использовать
  access: 'READ_ONLY для фулфилмента'
}
```

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

```graphql
# Просмотр расходников селлеров на складе (только для ФФ)
query GetSellerSuppliesOnWarehouse {
  sellerSuppliesOnWarehouse {
    id
    name
    sellerOwnerId # ID селлера-владельца
    currentStock
    type # = SELLER_CONSUMABLES
  }
}
```

---

## 🚀 **V2 СИСТЕМА УПРАВЛЕНИЯ ДАННЫМИ**

### **АРХИТЕКТУРА СИНХРОНИЗАЦИИ КОМПОНЕНТОВ**

#### **1. ЕДИНЫЙ ИСТОЧНИК ДАННЫХ**

```typescript
// Все компоненты фулфилмента используют одну таблицу БД
const dataSource = 'fulfillmentConsumableInventory'

// Связанные компоненты:
const components = [
  '/fulfillment-warehouse', // Главный dashboard (карточка "РАСХОДНИКИ ФУЛФИЛМЕНТА")
  '/fulfillment-warehouse/supplies', // Подраздел (карточка "ОСТАТОК" + таблица)
  '/services', // Раздел услуг (вкладка "Расходники")
]
```

#### **2. ОБЯЗАТЕЛЬНЫЕ ПРАВИЛА СИНХРОНИЗАЦИИ**

**GraphQL Queries - одинаковые настройки:**

```typescript
// ✅ ПРАВИЛЬНО - для всех связанных компонентов
useQuery(FULFILLMENT_SUPPLIES_QUERY, {
  fetchPolicy: 'cache-and-network', // Всегда актуальные данные
  pollInterval: 30000, // Обновление каждые 30 сек
  errorPolicy: 'all', // Показывать частичные данные при ошибках
})

// ❌ НЕПРАВИЛЬНО - разные настройки создают рассинхронизацию
useQuery(QUERY_A, { fetchPolicy: 'cache-and-network' }) // компонент A
useQuery(QUERY_B, {}) // компонент B (default cache-first)
```

#### **3. КЛЮЧЕВЫЕ ПОЛЯ ДЛЯ СВЯЗИ ДАННЫХ**

```typescript
interface FulfillmentConsumableV2 {
  id: string // Уникальный ID записи инвентаря
  productId: string // ← ОБЯЗАТЕЛЬНО! Для фильтрации истории поставок
  fulfillmentCenterId: string // Привязка к конкретному ФФ
  currentStock: number // Текущий остаток (основа для всех расчётов)
  totalReceived: number // Общее количество поступлений
  averageCost: Decimal // Средняя стоимость для расчёта общей стоимости
}
```

#### **4. ПРАВИЛА ГРУППИРОВКИ И ФИЛЬТРАЦИИ**

**✅ ПРАВИЛЬНАЯ фильтрация истории поставок:**

```typescript
const getSupplyHistory = (supply: Supply): Supply[] => {
  // Фильтруем по стабильному productId
  return allDeliveries.filter((delivery) => delivery.items?.some((item) => item.productId === supply.productId))
}
```

**❌ НЕПРАВИЛЬНАЯ фильтрация:**

```typescript
// Никогда не используйте нестабильные поля для фильтрации
return supplies.filter(
  (s) => s.name === supply.name && s.category === supply.category, // ← Может дать дубли!
)
```

#### **5. АГРЕГАЦИЯ СТАТИСТИКИ**

**Master-Detail консистентность:**

```typescript
// Главный dashboard - карточка "РАСХОДНИКИ ФУЛФИЛМЕНТА"
const masterValue = warehouseStats.fulfillmentSupplies.current

// Подраздел - карточка "ОСТАТОК"
const detailValue = supplies.reduce((sum, s) => sum + s.currentStock, 0)

// ОБЯЗАТЕЛЬНО: masterValue === detailValue
```

#### **6. КОМПОНЕНТЫ СТАТИСТИКИ**

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

```typescript
// Главный раздел (/fulfillment-warehouse)
interface WarehouseStatsCards {
  'РАСХОДНИКИ ФУЛФИЛМЕНТА': number // Общий остаток всех расходников ФФ
  // ... другие карточки
}

// Подраздел (/fulfillment-warehouse/supplies)
interface SuppliesStatsCards {
  'ВСЕГО ПОЗИЦИЙ': number // Количество уникальных товаров
  ДОСТУПНО: number // Товары в наличии (currentStock > 0)
  ОСТАТОК: number // ← Сумма всех currentStock (= карточке выше)
  'НЕТ В НАЛИЧИИ': number // Товары с нулевыми остатками
  'ОБЩАЯ СТОИМОСТЬ': string // Стоимость всех товаров на складе
  'В ПУТИ': number // Товары со статусом в транспортировке
}
```

---

## 🔄 WORKFLOW ПОСТАВОК ДЛЯ ФУЛФИЛМЕНТА

### РОЛЬ В 8-СТАТУСНОЙ СИСТЕМЕ:

#### 1. КАК ЗАКАЗЧИК (заказывает расходники):

```typescript
// ФФ создает заказы собственных расходников
const fulfillmentOrdersFlow = {
  status: 'PENDING',
  role: 'Инициатор заказа',
  partnerId: 'WHOLESALE_ORGANIZATION_ID', // Поставщик
  consumableType: 'FULFILLMENT_CONSUMABLES',

  // ФФ может отменить свой заказ
  actions: ['CANCEL_ORDER'],
}
```

#### 2. КАК ПОЛУЧАТЕЛЬ (принимает товары селлеров):

```typescript
// ФФ принимает товары от поставщиков для селлеров
const fulfillmentReceiveFlow = {
  status: 'SHIPPED → DELIVERED',
  role: 'Получатель товаров',
  action: 'fulfillmentReceiveOrder', // Подтверждение приемки

  responsibility: ['Проверка качества и количества', 'Размещение на складе', 'Обновление остатков'],
}
```

**Resolver приемки:**

```typescript
// Из кода resolvers.ts
const fulfillmentReceiveOrder = async (id: string) => {
  // Обновление статуса SHIPPED → DELIVERED
  await prisma.supplyOrder.update({
    where: { id },
    data: { status: 'DELIVERED' },
  })
}
```

### СЧЕТЧИКИ АКТИВНЫХ ПОСТАВОК:

```typescript
// Из кода: pendingSuppliesCount для фулфилмента
const fulfillmentCounters = {
  ourSupplyOrders: 'Собственные заказы расходников', // ФФ → поставщик
  sellerSupplyOrders: 'Заказы товаров от селлеров', // селлер → ФФ

  // Логика подсчета:
  ourSupplyOrders: 'organizationId = currentUser.organization.id',
  sellerSupplyOrders: 'fulfillmentCenterId = currentUser.organization.id',
}
```

## 🏭 СКЛАДСКИЕ ОПЕРАЦИИ

### 1. ПРИЕМКА ТОВАРОВ

```typescript
interface ReceivingProcess {
  trigger: 'SupplyOrder status: SHIPPED → DELIVERED'
  responsibilities: [
    'Проверка соответствия заказу',
    'Контроль качества товаров',
    'Обновление складских остатков',
    'Размещение товаров по ячейкам',
  ]

  mutations: ['fulfillmentReceiveOrder(id: ID!)', 'updateProductInWarehouse(...)']
}
```

### 2. УПРАВЛЕНИЕ СКЛАДОМ

```typescript
// 3-уровневая структура склада
interface WarehouseStructure {
  level1: "Партнеры (селлеры)"           // Организации
  level2: "Категории товаров"            // Типы продукции
  level3: "Конкретные товары/расходники" // SKU
}

// GraphQL запрос структуры склада
query GetWarehouseData {
  warehouseData {
    partners {
      organization { name, type }
      categories {
        name
        products { name, currentStock }
      }
    }
  }
}
```

### 3. УЧЕТ РАСХОДНИКОВ

```typescript
interface ConsumablesTracking {
  // Собственные расходники ФФ
  fulfillmentConsumables: {
    tracking: 'Расход на собственные операции'
    replenishment: 'Заказ у поставщиков'
    costing: 'Затраты на операции'
  }

  // Расходники селлеров (на хранении)
  sellerConsumables: {
    tracking: 'Только учет остатков'
    usage: 'Селлеры используют в рецептурах'
    billing: 'Селлеры платят за хранение'
  }
}
```

## 🎛️ ИНТЕГРАЦИЯ С МАРКЕТПЛЕЙСАМИ

### ОТПРАВКА ТОВАРОВ НА WB/OZON:

```typescript
interface MarketplaceIntegration {
  // ФФ не имеет собственных API ключей маркетплейсов
  apiAccess: 'Через селлеров (их API ключи)'

  process: {
    step1: 'Селлер создает поставку в WB/Ozon'
    step2: 'ФФ получает задание на сборку'
    step3: 'ФФ упаковывает по рецептуре'
    step4: 'ФФ передает курьеру маркетплейса'
  }

  // Создание поставок Wildberries для селлеров
  mutations: ['createWildberriesSupply', 'updateWildberriesSupply']
}
```

## 🔐 ПРАВА ДОСТУПА И БЕЗОПАСНОСТЬ

### ДОСТУП К ДАННЫМ:

```typescript
const fulfillmentAccess = {
  // ✅ Полный доступ
  own: {
    supplies: 'FULFILLMENT_CONSUMABLES',
    services: 'Услуги фулфилмента',
    employees: 'Сотрудники ФФ',
    supplyOrders: 'Собственные заказы расходников',
  },

  // ✅ Доступ на чтение
  partners: {
    sellerSupplies: 'SELLER_CONSUMABLES на складе',
    incomingOrders: 'Заказы товаров от селлеров',
    partnerServices: 'Услуги партнеров (для рецептур)',
  },

  // ❌ Запрещенный доступ
  restricted: {
    sellerApiKeys: 'API ключи маркетплейсов селлеров',
    sellerFinances: 'Финансовые данные селлеров',
    sellerStatistics: 'Статистика продаж селлеров',
  },
}
```

### ВАЛИДАЦИЯ ОПЕРАЦИЙ:

```typescript
// Проверки в resolvers для фулфилмента
const fulfillmentValidation = {
  receiveOrder: 'Может принимать только заказы где он - получатель',
  viewWarehouse: 'Видит только товары на своем складе',
  manageSupplies: 'Может управлять только FULFILLMENT_CONSUMABLES',

  // Из кода: проверка принадлежности к организации
  check: `
    const hasAccess = organization.users.some(user => 
      user.id === context.user!.id
    )
  `,
}
```

## 📊 DASHBOARD И ИНТЕРФЕЙСЫ

### ОСНОВНЫЕ РАЗДЕЛЫ КАБИНЕТА:

```typescript
interface FulfillmentDashboard {
  sections: {
    warehouse: 'Управление складом' // Основной раздел
    supplies: 'Расходники и заказы' // Двойная система
    orders: 'Обработка заказов селлеров' // Incoming orders
    services: 'Услуги фулфилмента' // Каталог услуг
    employees: 'Управление персоналом' // Сотрудники
    statistics: 'Склад и производительность' // Аналитика
  }
}
```

### КОМПОНЕНТЫ ИНТЕРФЕЙСА:

```typescript
// Специализированные компоненты для фулфилмента
const fulfillmentComponents = [
  'fulfillment-warehouse-dashboard.tsx', // Основной склад
  'fulfillment-supplies-dashboard.tsx', // Управление расходниками
  'supplies-stats.tsx', // Статистика склада
  'delivery-details.tsx', // Детали доставок
  'wb-return-claims.tsx', // Возвраты с маркетплейсов
]
```

## ⚠️ КРИТИЧЕСКИЕ ПРАВИЛА ДОМЕНА

### 1. РАЗДЕЛЕНИЕ ТИПОВ РАСХОДНИКОВ

> **НЕЛЬЗЯ** смешивать FULFILLMENT_CONSUMABLES и SELLER_CONSUMABLES

### 2. РОЛЬ В WORKFLOW

> Фулфилмент всегда **конечный получатель** товаров, но может быть **инициатором** заказов расходников

### 3. ЭКОНОМИЧЕСКАЯ МОДЕЛЬ

> Доходы от **услуг селлерам** и **продажи расходников**, НЕ от прямых продаж на маркетплейсах

### 4. ПАРТНЕРСТВО С СЕЛЛЕРАМИ

> Обязательное партнерство с селлерами для предоставления услуг и хранения их товаров

### 5. БЕЗОПАСНОСТЬ ДАННЫХ

> Нет доступа к API ключам маркетплейсов селлеров, работа через их интеграции

---

_Извлечено из анализа: GraphQL resolvers, бизнес-логика, архитектура системы_  
_Дата создания: 2025-08-21_  
_Основано на коде: src/graphql/resolvers.ts, business rules, workflow patterns_
