Restructure catalog to root categories + collapsible groups

- Migration: replace 45 leaf categories (diag.scan, engine.mech…) with
  17 root categories (diag, engine…); update labors.category by taking
  the prefix before the first dot; delete the leaf LaborCategory rows
- ImportLaborCatalogCommand: rewritten to use root categories directly
  so future imports go to the right level from the start
- LaborResource: add ->collapsible() to groups so user can collapse/
  expand each category section to see only headers or only one group
- entrypoint.sh: remove one-time catalog import (was already done)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-09-08 05:17:14 +00:00
parent cbf8deabf3
commit 7ed60b1dbf
4 changed files with 105 additions and 30 deletions
@@ -0,0 +1,81 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
/** Root categories from psauto-katalog-rabot-full.json (parent_id=null nodes). */
private const ROOTS = [
['code' => 'diag', 'sort' => 10, 'name_ru' => 'Диагностика', 'name_en' => 'Diagnostics'],
['code' => 'to', 'sort' => 20, 'name_ru' => 'Техническое обслуживание', 'name_en' => 'Maintenance'],
['code' => 'engine', 'sort' => 30, 'name_ru' => 'Двигатель и навесное', 'name_en' => 'Engine'],
['code' => 'fuel', 'sort' => 40, 'name_ru' => 'Топливная система', 'name_en' => 'Fuel system'],
['code' => 'trans', 'sort' => 50, 'name_ru' => 'Трансмиссия', 'name_en' => 'Transmission'],
['code' => 'chassis', 'sort' => 60, 'name_ru' => 'Ходовая часть', 'name_en' => 'Suspension'],
['code' => 'steering', 'sort' => 70, 'name_ru' => 'Рулевое управление', 'name_en' => 'Steering'],
['code' => 'brakes', 'sort' => 80, 'name_ru' => 'Тормозная система', 'name_en' => 'Brakes'],
['code' => 'wheels', 'sort' => 90, 'name_ru' => 'Колёса и развал', 'name_en' => 'Wheels & Alignment'],
['code' => 'electric', 'sort' => 100, 'name_ru' => 'Электрика и электроника', 'name_en' => 'Electrical'],
['code' => 'climate', 'sort' => 110, 'name_ru' => 'Климат и комфорт', 'name_en' => 'Climate & Comfort'],
['code' => 'body', 'sort' => 120, 'name_ru' => 'Кузовные работы', 'name_en' => 'Bodywork'],
['code' => 'hybrid', 'sort' => 130, 'name_ru' => 'Гибриды и электромобили', 'name_en' => 'Hybrid & EV'],
['code' => 'detailing', 'sort' => 140, 'name_ru' => 'Детейлинг и мойка', 'name_en' => 'Detailing & Wash'],
['code' => 'extra', 'sort' => 150, 'name_ru' => 'Дополнительное оборудование', 'name_en' => 'Extra equipment'],
['code' => 'service', 'sort' => 160, 'name_ru' => 'Сервисные операции', 'name_en' => 'Service operations'],
['code' => 'safety', 'sort' => 170, 'name_ru' => 'Пассивная безопасность', 'name_en' => 'Passive safety'],
];
public function up(): void
{
$companies = DB::table('companies')->pluck('id');
foreach ($companies as $companyId) {
// 1. Insert root categories (skip if already exists by name=code)
foreach (self::ROOTS as $idx => $r) {
$exists = DB::table('labor_categories')
->where('company_id', $companyId)
->where('name', $r['code'])
->exists();
if (! $exists) {
DB::table('labor_categories')->insert([
'company_id' => $companyId,
'name' => $r['code'],
'name_ro' => $r['name_ru'], // RO translation TBD by user
'name_ru' => $r['name_ru'],
'name_en' => $r['name_en'],
'sort_order' => $r['sort'],
'created_at' => now(),
'updated_at' => now(),
]);
}
}
// 2. Re-point labors: "diag.scan" → "diag" (take prefix before first dot)
// Only applies to leaf codes that contain a dot.
$leafLabors = DB::table('labors')
->where('company_id', $companyId)
->where('category', 'like', '%.%')
->get(['id', 'category']);
foreach ($leafLabors as $labor) {
$rootCode = explode('.', $labor->category)[0];
DB::table('labors')
->where('id', $labor->id)
->update(['category' => $rootCode]);
}
// 3. Delete leaf labor_categories (those with a dot in their name)
DB::table('labor_categories')
->where('company_id', $companyId)
->where('name', 'like', '%.%')
->delete();
}
}
public function down(): void
{
// Irreversible restructuring — data would need re-import
}
};