app->instance(LeadPromoCodeAllocator::class, new class extends LeadPromoCodeAllocator { public function ensureCodes(UserLead $lead, LeadCohort $cohort): void { $lead->forceFill([ 'promo_code_monthly' => $lead->promo_code_monthly ?? 'WM-FAKE-M-'.substr($lead->id, 0, 4), 'promo_code_yearly' => $lead->promo_code_yearly ?? 'WM-FAKE-Y-'.substr($lead->id, 0, 4), ])->save(); } }); }); it('sends invitations to the next batch ordered by position', function (): void { UserLead::factory()->count(15)->state(new Sequence( ...array_map(fn (int $i) => ['position' => $i, 'email_verified_at' => now()], range(1, 15)), ))->create(); $this->artisan('leads:send-invitations', ['--limit' => 5, '--force' => true]) ->assertSuccessful(); Mail::assertQueued(UserLeadInvitation::class, 5); expect(UserLead::query()->whereNotNull('invitation_sent_at')->count())->toBe(5); $invited = UserLead::query()->whereNotNull('invitation_sent_at')->orderBy('position')->pluck('position')->all(); expect($invited)->toBe([1, 2, 3, 4, 5]); }); it('skips already-invited leads on subsequent runs', function (): void { UserLead::factory()->count(6)->state(new Sequence( ...array_map(fn (int $i) => ['position' => $i, 'email_verified_at' => now()], range(1, 6)), ))->create(); UserLead::query()->where('position', 1)->update(['invitation_sent_at' => now()]); $this->artisan('leads:send-invitations', ['--limit' => 3, '--force' => true]) ->assertSuccessful(); $invited = UserLead::query()->whereNotNull('invitation_sent_at')->orderBy('position')->pluck('position')->all(); expect($invited)->toBe([1, 2, 3, 4]); }); it('ignores leads with null or zero position', function (): void { UserLead::factory()->ranked(1)->create(); UserLead::factory()->unverified()->create(); UserLead::withoutEvents(function (): void { UserLead::factory()->create(['position' => 0, 'email_verified_at' => now()]); }); $this->artisan('leads:send-invitations', ['--limit' => 50, '--force' => true]) ->assertSuccessful(); Mail::assertQueued(UserLeadInvitation::class, 1); }); it('records the cohort on each invited lead', function (): void { UserLead::factory()->count(12)->state(new Sequence( ...array_map(fn (int $i) => ['position' => $i, 'email_verified_at' => now()], range(1, 12)), ))->create(); $this->artisan('leads:send-invitations', ['--limit' => 12, '--force' => true]) ->assertSuccessful(); $cohorts = UserLead::query()->orderBy('position')->pluck('cohort')->all(); expect($cohorts[0])->toBe(LeadCohort::Founder); expect($cohorts[9])->toBe(LeadCohort::Founder); expect($cohorts[10])->toBe(LeadCohort::EarlyBird); });