Документация ЛК
Модули

Склады

Модуль "Склады"

Версия: 1.0
Дата: 2025-11-26
Статус: Реализован


Содержание

  1. Общее описание
  2. Текущая реализация
  3. Права доступа
  4. Описание полей
  5. UI/UX
  6. Бизнес-логика
  7. Выявленные проблемы
  8. Рекомендации

1. Общее описание

1.1 Предназначение модуля

Модуль "Склады" предназначен для учёта физических товаров на складах компании. Каждый товар на складе — это конкретная единица продукции с серийным номером, опциями и параметрами.

Основные функции:

  • Ведение реестра складов (физические локации)
  • Учёт товарных единиц на каждом складе
  • Отслеживание статуса товара (на складе / привязан к заказу)
  • Управление опциями и наращиванием для товаров
  • Привязка компаний к конкретным складам

1.2 Связь с другими модулями

МодульСвязь
Каталог (Товары)product_id — какой товар на складе
ЗаказыСкладские единицы привязываются к позициям заказа
Дилеры (компании)Компания может быть привязана к складу (company.stock_id)
ПроизводствоПользователи производства видят только свой склад
ОпцииОпции товара применяются к складской единице

1.3 Статистика

МетрикаЗначение
Всего складов3
Активных3
Товаров на складах19
В наличии16
Привязано к заказам3
Компаний со складом3

2. Текущая реализация

2.1 Архитектура

┌─────────────────────────────────────────────────────────────────────────────┐
│                           МОДУЛЬ "СКЛАДЫ"                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  РОУТЫ (routes/web.php)                                                      │
│  ├── GET /stocks         → StockController@index → Список складов            │
│  └── GET /stocks/edit/{id} → StockController@show → Карточка склада          │
│                                                                              │
│  КОНТРОЛЛЕР (StockController.php)                                            │
│  └── Проверка прав: stock_can_view                                           │
│                                                                              │
│  LIVEWIRE КОМПОНЕНТЫ                                                         │
│  ├── Stocks/Listing.php  — Таблица складов (inline-редактирование)          │
│  ├── Stocks/Add.php      — Модальное создание склада                        │
│  ├── Stocks/Edit.php     — Таблица товаров на складе                        │
│  └── Stocks/Control.php  — Добавление товара на склад                       │
│                                                                              │
│  МОДЕЛИ                                                                      │
│  ├── Stock          — Склад                                                 │
│  └── ProductStock   — Товар на складе (связь Product ↔ Stock)               │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

2.2 Структура БД

Таблица stocks

ПолеТипОписание
idbigintPK
namestring(300)Название склада
phonestring(20)Телефон
addressstring(400)Адрес
descriptiontextОписание (HTML)
activebooleanАктивен
created_attimestamp
updated_attimestamp

Таблица product_stocks (товары на складе)

ПолеТипОписание
idbigintPK
product_idFKТовар из каталога
stock_idFKСклад
heightdecimal(8,2)Наращивание горловины
snstringСерийный номер
in_stockbooleanНа складе (true) / Привязан к заказу (false)
created_attimestamp
updated_attimestamp

Таблица option_product_stock (опции товара на складе)

ПолеТипОписание
option_idFKОпция
product_stock_idFKСкладская единица

Таблица order_item_product_stock (связь с заказами)

ПолеТипОписание
order_item_idFKПозиция заказа
product_stock_idFKСкладская единица

2.3 Файлы модуля

app/
├── Http/Controllers/
│   └── StockController.php
├── Livewire/Stocks/
│   ├── Add.php       — Создание склада (модальное)
│   ├── Control.php   — Добавление товара на склад
│   ├── Edit.php      — Просмотр/редактирование товаров
│   └── Listing.php   — Список складов
└── Models/
    ├── Stock.php
    └── ProductStock.php

database/migrations/
├── 2024_03_21_000728_create_stocks_table.php
├── 2024_03_21_204016_create_product_stocks_table.php
├── 2024_03_21_204829_create_option_product_stock_table.php
└── 2025_09_21_120000_create_order_item_product_stock_table.php

3. Права доступа

3.1 Политики

ПолитикаОписание
stock_can_viewПросмотр списка складов и товаров
stock_can_addСоздание склада
stock_can_editРедактирование склада и товаров
stock_can_deleteУдаление склада и товаров
stock_manager_can_deleteУдаление (для менеджеров) — упоминается, но не реализовано

3.2 Особый доступ для Производства

Пользователи группы Производство (group_id = 4) имеют ограниченный доступ:

// Listing.php — фильтрация для производства
if ($this->authUser->group_id == 4) { // Производство
    if ($this->authUser->stock_id) {
        $query->where('id', $this->authUser->stock_id);  // Только свой склад
    } else {
        $query->where('id', 0);  // Нет доступа
    }
}
// Edit.php, Control.php — проверка доступа к конкретному складу
if ($this->authUser->group_id == 4) {
    if (!$this->authUser->stock_id || $this->authUser->stock_id != $this->id) {
        abort(403, 'Доступ запрещён');
    }
}

3.3 Матрица доступа по ролям

РольПросмотрСозданиеРедактир.УдалениеДобавл. товар
Администратор✅ Все
Менеджер
Производство⚠️ Свой⚠️ Свой⚠️ Свой
Дилер

4. Описание полей

4.1 Создание/редактирование склада

ПолеТипОбязательноеОписание
nameTextInputНазвание склада
addressTextInputАдрес
phoneTextInputТелефон (маска +7)
descriptionRichEditorОписание (с HTML)

4.2 Добавление товара на склад (Control.php)

ПолеТипОбязательноеОписание
product_idSelectВыбор товара из каталога
snTextInputСерийный номер
heightNumberНаращивание (шаг = product.step_size)
options.*Checkbox[]Опции товара (динамически)

4.3 Редактирование товара на складе (Edit.php)

ПолеТипОсобенности
snTextInputСерийный номер
heightNumberС шагом из товара
options.*Checkbox[]Динамически из опций товара

4.4 Колонки таблицы товаров

КолонкаОписаниеДействия
product.nameНазвание товараПоиск
snСерийный номерПоиск
heightНаращиваниеПоиск
options.nameОпцииПоиск
in_stockНа складеToggleColumn с логикой отвязки
created_atДата добавленияСортировка

5. UI/UX

5.1 Список складов

┌─────────────────────────────────────────────────────────────────────────────┐
│ Склады                                                      [+ Создать]     │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                    [Поиск...] [Столбцы ▾]   │
├──────┬─────────────────┬────────────────────────────┬──────────┬────────────┤
│ ☐    │ Имя             │ Адрес                      │ Телефон  │ Активен    │
├──────┼─────────────────┼────────────────────────────┼──────────┼────────────┤
│ ☐    │ Вертек          │ Московская обл., д. Елкино │          │ [●]        │
│ ☐    │ Склад СПБ       │ Шушары Московское ш. 121   │ +7(812)..│ [●]        │
│ ☐    │ Базис           │ Московская обл. Верховье   │          │ [●]        │
└──────┴─────────────────┴────────────────────────────┴──────────┴────────────┘

Действия:
✅ [Изменить] — модальное редактирование
✅ [Удалить] — с подтверждением
✅ Клик по строке → переход в карточку склада

Особенности:
- Создание через модальное окно (не отдельная страница)
- Inline-редактирование через модалку
- ToggleColumn для активности

5.2 Карточка склада (товары)

┌─────────────────────────────────────────────────────────────────────────────┐
│ [← Назад]  Вертек                               [+ Добавить на склад]       │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                    [Поиск...] [Столбцы ▾]   │
├──────┬─────────────────┬──────────────┬────────┬──────────┬────────┬────────┤
│ ☐    │ Название товара │ Серийный №   │ Наращ. │ Опции    │На скл. │ Дата   │
├──────┼─────────────────┼──────────────┼────────┼──────────┼────────┼────────┤
│ ☐    │ Тверь CLASSIC   │ 2407121747   │ 0.00   │ Вход ДУ  │ [ ]    │ 12.07  │
│ ☐    │ Тверь CLASSIC 2П│ rtuijtygkigyk│ 0.00   │ Вход ДУ  │ [ ]    │ 10.07  │
└──────┴─────────────────┴──────────────┴────────┴──────────┴────────┴────────┘

Действия:
✅ [Редактировать] — модальное редактирование SN, height, опций
✅ [Удалить] — удаление складской единицы

Переключатель "На складе":
⚠️ Включение (→ true) = ВОЗВРАТ товара на склад + ОТВЯЗКА от заказов

5.3 Модальное добавление товара

┌─────────────────────────────────────────────────────────────────┐
│ Добавить на склад                                        [×]    │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Выберите продукт    [123 - Тверь CLASSIC 0,8П           ] ▾    │
│                                                                  │
│  Серийный номер      [2407131456                           ]    │
│                                                                  │
│  ── Динамические поля (появляются после выбора товара) ──       │
│                                                                  │
│  Нарощенная высота горловины  [0.00                      ]      │
│  ☐ Вход торцевой ДУ 110                                         │
│  ☐ Вход боковой ДУ 50                                           │
│                                                                  │
├─────────────────────────────────────────────────────────────────┤
│                                              [Отмена] [Создать] │
└─────────────────────────────────────────────────────────────────┘

6. Бизнес-логика

6.1 Жизненный цикл складской единицы

┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   ДОБАВЛЕНИЕ    │     │   ПРИВЯЗКА      │     │   ВОЗВРАТ       │
│   НА СКЛАД      │────>│   К ЗАКАЗУ      │────>│   НА СКЛАД      │
│                 │     │                 │     │                 │
│ in_stock = true │     │ in_stock = false│     │ in_stock = true │
│ sn, height, opts│     │ → order_item    │     │ → detach items  │
└─────────────────┘     └─────────────────┘     └─────────────────┘

6.2 Логика возврата на склад

При переключении in_stock на true происходит отвязка от всех заказов:

// Edit.php — afterStateUpdated для ToggleColumn
if ($state === true) {
    DB::transaction(function () use ($record) {
        // 1. Отвязываем через pivot-таблицу (новая схема)
        if (Schema::hasTable('order_item_product_stock')) {
            $related = $record->orderItemsPivot()->get();
            if ($related->count() > 0) {
                // Обнуляем SN на позициях заказа
                OrderItem::whereIn('id', $related->pluck('id'))
                    ->update(['sn' => null]);
                $record->orderItemsPivot()->detach();
            }
        }
        
        // 2. Очищаем легаси-связь (product_stock_id)
        $legacy = OrderItem::where('product_stock_id', $record->id);
        if ($legacy->exists()) {
            $legacy->update(['product_stock_id' => null, 'sn' => null]);
        }
        
        $record->in_stock = true;
        $record->save();
    });
    
    Notification::make()
        ->title('Товар возвращён на склад')
        ->body('Единица отвязана от всех заказов.')
        ->warning()
        ->send();
}

6.3 Связи модели ProductStock

class ProductStock extends Model
{
    // Товар из каталога
    public function product() { return $this->belongsTo(Product::class); }
    
    // Склад
    public function stock() { return $this->belongsTo(Stock::class); }
    
    // Опции (many-to-many через option_product_stock)
    public function options() { 
        return $this->belongsToMany(Option::class, 'option_product_stock'); 
    }
    
    // Легаси-связь с позициями заказа
    public function orderItems() { 
        return $this->hasMany(OrderItem::class, 'product_stock_id'); 
    }
    
    // Новая связь через pivot
    public function orderItemsPivot() { 
        return $this->belongsToMany(OrderItem::class, 'order_item_product_stock'); 
    }
}

6.4 Динамические поля при добавлении

При выборе товара подгружаются его опции и параметры:

// Control.php
protected function getProductData(): array
{
    $out = [];
    if ($this->productID) {
        $product = Product::find($this->productID);
        
        // Поле высоты с шагом из товара
        if ($product->step_size) {
            $out[] = TextInput::make('height')
                ->label('Нарощенная высота горловины')
                ->numeric()
                ->step($product->step_size);
        }
        
        // Чекбоксы опций товара
        if ($product->options()->count()) {
            foreach ($product->options as $option) {
                $out[] = Checkbox::make('options.'.$option->id)
                    ->label($option->name);
            }
        }
    }
    return $out;
}

6.5 Привязка склада к компании

Компания может быть привязана к конкретному складу:

Company.stock_id → Stock.id

Это влияет на:

  • Откуда берутся товары при создании заказа
  • Видимость склада для производства

7. Выявленные проблемы

7.1 Критические

#ПроблемаФайлВлияние
Критических проблем не обнаружено

7.2 Средние

#ПроблемаОписаниеРешение
1Нет проверки stock_can_addAdd.php не проверяет право на созданиеДобавить проверку
2stock_manager_can_delete не реализованоУпоминается в коде, но нигде не используетсяУдалить или реализовать
3Две схемы связи с заказамиLegacy (product_stock_id) и новая (pivot)Мигрировать на одну
4Нет валидации SN на уникальностьМожно создать дублиДобавить unique

7.3 Низкие

#ПроблемаОписание
5Нет истории перемещенийНе видно когда товар привязывали/отвязывали
6Нет экспортаНельзя выгрузить список товаров на складе
7Нет фильтровТолько поиск, нет фильтра "Только на складе"
8Нет инвентаризацииНет массовой проверки наличия

8. Рекомендации

8.1 Приоритет: Высокий

Добавить проверку прав при создании

// Add.php — createAction()
return CreateAction::make('create')
    ->visible(fn () => Request::user()->check_access('stock_can_add'))
    // ...

8.2 Приоритет: Средний

Добавить уникальность SN

TextInput::make('sn')
    ->label('Серийный номер')
    ->unique(table: ProductStock::class, ignoreRecord: true)

Добавить фильтр по наличию

->filters([
    Tables\Filters\TernaryFilter::make('in_stock')
        ->label('На складе')
        ->boolean()
        ->trueLabel('В наличии')
        ->falseLabel('Привязаны к заказам'),
])

8.3 Приоритет: Низкий

Добавить экспорт товаров

Action::make('export')
    ->label('Экспорт')
    ->icon('heroicon-o-arrow-down-tray')
    ->action(function () {
        // Аналогично Dealers/Listing.php
    })

Приложение: SQL для аналитики

Товары на складе с опциями

SELECT 
    s.name as stock,
    p.name as product,
    ps.sn,
    ps.height,
    ps.in_stock,
    GROUP_CONCAT(o.name SEPARATOR ', ') as options
FROM product_stocks ps
JOIN stocks s ON ps.stock_id = s.id
JOIN products p ON ps.product_id = p.id
LEFT JOIN option_product_stock ops ON ps.id = ops.product_stock_id
LEFT JOIN options o ON ops.option_id = o.id
GROUP BY ps.id
ORDER BY s.name, ps.created_at DESC;

Товары привязанные к заказам

SELECT 
    ps.sn,
    p.name as product,
    s.name as stock,
    o.id as order_id,
    oi.id as order_item_id
FROM product_stocks ps
JOIN products p ON ps.product_id = p.id
JOIN stocks s ON ps.stock_id = s.id
LEFT JOIN order_item_product_stock oips ON ps.id = oips.product_stock_id
LEFT JOIN order_items oi ON oips.order_item_id = oi.id
LEFT JOIN orders o ON oi.order_id = o.id
WHERE ps.in_stock = 0;

Статистика по складам

SELECT 
    s.name,
    COUNT(ps.id) as total_items,
    SUM(CASE WHEN ps.in_stock = 1 THEN 1 ELSE 0 END) as in_stock,
    SUM(CASE WHEN ps.in_stock = 0 THEN 1 ELSE 0 END) as in_orders
FROM stocks s
LEFT JOIN product_stocks ps ON s.id = ps.stock_id
GROUP BY s.id, s.name;

Документ подготовлен на основе анализа исходного кода проекта

On this page

Модуль "Склады"Содержание1. Общее описание1.1 Предназначение модуля1.2 Связь с другими модулями1.3 Статистика2. Текущая реализация2.1 Архитектура2.2 Структура БДТаблица stocksТаблица product_stocks (товары на складе)Таблица option_product_stock (опции товара на складе)Таблица order_item_product_stock (связь с заказами)2.3 Файлы модуля3. Права доступа3.1 Политики3.2 Особый доступ для Производства3.3 Матрица доступа по ролям4. Описание полей4.1 Создание/редактирование склада4.2 Добавление товара на склад (Control.php)4.3 Редактирование товара на складе (Edit.php)4.4 Колонки таблицы товаров5. UI/UX5.1 Список складов5.2 Карточка склада (товары)5.3 Модальное добавление товара6. Бизнес-логика6.1 Жизненный цикл складской единицы6.2 Логика возврата на склад6.3 Связи модели ProductStock6.4 Динамические поля при добавлении6.5 Привязка склада к компании7. Выявленные проблемы7.1 Критические7.2 Средние7.3 Низкие8. Рекомендации8.1 Приоритет: ВысокийДобавить проверку прав при создании8.2 Приоритет: СреднийДобавить уникальность SNДобавить фильтр по наличию8.3 Приоритет: НизкийДобавить экспорт товаровПриложение: SQL для аналитикиТовары на складе с опциямиТовары привязанные к заказамСтатистика по складам