join('courses', 'courses.id', '=', 'course_signs.course_id') ->whereNull('courses.deleted_at') ->whereIn('courses.id', (clone $courses)->select('courses.id')) ->where('course_signs.status', 1) ->select('course_signs.user_id') ->selectRaw('MIN(courses.start_date) as source_start_date') ->groupBy('course_signs.user_id'); return User::query() ->joinSub($sources, 'schoolmate_sources', function ($join) { $join->on('users.id', '=', 'schoolmate_sources.user_id'); }) ->whereRaw('COALESCE(users.is_schoolmate, 0) != 1') ->select('users.*', 'schoolmate_sources.source_start_date'); } public function automaticCourses() { // 保留开课前一天入库的原行为,同时补查历史及开课后审核通过的学员。 return Course::where('auto_schoolmate', 1) ->whereNotNull('start_date') ->whereDate('start_date', '<=', now()->addDay()->toDateString()); } public function promote(int $userId, string $startDate): int { return DB::transaction(function () use ($userId, $startDate) { // 手工补齐和自动任务同时运行时,不覆盖已有校友的入库时间。 $user = User::whereKey($userId)->lockForUpdate()->first(); if (!$user || $user->is_schoolmate == 1) { return 0; } return User::batchUpdateToSchoolmate([$userId], $startDate); }); } }