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:
@@ -21,8 +21,8 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
'source_purchase_id',
|
||||
'source_catalog_item_id',
|
||||
'source_variant_id',
|
||||
'starts_at',
|
||||
'expires_at',
|
||||
'validity_time_id',
|
||||
'service_date',
|
||||
'used_at',
|
||||
'scanner_user_id',
|
||||
'user_id',
|
||||
@@ -45,8 +45,8 @@ class Ticket extends Model
|
||||
'source_catalog_item_id' => 'integer',
|
||||
'source_variant_id' => 'integer',
|
||||
'source_purchase_id' => 'integer',
|
||||
'starts_at' => 'datetime',
|
||||
'expires_at' => 'datetime',
|
||||
'validity_time_id' => 'integer',
|
||||
'service_date' => 'date',
|
||||
'used_at' => 'datetime',
|
||||
'scanner_user_id' => 'integer',
|
||||
'user_id' => 'integer',
|
||||
@@ -89,6 +89,12 @@ class Ticket extends Model
|
||||
return $this->belongsTo(Variant::class, 'source_variant_id');
|
||||
}
|
||||
|
||||
/** @return BelongsTo<ValidityTime, $this> */
|
||||
public function validityTime(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ValidityTime::class);
|
||||
}
|
||||
|
||||
public function isValid(): bool
|
||||
{
|
||||
$now = now();
|
||||
@@ -121,13 +127,17 @@ class Ticket extends Model
|
||||
|
||||
public function getEffectiveStartsAt(): ?CarbonInterface
|
||||
{
|
||||
return $this->sourceVariant?->getMinimumUseDate()
|
||||
?? $this->starts_at;
|
||||
return $this->validityTime?->startsAt(
|
||||
$this->service_date,
|
||||
$this->tenant?->timezone ?? config('app.timezone'),
|
||||
);
|
||||
}
|
||||
|
||||
public function getEffectiveExpiresAt(): ?CarbonInterface
|
||||
{
|
||||
return $this->sourceVariant?->getMaximumUseDate()
|
||||
?? $this->expires_at;
|
||||
return $this->validityTime?->expiresAt(
|
||||
$this->service_date,
|
||||
$this->tenant?->timezone ?? config('app.timezone'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
87
app/Domains/Ticket/Models/ValidityTime.php
Normal file
87
app/Domains/Ticket/Models/ValidityTime.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Domains\Ticket\Models;
|
||||
|
||||
use App\Domains\Catalog\Models\AttributeOption;
|
||||
use App\Domains\Catalog\Models\CatalogItem;
|
||||
use App\Domains\Ticket\Enums\ValidityTimeType;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Carbon\CarbonInterface;
|
||||
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
#[Fillable([
|
||||
'type',
|
||||
'start_time',
|
||||
'end_time',
|
||||
'fixed_starts_at',
|
||||
'fixed_expires_at',
|
||||
'active',
|
||||
])]
|
||||
class ValidityTime extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'type' => ValidityTimeType::class,
|
||||
'fixed_starts_at' => 'datetime',
|
||||
'fixed_expires_at' => 'datetime',
|
||||
'active' => 'boolean',
|
||||
];
|
||||
}
|
||||
|
||||
/** @return HasMany<CatalogItem, $this> */
|
||||
public function catalogItems(): HasMany
|
||||
{
|
||||
return $this->hasMany(CatalogItem::class);
|
||||
}
|
||||
|
||||
/** @return HasMany<AttributeOption, $this> */
|
||||
public function attributeOptions(): HasMany
|
||||
{
|
||||
return $this->hasMany(AttributeOption::class);
|
||||
}
|
||||
|
||||
/** @return HasMany<Ticket, $this> */
|
||||
public function tickets(): HasMany
|
||||
{
|
||||
return $this->hasMany(Ticket::class);
|
||||
}
|
||||
|
||||
public function startsAt(?CarbonInterface $serviceDate, string $timezone): ?CarbonInterface
|
||||
{
|
||||
if ($this->type === ValidityTimeType::FixedWindow) {
|
||||
return $this->fixed_starts_at;
|
||||
}
|
||||
|
||||
return $this->atServiceDate($serviceDate, $this->start_time, $timezone);
|
||||
}
|
||||
|
||||
public function expiresAt(?CarbonInterface $serviceDate, string $timezone): ?CarbonInterface
|
||||
{
|
||||
if ($this->type === ValidityTimeType::FixedWindow) {
|
||||
return $this->fixed_expires_at;
|
||||
}
|
||||
|
||||
return $this->atServiceDate($serviceDate, $this->end_time, $timezone);
|
||||
}
|
||||
|
||||
private function atServiceDate(
|
||||
?CarbonInterface $serviceDate,
|
||||
?string $time,
|
||||
string $timezone,
|
||||
): ?CarbonInterface {
|
||||
if ($serviceDate === null || $time === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return CarbonImmutable::parse(
|
||||
$serviceDate->format('Y-m-d').' '.$time,
|
||||
$timezone,
|
||||
)->utc();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user