From 0d54887602a1089a5b2cc15149020b161e3f01f0 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Mon, 14 Sep 2026 14:19:29 -0300 Subject: [PATCH] feat(event): audit suspended event dates --- .../Controllers/AdminApp/EventController.php | 1 + .../Event/Enums/EventDateChangeType.php | 9 ++ app/Domains/Event/Models/EventDate.php | 12 +- ...DateReschedule.php => EventDateChange.php} | 5 +- app/Domains/Event/Services/EventService.php | 25 +++- ...lize_event_date_reschedules_as_changes.php | 115 ++++++++++++++++++ .../Event/AdminAppEventControllerTest.php | 22 +++- 7 files changed, 174 insertions(+), 15 deletions(-) create mode 100644 app/Domains/Event/Enums/EventDateChangeType.php rename app/Domains/Event/Models/{EventDateReschedule.php => EventDateChange.php} (90%) create mode 100644 database/migrations/2026_09_14_040000_generalize_event_date_reschedules_as_changes.php diff --git a/app/Domains/Event/Controllers/AdminApp/EventController.php b/app/Domains/Event/Controllers/AdminApp/EventController.php index 624320d..bb1a783 100644 --- a/app/Domains/Event/Controllers/AdminApp/EventController.php +++ b/app/Domains/Event/Controllers/AdminApp/EventController.php @@ -63,6 +63,7 @@ class EventController extends Controller $this->eventService->suspendDateForTenant( $request->user()->tenant()->firstOrFail(), $eventDate, + $request->user(), ) ); } diff --git a/app/Domains/Event/Enums/EventDateChangeType.php b/app/Domains/Event/Enums/EventDateChangeType.php new file mode 100644 index 0000000..1dba386 --- /dev/null +++ b/app/Domains/Event/Enums/EventDateChangeType.php @@ -0,0 +1,9 @@ +hasMany(self::class, 'rescheduled_to_event_date_id'); } - /** @return HasMany */ - public function rescheduleHistory(): HasMany + /** @return HasMany */ + public function changeHistory(): HasMany { - return $this->hasMany(EventDateReschedule::class, 'source_event_date_id'); + return $this->hasMany(EventDateChange::class, 'source_event_date_id'); } - /** @return HasMany */ - public function destinationRescheduleHistory(): HasMany + /** @return HasMany */ + public function destinationChangeHistory(): HasMany { - return $this->hasMany(EventDateReschedule::class, 'destination_event_date_id'); + return $this->hasMany(EventDateChange::class, 'destination_event_date_id'); } /** @return HasMany */ diff --git a/app/Domains/Event/Models/EventDateReschedule.php b/app/Domains/Event/Models/EventDateChange.php similarity index 90% rename from app/Domains/Event/Models/EventDateReschedule.php rename to app/Domains/Event/Models/EventDateChange.php index 89291be..635c8d6 100644 --- a/app/Domains/Event/Models/EventDateReschedule.php +++ b/app/Domains/Event/Models/EventDateChange.php @@ -3,6 +3,7 @@ namespace App\Domains\Event\Models; use App\Domains\Auth\Models\User; +use App\Domains\Event\Enums\EventDateChangeType; use App\Domains\Tenant\Models\Tenant; use Illuminate\Database\Eloquent\Attributes\Fillable; use Illuminate\Database\Eloquent\Model; @@ -10,19 +11,21 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; #[Fillable([ 'tenant_code', + 'change_type', 'source_event_date_id', 'destination_event_date_id', 'created_by_user_id', 'previous_date', 'new_date', ])] -class EventDateReschedule extends Model +class EventDateChange extends Model { public $timestamps = false; protected function casts(): array { return [ + 'change_type' => EventDateChangeType::class, 'source_event_date_id' => 'integer', 'destination_event_date_id' => 'integer', 'created_by_user_id' => 'integer', diff --git a/app/Domains/Event/Services/EventService.php b/app/Domains/Event/Services/EventService.php index 39d5607..8ea5d72 100644 --- a/app/Domains/Event/Services/EventService.php +++ b/app/Domains/Event/Services/EventService.php @@ -5,10 +5,11 @@ namespace App\Domains\Event\Services; use App\Domains\Auth\Models\User; use App\Domains\Catalog\Models\Variant; use App\Domains\Catalog\Services\VariantReplacementService; +use App\Domains\Event\Enums\EventDateChangeType; use App\Domains\Event\Events\EventDateRescheduled; use App\Domains\Event\Events\EventDateSuspended; use App\Domains\Event\Models\EventDate; -use App\Domains\Event\Models\EventDateReschedule; +use App\Domains\Event\Models\EventDateChange; use App\Domains\Tenant\Models\Tenant; use App\Domains\Ticket\Models\Ticket; use Illuminate\Support\Collection; @@ -131,8 +132,9 @@ class EventService $source->update(['rescheduled_to_event_date_id' => $destination->getKey()]); $this->variantReplacementService->replaceEventDate($source, $effectiveDestination); - EventDateReschedule::query()->create([ + EventDateChange::query()->create([ 'tenant_code' => $tenant->codigo, + 'change_type' => EventDateChangeType::Rescheduled, 'source_event_date_id' => $source->getKey(), 'destination_event_date_id' => $destination->getKey(), 'created_by_user_id' => $createdBy?->getKey(), @@ -153,9 +155,12 @@ class EventService }); } - public function suspendDateForTenant(Tenant $tenant, EventDate $eventDate): EventDate - { - return DB::transaction(function () use ($tenant, $eventDate): EventDate { + public function suspendDateForTenant( + Tenant $tenant, + EventDate $eventDate, + ?User $createdBy = null, + ): EventDate { + return DB::transaction(function () use ($tenant, $eventDate, $createdBy): EventDate { $date = $this->lockedDateForTenant($tenant, $eventDate); if ($date->rescheduled_to_event_date_id !== null) { @@ -176,6 +181,16 @@ class EventService $this->variantReplacementService->disableForSuspension($date); $this->disableTicketsWithoutUsableDates($tenant, $date); + EventDateChange::query()->create([ + 'tenant_code' => $tenant->codigo, + 'change_type' => EventDateChangeType::Suspended, + 'source_event_date_id' => $date->getKey(), + 'destination_event_date_id' => null, + 'created_by_user_id' => $createdBy?->getKey(), + 'previous_date' => $date->date->format('Y-m-d'), + 'new_date' => null, + ]); + EventDateSuspended::dispatch( $tenant->codigo, $date->getKey(), diff --git a/database/migrations/2026_09_14_040000_generalize_event_date_reschedules_as_changes.php b/database/migrations/2026_09_14_040000_generalize_event_date_reschedules_as_changes.php new file mode 100644 index 0000000..294211c --- /dev/null +++ b/database/migrations/2026_09_14_040000_generalize_event_date_reschedules_as_changes.php @@ -0,0 +1,115 @@ +createEventDateChangesTable(); + + DB::table('event_date_changes')->insertUsing( + [ + 'tenant_code', + 'change_type', + 'source_event_date_id', + 'destination_event_date_id', + 'created_by_user_id', + 'previous_date', + 'new_date', + 'created_at', + ], + DB::table('event_date_reschedules')->select([ + 'tenant_code', + DB::raw("'rescheduled'"), + 'source_event_date_id', + 'destination_event_date_id', + 'created_by_user_id', + 'previous_date', + 'new_date', + 'created_at', + ]), + ); + + Schema::drop('event_date_reschedules'); + } + + public function down(): void + { + $this->createEventDateReschedulesTable(); + + DB::table('event_date_reschedules')->insertUsing( + [ + 'tenant_code', + 'source_event_date_id', + 'destination_event_date_id', + 'created_by_user_id', + 'previous_date', + 'new_date', + 'created_at', + ], + DB::table('event_date_changes') + ->where('change_type', 'rescheduled') + ->whereNotNull('destination_event_date_id') + ->whereNotNull('new_date') + ->select([ + 'tenant_code', + 'source_event_date_id', + 'destination_event_date_id', + 'created_by_user_id', + 'previous_date', + 'new_date', + 'created_at', + ]), + ); + + Schema::drop('event_date_changes'); + } + + private function createEventDateChangesTable(): void + { + Schema::create('event_date_changes', function (Blueprint $table): void { + $table->id(); + $table->string('tenant_code'); + $table->string('change_type', 16); + $table->foreignId('source_event_date_id')->nullable()->constrained('event_dates')->nullOnDelete(); + $table->foreignId('destination_event_date_id')->nullable()->constrained('event_dates')->nullOnDelete(); + $table->foreignId('created_by_user_id')->nullable()->constrained('users')->nullOnDelete(); + $table->date('previous_date'); + $table->date('new_date')->nullable(); + $table->timestamp('created_at')->useCurrent(); + + $table->foreign('tenant_code') + ->references('codigo') + ->on('tenants') + ->cascadeOnUpdate() + ->cascadeOnDelete(); + $table->index(['tenant_code', 'created_at']); + $table->index(['source_event_date_id', 'change_type']); + }); + } + + private function createEventDateReschedulesTable(): void + { + Schema::create('event_date_reschedules', function (Blueprint $table): void { + $table->id(); + $table->string('tenant_code'); + $table->foreignId('source_event_date_id')->nullable()->constrained('event_dates')->nullOnDelete(); + $table->foreignId('destination_event_date_id')->nullable()->constrained('event_dates')->nullOnDelete(); + $table->foreignId('created_by_user_id')->nullable()->constrained('users')->nullOnDelete(); + $table->date('previous_date'); + $table->date('new_date'); + $table->timestamp('created_at')->useCurrent(); + + $table->foreign('tenant_code') + ->references('codigo') + ->on('tenants') + ->cascadeOnUpdate() + ->cascadeOnDelete(); + $table->index(['tenant_code', 'created_at']); + }); + } +}; diff --git a/tests/Feature/Event/AdminAppEventControllerTest.php b/tests/Feature/Event/AdminAppEventControllerTest.php index a849ea9..74e050d 100644 --- a/tests/Feature/Event/AdminAppEventControllerTest.php +++ b/tests/Feature/Event/AdminAppEventControllerTest.php @@ -270,8 +270,9 @@ class AdminAppEventControllerTest extends TestCase }); $this->assertDatabaseCount('event_dates', 2); - $this->assertDatabaseHas('event_date_reschedules', [ + $this->assertDatabaseHas('event_date_changes', [ 'tenant_code' => $tenant->codigo, + 'change_type' => 'rescheduled', 'source_event_date_id' => $original->id, 'destination_event_date_id' => $destination->id, 'created_by_user_id' => $admin->id, @@ -323,9 +324,10 @@ class AdminAppEventControllerTest extends TestCase ])->assertOk()->assertJsonPath('data.status', 'rescheduled'); $this->assertDatabaseCount('event_dates', 3); - $this->assertDatabaseCount('event_date_reschedules', 2); - $this->assertDatabaseHas('event_date_reschedules', [ + $this->assertDatabaseCount('event_date_changes', 2); + $this->assertDatabaseHas('event_date_changes', [ 'tenant_code' => $tenant->codigo, + 'change_type' => 'rescheduled', 'source_event_date_id' => $destination->id, 'created_by_user_id' => $admin->id, 'previous_date' => '2027-10-20', @@ -418,6 +420,20 @@ class AdminAppEventControllerTest extends TestCase && $event->purchaseTickets === []; }); + $this->assertDatabaseHas('event_date_changes', [ + 'tenant_code' => $tenant->codigo, + 'change_type' => 'suspended', + 'source_event_date_id' => $suspendedDate->id, + 'destination_event_date_id' => null, + 'created_by_user_id' => $admin->id, + 'previous_date' => '2027-10-09', + 'new_date' => null, + ]); + + $this->postJson("/api/v1/adminapp/tenant/event-dates/{$suspendedDate->id}/suspend") + ->assertOk(); + $this->assertDatabaseCount('event_date_changes', 1); + $this->assertNotNull($singleDateTicket->fresh()->disabled_at); $this->assertNull($multipleDateTicket->fresh()->disabled_at); $this->assertNotNull($singleDateVariant->fresh()->sales_disabled_at);