'integer', 'source_variant_id' => 'integer', 'source_purchase_id' => 'integer', 'used_at' => 'datetime', 'scanner_user_id' => 'integer', 'user_id' => 'integer', ]; } /** @return BelongsTo */ public function tenant(): BelongsTo { return $this->belongsTo(Tenant::class, 'tenant_code', 'codigo'); } /** @return BelongsTo */ public function user(): BelongsTo { return $this->belongsTo(User::class); } /** @return BelongsTo */ public function scannerUser(): BelongsTo { return $this->belongsTo(User::class, 'scanner_user_id'); } /** @return BelongsTo */ public function sourcePurchase(): BelongsTo { return $this->belongsTo(Purchase::class, 'source_purchase_id'); } /** @return BelongsTo */ public function sourceCatalogItem(): BelongsTo { return $this->belongsTo(CatalogItem::class, 'source_catalog_item_id'); } /** @return BelongsTo */ public function sourceVariant(): BelongsTo { return $this->belongsTo(Variant::class, 'source_variant_id'); } /** @return HasMany */ public function validityGroups(): HasMany { return $this->hasMany(TicketValidityGroup::class); } public function isValid(): bool { if ($this->used_at !== null) { return false; } $validityGroups = $this->resolvedValidityGroups(); return $validityGroups->isEmpty() || $validityGroups->contains( fn (TicketValidityGroup $group): bool => $group->isValid() ); } public function getIsValidAttribute(): bool { return $this->isValid(); } public function getIsExpiredAttribute(): bool { $validityGroups = $this->resolvedValidityGroups(); return $this->used_at === null && $validityGroups->isNotEmpty() && $validityGroups->every( fn (TicketValidityGroup $group): bool => $group->isExpired() ); } public function getIsUsedAttribute(): bool { return $this->used_at !== null; } public function getStatusAttribute(): string { if ($this->is_used) { return self::STATUS_USED; } if ($this->is_expired) { return self::STATUS_EXPIRED; } return self::STATUS_ACTIVE; } public function getEffectiveStartsAt(): ?CarbonInterface { return $this->resolvedValidityGroups() ->map(fn (TicketValidityGroup $group): ?CarbonInterface => $group->effectiveStartsAt()) ->filter() ->sortBy(fn (CarbonInterface $startsAt): int => $startsAt->getTimestamp()) ->first(); } public function getEffectiveExpiresAt(): ?CarbonInterface { return $this->resolvedValidityGroups() ->map(fn (TicketValidityGroup $group): ?CarbonInterface => $group->effectiveExpiresAt()) ->filter() ->sortByDesc(fn (CarbonInterface $expiresAt): int => $expiresAt->getTimestamp()) ->first(); } /** @return Collection */ public function allValidityTimes(): Collection { return $this->resolvedValidityGroups() ->flatMap(fn (TicketValidityGroup $group): EloquentCollection => $group->resolvedValidityTimes()) ->unique( fn (ValidityTime $validityTime): int => $validityTime->getKey() ?? spl_object_id($validityTime) ) ->values(); } /** @return EloquentCollection */ public function resolvedValidityGroups(): EloquentCollection { if ($this->relationLoaded('validityGroups')) { return $this->getRelation('validityGroups'); } if (! $this->exists) { return new EloquentCollection; } $validityGroups = $this->validityGroups() ->with('validityTimes') ->get(); $this->setRelation('validityGroups', $validityGroups); return $validityGroups; } }