feat(ticket): resolve effective event dates and handle reschedule chains
This commit is contained in:
37
app/Domains/Event/Services/EffectiveEventDateResolver.php
Normal file
37
app/Domains/Event/Services/EffectiveEventDateResolver.php
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Domains\Event\Services;
|
||||||
|
|
||||||
|
use App\Domains\Event\Models\EventDate;
|
||||||
|
|
||||||
|
class EffectiveEventDateResolver
|
||||||
|
{
|
||||||
|
public function resolve(EventDate $eventDate): ?EventDate
|
||||||
|
{
|
||||||
|
$current = $eventDate;
|
||||||
|
$visited = [];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
$identity = $current->getKey() === null
|
||||||
|
? 'object:'.spl_object_id($current)
|
||||||
|
: 'key:'.$current->getKey();
|
||||||
|
|
||||||
|
if (isset($visited[$identity])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$visited[$identity] = true;
|
||||||
|
|
||||||
|
if ($current->rescheduled_to_event_date_id === null) {
|
||||||
|
return $current->cancelled_at === null ? $current : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$current->loadMissing('rescheduledTo');
|
||||||
|
$current = $current->rescheduledTo;
|
||||||
|
|
||||||
|
if ($current === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ namespace App\Domains\Ticket\Services;
|
|||||||
|
|
||||||
use App\Domains\Catalog\Models\Variant;
|
use App\Domains\Catalog\Models\Variant;
|
||||||
use App\Domains\Catalog\Models\VariantDefinition;
|
use App\Domains\Catalog\Models\VariantDefinition;
|
||||||
|
use App\Domains\Event\Models\EventDate;
|
||||||
|
use App\Domains\Event\Services\EffectiveEventDateResolver;
|
||||||
use App\Domains\Ticket\Models\Ticket;
|
use App\Domains\Ticket\Models\Ticket;
|
||||||
use App\Domains\Ticket\Models\ValidityTime;
|
use App\Domains\Ticket\Models\ValidityTime;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -17,6 +19,14 @@ use Illuminate\Support\Collection;
|
|||||||
*/
|
*/
|
||||||
class TicketValidityResolver
|
class TicketValidityResolver
|
||||||
{
|
{
|
||||||
|
private readonly EffectiveEventDateResolver $effectiveEventDateResolver;
|
||||||
|
|
||||||
|
public function __construct(?EffectiveEventDateResolver $effectiveEventDateResolver = null)
|
||||||
|
{
|
||||||
|
$this->effectiveEventDateResolver = $effectiveEventDateResolver
|
||||||
|
?? new EffectiveEventDateResolver;
|
||||||
|
}
|
||||||
|
|
||||||
/** Relaciones necesarias para resolver tickets sin consultas N+1. */
|
/** Relaciones necesarias para resolver tickets sin consultas N+1. */
|
||||||
public const RELATIONS = [
|
public const RELATIONS = [
|
||||||
'sourceVariant.eventDates.validityTime',
|
'sourceVariant.eventDates.validityTime',
|
||||||
@@ -56,7 +66,18 @@ class TicketValidityResolver
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
$dimensions = collect();
|
$dimensions = collect();
|
||||||
$eventDates = $variant->selectedEventDates();
|
$selectedEventDates = $variant->selectedEventDates();
|
||||||
|
$eventDates = $selectedEventDates
|
||||||
|
->map(fn (EventDate $eventDate): ?EventDate => $this->effectiveEventDateResolver->resolve($eventDate))
|
||||||
|
->filter()
|
||||||
|
->unique(fn (EventDate $eventDate): int => $eventDate->getKey() ?? spl_object_id($eventDate))
|
||||||
|
->values();
|
||||||
|
|
||||||
|
if ($selectedEventDates->isNotEmpty() && $eventDates->isEmpty()) {
|
||||||
|
return ResolvedTicketValidity::unresolvable();
|
||||||
|
}
|
||||||
|
|
||||||
|
$eventDates->each->loadMissing('validityTime');
|
||||||
|
|
||||||
if ($eventDates->contains(fn ($eventDate): bool => $eventDate->validityTime === null)) {
|
if ($eventDates->contains(fn ($eventDate): bool => $eventDate->validityTime === null)) {
|
||||||
return ResolvedTicketValidity::unresolvable();
|
return ResolvedTicketValidity::unresolvable();
|
||||||
|
|||||||
@@ -471,7 +471,9 @@ class TicketGeneratorServiceTest extends TestCase
|
|||||||
$this->assertCount(2, $ticket->resolvedValidityGroups());
|
$this->assertCount(2, $ticket->resolvedValidityGroups());
|
||||||
$this->assertTrue($ticket->resolvedValidityGroups()->every(
|
$this->assertTrue($ticket->resolvedValidityGroups()->every(
|
||||||
fn ($group): bool => $group->validityTimes->count() === 2
|
fn ($group): bool => $group->validityTimes->count() === 2
|
||||||
&& $group->validityTimes->contains($lunch)
|
&& $group->validityTimes->contains(
|
||||||
|
fn (ValidityTime $validityTime): bool => $validityTime->is($lunch)
|
||||||
|
)
|
||||||
));
|
));
|
||||||
$this->assertEqualsCanonicalizing(
|
$this->assertEqualsCanonicalizing(
|
||||||
$dates->pluck('validity_time_id')->all(),
|
$dates->pluck('validity_time_id')->all(),
|
||||||
|
|||||||
Reference in New Issue
Block a user