feat(tickets): enhance ticket search functionality and add ticket counts to response

This commit is contained in:
ncoronel 2026-08-28 15:14:11 -03:00
parent c792e7d306
commit ba0e2dd00c
5 changed files with 85 additions and 26 deletions

View File

@ -3,21 +3,20 @@
namespace App\Domains\Ticket\Controllers\AdminApp; namespace App\Domains\Ticket\Controllers\AdminApp;
use App\Domains\Ticket\Requests\AdminAppTicketIndexRequest; use App\Domains\Ticket\Requests\AdminAppTicketIndexRequest;
use App\Domains\Ticket\Resources\TicketResource; use App\Domains\Ticket\Resources\AdminApp\AdminAppTicketCollection;
use App\Domains\Ticket\Services\AdminAppTicketService; use App\Domains\Ticket\Services\AdminAppTicketService;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
class TicketController extends Controller class TicketController extends Controller
{ {
public function __construct(private readonly AdminAppTicketService $ticketService) {} public function __construct(private readonly AdminAppTicketService $ticketService) {}
public function index(AdminAppTicketIndexRequest $request): AnonymousResourceCollection public function index(AdminAppTicketIndexRequest $request): AdminAppTicketCollection
{ {
$tenant = $request->user()->tenant()->firstOrFail(); $tenant = $request->user()->tenant()->firstOrFail();
return TicketResource::collection( return new AdminAppTicketCollection(
$this->ticketService->list($tenant, $request->validated()) $this->ticketService->search($tenant, $request->validated())
)->additional($this->ticketService->counts($tenant)); );
} }
} }

View File

@ -0,0 +1,35 @@
<?php
namespace App\Domains\Ticket\Resources\AdminApp;
use App\Domains\Ticket\Resources\TicketResource;
use App\Domains\Ticket\Services\AdminAppTicketResult;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\ResourceCollection;
class AdminAppTicketCollection extends ResourceCollection
{
/** @var class-string<TicketResource> */
public $collects = TicketResource::class;
private readonly int $scannedTickets;
private readonly int $totalTickets;
public function __construct(AdminAppTicketResult $result)
{
parent::__construct($result->tickets);
$this->scannedTickets = $result->scannedTickets;
$this->totalTickets = $result->totalTickets;
}
/** @return array{scanned_tickets: int, total_tickets: int} */
public function with(Request $request): array
{
return [
'scanned_tickets' => $this->scannedTickets,
'total_tickets' => $this->totalTickets,
];
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Domains\Ticket\Services;
use App\Domains\Ticket\Models\Ticket;
use Illuminate\Pagination\LengthAwarePaginator;
final readonly class AdminAppTicketResult
{
/** @param LengthAwarePaginator<Ticket> $tickets */
public function __construct(
public LengthAwarePaginator $tickets,
public int $scannedTickets,
public int $totalTickets,
) {}
}

View File

@ -5,26 +5,39 @@ namespace App\Domains\Ticket\Services;
use App\Domains\Tenant\Models\Tenant; use App\Domains\Tenant\Models\Tenant;
use App\Domains\Ticket\Models\Ticket; use App\Domains\Ticket\Models\Ticket;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Pagination\LengthAwarePaginator;
class AdminAppTicketService class AdminAppTicketService
{ {
/** @return array{scanned_tickets: int, total_tickets: int} */ /**
public function counts(Tenant $tenant): array * @param array{q?: string|null, page?: int, per_page?: int} $filters
*/
public function search(Tenant $tenant, array $filters = []): AdminAppTicketResult
{ {
$query = Ticket::query()->where('tenant_code', $tenant->codigo); $query = $this->baseQuery($tenant, $filters);
return [ $tickets = (clone $query)
'scanned_tickets' => (clone $query)->whereNotNull('used_at')->count(), ->with([
'total_tickets' => $query->count(), ...TicketValidityResolver::RELATIONS,
]; ...TicketPresentationResolver::RELATIONS,
'user',
'sourceCatalogItem.category',
])
->orderByDesc('id')
->paginateFromRequest()
->withQueryString();
return new AdminAppTicketResult(
tickets: $tickets,
scannedTickets: (clone $query)->whereNotNull('used_at')->count(),
totalTickets: $tickets->total(),
);
} }
/** /**
* @param array{q?: string|null, page?: int, per_page?: int} $filters * @param array{q?: string|null, page?: int, per_page?: int} $filters
* @return LengthAwarePaginator<Ticket> * @return Builder<Ticket>
*/ */
public function list(Tenant $tenant, array $filters = []): LengthAwarePaginator private function baseQuery(Tenant $tenant, array $filters): Builder
{ {
$search = trim((string) ($filters['q'] ?? '')); $search = trim((string) ($filters['q'] ?? ''));
@ -38,15 +51,6 @@ class AdminAppTicketService
fn (Builder $searchQuery): Builder => $searchQuery fn (Builder $searchQuery): Builder => $searchQuery
->where('ticket', 'like', "%{$search}%"), ->where('ticket', 'like', "%{$search}%"),
); );
}) });
->with([
...TicketValidityResolver::RELATIONS,
...TicketPresentationResolver::RELATIONS,
'user',
'sourceCatalogItem.category',
])
->orderByDesc('id')
->paginateFromRequest()
->withQueryString();
} }
} }

View File

@ -98,6 +98,11 @@ class AdminAppTicketControllerTest extends TestCase
$this->getJson('/api/v1/adminapp/tenant/tickets?q=does-not-match') $this->getJson('/api/v1/adminapp/tenant/tickets?q=does-not-match')
->assertOk() ->assertOk()
->assertJsonCount(0, 'data') ->assertJsonCount(0, 'data')
->assertJsonPath('scanned_tickets', 0)
->assertJsonPath('total_tickets', 0);
$this->getJson('/api/v1/adminapp/tenant/tickets')
->assertOk()
->assertJsonPath('scanned_tickets', 1) ->assertJsonPath('scanned_tickets', 1)
->assertJsonPath('total_tickets', 2); ->assertJsonPath('total_tickets', 2);
} }