Files
shopit-back/app/Domains/Ticket/Services/TicketGeneratorService.php

87 lines
2.8 KiB
PHP

<?php
namespace App\Domains\Ticket\Services;
use App\Domains\Auth\Models\User;
use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Ticket\Exceptions\TicketGenerationException;
use App\Domains\Ticket\Models\Ticket;
use Carbon\CarbonInterface;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class TicketGeneratorService
{
/**
* @return Collection<int, Ticket>
*/
public function generate(CatalogItem $catalogItem, User $user, int $quantity = 1): Collection
{
if ($quantity < 1) {
throw TicketGenerationException::invalidQuantity();
}
$now = now();
return DB::transaction(function () use ($catalogItem, $user, $quantity, $now): Collection {
$catalogItems = $this->resolveCatalogItems($catalogItem, $quantity, $now);
return $catalogItems->map(fn (CatalogItem $item): Ticket => Ticket::query()->create([
'tenant_code' => $item->tenant_code,
'ticket' => (string) Str::uuid(),
'name' => $item->nombre,
'description' => (string) ($item->descripcion ?? ''),
'starts_at' => $item->minimum_use_date,
'expires_at' => $item->maximum_use_date,
'used_at' => null,
'user_id' => $user->getKey(),
]));
});
}
/**
* @return Collection<int, CatalogItem>
*/
private function resolveCatalogItems(
CatalogItem $catalogItem,
int $quantity,
CarbonInterface $now,
): Collection {
if (! $catalogItem->isBundle()) {
$this->validateCatalogItem($catalogItem, $now);
return Collection::times($quantity, fn (): CatalogItem => $catalogItem);
}
$catalogItem->loadMissing('bundleComponents.catalogItem');
if ($catalogItem->bundleComponents->isEmpty()) {
throw TicketGenerationException::emptyBundle($catalogItem);
}
return $catalogItem->bundleComponents
->flatMap(function ($component) use ($quantity, $now): Collection {
$componentItem = $component->catalogItem;
$this->validateCatalogItem($componentItem, $now);
return Collection::times(
$quantity * $component->quantity,
fn (): CatalogItem => $componentItem,
);
})
->values();
}
private function validateCatalogItem(CatalogItem $catalogItem, CarbonInterface $now): void
{
if (! $catalogItem->has_tickets) {
throw TicketGenerationException::ticketsDisabled($catalogItem);
}
if ($catalogItem->maximum_use_date?->lessThanOrEqualTo($now)) {
throw TicketGenerationException::maximumUseDateReached($catalogItem);
}
}
}