where('is_system', true) ->exists(); if (!$hasSystemCostCenter) { CostCenter::create([ 'user_id' => $userId, 'name' => 'Geral', 'code' => 'GERAL', 'description' => 'Centro de custo padrão para transações não categorizadas', 'color' => '#6c757d', 'icon' => 'FaFolder', 'is_active' => true, 'is_system' => true, ]); } $query = CostCenter::where('user_id', $userId) ->with('keywords'); if ($request->has('is_active')) { $query->where('is_active', $request->boolean('is_active')); } // Ordenar com centro de custo do sistema primeiro, depois por nome $costCenters = $query->orderByDesc('is_system')->orderBy('name')->get(); return response()->json([ 'success' => true, 'data' => $costCenters, ]); } /** * Criar novo centro de custo */ public function store(Request $request): JsonResponse { $validated = $request->validate([ 'name' => 'required|string|max:100', 'code' => 'nullable|string|max:20|unique:cost_centers,code,NULL,id,user_id,' . Auth::id(), 'description' => 'nullable|string', 'color' => 'nullable|string|max:7', 'icon' => 'nullable|string|max:50', 'is_active' => 'nullable|boolean', 'keywords' => 'nullable|array', 'keywords.*' => 'string|max:100', ]); $keywords = $validated['keywords'] ?? []; unset($validated['keywords']); $validated['user_id'] = Auth::id(); DB::beginTransaction(); try { $costCenter = CostCenter::create($validated); // Adicionar palavras-chave foreach ($keywords as $keyword) { $costCenter->keywords()->create([ 'keyword' => trim($keyword), 'is_case_sensitive' => false, 'is_active' => true, ]); } DB::commit(); return response()->json([ 'success' => true, 'message' => 'Centro de custo criado com sucesso', 'data' => $costCenter->load('keywords'), ], 201); } catch (\Exception $e) { DB::rollBack(); return response()->json([ 'success' => false, 'message' => 'Erro ao criar centro de custo: ' . $e->getMessage(), ], 500); } } /** * Exibir um centro de custo específico */ public function show(int $id): JsonResponse { $costCenter = CostCenter::where('user_id', Auth::id()) ->with('keywords') ->findOrFail($id); return response()->json([ 'success' => true, 'data' => $costCenter, ]); } /** * Atualizar um centro de custo */ public function update(Request $request, int $id): JsonResponse { $costCenter = CostCenter::where('user_id', Auth::id())->findOrFail($id); // Impedir edição de centro de custo do sistema if ($costCenter->is_system) { return response()->json([ 'success' => false, 'message' => 'O centro de custo do sistema não pode ser editado', ], 403); } $validated = $request->validate([ 'name' => 'sometimes|required|string|max:100', 'code' => 'nullable|string|max:20|unique:cost_centers,code,' . $id . ',id,user_id,' . Auth::id(), 'description' => 'nullable|string', 'color' => 'nullable|string|max:7', 'icon' => 'nullable|string|max:50', 'is_active' => 'nullable|boolean', 'keywords' => 'nullable|array', 'keywords.*' => 'string|max:100', ]); $keywords = $validated['keywords'] ?? null; unset($validated['keywords']); DB::beginTransaction(); try { $costCenter->update($validated); // Se keywords foram fornecidas, sincronizar if ($keywords !== null) { // Remover antigas $costCenter->keywords()->delete(); // Adicionar novas foreach ($keywords as $keyword) { $costCenter->keywords()->create([ 'keyword' => trim($keyword), 'is_case_sensitive' => false, 'is_active' => true, ]); } } DB::commit(); return response()->json([ 'success' => true, 'message' => 'Centro de custo atualizado com sucesso', 'data' => $costCenter->fresh()->load('keywords'), ]); } catch (\Exception $e) { DB::rollBack(); return response()->json([ 'success' => false, 'message' => 'Erro ao atualizar centro de custo: ' . $e->getMessage(), ], 500); } } /** * Deletar um centro de custo (soft delete) */ public function destroy(int $id): JsonResponse { $costCenter = CostCenter::where('user_id', Auth::id())->findOrFail($id); // Impedir exclusão de centro de custo do sistema if ($costCenter->is_system) { return response()->json([ 'success' => false, 'message' => 'O centro de custo do sistema não pode ser excluído', ], 403); } $costCenter->keywords()->delete(); $costCenter->delete(); return response()->json([ 'success' => true, 'message' => 'Centro de custo excluído com sucesso', ]); } /** * Adicionar palavra-chave a um centro de custo */ public function addKeyword(Request $request, int $id): JsonResponse { $costCenter = CostCenter::where('user_id', Auth::id())->findOrFail($id); $validated = $request->validate([ 'keyword' => 'required|string|max:100', 'is_case_sensitive' => 'nullable|boolean', ]); $keyword = $costCenter->keywords()->create([ 'keyword' => trim($validated['keyword']), 'is_case_sensitive' => $validated['is_case_sensitive'] ?? false, 'is_active' => true, ]); return response()->json([ 'success' => true, 'message' => 'Palavra-chave adicionada com sucesso', 'data' => $keyword, ], 201); } /** * Remover palavra-chave de um centro de custo */ public function removeKeyword(int $id, int $keywordId): JsonResponse { $costCenter = CostCenter::where('user_id', Auth::id())->findOrFail($id); $keyword = $costCenter->keywords()->findOrFail($keywordId); $keyword->delete(); return response()->json([ 'success' => true, 'message' => 'Palavra-chave removida com sucesso', ]); } /** * Encontrar centro de custo por texto (usando palavras-chave) */ public function matchByText(Request $request): JsonResponse { $validated = $request->validate([ 'text' => 'required|string', ]); $text = $validated['text']; $textLower = strtolower($text); $keywords = CostCenterKeyword::whereHas('costCenter', function ($query) { $query->where('user_id', Auth::id())->where('is_active', true); }) ->where('is_active', true) ->with('costCenter') ->get(); $matches = []; foreach ($keywords as $keyword) { $searchText = $keyword->is_case_sensitive ? $text : $textLower; $searchKeyword = $keyword->is_case_sensitive ? $keyword->keyword : strtolower($keyword->keyword); if (str_contains($searchText, $searchKeyword)) { $matches[] = [ 'cost_center' => $keyword->costCenter, 'matched_keyword' => $keyword->keyword, ]; } } return response()->json([ 'success' => true, 'data' => $matches, ]); } }