diff --git a/app/Domains/Catalog/Services/VariantReplacementService.php b/app/Domains/Catalog/Services/VariantReplacementService.php index 3070614..e4422d3 100644 --- a/app/Domains/Catalog/Services/VariantReplacementService.php +++ b/app/Domains/Catalog/Services/VariantReplacementService.php @@ -8,9 +8,7 @@ use App\Domains\Catalog\Models\StockReservation; use App\Domains\Catalog\Models\StockReservationLine; use App\Domains\Catalog\Models\Variant; use App\Domains\Event\Models\EventDate; -use App\Domains\Event\Services\EffectiveEventDateResolver; use Illuminate\Support\Collection; -use Illuminate\Support\Facades\DB; class VariantReplacementService { @@ -72,7 +70,14 @@ class VariantReplacementService ->get(); foreach ($variants as $variant) { - $remainingDateIds = $this->usableDateIds($variant); + $remainingDateIds = $variant->selectedEventDates() + ->filter(fn (EventDate $date): bool => $date->suspended_at === null + && $date->rescheduled_to_event_date_id === null) + ->pluck('id') + ->map(fn ($id): int => (int) $id) + ->unique() + ->sort() + ->values(); if ($remainingDateIds->isEmpty()) { $variant->update(['sales_disabled_at' => now()]); @@ -80,75 +85,22 @@ class VariantReplacementService continue; } - $this->replaceWithUsableDates($variant, $remainingDateIds); - } - } - - public function restorePreviouslySuspendedVariants(): int - { - return DB::transaction(function (): int { - $variants = Variant::query() - ->whereNotNull('sales_disabled_at') - ->whereNull('replaced_by_variant_id') - ->with(['eventDates', 'eventDate', 'definitions', 'allAttachments']) - ->orderBy('id') - ->lockForUpdate() - ->get(); - $restored = 0; - - foreach ($variants as $variant) { - if (! $variant->selectedEventDates()->contains( - fn (EventDate $date): bool => $date->suspended_at !== null, - )) { - continue; - } - - $usableDateIds = $this->usableDateIds($variant); - if ($usableDateIds->isEmpty()) { - continue; - } - - $this->replaceWithUsableDates($variant, $usableDateIds); - $restored++; + $replacement = $this->findEquivalent($variant, $remainingDateIds); + if ($replacement === null) { + $replacement = $this->cloneWithDates($variant, $remainingDateIds); + } else { + $this->mergeInventoryInto($variant, $replacement); } - return $restored; - }); - } + $variant->update([ + 'replaced_by_variant_id' => $replacement->getKey(), + 'sales_disabled_at' => now(), + ]); - /** @return Collection */ - private function usableDateIds(Variant $variant): Collection - { - $resolver = app(EffectiveEventDateResolver::class); - - return $variant->selectedEventDates() - ->map(fn (EventDate $date): ?EventDate => $resolver->resolve($date)) - ->filter() - ->pluck('id') - ->map(fn ($id): int => (int) $id) - ->unique() - ->sort() - ->values(); - } - - /** @param Collection $dateIds */ - private function replaceWithUsableDates(Variant $variant, Collection $dateIds): void - { - $replacement = $this->findEquivalent($variant, $dateIds); - if ($replacement === null) { - $replacement = $this->cloneWithDates($variant, $dateIds); - } else { - $this->mergeInventoryInto($variant, $replacement); + BundleComponent::query() + ->where('component_variant_id', $variant->getKey()) + ->update(['component_variant_id' => $replacement->getKey()]); } - - $variant->update([ - 'replaced_by_variant_id' => $replacement->getKey(), - 'sales_disabled_at' => $variant->sales_disabled_at ?? now(), - ]); - - BundleComponent::query() - ->where('component_variant_id', $variant->getKey()) - ->update(['component_variant_id' => $replacement->getKey()]); } /** @param Collection $eventDateIds */ diff --git a/app/Domains/FiestaFutbolInfantil/Resources/EntryResource.php b/app/Domains/FiestaFutbolInfantil/Resources/EntryResource.php index 4442bd3..41e414f 100644 --- a/app/Domains/FiestaFutbolInfantil/Resources/EntryResource.php +++ b/app/Domains/FiestaFutbolInfantil/Resources/EntryResource.php @@ -12,12 +12,7 @@ class EntryResource extends JsonResource /** @return array */ public function toArray(Request $request): array { - $variant = $this->variants - ->filter(fn ($candidate): bool => $candidate->sales_disabled_at === null - && $candidate->replaced_by_variant_id === null) - ->sortByDesc('id') - ->first() - ?? $this->variants->sortByDesc('id')->firstOrFail(); + $variant = $this->variants->sole(); return [ 'id' => $this->id, diff --git a/app/Domains/FiestaFutbolInfantil/Services/EntryService.php b/app/Domains/FiestaFutbolInfantil/Services/EntryService.php index 97e6999..0c44363 100644 --- a/app/Domains/FiestaFutbolInfantil/Services/EntryService.php +++ b/app/Domains/FiestaFutbolInfantil/Services/EntryService.php @@ -97,8 +97,6 @@ class EntryService $variants = Variant::query() ->where('catalog_item_id', $catalogItem->id) - ->whereNull('sales_disabled_at') - ->whereNull('replaced_by_variant_id') ->lockForUpdate() ->get(); diff --git a/database/migrations/2026_09_16_000000_restore_variants_with_remaining_event_dates.php b/database/migrations/2026_09_16_000000_restore_variants_with_remaining_event_dates.php deleted file mode 100644 index 86b903d..0000000 --- a/database/migrations/2026_09_16_000000_restore_variants_with_remaining_event_dates.php +++ /dev/null @@ -1,17 +0,0 @@ -restorePreviouslySuspendedVariants(); - } - - public function down(): void - { - // Historical variants and their purchases must remain intact. - } -}; diff --git a/tests/Feature/Event/AdminAppEventControllerTest.php b/tests/Feature/Event/AdminAppEventControllerTest.php index ef5b469..72e27ee 100644 --- a/tests/Feature/Event/AdminAppEventControllerTest.php +++ b/tests/Feature/Event/AdminAppEventControllerTest.php @@ -11,7 +11,6 @@ use App\Domains\Catalog\Models\Inventory; use App\Domains\Catalog\Models\StockReservation; use App\Domains\Catalog\Models\StockReservationLine; use App\Domains\Catalog\Models\Variant; -use App\Domains\Catalog\Services\VariantReplacementService; use App\Domains\Event\Events\EventDateRescheduled; use App\Domains\Event\Events\EventDateSuspended; use App\Domains\Purchase\Services\Checkout\CatalogSelectionResolver; @@ -576,36 +575,6 @@ class AdminAppEventControllerTest extends TestCase $this->assertFalse($ticket->fresh()->resolvedValidity()->isResolvable); } - public function test_previous_suspensions_restore_variants_with_usable_dates(): void - { - $tenant = $this->createTenant('acme'); - $suspendedDate = $tenant->eventDates()->create([ - 'date' => '2027-10-09', - 'time_start' => '09:00', - 'time_end' => '18:30', - 'suspended_at' => now(), - ]); - $usableDate = $tenant->eventDates()->create([ - 'date' => '2027-10-10', - 'time_start' => '09:00', - 'time_end' => '18:30', - ]); - $variant = $this->createVariant($tenant); - $variant->eventDates()->sync([$suspendedDate->id, $usableDate->id]); - $variant->inventory->update(['real_stock' => 5]); - $variant->update(['sales_disabled_at' => now()]); - - $service = app(VariantReplacementService::class); - $this->assertSame(1, $service->restorePreviouslySuspendedVariants()); - $this->assertSame(0, $service->restorePreviouslySuspendedVariants()); - - $replacement = $variant->fresh()->replacement; - $this->assertNotNull($replacement); - $this->assertSame([$usableDate->id], $replacement->selectedEventDates()->pluck('id')->all()); - $this->assertSame(5, $replacement->inventory->availableStock()); - $this->assertTrue(CatalogItem::query()->whereKey($variant->catalog_item_id)->whereAvailable()->exists()); - } - public function test_update_and_date_creation_validate_their_own_payloads(): void { $tenant = $this->createTenant('acme');