# Модуль управления запчастями ## Обзор Модуль управления запчастями добавляет полнофункциональную систему для: - Ведения каталога запчастей - Управления заказами деталей - Автоматического списания при использовании в рекламациях - Контроля наличия на складе ## Основные возможности ### 1. Каталог запчастей **ВАЖНО:** Каталог запчастей является **общим для всех лет**. Одна запчасть (по артикулу) существует во всех годах, но количества рассчитываются только для текущего выбранного года. **Доступ:** Меню → Запчасти → вкладка "Каталог" **Функции:** - Просмотр всех запчастей с вычисляемыми остатками - Добавление/редактирование запчастей (только admin) - Загрузка изображений запчастей - Экспорт/импорт каталога в Excel - Управление ценами (закупка, заказчик, экспертиза) - Установка минимального остатка **Вычисляемые поля:** - **Кол-во без док** - количество на складе без документов (для текущего года) - **Кол-во с док** - количество на складе с документами (для текущего года) - **Кол-во общее** - сумма двух предыдущих **Кликабельные ячейки:** Клик по ячейке с количеством открывает вкладку "Заказы деталей" с автоматическим фильтром по: - Артикулу - Наличию документов (если кликнули на "без док" или "с док") - Статусу "На складе" - Остатку > 0 ### 2. Заказы деталей **ВАЖНО:** Заказы **разделены по годам**. Каждый заказ принадлежит конкретному году. **Доступ:** Меню → Запчасти → вкладка "Заказы деталей" **Функции:** - Создание заказа детали (admin, manager) - Изменение статуса (Заказано → На складе → Отгружено) - Отгрузка детали (списание) с указанием куда/для чего - Просмотр истории списаний - Автоматическое изменение статуса на "Отгружено" при полном списании **Статусы заказа:** - **Заказано** - деталь в процессе заказа - **На складе** - деталь поступила и доступна для использования - **Отгружено** - деталь полностью списана **История списаний:** - Дата и время списания - Количество - Примечание (куда/для чего) - Пользователь - Флаг "автоматическое" (если списано через рекламацию) - Ссылка на рекламацию (если применимо) ### 3. Контроль наличия **Доступ:** Меню → Запчасти → вкладка "Контроль наличия" **Две таблицы:** **Критический недостаток (красные строки):** - Запчасти с **отрицательным количеством** - Означает, что была попытка списать больше, чем есть на складе - Автоматически создаётся виртуальный заказ с отрицательным остатком **Ниже минимального остатка (желтые строки):** - Запчасти, у которых общее количество < минимальный остаток - Предупреждение о необходимости пополнения ### 4. Интеграция с рекламациями **Автоматическое списание:** При добавлении детали в рекламацию система: 1. Проверяет, есть ли запчасть с таким артикулом в каталоге 2. Если есть - автоматически списывает из подходящего заказа (FIFO) 3. Если нет достаточного количества - создаёт виртуальный заказ с недостачей 4. Сохраняет связь запчасть-рекламация **Чекбокс "С док.":** - В форме деталей рекламации добавлен чекбокс "С док." - Определяет, нужна ли запчасть с документами или без - Влияет на выбор заказа для списания ### 5. Справочник расценок **Доступ:** Меню → Запчасти → (отдельный раздел, только для admin) **Функции:** - Ведение справочника кодов расценок - Добавление/редактирование/удаление кодов - Расшифровка кодов - Tooltip при наведении на код в каталоге (планируется) ## Мультигодовая архитектура **КРИТИЧНО ВАЖНО:** ### Каталог запчастей (БЕЗ year): - Таблица `spare_parts` **НЕ имеет** поле `year` - Модель `SparePart` **НЕ использует** `YearScope` - Одна запчасть видна во всех годах ### Заказы деталей (С year): - Таблица `spare_part_orders` **имеет** поле `year` - Модель `SparePartOrder` **использует** `YearScope` - Заказы разделены по годам ### Логика вычисления количеств: - Вычисляемые поля (`quantity_without_docs`, `quantity_with_docs`) в модели `SparePart` - Учитывают **только заказы текущего года** из сессии `year()` - При смене года количества пересчитываются автоматически **Пример:** ```php // Запчасть "BOLT-001" существует одна $sparePart = SparePart::where('article', 'BOLT-001')->first(); // Год 2024: есть заказ на 100 шт session(['year' => 2024]); echo $sparePart->total_quantity; // 100 // Год 2025: есть заказ на 50 шт session(['year' => 2025]); echo $sparePart->total_quantity; // 50 // Год 2026: нет заказов session(['year' => 2026]); echo $sparePart->total_quantity; // 0 ``` ## Структура базы данных ### Таблицы: 1. `spare_parts` - каталог запчастей (БЕЗ year) 2. `spare_part_orders` - заказы деталей (С year) 3. `spare_part_order_shipments` - история списаний (БЕЗ year, привязана к заказу) 4. `pricing_codes` - справочник расценок 5. `reclamation_spare_part` - pivot таблица запчасти-рекламации ### View: - `spare_part_orders_view` - представление для заказов с join'ами ## Экспорт/Импорт ### Экспорт каталога: - Кнопка "Экспорт" (только admin) - Выполняется через очередь (`ExportSparePartsJob`) - Шаблон: `/templates/SpareParts.xlsx` - **ВАЖНО:** Вычисляемые поля (количества) экспортируются для текущего года! ### Формат Excel (13 колонок, БЕЗ года): | ID | Артикул | Где используется | Кол-во без док | Кол-во с док | Кол-во общее | Примечание | Цена закупки | Цена для заказчика | Цена экспертизы | № по ТСН | Шифр расценки | Минимальный остаток | ## Изображения **Расположение:** `/public/images/spare_parts/` **Формат имени:** `{article}.jpg` **Пример:** `TEST-001.jpg` **Загрузка:** - Форма редактирования запчасти → кнопка "Загрузить изображение" (только admin) - Автоматическое отображение в каталоге и формах ## Роли и права доступа ### Admin: - Полный доступ ко всем функциям - Создание/редактирование/удаление запчастей - Экспорт/импорт - Управление заказами и списание - Доступ к ценам закупки ### Manager: - Просмотр каталога - Создание/редактирование заказов деталей - Списание деталей - Просмотр контроля наличия - **НЕТ доступа** к ценам закупки ### Другие роли: - Только просмотр ## Технические детали ### Сервисы: - `SparePartInventoryService` - логика автосписания и контроля - `Export/ExportSparePartsService` - экспорт в Excel ### Jobs: - `Export/ExportSparePartsJob` - фоновая задача экспорта ### Form Requests: - `StoreSparePartRequest` - валидация запчасти - `StoreSparePartOrderRequest` - валидация заказа - `ShipSparePartOrderRequest` - валидация отгрузки - `StoreReclamationDetailsRequest` - обновлён для поддержки `with_documents` ### Контроллеры: - `SparePartController` - каталог - `SparePartOrderController` - заказы - `SparePartInventoryController` - контроль наличия - `PricingCodeController` - справочник расценок - `ReclamationController` - обновлён для интеграции ## Маршруты ```php // Каталог GET /spare-parts POST /spare-parts (admin) GET /spare-parts/create (admin) GET /spare-parts/{id} PUT /spare-parts/{id} (admin) DELETE /spare-parts/{id} (admin) POST /spare-parts/export (admin) POST /spare-parts/{id}/upload-image (admin) // Заказы GET /spare-part-orders POST /spare-part-orders (admin, manager) GET /spare-part-orders/create (admin, manager) GET /spare-part-orders/{id} PUT /spare-part-orders/{id} (admin, manager) DELETE /spare-part-orders/{id} (admin) POST /spare-part-orders/{id}/ship (admin, manager) POST /spare-part-orders/{id}/set-in-stock (admin, manager) // Контроль GET /spare-part-inventory // Справочник GET /pricing-codes (admin) POST /pricing-codes (admin) PUT /pricing-codes/{id} (admin) DELETE /pricing-codes/{id} (admin) // API GET /api/pricing-codes/{code} ``` ## Тестирование ### Создание тестовых данных: ```bash docker exec dkr-app-1 php artisan tinker ``` ```php // Создать запчасть $sp = SparePart::create([ 'article' => 'TEST-001', 'used_in_maf' => 'Качели', 'customer_price' => 150.00, 'min_stock' => 10 ]); // Создать заказ $order = SparePartOrder::create([ 'spare_part_id' => $sp->id, 'source_text' => 'Поставщик А', 'status' => 'in_stock', 'ordered_quantity' => 100, 'with_documents' => true, 'user_id' => 1 ]); // Проверить количество echo $sp->quantity_with_docs; // 100 ``` ### Тест автосписания: ```php $service = new SparePartInventoryService(); $service->deductForReclamation('TEST-001', 10, true, $reclamationId); // Проверить $sp->refresh(); echo $sp->quantity_with_docs; // 90 ``` ## Известные особенности 1. **Отрицательные остатки** - разрешены и означают недостачу 2. **Виртуальные заказы** - автоматически создаются при недостаче со статусом "На складе" и отрицательным остатком 3. **FIFO** - при списании выбирается самый ранний заказ с подходящими параметрами 4. **Пересчёт количеств** - происходит динамически при каждом обращении к атрибутам модели