Add tests for ticket validity and event date formatting

- Create TicketValiditySchemaTest to verify database schema for ticket validity.
- Update CatalogModelsTest to include tests for event date attributes and selection options.
- Introduce EventDateTextFormatterTest for formatting event dates in Spanish.
- Refactor EventModelsTest to include validity time relationships.
- Add SaleDetailResourceTest to ensure correct serialization of purchase items.
- Enhance TicketTest with validity time checks and status management.
- Implement ValidityTimeResourceTest to validate resource output for different validity types.
- Add ValidityTimeTest to verify casting and validity checks for validity time types.
This commit is contained in:
2026-08-11 12:41:35 -03:00
parent b294e5c46e
commit 02cf3f3773
166 changed files with 10203 additions and 1849 deletions

View File

@@ -1,6 +1,5 @@
<?php
use App\Domains\Catalog\Enums\EventProductType;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
@@ -43,9 +42,6 @@ return new class extends Migration
->after('tenant_code')
->constrained('events')
->nullOnDelete();
$table->enum('event_product_type', EventProductType::values())
->nullable()
->after('event_id');
});
Schema::table('variantes', function (Blueprint $table): void {
@@ -71,7 +67,6 @@ return new class extends Migration
Schema::table('catalog_items', function (Blueprint $table): void {
$table->dropConstrainedForeignId('event_id');
$table->dropColumn('event_product_type');
});
Schema::dropIfExists('event_dates');

View File

@@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('validity_times', function (Blueprint $table): void {
$table->id();
$table->string('type');
$table->time('start_time')->nullable();
$table->time('end_time')->nullable();
$table->dateTime('fixed_starts_at')->nullable();
$table->dateTime('fixed_expires_at')->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('validity_times');
}
};

View File

@@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('catalog_items', function (Blueprint $table): void {
$table->foreignId('validity_time_id')
->nullable()
->after('has_tickets')
->constrained('validity_times')
->cascadeOnUpdate()
->nullOnDelete();
});
Schema::table('attribute_options', function (Blueprint $table): void {
$table->foreignId('validity_time_id')
->nullable()
->after('attribute_id')
->constrained('validity_times')
->cascadeOnUpdate()
->nullOnDelete();
});
}
public function down(): void
{
Schema::table('attribute_options', function (Blueprint $table): void {
$table->dropConstrainedForeignId('validity_time_id');
});
Schema::table('catalog_items', function (Blueprint $table): void {
$table->dropConstrainedForeignId('validity_time_id');
});
}
};

View File

@@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('tickets', function (Blueprint $table): void {
$table->foreignId('validity_time_id')
->nullable()
->after('source_variant_id')
->constrained('validity_times')
->cascadeOnUpdate()
->restrictOnDelete();
});
}
public function down(): void
{
Schema::table('tickets', function (Blueprint $table): void {
$table->dropConstrainedForeignId('validity_time_id');
});
}
};

View File

@@ -0,0 +1,92 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
$this->preserveFixedWindows(
'catalog_items',
'minimum_use_date',
'maximum_use_date',
);
$this->preserveFixedWindows('tickets', 'starts_at', 'expires_at');
Schema::table('tickets', function (Blueprint $table): void {
$table->dropColumn(['starts_at', 'expires_at']);
});
Schema::table('catalog_items', function (Blueprint $table): void {
$table->dropColumn(['minimum_use_date', 'maximum_use_date']);
});
Schema::table('variantes', function (Blueprint $table): void {
$table->dropColumn(['minimum_use_date', 'maximum_use_date']);
});
}
public function down(): void
{
Schema::table('variantes', function (Blueprint $table): void {
$table->dateTime('minimum_use_date')->nullable();
$table->dateTime('maximum_use_date')->nullable();
});
Schema::table('catalog_items', function (Blueprint $table): void {
$table->dateTime('minimum_use_date')->nullable();
$table->dateTime('maximum_use_date')->nullable();
});
Schema::table('tickets', function (Blueprint $table): void {
$table->dateTime('starts_at')->nullable();
$table->dateTime('expires_at')->nullable();
});
}
private function preserveFixedWindows(
string $table,
string $startsAtColumn,
string $expiresAtColumn,
): void {
DB::table($table)
->whereNull('validity_time_id')
->where(function ($query) use ($startsAtColumn, $expiresAtColumn): void {
$query->whereNotNull($startsAtColumn)
->orWhereNotNull($expiresAtColumn);
})
->select([$startsAtColumn, $expiresAtColumn])
->distinct()
->get()
->each(function ($window) use ($table, $startsAtColumn, $expiresAtColumn): void {
$startsAt = $window->{$startsAtColumn};
$expiresAt = $window->{$expiresAtColumn};
$validityTimeId = DB::table('validity_times')->insertGetId([
'type' => 'fixed_window',
'start_time' => null,
'end_time' => null,
'fixed_starts_at' => $startsAt,
'fixed_expires_at' => $expiresAt,
'created_at' => now(),
'updated_at' => now(),
]);
DB::table($table)
->whereNull('validity_time_id')
->when(
$startsAt === null,
fn ($query) => $query->whereNull($startsAtColumn),
fn ($query) => $query->where($startsAtColumn, $startsAt),
)
->when(
$expiresAt === null,
fn ($query) => $query->whereNull($expiresAtColumn),
fn ($query) => $query->where($expiresAtColumn, $expiresAt),
)
->update(['validity_time_id' => $validityTimeId]);
});
}
};

View File

@@ -0,0 +1,22 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('catalog_items', function (Blueprint $table): void {
$table->unsignedInteger('max_units_per_user')->nullable();
});
}
public function down(): void
{
Schema::table('catalog_items', function (Blueprint $table): void {
$table->dropColumn('max_units_per_user');
});
}
};

View File

@@ -0,0 +1,125 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('tenants', function (Blueprint $table): void {
$table->string('event_title')->nullable()->after('nombre');
$table->string('event_location')->nullable()->after('event_title');
});
Schema::table('event_dates', function (Blueprint $table): void {
$table->string('tenant_code')->nullable()->after('id');
});
DB::table('tenants')
->whereNotNull('active_event_id')
->orderBy('id')
->each(function (object $tenant): void {
$event = DB::table('events')->where('id', $tenant->active_event_id)->first();
if ($event === null) {
return;
}
DB::table('tenants')->where('id', $tenant->id)->update([
'event_title' => $event->name,
'event_location' => $event->address,
]);
});
DB::table('events')->orderBy('id')->each(function (object $event): void {
DB::table('event_dates')
->where('event_id', $event->id)
->update(['tenant_code' => $event->tenant_code]);
});
Schema::table('tenants', function (Blueprint $table): void {
$table->dropConstrainedForeignId('active_event_id');
});
Schema::table('catalog_items', function (Blueprint $table): void {
$table->dropConstrainedForeignId('event_id');
});
Schema::table('compras', function (Blueprint $table): void {
$table->dropConstrainedForeignId('event_id');
});
Schema::table('event_dates', function (Blueprint $table): void {
$table->dropConstrainedForeignId('event_id');
$table->string('tenant_code')->nullable(false)->change();
$table->foreign('tenant_code')
->references('codigo')
->on('tenants')
->cascadeOnUpdate()
->cascadeOnDelete();
});
Schema::dropIfExists('events');
}
public function down(): void
{
Schema::create('events', function (Blueprint $table): void {
$table->id();
$table->string('tenant_code');
$table->string('name');
$table->string('address');
$table->foreign('tenant_code')
->references('codigo')
->on('tenants')
->cascadeOnUpdate()
->cascadeOnDelete();
});
Schema::table('tenants', function (Blueprint $table): void {
$table->foreignId('active_event_id')->nullable();
});
Schema::table('catalog_items', function (Blueprint $table): void {
$table->foreignId('event_id')->nullable();
});
Schema::table('compras', function (Blueprint $table): void {
$table->foreignId('event_id')->nullable();
});
Schema::table('event_dates', function (Blueprint $table): void {
$table->foreignId('event_id')->nullable();
});
DB::table('tenants')->orderBy('id')->each(function (object $tenant): void {
if ($tenant->event_title === null && $tenant->event_location === null) {
return;
}
$eventId = DB::table('events')->insertGetId([
'tenant_code' => $tenant->codigo,
'name' => $tenant->event_title ?? $tenant->nombre,
'address' => $tenant->event_location ?? '',
]);
DB::table('tenants')->where('id', $tenant->id)->update(['active_event_id' => $eventId]);
DB::table('catalog_items')->where('tenant_code', $tenant->codigo)->update(['event_id' => $eventId]);
DB::table('compras')->where('tenant_codigo', $tenant->codigo)->update(['event_id' => $eventId]);
DB::table('event_dates')->where('tenant_code', $tenant->codigo)->update(['event_id' => $eventId]);
});
Schema::table('tenants', function (Blueprint $table): void {
$table->foreign('active_event_id')->references('id')->on('events')->nullOnDelete();
$table->dropColumn(['event_title', 'event_location']);
});
Schema::table('catalog_items', function (Blueprint $table): void {
$table->foreign('event_id')->references('id')->on('events')->nullOnDelete();
});
Schema::table('compras', function (Blueprint $table): void {
$table->foreign('event_id')->references('id')->on('events')->nullOnDelete();
});
Schema::table('event_dates', function (Blueprint $table): void {
$table->dropForeign(['tenant_code']);
$table->dropColumn('tenant_code');
$table->foreign('event_id')->references('id')->on('events')->cascadeOnDelete();
});
}
};

View File

@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('variantes', function (Blueprint $table): void {
$table->index(['catalog_item_id', 'event_date_id']);
});
Schema::table('variantes', function (Blueprint $table): void {
$table->dropUnique(['catalog_item_id', 'event_date_id']);
});
}
public function down(): void
{
Schema::table('variantes', function (Blueprint $table): void {
$table->unique(['catalog_item_id', 'event_date_id']);
});
Schema::table('variantes', function (Blueprint $table): void {
$table->dropIndex(['catalog_item_id', 'event_date_id']);
});
}
};

View File

@@ -0,0 +1,75 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
public function up(): void
{
$now = now();
DB::table('tenants')
->whereExists(fn ($query) => $query
->selectRaw('1')
->from('event_dates')
->whereColumn('event_dates.tenant_code', 'tenants.codigo'))
->orderBy('id')
->each(function (object $tenant) use ($now): void {
DB::table('attribute')->updateOrInsert(
[
'tenant_codigo' => $tenant->codigo,
'codigo' => 'event_date',
],
[
'nombre' => 'Fecha',
'is_required' => true,
'metadata_schema' => null,
'type' => 'event_date',
'updated_at' => $now,
'created_at' => $now,
],
);
});
DB::table('catalog_items')
->whereExists(fn ($query) => $query
->selectRaw('1')
->from('variantes')
->whereColumn('variantes.catalog_item_id', 'catalog_items.id')
->whereNotNull('variantes.event_date_id'))
->orderBy('id')
->each(function (object $catalogItem) use ($now): void {
$attributeId = DB::table('attribute')
->where('tenant_codigo', $catalogItem->tenant_code)
->where('codigo', 'event_date')
->value('id');
if ($attributeId === null) {
return;
}
DB::table('item_attributes')->updateOrInsert(
[
'catalog_item_id' => $catalogItem->id,
'attribute_id' => $attributeId,
],
[
'updated_at' => $now,
'created_at' => $now,
],
);
});
}
public function down(): void
{
$attributeIds = DB::table('attribute')
->where('codigo', 'event_date')
->where('type', 'event_date')
->pluck('id');
DB::table('item_attributes')->whereIn('attribute_id', $attributeIds)->delete();
DB::table('attribute')->whereIn('id', $attributeIds)->delete();
}
};

View File

@@ -0,0 +1,42 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('item_attributes', function (Blueprint $table): void {
$table->boolean('allow_multi_select')->default(false)->after('attribute_id');
});
Schema::create('variant_event_dates', function (Blueprint $table): void {
$table->foreignId('variant_id')->constrained('variantes')->cascadeOnDelete();
$table->foreignId('event_date_id')->constrained('event_dates')->cascadeOnDelete();
$table->primary(['variant_id', 'event_date_id']);
$table->index(['event_date_id', 'variant_id']);
});
DB::table('variantes')
->whereNotNull('event_date_id')
->orderBy('id')
->each(function (object $variant): void {
DB::table('variant_event_dates')->insertOrIgnore([
'variant_id' => $variant->id,
'event_date_id' => $variant->event_date_id,
]);
});
}
public function down(): void
{
Schema::dropIfExists('variant_event_dates');
Schema::table('item_attributes', function (Blueprint $table): void {
$table->dropColumn('allow_multi_select');
});
}
};

View File

@@ -0,0 +1,22 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('variant_values', function (Blueprint $table): void {
$table->dropUnique('variant_values_variant_id_item_attribute_id_unique');
});
}
public function down(): void
{
Schema::table('variant_values', function (Blueprint $table): void {
$table->unique(['variant_id', 'item_attribute_id']);
});
}
};

View File

@@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('variantes', function (Blueprint $table): void {
$table->text('descripcion')->nullable()->after('inventory_id');
$table->decimal('precio', 10, 2)->nullable()->after('descripcion');
});
DB::table('variantes')->orderBy('id')->each(function (object $variant): void {
$price = DB::table('catalog_items')
->where('id', $variant->catalog_item_id)
->value('precio');
DB::table('variantes')->where('id', $variant->id)->update([
'precio' => $price,
]);
});
}
public function down(): void
{
Schema::table('variantes', function (Blueprint $table): void {
$table->dropColumn(['descripcion', 'precio']);
});
}
};

View File

@@ -0,0 +1,37 @@
<?php
use App\Domains\Event\Services\EventDateTextFormatter;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('tenants', function (Blueprint $table): void {
$table->text('event_date_text')->nullable()->after('event_location');
});
$formatter = new EventDateTextFormatter;
DB::table('tenants')->orderBy('id')->each(function (object $tenant) use ($formatter): void {
$dates = DB::table('event_dates')
->where('tenant_code', $tenant->codigo)
->orderBy('date')
->pluck('date');
DB::table('tenants')->where('id', $tenant->id)->update([
'event_date_text' => $formatter->format($dates),
]);
});
}
public function down(): void
{
Schema::table('tenants', function (Blueprint $table): void {
$table->dropColumn('event_date_text');
});
}
};

View File

@@ -0,0 +1,43 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('item_attributes', function (Blueprint $table): void {
$table->unsignedInteger('sort_order')->default(0)->after('allow_multi_select');
});
$foodItemAttributes = DB::table('item_attributes')
->join('catalog_items', 'catalog_items.id', '=', 'item_attributes.catalog_item_id')
->join('attribute', 'attribute.id', '=', 'item_attributes.attribute_id')
->where('catalog_items.slug', 'comida')
->whereIn('attribute.codigo', ['event_date', 'horario', 'servicio'])
->select('item_attributes.id', 'attribute.codigo')
->get();
$sortOrders = [
'event_date' => 1,
'horario' => 2,
'servicio' => 3,
];
foreach ($foodItemAttributes as $itemAttribute) {
DB::table('item_attributes')
->where('id', $itemAttribute->id)
->update(['sort_order' => $sortOrders[$itemAttribute->codigo]]);
}
}
public function down(): void
{
Schema::table('item_attributes', function (Blueprint $table): void {
$table->dropColumn('sort_order');
});
}
};

View File

@@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
public function up(): void
{
DB::table('catalog_items')
->where('tenant_code', 'fiesta_futbol_infantil')
->update(['has_tickets' => true]);
}
public function down(): void
{
$entryCategoryIds = DB::table('categorias')
->select('id')
->where('tenant_code', 'fiesta_futbol_infantil')
->where('nombre', 'Entradas');
DB::table('catalog_items')
->where('tenant_code', 'fiesta_futbol_infantil')
->whereNotIn('category_id', $entryCategoryIds)
->update(['has_tickets' => false]);
}
};

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
if (! Schema::hasColumn('catalog_items', 'event_product_type')) {
return;
}
Schema::table('catalog_items', function (Blueprint $table): void {
$table->dropColumn('event_product_type');
});
}
public function down(): void
{
if (Schema::hasColumn('catalog_items', 'event_product_type')) {
return;
}
Schema::table('catalog_items', function (Blueprint $table): void {
$table->enum('event_product_type', ['entrada', 'producto'])
->nullable()
->after('tenant_code');
});
}
};

View File

@@ -0,0 +1,23 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('tenants', function (Blueprint $table): void {
$table->boolean('display_categories')->default(true)->after('search_items_per_page');
$table->boolean('display_seach_bar')->default(true)->after('display_categories');
});
}
public function down(): void
{
Schema::table('tenants', function (Blueprint $table): void {
$table->dropColumn(['display_categories', 'display_seach_bar']);
});
}
};

View File

@@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
public function up(): void
{
DB::table('tenants')
->where('codigo', 'fiesta_futbol_infantil')
->update([
'display_categories' => false,
'display_seach_bar' => false,
]);
DB::table('tenants')
->where('codigo', 'sonder')
->update([
'display_categories' => true,
'display_seach_bar' => true,
]);
}
public function down(): void {}
};

View File

@@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
DB::table('websites_extras')
->whereNull('is_enabled')
->update(['is_enabled' => true]);
Schema::table('websites_extras', function (Blueprint $table): void {
$table->boolean('is_enabled')->default(true)->nullable(false)->change();
});
}
public function down(): void
{
Schema::table('websites_extras', function (Blueprint $table): void {
$table->boolean('is_enabled')->nullable()->default(null)->change();
});
}
};

View File

@@ -0,0 +1,32 @@
<?php
use App\Domains\Ticket\Enums\TicketGenerationPolicy;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('catalog_items', function (Blueprint $table): void {
$table->enum('ticket_generation_policy', TicketGenerationPolicy::values())
->default(TicketGenerationPolicy::PerEventDate->value)
->after('has_tickets');
});
DB::table('catalog_items')
->where('tenant_code', 'fiesta_futbol_infantil')
->update([
'ticket_generation_policy' => TicketGenerationPolicy::OnePerUnit->value,
]);
}
public function down(): void
{
Schema::table('catalog_items', function (Blueprint $table): void {
$table->dropColumn('ticket_generation_policy');
});
}
};

View File

@@ -0,0 +1,63 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('ticket_validity_times', function (Blueprint $table): void {
$table->foreignId('ticket_id')
->constrained('tickets')
->cascadeOnUpdate()
->cascadeOnDelete();
$table->foreignId('validity_time_id')
->constrained('validity_times')
->cascadeOnUpdate()
->restrictOnDelete();
$table->primary(['ticket_id', 'validity_time_id']);
});
DB::table('ticket_validity_times')->insertUsing(
['ticket_id', 'validity_time_id'],
DB::table('tickets')
->select(['id', 'validity_time_id'])
->whereNotNull('validity_time_id'),
);
Schema::table('tickets', function (Blueprint $table): void {
$table->dropConstrainedForeignId('validity_time_id');
});
}
public function down(): void
{
Schema::table('tickets', function (Blueprint $table): void {
$table->foreignId('validity_time_id')
->nullable()
->after('source_variant_id')
->constrained('validity_times')
->cascadeOnUpdate()
->restrictOnDelete();
});
DB::table('ticket_validity_times')
->orderBy('ticket_id')
->orderBy('validity_time_id')
->get()
->groupBy('ticket_id')
->each(function ($validityTimes, int|string $ticketId): void {
DB::table('tickets')
->where('id', $ticketId)
->update([
'validity_time_id' => $validityTimes->first()->validity_time_id,
]);
});
Schema::dropIfExists('ticket_validity_times');
}
};

View File

@@ -0,0 +1,68 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('event_dates', function (Blueprint $table): void {
$table->unsignedBigInteger('validity_time_id')
->nullable()
->unique()
->after('id');
});
DB::table('event_dates')
->orderBy('id')
->each(function (object $eventDate): void {
$startsAt = $eventDate->date.' '.$eventDate->time_start;
$expiresAt = $eventDate->date.' '.$eventDate->time_end;
if (strtotime($expiresAt) <= strtotime($startsAt)) {
$expiresAt = date('Y-m-d H:i:s', strtotime($expiresAt.' +1 day'));
}
$validityTimeId = DB::table('validity_times')->insertGetId([
'type' => 'fixed_window',
'start_time' => null,
'end_time' => null,
'fixed_starts_at' => $startsAt,
'fixed_expires_at' => $expiresAt,
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('event_dates')
->where('id', $eventDate->id)
->update(['validity_time_id' => $validityTimeId]);
});
Schema::table('event_dates', function (Blueprint $table): void {
$table->unsignedBigInteger('validity_time_id')->nullable(false)->change();
$table->foreign('validity_time_id')
->references('id')
->on('validity_times')
->restrictOnDelete();
});
}
public function down(): void
{
$validityTimeIds = DB::table('event_dates')
->pluck('validity_time_id')
->filter()
->all();
Schema::table('event_dates', function (Blueprint $table): void {
$table->dropForeign(['validity_time_id']);
$table->dropUnique(['validity_time_id']);
$table->dropColumn('validity_time_id');
});
DB::table('validity_times')->whereIn('id', $validityTimeIds)->delete();
}
};

View File

@@ -0,0 +1,88 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('ticket_validity_groups', function (Blueprint $table): void {
$table->id();
$table->foreignId('ticket_id')
->constrained('tickets')
->cascadeOnUpdate()
->cascadeOnDelete();
});
Schema::create('ticket_validity_group_times', function (Blueprint $table): void {
$table->foreignId('ticket_validity_group_id')
->constrained('ticket_validity_groups')
->cascadeOnUpdate()
->cascadeOnDelete();
$table->foreignId('validity_time_id')
->constrained('validity_times')
->cascadeOnUpdate()
->restrictOnDelete();
$table->primary(['ticket_validity_group_id', 'validity_time_id']);
});
// Every former pivot row was an OR alternative, so each one becomes
// an independent group to preserve existing ticket behavior.
DB::table('ticket_validity_times')
->orderBy('ticket_id')
->orderBy('validity_time_id')
->each(function (object $association): void {
$groupId = DB::table('ticket_validity_groups')->insertGetId([
'ticket_id' => $association->ticket_id,
]);
DB::table('ticket_validity_group_times')->insert([
'ticket_validity_group_id' => $groupId,
'validity_time_id' => $association->validity_time_id,
]);
});
Schema::dropIfExists('ticket_validity_times');
}
public function down(): void
{
Schema::create('ticket_validity_times', function (Blueprint $table): void {
$table->foreignId('ticket_id')
->constrained('tickets')
->cascadeOnUpdate()
->cascadeOnDelete();
$table->foreignId('validity_time_id')
->constrained('validity_times')
->cascadeOnUpdate()
->restrictOnDelete();
$table->primary(['ticket_id', 'validity_time_id']);
});
DB::table('ticket_validity_group_times')
->join(
'ticket_validity_groups',
'ticket_validity_groups.id',
'=',
'ticket_validity_group_times.ticket_validity_group_id',
)
->select([
'ticket_validity_groups.ticket_id',
'ticket_validity_group_times.validity_time_id',
])
->distinct()
->orderBy('ticket_validity_groups.ticket_id')
->each(fn (object $association) => DB::table('ticket_validity_times')->insert([
'ticket_id' => $association->ticket_id,
'validity_time_id' => $association->validity_time_id,
]));
Schema::dropIfExists('ticket_validity_group_times');
Schema::dropIfExists('ticket_validity_groups');
}
};