feat(ticket): implement validity time management for tickets and catalog items
- Added ValidityTime model and migration to manage ticket validity periods. - Updated TicketGeneratorService to resolve and assign validity times to tickets. - Refactored ticket generation logic to remove legacy date fields and use validity time. - Introduced timezone support for tenants to handle service dates correctly. - Updated migrations to remove deprecated columns and add foreign keys for validity times. - Modified seeders and tests to accommodate new validity time structure. - Enhanced tests to validate ticket generation and validity time behavior.
This commit is contained in:
@@ -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('tenants', function (Blueprint $table): void {
|
||||
$table->string('timezone')->default('UTC')->after('dominio');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('tenants', function (Blueprint $table): void {
|
||||
$table->dropColumn('timezone');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -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::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->boolean('active')->default(true);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('validity_times');
|
||||
}
|
||||
};
|
||||
@@ -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');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
<?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();
|
||||
$table->date('service_date')->nullable()->after('validity_time_id');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('tickets', function (Blueprint $table): void {
|
||||
$table->dropConstrainedForeignId('validity_time_id');
|
||||
$table->dropColumn('service_date');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,93 @@
|
||||
<?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,
|
||||
'active' => true,
|
||||
'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]);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -14,6 +14,8 @@ use App\Domains\Catalog\Models\FeaturedGroup;
|
||||
use App\Domains\Catalog\Services\CatalogService;
|
||||
use App\Domains\Event\Models\Event;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticket\Enums\ValidityTimeType;
|
||||
use App\Domains\Ticket\Models\ValidityTime;
|
||||
use Illuminate\Database\Seeder;
|
||||
use RuntimeException;
|
||||
|
||||
@@ -79,6 +81,11 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
||||
$dates = $eventDates->keys()->all();
|
||||
$minimumUseDate = $dates[0].' 00:00:00';
|
||||
$maximumUseDate = $dates[array_key_last($dates)].' 23:59:59';
|
||||
$eventValidityTime = ValidityTime::query()->firstOrCreate([
|
||||
'type' => ValidityTimeType::FixedWindow,
|
||||
'fixed_starts_at' => $minimumUseDate,
|
||||
'fixed_expires_at' => $maximumUseDate,
|
||||
]);
|
||||
|
||||
$generalAdmission = $this->catalogService->create([
|
||||
'tenant_code' => $tenant->codigo,
|
||||
@@ -91,8 +98,7 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
||||
'precio' => 10000,
|
||||
'inventory_policy' => InventoryPolicy::Unlimited->value,
|
||||
'has_tickets' => true,
|
||||
'minimum_use_date' => $minimumUseDate,
|
||||
'maximum_use_date' => $maximumUseDate,
|
||||
'validity_time_id' => $eventValidityTime->id,
|
||||
'variants' => array_map(
|
||||
fn (string $date): array => [
|
||||
'real_stock' => 0,
|
||||
@@ -120,8 +126,7 @@ class FiestaFutbolInfantilProductSeeder extends Seeder
|
||||
'descripcion' => $item['descripcion'] ?? $item['nombre'],
|
||||
'inventory_policy' => InventoryPolicy::Unlimited->value,
|
||||
'real_stock' => 0,
|
||||
'minimum_use_date' => $minimumUseDate,
|
||||
'maximum_use_date' => $maximumUseDate,
|
||||
'validity_time_id' => $eventValidityTime->id,
|
||||
...$item,
|
||||
]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user