withCount('formulas') ->withCount(['formulas as active_formulas_count' => function ($q) { $q->where('is_active', true); }]); // 테넌트 필터 if ($tenantId && $tenantId !== 'all') { $query->where('tenant_id', $tenantId); } // 검색 if (! empty($filters['search'])) { $search = $filters['search']; $query->where(function ($q) use ($search) { $q->where('name', 'like', "%{$search}%") ->orWhere('code', 'like', "%{$search}%") ->orWhere('description', 'like', "%{$search}%"); }); } // 활성화 필터 if (isset($filters['is_active']) && $filters['is_active'] !== '') { $query->where('is_active', (bool) $filters['is_active']); } // 정렬 $sortBy = $filters['sort_by'] ?? 'sort_order'; $sortDirection = $filters['sort_direction'] ?? 'asc'; $query->orderBy($sortBy, $sortDirection); return $query->paginate($perPage); } /** * 전체 카테고리 목록 (선택용) */ public function getAllCategories(): Collection { $tenantId = session('selected_tenant_id'); return QuoteFormulaCategory::query() ->where('tenant_id', $tenantId) ->where('is_active', true) ->orderBy('sort_order') ->get(); } /** * 활성 카테고리 목록 (드롭다운용) */ public function getActiveCategories(): Collection { return $this->getAllCategories(); } /** * 카테고리 상세 조회 */ public function getCategoryById(int $id): ?QuoteFormulaCategory { return QuoteFormulaCategory::with('formulas')->find($id); } /** * 카테고리 생성 */ public function createCategory(array $data): QuoteFormulaCategory { $tenantId = session('selected_tenant_id'); return DB::transaction(function () use ($data, $tenantId) { // 자동 sort_order 할당 if (! isset($data['sort_order'])) { $maxOrder = QuoteFormulaCategory::where('tenant_id', $tenantId)->max('sort_order'); $data['sort_order'] = ($maxOrder ?? 0) + 1; } return QuoteFormulaCategory::create([ 'tenant_id' => $tenantId, 'code' => $data['code'], 'name' => $data['name'], 'description' => $data['description'] ?? null, 'sort_order' => $data['sort_order'], 'is_active' => $data['is_active'] ?? true, 'created_by' => auth()->id(), ]); }); } /** * 카테고리 수정 */ public function updateCategory(int $id, array $data): QuoteFormulaCategory { $category = QuoteFormulaCategory::findOrFail($id); $category->update([ 'code' => $data['code'] ?? $category->code, 'name' => $data['name'] ?? $category->name, 'description' => array_key_exists('description', $data) ? $data['description'] : $category->description, 'sort_order' => $data['sort_order'] ?? $category->sort_order, 'is_active' => $data['is_active'] ?? $category->is_active, 'updated_by' => auth()->id(), ]); return $category->fresh(); } /** * 카테고리 삭제 */ public function deleteCategory(int $id): void { $category = QuoteFormulaCategory::findOrFail($id); // 연관 수식이 있으면 삭제 불가 if ($category->formulas()->count() > 0) { throw new \Exception('연관된 수식이 있어 삭제할 수 없습니다. 먼저 수식을 삭제해주세요.'); } $category->delete(); } /** * 카테고리 순서 변경 */ public function reorderCategories(array $orderData): void { DB::transaction(function () use ($orderData) { foreach ($orderData as $item) { QuoteFormulaCategory::where('id', $item['id']) ->update(['sort_order' => $item['sort_order']]); } }); } /** * 카테고리 활성/비활성 토글 */ public function toggleActive(int $id): QuoteFormulaCategory { $category = QuoteFormulaCategory::findOrFail($id); $category->is_active = ! $category->is_active; $category->updated_by = auth()->id(); $category->save(); return $category; } /** * 코드 중복 체크 */ public function isCodeExists(string $code, ?int $excludeId = null): bool { $tenantId = session('selected_tenant_id'); $query = QuoteFormulaCategory::where('tenant_id', $tenantId) ->where('code', $code); if ($excludeId) { $query->where('id', '!=', $excludeId); } return $query->exists(); } /** * 카테고리 통계 */ public function getCategoryStats(): array { $tenantId = session('selected_tenant_id'); return [ 'total' => QuoteFormulaCategory::where('tenant_id', $tenantId)->count(), 'active' => QuoteFormulaCategory::where('tenant_id', $tenantId)->where('is_active', true)->count(), 'inactive' => QuoteFormulaCategory::where('tenant_id', $tenantId)->where('is_active', false)->count(), ]; } }