customer = Customer::factory()->create(['fullname' => 'Nguyễn Văn A']); $role = Role::create(['name' => 'support', 'guard_name' => 'admin']); foreach (['support.view', 'support.edit'] as $permission) { $role->givePermissionTo(Permission::firstOrCreate(['name' => $permission, 'guard_name' => 'admin'])); } $this->admin = User::factory()->create(['username' => 'hotro']); $this->admin->assignRole($role); } private function makeTicket(string $status, array $attributes = []): Ticket { return Ticket::create(array_merge([ 'uuid' => (string) Str::uuid(), 'ticket_num' => 'TKT-' . Str::upper(Str::random(6)), 'subject' => 'Subject', 'description' => 'Description', 'status' => $status, 'room' => 'technical', 'customer_id' => $this->customer->id, ], $attributes)); } public function test_counts_only_open_and_pending_tickets(): void { foreach (['open', 'open', 'pending', 'resolved', 'closed'] as $status) { $this->makeTicket($status); } $this->actingAs($this->admin, 'admin') ->getJson('/api/v1/administrator/tickets/pending-count') ->assertOk() ->assertJsonPath('data.count', 3); } public function test_detail_returns_status_history_with_causer(): void { $ticket = $this->makeTicket('open'); $this->actingAs($this->admin, 'admin') ->patchJson("/api/v1/administrator/tickets/{$ticket->ticket_num}/status", ['status' => 'pending'])->assertOk(); $this->actingAs($this->admin, 'admin') ->patchJson("/api/v1/administrator/tickets/{$ticket->ticket_num}/status", ['status' => 'resolved'])->assertOk(); $history = $this->actingAs($this->admin, 'admin') ->getJson("/api/v1/administrator/tickets/{$ticket->ticket_num}") ->assertOk() ->json('data.status_history'); $this->assertSame( [['pending', 'resolved'], ['open', 'pending'], [null, 'open']], array_map(fn ($log) => [$log['from'], $log['to']], $history), ); $this->assertSame('hotro', $history[0]['causer_name']); $this->assertSame('admin', $history[0]['causer_type']); } public function test_exports_filtered_tickets_to_branded_excel(): void { $this->makeTicket('open', ['subject' => 'VPS không vào được', 'ticket_num' => 'TKT-EXPORT', 'data' => json_encode(['priority' => 'high'])]); $this->makeTicket('closed', ['subject' => 'Ticket khác']); $response = $this->actingAs($this->admin, 'admin') ->get('/api/v1/administrator/tickets/export?' . http_build_query(['filter' => 'vps', 'status' => ['open']])) ->assertOk(); $sheet = IOFactory::load($response->baseResponse->getFile()->getPathname())->getActiveSheet(); $this->assertSame('DANH SÁCH TICKET HỖ TRỢ', $sheet->getCell('A6')->getValue()); $this->assertSame('Mã ticket', $sheet->getCell('A7')->getValue()); $this->assertSame( ['TKT-EXPORT', 'VPS không vào được', 'Nguyễn Văn A', $this->customer->email, 'Kỹ thuật', 'Cao', 'Mở', 0], array_slice($sheet->rangeToArray('A8:J8', null, true, false)[0], 0, 8), ); $this->assertNull($sheet->getCell('A9')->getValue()); $this->actingAs(User::factory()->create(), 'admin') ->getJson('/api/v1/administrator/tickets/export') ->assertForbidden(); } }