PM_Console/backend/app/Http/Controllers/Api/DepartmentController.php

373 خطوط
14 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Department;
use App\Models\User;
use App\Services\ActivityLogService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
class DepartmentController extends Controller
{
public function __construct(protected ActivityLogService $activityLogService) {}
public function index(): JsonResponse
{
try {
$departments = Department::with(['manager', 'children', 'members'])->orderBy('sort_order')->get();
$departmentIds = $departments->pluck('id');
$tree = $departments
->filter(fn ($department) => $department->parent_id === null || ! $departmentIds->contains($department->parent_id))
->values()
->map(fn ($d) => $this->formatNode($d, $departments));
return response()->json([
'success' => true,
'data' => $tree,
'flat' => $departments->values()->map(fn ($d) => [
'id' => $d->id,
'name' => $d->name,
'type' => $d->type ?? 'department',
'parent_id' => $d->parent_id,
'parent_name' => $departments->firstWhere('id', $d->parent_id)?->name,
'children_count' => $departments->where('parent_id', $d->id)->count(),
]),
'message' => 'ساختار سازمانی',
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'خطا در دریافت ساختار سازمانی',
], 500);
}
}
private function formatNode($dept, $all): array
{
$children = $all->where('parent_id', $dept->id)->values();
return [
'id' => $dept->id,
'name' => $dept->name,
'description' => $dept->description,
'type' => $dept->type ?? 'department',
'parent_id' => $dept->parent_id,
'manager' => $dept->manager ? ['id' => $dept->manager->id, 'name' => $dept->manager->name] : null,
'manager_id' => $dept->manager_id,
'manager_changed_at' => $dept->manager_changed_at,
'is_active' => $dept->is_active,
'sort_order' => $dept->sort_order,
'users_count' => $dept->members()->count() ?: $dept->users()->count(),
'children' => $children->map(fn ($c) => $this->formatNode($c, $all)),
];
}
public function store(Request $request): JsonResponse
{
try {
$request->validate([
'name' => 'required|string|max:255',
'description' => 'nullable|string',
'type' => 'nullable|string|in:organization,department,unit,team',
'parent_id' => 'nullable|exists:departments,id',
'manager_id' => 'nullable|exists:users,id',
'is_active' => 'nullable|boolean',
'sort_order' => 'nullable|integer',
]);
$data = $request->only(['name', 'description', 'type', 'parent_id', 'manager_id', 'is_active', 'sort_order']);
$data['type'] = $data['type'] ?? 'department';
$data['is_active'] = $data['is_active'] ?? true;
if (! empty($data['manager_id'])) {
$data['manager_changed_at'] = now();
}
$dept = Department::create($data);
$this->activityLogService->log(
$request->user()?->id,
'create_department',
"بخش {$dept->name} ایجاد شد",
'department',
$dept->id,
null,
null,
['new' => $dept->only(['name', 'type', 'parent_id', 'manager_id', 'is_active'])]
);
return response()->json([
'success' => true,
'data' => $dept->load('manager'),
'message' => 'دپارتمان با موفقیت ایجاد شد',
], 201);
} catch (ValidationException $e) {
throw $e;
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'خطا در ایجاد دپارتمان',
], 500);
}
}
public function show(Department $department): JsonResponse
{
try {
$department->load(['manager', 'parent', 'children']);
return response()->json([
'success' => true,
'data' => $department,
'message' => 'اطلاعات دپارتمان',
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'خطا در دریافت اطلاعات دپارتمان',
], 500);
}
}
public function update(Request $request, Department $department): JsonResponse
{
try {
$request->validate([
'name' => 'sometimes|required|string|max:255',
'description' => 'nullable|string',
'type' => 'nullable|string|in:organization,department,unit,team',
'parent_id' => 'nullable|exists:departments,id',
'manager_id' => 'nullable|exists:users,id',
'is_active' => 'nullable|boolean',
'sort_order' => 'nullable|integer',
]);
$old = $department->only(['name', 'description', 'type', 'parent_id', 'manager_id', 'is_active', 'sort_order']);
$payload = $request->only(['name', 'description', 'type', 'parent_id', 'manager_id', 'is_active', 'sort_order']);
if (array_key_exists('manager_id', $payload) && (int) $payload['manager_id'] !== (int) $department->manager_id) {
$payload['manager_changed_at'] = now();
}
$department->update($payload);
$changed = collect($payload)
->except('manager_changed_at')
->filter(fn ($value, $key) => array_key_exists($key, $old) && $old[$key] != $department->{$key})
->map(fn ($value, $key) => ['old' => $old[$key], 'new' => $department->{$key}])
->all();
if (! empty($changed)) {
$this->activityLogService->log(
$request->user()?->id,
array_key_exists('manager_id', $changed) ? 'change_department_manager' : 'update_department',
array_key_exists('manager_id', $changed)
? "مدیر بخش {$department->name} تغییر کرد"
: "بخش {$department->name} ویرایش شد",
'department',
$department->id,
null,
null,
['changes' => $changed]
);
}
return response()->json([
'success' => true,
'data' => $department->fresh()->load('manager'),
'message' => 'دپارتمان به‌روزرسانی شد',
]);
} catch (ValidationException $e) {
throw $e;
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'خطا در به‌روزرسانی دپارتمان',
], 500);
}
}
public function destroy(Request $request, Department $department): JsonResponse
{
try {
if ($department->children()->exists()) {
return response()->json([
'success' => false,
'message' => 'این دپارتمان دارای زیرمجموعه است. ابتدا زیرمجموعه‌ها را حذف کنید.',
], 400);
}
if ($department->members()->exists() || $department->users()->exists()) {
return response()->json([
'success' => false,
'message' => 'این بخش عضو دارد. ابتدا اعضا را منتقل کنید یا بخش را غیرفعال کنید.',
], 400);
}
$departmentName = $department->name;
$departmentId = $department->id;
$department->delete();
$this->activityLogService->log(
$request->user()?->id,
'delete_department',
"بخش {$departmentName} حذف شد",
'department',
$departmentId
);
return response()->json([
'success' => true,
'message' => 'دپارتمان حذف شد',
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'خطا در حذف دپارتمان',
], 500);
}
}
public function addMember(Request $request, Department $department): JsonResponse
{
try {
$request->validate([
'user_id' => 'required|exists:users,id',
'role_in_team' => 'nullable|string|max:255',
'is_primary' => 'nullable|boolean',
]);
$user = User::findOrFail($request->user_id);
$isPrimary = $request->boolean('is_primary');
$this->syncMember($department, $user, $request->role_in_team, $isPrimary);
$this->activityLogService->log(
$request->user()?->id,
'add_department_member',
"{$user->name} به {$department->name} اضافه شد",
'department',
$department->id,
null,
null,
['user_id' => $user->id, 'role_in_team' => $request->role_in_team, 'is_primary' => $isPrimary]
);
return response()->json(['success' => true, 'message' => 'عضو اضافه شد']);
} catch (ValidationException $e) {
throw $e;
} catch (\Exception $e) {
return response()->json(['success' => false, 'message' => 'خطا در افزودن عضو'], 500);
}
}
public function updateMember(Request $request, Department $department, User $user): JsonResponse
{
try {
$request->validate([
'role_in_team' => 'nullable|string|max:255',
'is_primary' => 'nullable|boolean',
]);
$isPrimary = $request->boolean('is_primary');
$this->syncMember($department, $user, $request->role_in_team, $isPrimary);
$this->activityLogService->log(
$request->user()?->id,
'update_department_member',
"عضویت {$user->name} در {$department->name} ویرایش شد",
'department',
$department->id,
null,
null,
['user_id' => $user->id, 'role_in_team' => $request->role_in_team, 'is_primary' => $isPrimary]
);
return response()->json(['success' => true, 'message' => 'عضویت به‌روزرسانی شد']);
} catch (ValidationException $e) {
throw $e;
} catch (\Exception $e) {
return response()->json(['success' => false, 'message' => 'خطا در به‌روزرسانی عضویت'], 500);
}
}
public function removeMember(Request $request, Department $department, User $user): JsonResponse
{
try {
$department->members()->detach($user->id);
if ((int) $user->department_id === (int) $department->id) {
$primary = $user->departments()->wherePivot('is_primary', true)->first();
$user->update([
'department_id' => $primary?->id,
'department' => $primary?->name,
]);
}
$this->activityLogService->log(
$request->user()?->id,
'remove_department_member',
"{$user->name} از {$department->name} حذف شد",
'department',
$department->id,
null,
null,
['user_id' => $user->id]
);
return response()->json(['success' => true, 'message' => 'عضو حذف شد']);
} catch (\Exception $e) {
return response()->json(['success' => false, 'message' => 'خطا در حذف عضو'], 500);
}
}
public function transferMember(Request $request, Department $department, User $user): JsonResponse
{
try {
$request->validate([
'target_department_id' => 'required|exists:departments,id',
'role_in_team' => 'nullable|string|max:255',
'is_primary' => 'nullable|boolean',
]);
$target = Department::findOrFail($request->target_department_id);
$department->members()->detach($user->id);
$this->syncMember($target, $user, $request->role_in_team, $request->boolean('is_primary', true));
$this->activityLogService->log(
$request->user()?->id,
'transfer_department_member',
"{$user->name} از {$department->name} به {$target->name} منتقل شد",
'department',
$department->id,
null,
null,
['user_id' => $user->id, 'from' => $department->id, 'to' => $target->id]
);
return response()->json(['success' => true, 'message' => 'عضو منتقل شد']);
} catch (ValidationException $e) {
throw $e;
} catch (\Exception $e) {
return response()->json(['success' => false, 'message' => 'خطا در انتقال عضو'], 500);
}
}
private function syncMember(Department $department, User $user, ?string $roleInTeam, bool $isPrimary): void
{
if ($isPrimary) {
DB::table('department_user')->where('user_id', $user->id)->update(['is_primary' => false]);
$user->update([
'department_id' => $department->id,
'department' => $department->name,
]);
}
$department->members()->syncWithoutDetaching([
$user->id => [
'role_in_team' => $roleInTeam,
'is_primary' => $isPrimary,
'joined_at' => now(),
],
]);
}
}