feat(ticket): add cancel ticket functionality and corresponding tests

This commit is contained in:
ncoronel 2026-09-10 16:28:45 -03:00
parent de259f4286
commit beb5d18b29
4 changed files with 57 additions and 0 deletions

View File

@ -5,10 +5,12 @@ namespace App\Domains\Ticket\Controllers\AdminApp;
use App\Domains\Ticket\Requests\AdminAppTicketExportRequest;
use App\Domains\Ticket\Requests\AdminAppTicketIndexRequest;
use App\Domains\Ticket\Resources\AdminApp\AdminAppTicketCollection;
use App\Domains\Ticket\Resources\AdminApp\AdminAppTicketResource;
use App\Domains\Ticket\Services\AdminAppTicketExcelService;
use App\Domains\Ticket\Services\AdminAppTicketPdfService;
use App\Domains\Ticket\Services\AdminAppTicketService;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
@ -29,6 +31,13 @@ class TicketController extends Controller
);
}
public function cancel(Request $request, int $ticket): AdminAppTicketResource
{
$tenant = $request->user()->tenant()->firstOrFail();
return new AdminAppTicketResource($this->ticketService->cancel($tenant, $ticket));
}
public function downloadPdf(AdminAppTicketExportRequest $request): Response
{
$tenant = $request->user()->tenant()->firstOrFail();

View File

@ -75,6 +75,18 @@ class AdminAppTicketService
return $databaseSorted ? $tickets : $this->sortTickets($tickets, $tenant, $filters);
}
public function cancel(Tenant $tenant, int $ticketId): Ticket
{
$ticket = Ticket::query()
->where('tenant_code', $tenant->codigo)
->findOrFail($ticketId);
$ticket->markAsCancelled();
$ticket->save();
return $ticket->refresh()->load(self::RELATIONS);
}
/**
* @param array{q?: string|null, category?: string|null, product?: string|null, type?: string|null, date?: string|null, size?: string|null, status?: string|null, page?: int, per_page?: int} $filters
* @return Builder<Ticket>

View File

@ -9,6 +9,10 @@ Route::prefix('v1/adminapp/tenant')
Route::get('tickets', [TicketController::class, 'index'])
->middleware('tenant.menu:adminapp.tickets')
->name('adminapp.tickets.index');
Route::post('tickets/{ticket}/cancel', [TicketController::class, 'cancel'])
->whereNumber('ticket')
->middleware('tenant.menu:adminapp.tickets')
->name('adminapp.tickets.cancel');
Route::get('tickets/pdf', [TicketController::class, 'downloadPdf'])
->middleware('tenant.menu:adminapp.tickets')
->name('adminapp.tickets.pdf');

View File

@ -80,6 +80,38 @@ class AdminAppTicketControllerTest extends TestCase
->assertJsonPath('meta.total', 1);
}
public function test_it_cancels_a_ticket_from_the_authenticated_tenant(): void
{
$tenant = $this->createTenant('ticket-cancellation');
$admin = $this->createAdminAppUser($tenant);
$this->grantTicketsMenu($tenant);
Sanctum::actingAs($admin);
$ticket = $this->createTicket($tenant, $admin);
$this->postJson("/api/v1/adminapp/tenant/tickets/{$ticket->id}/cancel")
->assertOk()
->assertJsonPath('data.id', $ticket->id)
->assertJsonPath('data.status', Ticket::STATUS_CANCELLED)
->assertJsonPath('data.status_label', 'Cancelado');
$this->assertNotNull($ticket->fresh()->cancelled_at);
}
public function test_it_does_not_cancel_a_ticket_with_another_terminal_status(): void
{
$tenant = $this->createTenant('ticket-cancellation');
$admin = $this->createAdminAppUser($tenant);
$this->grantTicketsMenu($tenant);
Sanctum::actingAs($admin);
$ticket = $this->createTicket($tenant, $admin, ['disabled_at' => now()]);
$this->postJson("/api/v1/adminapp/tenant/tickets/{$ticket->id}/cancel")
->assertUnprocessable()
->assertJsonValidationErrors('status');
$this->assertNull($ticket->fresh()->cancelled_at);
}
public function test_it_searches_by_id_and_does_not_search_by_uuid(): void
{
$tenant = $this->createTenant('fiesta_futbol_infantil');