refactor(event): move event configuration onto tenant
This commit is contained in:
@@ -7,7 +7,6 @@ use App\Domains\Catalog\Enums\CatalogItemType;
|
||||
use App\Domains\Catalog\Enums\EventProductType;
|
||||
use App\Domains\Catalog\Enums\InventoryPolicy;
|
||||
use App\Domains\Catalog\Services\CatalogInventoryService;
|
||||
use App\Domains\Event\Models\Event;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticket\Models\Ticket;
|
||||
use App\Domains\Ticket\Models\ValidityTime;
|
||||
@@ -20,7 +19,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
#[Fillable([
|
||||
'tenant_code',
|
||||
'event_id',
|
||||
'event_product_type',
|
||||
'category_id',
|
||||
'brand_id',
|
||||
@@ -55,7 +53,6 @@ class CatalogItem extends Model
|
||||
'category_id' => 'integer',
|
||||
'brand_id' => 'integer',
|
||||
'inventory_id' => 'integer',
|
||||
'event_id' => 'integer',
|
||||
'event_product_type' => EventProductType::class,
|
||||
'type' => CatalogItemType::class,
|
||||
'precio' => 'decimal:2',
|
||||
@@ -72,12 +69,6 @@ class CatalogItem extends Model
|
||||
return $this->belongsTo(Tenant::class, 'tenant_code', 'codigo');
|
||||
}
|
||||
|
||||
/** @return BelongsTo<Event, $this> */
|
||||
public function event(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Event::class);
|
||||
}
|
||||
|
||||
/** @return BelongsTo<Category, $this> */
|
||||
public function category(): BelongsTo
|
||||
{
|
||||
|
||||
@@ -26,18 +26,9 @@ class StoreCatalogItemRequest extends FormRequest
|
||||
return [
|
||||
'tenant_code' => ['prohibited'],
|
||||
'type' => ['sometimes', Rule::enum(CatalogItemType::class)],
|
||||
'event_id' => [
|
||||
'sometimes',
|
||||
'nullable',
|
||||
'required_with:event_product_type',
|
||||
Rule::exists('events', 'id')->where(
|
||||
fn ($query) => $query->where('tenant_code', $tenantCode)
|
||||
),
|
||||
],
|
||||
'event_product_type' => [
|
||||
'sometimes',
|
||||
'nullable',
|
||||
'required_with:event_id',
|
||||
Rule::enum(EventProductType::class),
|
||||
],
|
||||
'category_id' => [
|
||||
@@ -93,7 +84,7 @@ class StoreCatalogItemRequest extends FormRequest
|
||||
'nullable',
|
||||
'integer',
|
||||
Rule::exists('event_dates', 'id')->where(
|
||||
fn ($query) => $query->where('event_id', $this->input('event_id'))
|
||||
fn ($query) => $query->where('tenant_code', $tenantCode)
|
||||
),
|
||||
],
|
||||
'variants.*.inventory_id' => ['prohibited'],
|
||||
|
||||
@@ -23,7 +23,6 @@ class CatalogItemDetailResource extends JsonResource
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'type' => $this->type->value,
|
||||
'event_id' => $this->event_id,
|
||||
'event_product_type' => $this->event_product_type?->value,
|
||||
'category_id' => $this->category_id,
|
||||
'brand_id' => $this->brand_id,
|
||||
@@ -38,9 +37,7 @@ class CatalogItemDetailResource extends JsonResource
|
||||
'has_tickets' => $this->has_tickets,
|
||||
'validity_time_id' => $this->validity_time_id,
|
||||
'validity_time' => ValidityTimeResource::make($this->validityTime),
|
||||
'attributes' => $this->itemAttributes
|
||||
->map(fn (ItemAttribute $itemAttribute): array => $this->attributeData($itemAttribute))
|
||||
->values(),
|
||||
'attributes' => $this->attributesData(),
|
||||
'stock_tecnico' => $this->when(
|
||||
$selectedVariant === null,
|
||||
fn () => $this->availableStock(),
|
||||
@@ -111,19 +108,70 @@ class CatalogItemDetailResource extends JsonResource
|
||||
];
|
||||
}
|
||||
|
||||
/** @return Collection<int, array<string, mixed>> */
|
||||
private function attributesData(): Collection
|
||||
{
|
||||
$attributes = $this->itemAttributes
|
||||
->map(fn (ItemAttribute $itemAttribute): array => $this->attributeData($itemAttribute));
|
||||
|
||||
if ($this->variants->isEmpty() || $this->variants->contains(
|
||||
fn (Variant $variant): bool => $variant->event_date_id === null
|
||||
)) {
|
||||
return $attributes->values();
|
||||
}
|
||||
|
||||
$eventDateAttribute = [
|
||||
'id' => -1,
|
||||
'codigo' => 'event_date',
|
||||
'nombre' => 'Fecha',
|
||||
'is_required' => true,
|
||||
'metadata_schema' => null,
|
||||
'type' => 'event_date',
|
||||
'options' => $this->variants
|
||||
->pluck('eventDate')
|
||||
->filter()
|
||||
->unique('id')
|
||||
->sortBy(fn ($eventDate): string => $eventDate->date->format('Y-m-d').' '.$eventDate->time_start)
|
||||
->values()
|
||||
->map(fn ($eventDate, int $index): array => [
|
||||
'id' => $eventDate->id,
|
||||
'value' => (string) $eventDate->id,
|
||||
'label' => $eventDate->date->format('d/m/Y').' · '
|
||||
.substr($eventDate->time_start, 0, 5).' a '
|
||||
.substr($eventDate->time_end, 0, 5),
|
||||
'sort_order' => $index,
|
||||
'validity_time_id' => null,
|
||||
'validity_time' => null,
|
||||
'metadata' => [
|
||||
'date' => $eventDate->date->format('Y-m-d'),
|
||||
'time_start' => $eventDate->time_start,
|
||||
'time_end' => $eventDate->time_end,
|
||||
],
|
||||
]),
|
||||
];
|
||||
|
||||
return collect([$eventDateAttribute])->concat($attributes)->values();
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
private function variantData(Variant $variant): array
|
||||
{
|
||||
$values = $variant->definitions
|
||||
->mapWithKeys(fn ($definition) => [
|
||||
$definition->itemAttribute?->attribute?->codigo => $definition->value,
|
||||
])
|
||||
->filter(fn ($value, $key): bool => $key !== null);
|
||||
|
||||
if ($variant->event_date_id !== null) {
|
||||
$values->put('event_date', (string) $variant->event_date_id);
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $variant->id,
|
||||
'event_date_id' => $variant->event_date_id,
|
||||
'event_date' => $variant->eventDate?->date?->format('Y-m-d'),
|
||||
'stock_tecnico' => $this->variantStock($variant),
|
||||
'values' => $variant->definitions
|
||||
->mapWithKeys(fn ($definition) => [
|
||||
$definition->itemAttribute?->attribute?->codigo => $definition->value,
|
||||
])
|
||||
->filter(fn ($value, $key): bool => $key !== null),
|
||||
'values' => $values,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ class CatalogItemResource extends JsonResource
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'type' => $this->type->value,
|
||||
'event_id' => $this->event_id,
|
||||
'event_product_type' => $this->event_product_type?->value,
|
||||
'category_id' => $this->category_id,
|
||||
'brand_id' => $this->brand_id,
|
||||
|
||||
@@ -12,7 +12,6 @@ use App\Domains\Catalog\Models\Category;
|
||||
use App\Domains\Catalog\Models\Inventory;
|
||||
use App\Domains\Catalog\Models\ItemAttribute;
|
||||
use App\Domains\Catalog\Models\Variant;
|
||||
use App\Domains\Event\Models\Event;
|
||||
use App\Domains\Event\Models\EventDate;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
@@ -47,7 +46,14 @@ class CatalogService
|
||||
);
|
||||
$hasVariants = $attributeCodes !== [] || $hasEventDateVariants;
|
||||
|
||||
$this->validateEventData($data);
|
||||
if ($hasEventDateVariants && in_array('event_date', $attributeCodes, true)) {
|
||||
throw ValidationException::withMessages([
|
||||
'attribute_codes' => ['The event_date code is reserved for event dates.'],
|
||||
]);
|
||||
}
|
||||
|
||||
$this->validateEventProductType($data);
|
||||
$this->validateUniqueVariantCombinations($variants, $attributeCodes);
|
||||
|
||||
if ($type === CatalogItemType::Bundle) {
|
||||
$this->validateBundleData($data, $components);
|
||||
@@ -127,7 +133,6 @@ class CatalogService
|
||||
'inventory',
|
||||
'category',
|
||||
'brand',
|
||||
'event',
|
||||
'validityTime',
|
||||
'itemAttributes.attribute',
|
||||
'variants.inventory',
|
||||
@@ -147,7 +152,6 @@ class CatalogService
|
||||
'inventory',
|
||||
'category',
|
||||
'brand',
|
||||
'event',
|
||||
'validityTime',
|
||||
'itemAttributes.attribute.options.validityTime',
|
||||
'variants' => fn ($query) => $query->orderBy('id'),
|
||||
@@ -492,16 +496,15 @@ class CatalogService
|
||||
if (
|
||||
$eventDateId !== null
|
||||
&& (
|
||||
$catalogItem->event_id === null
|
||||
|| ! EventDate::query()
|
||||
! EventDate::query()
|
||||
->whereKey($eventDateId)
|
||||
->where('event_id', $catalogItem->event_id)
|
||||
->where('tenant_code', $catalogItem->tenant_code)
|
||||
->exists()
|
||||
)
|
||||
) {
|
||||
throw ValidationException::withMessages([
|
||||
"variants.{$index}.event_date_id" => [
|
||||
'The event date must belong to the catalog item event.',
|
||||
'The event date must belong to the catalog item tenant.',
|
||||
],
|
||||
]);
|
||||
}
|
||||
@@ -533,30 +536,14 @@ class CatalogService
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $data */
|
||||
private function validateEventData(array $data): void
|
||||
private function validateEventProductType(array $data): void
|
||||
{
|
||||
$eventId = $data['event_id'] ?? null;
|
||||
$eventProductType = $data['event_product_type'] ?? null;
|
||||
|
||||
if (($eventId === null) !== ($eventProductType === null)) {
|
||||
throw ValidationException::withMessages([
|
||||
'event_id' => ['Event and event product type must be provided together.'],
|
||||
]);
|
||||
}
|
||||
|
||||
if ($eventId === null) {
|
||||
if ($eventProductType === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! Event::query()
|
||||
->whereKey($eventId)
|
||||
->where('tenant_code', $data['tenant_code'] ?? null)
|
||||
->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'event_id' => ['The event must belong to the catalog item tenant.'],
|
||||
]);
|
||||
}
|
||||
|
||||
if (! in_array($eventProductType, EventProductType::values(), true)) {
|
||||
throw ValidationException::withMessages([
|
||||
'event_product_type' => ['The event product type is invalid.'],
|
||||
@@ -564,6 +551,35 @@ class CatalogService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $variants
|
||||
* @param array<int, string> $attributeCodes
|
||||
*/
|
||||
private function validateUniqueVariantCombinations(array $variants, array $attributeCodes): void
|
||||
{
|
||||
$seen = [];
|
||||
$attributeCodes = array_values(array_unique($attributeCodes));
|
||||
sort($attributeCodes);
|
||||
|
||||
foreach (array_values($variants) as $index => $variant) {
|
||||
$combination = [(string) ($variant['event_date_id'] ?? '')];
|
||||
|
||||
foreach ($attributeCodes as $attributeCode) {
|
||||
$value = trim((string) ($variant['values'][$attributeCode] ?? ''));
|
||||
$combination[] = Str::ascii(mb_strtolower($value));
|
||||
}
|
||||
|
||||
$key = implode('|', $combination);
|
||||
if (isset($seen[$key])) {
|
||||
throw ValidationException::withMessages([
|
||||
"variants.{$index}" => ['The variant combination must be unique.'],
|
||||
]);
|
||||
}
|
||||
|
||||
$seen[$key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
* @param array<int, array<string, mixed>> $variants
|
||||
|
||||
Reference in New Issue
Block a user