resolveUnitId($user); $startDate = $filters['contract_start_date'] ?? null; $endDate = $filters['contract_end_date'] ?? null; return Student::where('unit_id', $unitId) ->when($startDate || $endDate, function ($query) use ($startDate, $endDate) { $query->whereHas('contracts', function ($contractQuery) use ($startDate, $endDate) { $contractQuery->where('status', 'active'); if ($endDate) { $contractQuery->where('started_date', '<=', $endDate); } if ($startDate) { $contractQuery->where(function ($periodQuery) use ($startDate) { $periodQuery ->whereNull('end_date') ->orWhere('end_date', '>=', $startDate); }); } }); }) ->orderBy('created_at', 'desc') ->get(); } public function getFranchisorActive(array $unitIds = []): Collection { return Student::with('unit') ->whereHas('contracts', fn ($q) => $q->where('status', 'active')) ->when(!empty($unitIds), fn ($q) => $q->whereIn('unit_id', $unitIds)) ->orderBy('name') ->get(); } public function getFranchisorStudentDetail(int $id): ?array { $student = Student::with('unit')->find($id); if (!$student) { return null; } $contract = StudentContract::where('student_id', $id) ->where('status', 'active') ->first(); return [ 'id' => $student->id, 'name' => $student->name, 'phone' => $student->phone, 'unit' => $student->unit ? ['fantasy_name' => $student->unit->fantasy_name] : null, 'protocol' => $contract?->protocol, ]; } public function getFranchisorSummary(array $unitIds = []): array { $query = Student::query()->when(!empty($unitIds), fn ($q) => $q->whereIn('unit_id', $unitIds)); $total = $query->count(); $active = (clone $query)->where('status', 'active')->count(); return ['total' => $total, 'active' => $active]; } public function findById(int $id): ?Student { return Student::find($id); } public function create(User $user, array $data): Student { $token = $data['registration_draft_token'] ?? null; $responsibleData = $data['responsible'] ?? null; $avatar = $data['avatar'] ?? null; unset($data['registration_draft_token'], $data['responsible']); if ($token === null) { return $this->registrationDraftService->executeWithoutDraft( $user, $data, fn (array $studentData, int $unitId): Student => $this->persistStudent( $studentData, $responsibleData, $unitId, ), ); } return $this->registrationDraftService->consume( $user, $token, function (array $studentData, int $unitId) use ($responsibleData, $avatar): Student { if ($avatar !== null) { $studentData['avatar'] = $avatar; } return $this->persistStudent($studentData, $responsibleData, $unitId); }, ); } private function persistStudent(array $data, ?array $responsibleData, int $unitId): Student { $data = $this->handlePhoto($data); return DB::transaction(function () use ($data, $responsibleData, $unitId): Student { $student = (new Student) ->fill(array_merge($data, ['unit_id' => $unitId])) ->withResponsibleForCreation($responsibleData); $student->save(); if ($responsibleData !== null) { $student->responsibles()->create($responsibleData); } return $student->load('responsibles'); }); } public function update(int $id, array $data): ?Student { $model = $this->findById($id); if (!$model) { return null; } $data = $this->handlePhoto($data, $model->photo_url); $model->update($data); return $model->fresh(); } public function delete(int $id): bool { return DB::transaction(function () use ($id): bool { $model = Student::query()->lockForUpdate()->find($id); if (!$model) { return false; } $contracts = $model->contracts() ->lockForUpdate() ->get(['id', 'status']); if ($contracts->contains('status', 'active')) { throw ValidationException::withMessages([ 'student' => __('validation.student_has_active_contracts'), ]); } $photoUrl = $model->photo_url; $deleted = $model->delete(); if ($deleted && $photoUrl) { DB::afterCommit(fn () => Storage::delete($photoUrl)); } return $deleted; }); } // private function handlePhoto(array $data, ?string $oldPhotoPath = null): array { if (!isset($data['avatar'])) { return $data; } if ($data['avatar'] instanceof UploadedFile) { if ($oldPhotoPath) { Storage::delete($oldPhotoPath); } $data['photo_url'] = $data['avatar']->store('students/photos'); } elseif (is_null($data['avatar'])) { if ($oldPhotoPath) { Storage::delete($oldPhotoPath); } $data['photo_url'] = null; } unset($data['avatar']); return $data; } private function resolveUnitId(User $user): int { $activeUnitId = request()->input('active_unit_id'); if ($activeUnitId) { $unit = $user->units()->where('units.id', $activeUnitId)->first(); abort_if(!$unit, 403, 'Unidade não autorizada para este usuário.'); return $unit->id; } $unit = $user->units()->first(); abort_if(!$unit, 403, 'Usuário sem unidade associada.'); return $unit->id; } }