371 خطوط
14 KiB
PHP
371 خطوط
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(),
|
|
],
|
|
]);
|
|
}
|
|
}
|