seats->guardClient($emailField); $this->guardExpiry($expiresAt, active: true); $client = User::create([ 'type' => UserType::Client, 'active' => true, 'account_requested' => false, 'role_id' => Role::query()->where('name', SystemRole::Client->value)->value('id'), 'name' => $name, 'email' => $email, 'password' => $password, 'storage_quota_mb' => $storageQuotaMb, ]); // forceFill, and not part of the create() array above: like // StaffAccounts, email_verified_at is deliberately absent from // User::$fillable — where an account stands is a security decision // rather than an attribute — so mass assignment drops it in // silence. Every client-creation path used to pass it in that // array and lose it. The intent is real: an account created by // somebody who already knows who this is has no address to // confirm and nobody to confirm it to. (Inert today, since // MustVerifyEmail is not enabled on the model, but the column is // what a later switch would read.) // // expires_at is written the same way for its own reason: see the // note on its cast in User. $client->forceFill(['email_verified_at' => now(), 'expires_at' => $expiresAt])->save(); $this->activity->log(Action::UserCreated, subject: $client); if ($welcome && $this->settings->get(Setting::EmailNotificationsEnabled) === true) { $client->notify(new ClientWelcomeNotification); } return $client; } /** * An account cannot be both active and past its expiry date. * * Every surface that writes either value asks this before saving, * because the combination is not a state anybody means: an account * that looks switched on and refuses every sign-in, until the hourly * sweep quietly switches it off again. Somebody reactivating an * expired client has to give them a new date, or none. */ public function guardExpiry(?Carbon $expiresAt, bool $active, string $field = 'expires_at'): void { if ($active && $expiresAt !== null && $expiresAt->isPast()) { throw ValidationException::withMessages([ $field => __('This date has already passed. Choose a later date, or leave it empty for an account that never expires.'), ]); } } }