From 20dd246cd873e216535a8ffde6b0c49643a61de7 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Thu, 6 Aug 2026 16:13:29 -0300 Subject: [PATCH] feat(validity-time): add ValidityTimeResource and integrate into catalog and ticket resources --- .../Resources/CatalogFeaturedItemResource.php | 5 ++ .../Resources/CatalogItemDetailResource.php | 3 + .../Catalog/Resources/CatalogItemResource.php | 5 ++ .../Resources/CatalogSearchItemResource.php | 3 + .../Catalog/Services/CatalogService.php | 6 +- .../Catalog/Services/FeaturedGroupService.php | 1 + .../Ticket/Resources/TicketResource.php | 2 + .../Ticket/Resources/ValidityTimeResource.php | 34 ++++++++++++ .../Unit/Ticket/ValidityTimeResourceTest.php | 55 +++++++++++++++++++ 9 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 app/Domains/Ticket/Resources/ValidityTimeResource.php create mode 100644 tests/Unit/Ticket/ValidityTimeResourceTest.php diff --git a/app/Domains/Catalog/Resources/CatalogFeaturedItemResource.php b/app/Domains/Catalog/Resources/CatalogFeaturedItemResource.php index 2c44aaf..a080998 100644 --- a/app/Domains/Catalog/Resources/CatalogFeaturedItemResource.php +++ b/app/Domains/Catalog/Resources/CatalogFeaturedItemResource.php @@ -7,6 +7,7 @@ use App\Domains\Catalog\Enums\ProductLayout; use App\Domains\Catalog\Models\CatalogItem; use App\Domains\Catalog\Models\FeaturedGroup; use App\Domains\Catalog\Models\Variant; +use App\Domains\Ticket\Resources\ValidityTimeResource; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; @@ -30,6 +31,8 @@ class CatalogFeaturedItemResource extends JsonResource 'nombre' => $catalogItem->nombre, 'descripcion' => $catalogItem->descripcion, 'precio' => $catalogItem->precio, + 'validity_time_id' => $catalogItem->validity_time_id, + 'validity_time' => ValidityTimeResource::make($catalogItem->validityTime), 'stock_tecnico' => $catalogItem->availableStock(), 'variants' => $catalogItem->variants ->map(fn (Variant $variant): array => [ @@ -62,6 +65,8 @@ class CatalogFeaturedItemResource extends JsonResource 'type' => $catalogItem->type->value, 'nombre' => $catalogItem->nombre, 'precio' => $catalogItem->precio, + 'validity_time_id' => $catalogItem->validity_time_id, + 'validity_time' => ValidityTimeResource::make($catalogItem->validityTime), 'image' => $attachment?->getTemporaryUrl(1440), ]; } diff --git a/app/Domains/Catalog/Resources/CatalogItemDetailResource.php b/app/Domains/Catalog/Resources/CatalogItemDetailResource.php index 4e6acaa..3132411 100644 --- a/app/Domains/Catalog/Resources/CatalogItemDetailResource.php +++ b/app/Domains/Catalog/Resources/CatalogItemDetailResource.php @@ -6,6 +6,7 @@ use App\Domains\Catalog\Enums\InventoryPolicy; use App\Domains\Catalog\Models\CatalogItem; use App\Domains\Catalog\Models\ItemAttribute; use App\Domains\Catalog\Models\Variant; +use App\Domains\Ticket\Resources\ValidityTimeResource; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Support\Collection; @@ -35,6 +36,7 @@ class CatalogItemDetailResource extends JsonResource 'inventory_policy' => $this->inventory_policy?->value, 'has_tickets' => $this->has_tickets, 'validity_time_id' => $this->validity_time_id, + 'validity_time' => ValidityTimeResource::make($this->validityTime), 'attributes' => $this->itemAttributes ->map(fn (ItemAttribute $itemAttribute): array => $this->attributeData($itemAttribute)) ->values(), @@ -101,6 +103,7 @@ class CatalogItemDetailResource extends JsonResource 'label' => $option->label, 'sort_order' => $option->sort_order, 'validity_time_id' => $option->validity_time_id, + 'validity_time' => ValidityTimeResource::make($option->validityTime), 'metadata' => $option->metadata, ]) ->values(), diff --git a/app/Domains/Catalog/Resources/CatalogItemResource.php b/app/Domains/Catalog/Resources/CatalogItemResource.php index 25c3f7b..cc65946 100644 --- a/app/Domains/Catalog/Resources/CatalogItemResource.php +++ b/app/Domains/Catalog/Resources/CatalogItemResource.php @@ -3,6 +3,7 @@ namespace App\Domains\Catalog\Resources; use App\Domains\Catalog\Models\CatalogItem; +use App\Domains\Ticket\Resources\ValidityTimeResource; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; @@ -26,6 +27,10 @@ class CatalogItemResource extends JsonResource 'inventory_policy' => $this->inventory_policy?->value, 'has_tickets' => $this->has_tickets, 'validity_time_id' => $this->validity_time_id, + 'validity_time' => $this->whenLoaded( + 'validityTime', + fn () => ValidityTimeResource::make($this->validityTime), + ), 'real_stock' => $this->whenLoaded('inventory', fn () => $this->inventory?->real_stock), 'images' => $this->whenLoaded('attachments', fn () => $this->attachments ->map(fn ($attachment) => $attachment->getTemporaryUrl(1440)) diff --git a/app/Domains/Catalog/Resources/CatalogSearchItemResource.php b/app/Domains/Catalog/Resources/CatalogSearchItemResource.php index 3c83e7a..a11ebbf 100644 --- a/app/Domains/Catalog/Resources/CatalogSearchItemResource.php +++ b/app/Domains/Catalog/Resources/CatalogSearchItemResource.php @@ -5,6 +5,7 @@ namespace App\Domains\Catalog\Resources; use App\Domains\Catalog\Enums\InventoryPolicy; use App\Domains\Catalog\Models\CatalogItem; use App\Domains\Catalog\Models\Variant; +use App\Domains\Ticket\Resources\ValidityTimeResource; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; @@ -25,6 +26,8 @@ class CatalogSearchItemResource extends JsonResource 'nombre' => $this->nombre, 'descripcion' => $this->descripcion, 'precio' => $this->precio, + 'validity_time_id' => $this->validity_time_id, + 'validity_time' => ValidityTimeResource::make($this->validityTime), 'image' => $attachment?->getTemporaryUrl(1440), 'stock_tecnico' => $this->availableStock(), 'variants' => $this->variants diff --git a/app/Domains/Catalog/Services/CatalogService.php b/app/Domains/Catalog/Services/CatalogService.php index deac1e5..b9eacd1 100644 --- a/app/Domains/Catalog/Services/CatalogService.php +++ b/app/Domains/Catalog/Services/CatalogService.php @@ -128,6 +128,7 @@ class CatalogService 'category', 'brand', 'event', + 'validityTime', 'itemAttributes.attribute', 'variants.inventory', 'variants.attachments', @@ -147,7 +148,8 @@ class CatalogService 'category', 'brand', 'event', - 'itemAttributes.attribute.options', + 'validityTime', + 'itemAttributes.attribute.options.validityTime', 'variants' => fn ($query) => $query->orderBy('id'), 'variants.inventory', 'variants.attachments', @@ -203,6 +205,7 @@ class CatalogService ->with([ 'attachments', 'inventory', + 'validityTime', 'variants.inventory', 'variants.attachments', 'variants.eventDate', @@ -235,6 +238,7 @@ class CatalogService ->with([ 'attachments', 'inventory', + 'validityTime', 'variants.inventory', 'variants.attachments', 'variants.eventDate', diff --git a/app/Domains/Catalog/Services/FeaturedGroupService.php b/app/Domains/Catalog/Services/FeaturedGroupService.php index 3d68dcb..2e61579 100644 --- a/app/Domains/Catalog/Services/FeaturedGroupService.php +++ b/app/Domains/Catalog/Services/FeaturedGroupService.php @@ -40,6 +40,7 @@ class FeaturedGroupService ->with([ 'inventory', 'attachments', + 'validityTime', 'variants.inventory', 'variants.attachments', 'variants.eventDate', diff --git a/app/Domains/Ticket/Resources/TicketResource.php b/app/Domains/Ticket/Resources/TicketResource.php index a8d7714..ab9adcb 100644 --- a/app/Domains/Ticket/Resources/TicketResource.php +++ b/app/Domains/Ticket/Resources/TicketResource.php @@ -20,6 +20,8 @@ class TicketResource extends JsonResource 'description' => $this->description, 'source_catalog_item_id' => $this->source_catalog_item_id, 'source_variant_id' => $this->source_variant_id, + 'validity_time_id' => $this->validity_time_id, + 'validity_time' => ValidityTimeResource::make($this->validityTime), 'starts_at' => $this->getEffectiveStartsAt(), 'expires_at' => $this->getEffectiveExpiresAt(), 'used_at' => $this->used_at, diff --git a/app/Domains/Ticket/Resources/ValidityTimeResource.php b/app/Domains/Ticket/Resources/ValidityTimeResource.php new file mode 100644 index 0000000..912182c --- /dev/null +++ b/app/Domains/Ticket/Resources/ValidityTimeResource.php @@ -0,0 +1,34 @@ + */ + public function toArray(Request $request): array + { + $fields = match ($this->type) { + ValidityTimeType::TimeWindow => [ + 'start_time' => $this->start_time, + 'end_time' => $this->end_time, + ], + ValidityTimeType::FixedWindow => [ + 'fixed_starts_at' => $this->fixed_starts_at, + 'fixed_expires_at' => $this->fixed_expires_at, + ], + }; + + return [ + 'id' => $this->id, + 'type' => $this->type->value, + 'is_valid' => $this->isValid(), + ...array_filter($fields, fn (mixed $value): bool => $value !== null), + ]; + } +} diff --git a/tests/Unit/Ticket/ValidityTimeResourceTest.php b/tests/Unit/Ticket/ValidityTimeResourceTest.php new file mode 100644 index 0000000..34f202a --- /dev/null +++ b/tests/Unit/Ticket/ValidityTimeResourceTest.php @@ -0,0 +1,55 @@ + ValidityTimeType::TimeWindow, + 'start_time' => '11:00:00', + 'end_time' => null, + 'fixed_starts_at' => '2026-08-20 10:00:00', + ]))->resolve(); + + $this->assertSame('time_window', $resource['type']); + $this->assertTrue($resource['is_valid']); + $this->assertSame('11:00:00', $resource['start_time']); + $this->assertArrayNotHasKey('end_time', $resource); + $this->assertArrayNotHasKey('fixed_starts_at', $resource); + $this->assertArrayNotHasKey('fixed_expires_at', $resource); + } + + public function test_fixed_window_only_contains_non_null_datetime_fields(): void + { + Carbon::setTestNow('2026-08-20 11:00:00'); + $resource = ValidityTimeResource::make(new ValidityTime([ + 'type' => ValidityTimeType::FixedWindow, + 'start_time' => '11:00:00', + 'fixed_starts_at' => '2026-08-20 10:00:00', + 'fixed_expires_at' => null, + ]))->resolve(); + + $this->assertSame('fixed_window', $resource['type']); + $this->assertTrue($resource['is_valid']); + $this->assertArrayHasKey('fixed_starts_at', $resource); + $this->assertArrayNotHasKey('fixed_expires_at', $resource); + $this->assertArrayNotHasKey('start_time', $resource); + $this->assertArrayNotHasKey('end_time', $resource); + } +}