Модули
Места производства
Модуль "Места производства"
Версия: 1.0
Дата: 2025-11-26
Статус: Реализован
Содержание
- Общее описание
- Текущая реализация
- Права доступа
- Описание полей
- UI/UX
- Бизнес-логика
- Выявленные проблемы
- Рекомендации
1. Общее описание
1.1 Предназначение модуля
Модуль "Места производства" предназначен для управления производственными площадками компании. Каждое место производства имеет свою производительность (мощность) по дням недели, что используется для:
- Планирования загрузки производства
- Расчёта доступных дат для заказов
- Отображения в календаре производства
Основные функции:
- Ведение реестра мест производства
- Настройка производительности по дням недели
- Привязка заказов к конкретному производству
1.2 Связь с другими модулями
| Модуль | Связь |
|---|---|
| Заказы | Заказ привязан к месту производства (order.manufacture_id) |
| Дилеры (компании) | Компания может иметь привязку к производству (company.manufacture_id) |
| Каталог (Товары) | Товар может быть привязан к производству (many-to-many) |
| Календарь | Отображает заказы по местам производства |
| Резервации | Учитывает бронирования времени производства |
1.3 Статистика
| Метрика | Значение |
|---|---|
| Всего мест производства | 2 |
| Активных | 2 |
| Компаний с производством | 3 |
| Заказов с производством | 37 |
2. Текущая реализация
2.1 Архитектура
┌─────────────────────────────────────────────────────────────────────────────┐
│ МОДУЛЬ "МЕСТА ПРОИЗВОДСТВА" │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ РОУТЫ (routes/web.php) │
│ └── GET /manufactures → ManufactureController@index → Список │
│ │
│ КОНТРОЛЛЕР (ManufactureController.php) │
│ └── Проверка: group_id == 1 (только администраторы) │
│ │
│ LIVEWIRE КОМПОНЕНТЫ │
│ ├── Manufactures/Listing.php — Таблица (inline-редактирование) │
│ └── Manufactures/Add.php — Модальное создание │
│ │
│ МОДЕЛЬ │
│ └── Manufacture — место производства с JSON productivity │
│ │
│ СЕРВИС │
│ └── Services/Septik.php — расчёт свободного времени │
│ │
└─────────────────────────────────────────────────────────────────────────────┘2.2 Структура БД
Таблица manufactures
| Поле | Тип | Описание |
|---|---|---|
id | bigint | PK |
name | string | Название |
city | string | Город |
address | string | Адрес (nullable) |
phone | string(20) | Телефон |
description | text | Описание (HTML) |
productivity | json | Производительность по дням |
active | boolean | Активен |
created_at | timestamp | — |
updated_at | timestamp | — |
Таблица manufacture_product (связь с товарами)
| Поле | Тип | Описание |
|---|---|---|
manufacture_id | FK | Место производства |
product_id | FK | Товар |
2.3 Формат поля productivity
[
{
"days": [1, 2, 3, 4, 5], // пн-пт
"time": 600 // мощность в минутах
},
{
"days": [6, 7], // сб-вс
"time": 400
}
]Дни недели (ISO):
- 1 = понедельник
- 7 = воскресенье
2.4 Файлы модуля
app/
├── Http/Controllers/
│ └── ManufactureController.php
├── Livewire/Manufactures/
│ ├── Add.php
│ └── Listing.php
├── Models/
│ └── Manufacture.php
└── Services/
└── Septik.php ← расчёт загрузки
database/migrations/
├── 2024_03_21_213739_create_manufactures_table.php
├── 2024_04_16_132618_change_productivity_column_to_json_in_manufactures_table.php
└── 2024_04_22_220112_create_manufacture_product_table.php
resources/views/components/
└── productivity.blade.php ← отображение productivity в таблице3. Права доступа
3.1 Политики
| Политика | Описание |
|---|---|
manufacture_can_edit | Редактирование места производства |
3.2 Жёсткое ограничение в контроллере
// ManufactureController.php
public function index(Request $request)
{
$user = $request->user();
if (!$user or $user->group_id != 1) // Только администраторы!
abort(403);
return view('templates.manufactures.table');
}⚠️ Важно: Модуль доступен только администраторам (group_id = 1). Это проверяется напрямую в контроллере, а не через систему политик.
3.3 Матрица доступа по ролям
| Роль | Просмотр | Создание | Редактир. | Удаление |
|---|---|---|---|---|
| Администратор | ✅ | ✅ | ✅ | ✅ |
| Менеджер | ❌ | ❌ | ❌ | ❌ |
| Производство | ❌ | ❌ | ❌ | ❌ |
| Дилер | ❌ | ❌ | ❌ | ❌ |
4. Описание полей
4.1 Форма создания/редактирования
| Поле | Тип | Обязательное | Описание |
|---|---|---|---|
name | TextInput | ✅ | Название производства |
city | TextInput | ✅ | Город |
address | TextInput | ❌ | Адрес |
productivity | Repeater | ❌ | Мощность по дням (см. ниже) |
phone | TextInput | ❌ | Телефон (маска +7) |
description | RichEditor | ❌ | Описание (HTML) |
4.2 Поле Productivity (Repeater)
Repeater::make('productivity')->label('Продуктивность')
->schema([
CheckboxList::make('days')
->options([
1 => 'пн', 2 => 'вт', 3 => 'ср',
4 => 'чт', 5 => 'пт', 6 => 'сб', 7 => 'вс',
])
->columns(7),
TextInput::make('time')
->numeric()
->default(0),
])Логика:
- Можно создать несколько записей (строк)
- Для каждой записи выбираются дни недели
- Указывается мощность (время в минутах)
4.3 Колонки таблицы
| Колонка | Описание | Особенности |
|---|---|---|
name | Название | Поиск |
city | Город | Поиск |
phone | Телефон | Поиск |
productivity | Мощность | ViewColumn с кастомным отображением |
active | Активен | ToggleColumn |
5. UI/UX
5.1 Список мест производства
┌─────────────────────────────────────────────────────────────────────────────┐
│ Места производства [+ Создать] │
├─────────────────────────────────────────────────────────────────────────────┤
│ [Поиск...] [Столбцы ▾] │
├──────┬───────────────────────┬───────────┬──────────┬─────────────┬─────────┤
│ ☐ │ Имя │ City │ Телефон │ Productivity│ Активен │
├──────┼───────────────────────┼───────────┼──────────┼─────────────┼─────────┤
│ ☐ │ Производство Верховье │ Верховье │ │ пн-пт: 600 │ [●] │
│ │ │ │ │ сб-вс: 400 │ │
├──────┼───────────────────────┼───────────┼──────────┼─────────────┼─────────┤
│ ☐ │ Производство Елкино │ Елкино │ │ пн-пт: 300 │ [●] │
│ │ │ │ │ сб-вс: 200 │ │
└──────┴───────────────────────┴───────────┴──────────┴─────────────┴─────────┘
Действия:
✅ [Изменить] — модальное редактирование
✅ [Удалить] — с подтверждением
Особенности:
- Нет отдельной страницы редактирования
- Всё через модальные окна
- Productivity отображается кастомным Blade-компонентом5.2 Отображение Productivity
{{-- components/productivity.blade.php --}}
@foreach ($getState() as $item)
<div class="mb-1">
{{ App\Services\Septik::getDays($item['days']) }} - {{ $item['time'] }}
</div>
@endforeachПример вывода:
пн,вт,ср,чт,пт - 600
сб,вс - 4005.3 Модальное редактирование
┌─────────────────────────────────────────────────────────────────┐
│ Редактировать склад [×] │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Имя [Производство Верховье ] │
│ │
│ City [Верховье ] │
│ │
│ Address [ ] │
│ │
│ Продуктивность │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ [×] пн [×] вт [×] ср [×] чт [×] пт [ ] сб [ ] вс │ │
│ │ Time: [600 ] │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ [ ] пн [ ] вт [ ] ср [ ] чт [ ] пт [×] сб [×] вс │ │
│ │ Time: [400 ] │ │
│ └─────────────────────────────────────────────────────────┘ │
│ [+ Добавить строку] │
│ │
│ Телефон [+7(999) 123-45-67 ] │
│ │
│ Description [ ] │
│ │
├─────────────────────────────────────────────────────────────────┤
│ [Отмена] [Сохранить] │
└─────────────────────────────────────────────────────────────────┘6. Бизнес-логика
6.1 Расчёт свободного времени (Services/Septik.php)
Ключевой сервис системы — расчёт доступной мощности производства на дату.
class Septik
{
/**
* Возвращает свободное время (минуты) на производстве за дату
*/
public static function getFreeTime($manufacture, $date, $orders = null, $reservations = null): int
{
// 1. Получаем мощность производства на эту дату
$manufactureTime = static::getProductivityTime($m->productivity, $date);
// 2. Считаем занятое время заказами
$orders = Order::where('manufacture_id', $manufacture)
->whereDate('date_make', $date)->get();
foreach ($orders as $order) {
$ordersTime += $order->product->time;
}
// 3. Считаем время резерваций
$reservations = Reservation::where('manufacture_id', $manufacture)
->whereDate('date', $date)->get();
foreach ($reservations as $reservation) {
$reservationsTime += $reservation->time;
}
// 4. Свободное время = мощность - заказы - резервации
return $manufactureTime - $reservationsTime - $ordersTime;
}
}6.2 Формула загрузки
Свободное время = Мощность(дата) - Σ(время_заказов) - Σ(время_резерваций)Где:
Мощность(дата)— значениеtimeизproductivityдля дня недели этой датывремя_заказов— суммаproduct.timeвсех заказов на эту датувремя_резерваций— суммаtimeвсех резерваций на эту дату
6.3 Получение мощности по дате
public static function getProductivityTime($items, $date): int
{
foreach ($items as $item) {
$dayOfWeek = Carbon::parse($date)->dayOfWeekIso; // 1=пн, 7=вс
if (in_array($dayOfWeek, $item['days'])) {
return $item['time'] ?? 0;
}
}
return 0; // Если день не найден — мощность 0
}6.4 Поиск свободных дат для заказа
/**
* Находит 10 ближайших дат, когда товар можно произвести
*/
public static function getFreeDates($manufacture, $product): array
{
$freeDates = [];
$startDay = Carbon::today()->addDay(); // Начинаем с завтра
while (count($freeDates) < 10 && $datesChecked < 50) {
$day = $startDay->addDays($datesChecked);
// Если время товара < свободного времени — дата подходит
if ($product->time < static::getFreeTime($manufacture, $day)) {
$freeDates[] = $day->format('Y-m-d');
}
$datesChecked++;
}
return $freeDates;
}6.5 Связь с Календарём
В календаре заказы фильтруются по manufacture_id:
// Calendar/Day.php
$this->manufacture = session('calendar_selector'); // Выбранное производство
$query = Order::query();
if ($this->manufacture) {
$query = $query->where('manufacture_id', $this->manufacture);
}6.6 Связь с заказами и компаниями
Order.manufacture_id ──────────┐
▼
Company.manufacture_id ──────► Manufacture
│
Product ◄─────────────────────┴── manufacture_product (M:N)7. Выявленные проблемы
7.1 Критические
| # | Проблема | Файл | Влияние |
|---|---|---|---|
| — | Критических проблем не обнаружено | — | — |
7.2 Средние
| # | Проблема | Описание | Решение |
|---|---|---|---|
| 1 | Опечатка в modalHeading | 'Редактировать склад' вместо 'Редактировать производство' | Исправить текст |
| 2 | Жёсткая проверка group_id | Нет гибкости через систему политик | Использовать check_access() |
| 3 | Нет валидации productivity | Можно сохранить пустой массив или без времени | Добавить валидацию |
| 4 | Время в минутах неочевидно | Нет подсказки о единицах измерения | Добавить hint/suffix |
7.3 Низкие
| # | Проблема | Описание |
|---|---|---|
| 5 | Нелокализованные названия колонок | City, Productivity на английском |
| 6 | Нет истории изменений | Не отслеживается кто менял мощность |
| 7 | Нет отчёта по загрузке | Нельзя посмотреть статистику загрузки |
8. Рекомендации
8.1 Приоритет: Высокий
Исправить опечатку
// Listing.php:83 — было:
->modalHeading('Редактировать склад')
// Стало:
->modalHeading('Редактировать место производства')8.2 Приоритет: Средний
Добавить подсказку к полю time
TextInput::make('time')
->label('Мощность')
->numeric()
->suffix('минут')
->hint('Максимальное время производства за день')
->default(0),Локализовать колонки
Tables\Columns\TextColumn::make('city')
->label('Город')
->searchable(),8.3 Приоритет: Низкий
Добавить валидацию productivity
Repeater::make('productivity')
->minItems(1)
->schema([
CheckboxList::make('days')
->required()
->minItems(1),
TextInput::make('time')
->required()
->numeric()
->minValue(1),
])Приложение: SQL для аналитики
Загрузка производств
SELECT
m.name,
m.city,
COUNT(o.id) as orders_count,
DATE(o.date_make) as date
FROM manufactures m
LEFT JOIN orders o ON m.id = o.manufacture_id
WHERE o.date_make >= CURDATE()
GROUP BY m.id, m.name, m.city, DATE(o.date_make)
ORDER BY m.name, date;Компании без привязки к производству
SELECT id, org, city
FROM companies
WHERE manufacture_id IS NULL;Заказы по производствам за месяц
SELECT
m.name as manufacture,
COUNT(o.id) as total_orders,
SUM(o.cost) as total_cost
FROM manufactures m
LEFT JOIN orders o ON m.id = o.manufacture_id
WHERE o.created_at >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
GROUP BY m.id, m.name
ORDER BY total_orders DESC;Документ подготовлен на основе анализа исходного кода проекта