argument('company'); $company = is_numeric($companyArg) ? Company::find((int) $companyArg) : Company::where('slug', $companyArg)->first(); if (! $company) { $this->error("Company '{$companyArg}' not found."); return 1; } app(TenantManager::class)->setCurrent($company); $file = $this->option('file') ?: database_path('data/labor-catalog.json'); if (! file_exists($file)) { foreach ([ '/tmp/service/todo/psauto-katalog-rabot-full.json', storage_path('app/labor-catalog.json'), ] as $path) { if (file_exists($path)) { $file = $path; break; } } } if (! file_exists($file)) { $this->error("JSON file not found. Pass --file=/path/to/psauto-katalog-rabot-full.json"); return 1; } $data = json_decode(file_get_contents($file), true); $allCats = $data['categories'] ?? []; $operations = $data['operations'] ?? []; $catMap = collect($allCats)->keyBy('id'); // Identify leaf categories (those that have operations assigned to them) $usedCatIds = collect($operations)->pluck('service_category_id')->unique(); $leafCats = $catMap->only($usedCatIds->all()); $this->info("Company: {$company->name} (id={$company->id})"); $this->info("Categories to import: {$leafCats->count()}"); $this->info("Operations to import: " . count($operations)); $force = $this->option('force'); // ── 1. Upsert labor categories ──────────────────────────────────── $this->info('Importing categories...'); $catCodeToName = []; // leaf code → canonical name (= code itself) $sortBase = 100; foreach ($leafCats as $leaf) { $parent = $catMap->get($leaf['parent_id']); $nameRu = ($parent ? $parent['name'] . ' · ' : '') . $leaf['name']; $code = $leaf['code']; // canonical key $existing = LaborCategory::withoutGlobalScope(TenantScope::class) ->where('company_id', $company->id) ->where('name', $code) ->first(); if ($existing) { if ($force) { $existing->update(['name_ru' => $nameRu]); $this->line(" Updated cat: {$code}"); } } else { LaborCategory::withoutGlobalScope(TenantScope::class)->create([ 'company_id' => $company->id, 'name' => $code, 'name_ro' => $nameRu, 'name_ru' => $nameRu, 'sort_order' => $sortBase + ($leaf['sort_order'] ?? 0), ]); $this->line(" Created cat: {$code} ({$nameRu})"); } $catCodeToName[$leaf['id']] = $code; $sortBase += 5; } // ── 2. Upsert labors ───────────────────────────────────────────── $this->info('Importing operations...'); $created = 0; $updated = 0; $skipped = 0; foreach ($operations as $op) { $catId = $op['service_category_id']; $catKey = $catCodeToName[$catId] ?? null; if (! $catKey) { $skipped++; continue; } $hours = round(($op['norm_minutes'] ?? 0) / 60, 2); $price = round(($op['base_price_minor'] ?? 0) / 100, 2); $nameRu = $op['name']; $code = $op['code']; $existing = Labor::withoutGlobalScope(TenantScope::class) ->where('company_id', $company->id) ->where('code', $code) ->first(); if ($existing) { if ($force) { $existing->update([ 'name_ru' => $nameRu, 'hours' => $hours, 'price' => $price, ]); $updated++; } else { $skipped++; } } else { Labor::withoutGlobalScope(TenantScope::class)->create([ 'company_id' => $company->id, 'category' => $catKey, 'code' => $code, 'name_ro' => $nameRu, 'name_ru' => $nameRu, 'pricing_mode' => 'hourly', 'hours' => $hours, 'price' => $price, 'is_active' => (bool) ($op['is_active'] ?? true), ]); $created++; } } $this->info("Done. Created: {$created}, Updated: {$updated}, Skipped: {$skipped}"); return 0; } }