tenant = Tenant::factory()->create(); $this->project = Project::factory()->create(['tenant_id' => $this->tenant->id]); }); /** Вставляет сделку напрямую (deals партиционирована, фабрики нет). */ function seedManagerDeal(int $tenantId, int $projectId, array $overrides = []): void { DB::table('deals')->insert(array_merge([ 'tenant_id' => $tenantId, 'project_id' => $projectId, 'phone' => '+7999'.random_int(1000000, 9999999), 'status' => 'new', 'received_at' => Carbon::now()->startOfMonth()->addDays(10), 'created_at' => Carbon::now(), 'updated_at' => Carbon::now(), ], $overrides)); } /** ReportJob без сохранения — провайдер читает только tenant_id + parameters. */ function managersJob(int $tenantId): ReportJob { return new ReportJob([ 'tenant_id' => $tenantId, 'type' => 'managers_summary', 'parameters' => [ 'format' => 'csv', 'date_from' => Carbon::now()->startOfMonth()->toDateString(), 'date_to' => Carbon::now()->endOfMonth()->toDateString(), ], ]); } test('headers: 4 колонки', function () { expect((new ManagersSummaryProvider)->headers()) ->toBe(['Менеджер', 'Всего сделок', 'Оплачено', 'Конверсия (%)']); }); test('slug = managers', function () { expect((new ManagersSummaryProvider)->slug())->toBe('managers'); }); test('агрегирует сделки по менеджеру: total, won, конверсия', function () { $manager = User::factory()->create([ 'tenant_id' => $this->tenant->id, 'first_name' => 'Иван', 'last_name' => 'Петров', ]); seedManagerDeal($this->tenant->id, $this->project->id, ['manager_id' => $manager->id, 'status' => 'won']); seedManagerDeal($this->tenant->id, $this->project->id, ['manager_id' => $manager->id, 'status' => 'won']); seedManagerDeal($this->tenant->id, $this->project->id, ['manager_id' => $manager->id, 'status' => 'new']); $rows = (new ManagersSummaryProvider)->rows(managersJob($this->tenant->id)); expect($rows)->toHaveCount(1); expect($rows[0])->toBe(['Иван Петров', 3, 2, 66.7]); }); test('сделки без менеджера → строка «Не назначен»', function () { seedManagerDeal($this->tenant->id, $this->project->id, ['manager_id' => null, 'status' => 'new']); $rows = (new ManagersSummaryProvider)->rows(managersJob($this->tenant->id)); expect($rows)->toHaveCount(1); expect($rows[0][0])->toBe('Не назначен'); }); test('исключает soft-deleted и тестовые сделки', function () { $manager = User::factory()->create(['tenant_id' => $this->tenant->id]); seedManagerDeal($this->tenant->id, $this->project->id, ['manager_id' => $manager->id]); seedManagerDeal($this->tenant->id, $this->project->id, ['manager_id' => $manager->id, 'deleted_at' => Carbon::now()]); seedManagerDeal($this->tenant->id, $this->project->id, ['manager_id' => $manager->id, 'is_test' => true]); $rows = (new ManagersSummaryProvider)->rows(managersJob($this->tenant->id)); expect($rows)->toHaveCount(1); expect($rows[0][1])->toBe(1); }); test('изолирует по tenant_id', function () { $other = Tenant::factory()->create(); $otherProject = Project::factory()->create(['tenant_id' => $other->id]); seedManagerDeal($other->id, $otherProject->id); $rows = (new ManagersSummaryProvider)->rows(managersJob($this->tenant->id)); expect($rows)->toBe([]); });