155 lines
5.9 KiB
PHP
155 lines
5.9 KiB
PHP
<?php
|
|
|
|
namespace App\Domains\Ticket\Services;
|
|
|
|
use App\Domains\Tenant\Models\Tenant;
|
|
use App\Domains\Ticket\Models\Ticket;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
|
|
class AdminAppTicketService
|
|
{
|
|
/**
|
|
* @param array{q?: string|null, category?: string|null, product?: string|null, type?: string|null, date?: string|null, status?: string|null, page?: int, per_page?: int} $filters
|
|
*/
|
|
public function search(Tenant $tenant, array $filters = []): AdminAppTicketResult
|
|
{
|
|
$query = $this->baseQuery($tenant, $filters);
|
|
|
|
$tickets = (clone $query)
|
|
->with([
|
|
...TicketValidityResolver::RELATIONS,
|
|
...TicketPresentationResolver::RELATIONS,
|
|
'user',
|
|
'scannerUser',
|
|
'sourceCatalogItem.category',
|
|
'sourcePurchase.items',
|
|
])
|
|
->orderByDesc('id')
|
|
->paginateFromRequest()
|
|
->withQueryString();
|
|
|
|
return new AdminAppTicketResult(
|
|
tickets: $tickets,
|
|
scannedTickets: (clone $query)->whereNotNull('used_at')->count(),
|
|
totalTickets: $tickets->total(),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param array{q?: string|null, category?: string|null, product?: string|null, type?: string|null, date?: string|null, status?: string|null, page?: int, per_page?: int} $filters
|
|
* @return Builder<Ticket>
|
|
*/
|
|
private function baseQuery(Tenant $tenant, array $filters): Builder
|
|
{
|
|
$search = trim((string) ($filters['q'] ?? ''));
|
|
|
|
$query = Ticket::query()
|
|
->where('tenant_code', $tenant->codigo)
|
|
->when($search !== '', function (Builder $query) use ($search): void {
|
|
$query->when(
|
|
ctype_digit($search),
|
|
fn (Builder $searchQuery): Builder => $searchQuery
|
|
->where('tickets.id', (int) $search),
|
|
fn (Builder $searchQuery): Builder => $searchQuery
|
|
->where('ticket', 'like', "%{$search}%"),
|
|
);
|
|
})
|
|
->when($filters['category'] ?? null, function (Builder $query, string $category): void {
|
|
$query->whereHas('sourceCatalogItem.category', fn (Builder $categoryQuery): Builder => $categoryQuery
|
|
->whereRaw('LOWER(nombre) = ?', [mb_strtolower(trim($category))]));
|
|
})
|
|
->when($filters['product'] ?? null, function (Builder $query, string $product) use ($filters): void {
|
|
$this->applyProductFilter($query, (string) ($filters['category'] ?? ''), $product);
|
|
})
|
|
->when($filters['type'] ?? null, function (Builder $query, string $type) use ($filters): void {
|
|
$this->applyTypeFilter($query, (string) ($filters['category'] ?? ''), $type);
|
|
})
|
|
->when($filters['date'] ?? null, fn (Builder $query, string $date): Builder => $query
|
|
->whereHas('sourcePurchase', fn (Builder $purchaseQuery): Builder => $purchaseQuery
|
|
->whereDate('created_at', $date)));
|
|
|
|
$this->applyStatusFilter($query, $filters['status'] ?? null);
|
|
|
|
return $query;
|
|
}
|
|
|
|
/** @param Builder<Ticket> $query */
|
|
private function applyProductFilter(Builder $query, string $category, string $product): void
|
|
{
|
|
$category = $this->normalizedCategory($category);
|
|
|
|
if (in_array($category, ['alojamientos', 'camping'], true)) {
|
|
$this->whereVariantDefinition($query, 'tipo_alojamiento', $product);
|
|
|
|
return;
|
|
}
|
|
|
|
if (in_array($category, ['comidas', 'comida'], true)) {
|
|
$query->whereHas('sourceVariant', function (Builder $variantQuery) use ($product): void {
|
|
$variantQuery->where(function (Builder $dateQuery) use ($product): void {
|
|
$dateQuery
|
|
->where('event_date_id', $product)
|
|
->orWhereHas('eventDates', fn (Builder $eventDateQuery): Builder => $eventDateQuery
|
|
->whereKey($product));
|
|
});
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
$query->whereHas('sourceCatalogItem', fn (Builder $itemQuery): Builder => $itemQuery
|
|
->where('slug', $product));
|
|
}
|
|
|
|
/** @param Builder<Ticket> $query */
|
|
private function applyTypeFilter(Builder $query, string $category, string $type): void
|
|
{
|
|
$attribute = match ($this->normalizedCategory($category)) {
|
|
'comidas', 'comida' => 'horario',
|
|
'merchandising' => 'color',
|
|
default => null,
|
|
};
|
|
|
|
if ($attribute !== null) {
|
|
$this->whereVariantDefinition($query, $attribute, $type);
|
|
}
|
|
}
|
|
|
|
/** @param Builder<Ticket> $query */
|
|
private function whereVariantDefinition(Builder $query, string $attribute, string $value): void
|
|
{
|
|
$query->whereHas('sourceVariant.definitions', fn (Builder $definitionQuery): Builder => $definitionQuery
|
|
->where('value', $value)
|
|
->whereHas('itemAttribute.attribute', fn (Builder $attributeQuery): Builder => $attributeQuery
|
|
->where('codigo', $attribute)));
|
|
}
|
|
|
|
/** @param Builder<Ticket> $query */
|
|
private function applyStatusFilter(Builder $query, ?string $status): void
|
|
{
|
|
if ($status === null || $status === '') {
|
|
return;
|
|
}
|
|
|
|
if ($status === Ticket::STATUS_USED) {
|
|
$query->whereNotNull('used_at');
|
|
|
|
return;
|
|
}
|
|
|
|
$matchingIds = (clone $query)
|
|
->whereNull('used_at')
|
|
->with(TicketValidityResolver::RELATIONS)
|
|
->get()
|
|
->filter(fn (Ticket $ticket): bool => $ticket->status === $status)
|
|
->pluck('id');
|
|
|
|
$query->whereIn('tickets.id', $matchingIds);
|
|
}
|
|
|
|
private function normalizedCategory(string $category): string
|
|
{
|
|
return mb_strtolower(trim($category));
|
|
}
|
|
}
|