feat(ticket): implement ticket generation policies and validity time management
- Added `ticket_generation_policy` column to `catalog_items` table to manage ticket generation strategies. - Created `ticket_validity_times` table to allow multiple validity times per ticket. - Introduced `validity_time_id` column in `event_dates` table to associate event dates with validity times. - Established `ticket_validity_groups` and `ticket_validity_group_times` tables to group validity times for tickets. - Updated seeder to set default ticket generation policy for specific tenant. - Enhanced tests to cover new functionality, including ticket generation based on event dates and validity times. - Refactored ticket validity checks to accommodate multiple validity times in a group.
This commit is contained in:
@@ -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');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -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');
|
||||
}
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
@@ -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');
|
||||
}
|
||||
};
|
||||
@@ -11,6 +11,7 @@ use App\Domains\Catalog\Models\Category;
|
||||
use App\Domains\Catalog\Models\FeaturedGroup;
|
||||
use App\Domains\Catalog\Services\CatalogService;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticket\Enums\TicketGenerationPolicy;
|
||||
use Illuminate\Database\Seeder;
|
||||
use RuntimeException;
|
||||
|
||||
@@ -145,6 +146,7 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
||||
'inventory_policy' => InventoryPolicy::Tracked->value,
|
||||
...$data,
|
||||
'has_tickets' => true,
|
||||
'ticket_generation_policy' => TicketGenerationPolicy::OnePerUnit->value,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user