feat(tickets): enhance ticket search functionality and add ticket counts to response
This commit is contained in:
parent
c792e7d306
commit
ba0e2dd00c
|
|
@ -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));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue