Add tests for ticket validity and event date formatting

- Create TicketValiditySchemaTest to verify database schema for ticket validity.
- Update CatalogModelsTest to include tests for event date attributes and selection options.
- Introduce EventDateTextFormatterTest for formatting event dates in Spanish.
- Refactor EventModelsTest to include validity time relationships.
- Add SaleDetailResourceTest to ensure correct serialization of purchase items.
- Enhance TicketTest with validity time checks and status management.
- Implement ValidityTimeResourceTest to validate resource output for different validity types.
- Add ValidityTimeTest to verify casting and validity checks for validity time types.
This commit is contained in:
2026-08-11 12:41:35 -03:00
parent b294e5c46e
commit 02cf3f3773
166 changed files with 10203 additions and 1849 deletions

View File

@@ -7,7 +7,7 @@ use App\Domains\Catalog\Enums\GroupLayout;
use App\Domains\Catalog\Enums\ProductLayout;
use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Catalog\Models\Category;
use App\Domains\Event\Models\Event;
use App\Domains\Event\Models\EventDate;
use App\Domains\Menu\Models\Menu;
use App\Domains\Menu\Models\TenantMenu;
use Illuminate\Database\Eloquent\Attributes\Fillable;
@@ -33,7 +33,11 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
'search_product_layout',
'search_group_layout',
'search_items_per_page',
'active_event_id',
'display_categories',
'display_seach_bar',
'event_title',
'event_location',
'event_date_text',
])]
class Tenant extends Model
{
@@ -43,6 +47,8 @@ class Tenant extends Model
'search_product_layout' => ProductLayout::ColumnWithImage->value,
'search_group_layout' => GroupLayout::Paginated->value,
'search_items_per_page' => 12,
'display_categories' => true,
'display_seach_bar' => true,
];
public function getRouteKeyName(): string
@@ -61,7 +67,8 @@ class Tenant extends Model
'search_product_layout' => ProductLayout::class,
'search_group_layout' => GroupLayout::class,
'search_items_per_page' => 'integer',
'active_event_id' => 'integer',
'display_categories' => 'boolean',
'display_seach_bar' => 'boolean',
];
}
@@ -94,16 +101,12 @@ class Tenant extends Model
return $this->hasMany(CatalogItem::class, 'tenant_code', 'codigo');
}
/** @return HasMany<Event, $this> */
public function events(): HasMany
/** @return HasMany<EventDate, $this> */
public function eventDates(): HasMany
{
return $this->hasMany(Event::class, 'tenant_code', 'codigo');
}
/** @return BelongsTo<Event, $this> */
public function activeEvent(): BelongsTo
{
return $this->belongsTo(Event::class, 'active_event_id');
return $this->hasMany(EventDate::class, 'tenant_code', 'codigo')
->orderBy('date')
->orderBy('time_start');
}
/**

View File

@@ -19,6 +19,10 @@ class WebsiteExtra extends Model
protected $table = 'websites_extras';
protected $attributes = [
'is_enabled' => true,
];
private mixed $resolvedConfig = null;
private bool $hasResolvedConfig = false;

View File

@@ -75,6 +75,8 @@ class StoreTenantRequest extends FormRequest
'search_product_layout' => ['sometimes', Rule::enum(ProductLayout::class)],
'search_group_layout' => ['sometimes', Rule::enum(GroupLayout::class)],
'search_items_per_page' => ['sometimes', 'integer', 'min:4', 'max:48'],
'display_categories' => ['sometimes', 'boolean'],
'display_seach_bar' => ['sometimes', 'boolean'],
'website_type_code' => [
'required_with:extras',
'sometimes',

View File

@@ -85,6 +85,8 @@ class UpdateTenantRequest extends FormRequest
'search_product_layout' => ['sometimes', Rule::enum(ProductLayout::class)],
'search_group_layout' => ['sometimes', Rule::enum(GroupLayout::class)],
'search_items_per_page' => ['sometimes', 'integer', 'min:4', 'max:48'],
'display_categories' => ['sometimes', 'boolean'],
'display_seach_bar' => ['sometimes', 'boolean'],
];
}
}

View File

@@ -9,6 +9,7 @@ use App\Domains\Tenant\Models\Tenant;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
/**
* @mixin Tenant
@@ -32,14 +33,13 @@ class TenantResource extends JsonResource
'header_bg_color' => $this->header_bg_color,
'footer_bg_color' => $this->footer_bg_color,
'website_type_code' => $this->website_type_code,
'active_event_id' => $this->active_event_id,
'active_event' => $this->whenLoaded('activeEvent', fn () => $this->activeEvent === null
'event_date_text' => $this->event_date_text,
'event' => $this->whenLoaded('eventDates', fn () => $this->event_title === null
? null
: [
'id' => $this->activeEvent->id,
'name' => $this->activeEvent->name,
'address' => $this->activeEvent->address,
'dates' => $this->activeEvent->dates->map(fn ($eventDate): array => [
'title' => $this->event_title,
'location' => $this->event_location,
'dates' => $this->eventDates->map(fn ($eventDate): array => [
'id' => $eventDate->id,
'date' => $eventDate->date->format('Y-m-d'),
'time_start' => $eventDate->time_start,
@@ -62,6 +62,8 @@ class TenantResource extends JsonResource
'search_product_layout' => $this->search_product_layout->value,
'search_group_layout' => $this->search_group_layout->value,
'search_items_per_page' => $this->search_items_per_page,
'display_categories' => $this->display_categories,
'display_seach_bar' => $this->display_seach_bar,
'social_media' => $this->whenLoaded(
'socialMedia',
fn () => $this->socialMedia
@@ -158,6 +160,10 @@ class TenantResource extends JsonResource
$formatted['submenues'] = $childrenByParent
->get($menu->code, collect())
->sortBy(
fn (Menu $submenu) => Str::lower(Str::ascii($submenu->label)),
SORT_NATURAL
)
->map($formatMenu)
->values();
@@ -167,6 +173,10 @@ class TenantResource extends JsonResource
return $menus
->filter(fn (Menu $menu) => $menu->parent_menu_code === null
|| ! $menuCodes->has($menu->parent_menu_code))
->sortBy(
fn (Menu $menu) => Str::lower(Str::ascii($menu->label)),
SORT_NATURAL
)
->map($formatMenu)
->values();
}

View File

@@ -15,7 +15,7 @@ class TenantInformationService
'footerLogo',
'socialMedia',
'websiteExtras.websiteTypeExtra',
'activeEvent.dates',
'eventDates',
];
/**

View File

@@ -0,0 +1,30 @@
# Dominio Tenant
## Propósito
Es la raíz del modelo multi-tenant. Gestiona organizaciones/sitios, tipos de web, redes sociales, logos y extras configurables por sitio.
## Modelo
- `Tenant`: entidad principal, resuelta en rutas por `codigo`; relaciona catálogo, fechas, redes, menús y configuración visual.
- `WebsiteType`: plantilla o tipo de sitio disponible.
- `WebsiteTypeExtra`: definición de un extra y su configuración admitida.
- `WebsiteExtra`: valor resuelto y estado del extra para un tenant.
- `SocialMedia`: catálogo de redes sociales asociables.
## Servicios
- `TenantService`: crea y actualiza tenants, incluyendo sus recursos asociados.
- `TenantInformationService`: carga un tenant y las relaciones requeridas por cada contexto.
- `WebsiteTypeService`: crea o actualiza tipos de sitio.
- `WebsiteExtraService`: construye reglas dinámicas, crea, actualiza y habilita/deshabilita extras.
- `TenantDomainNormalizer`: normaliza dominios antes de resolver el tenant.
## Endpoints
- Recurso REST público/administrativo `/tenants`.
- Bajo `/v1/adminapp/tenant/website-extras`, con autenticación y contexto de tenant: consulta general, detalle, actualización y activación/desactivación.
## Dependencias y reglas
Usa `Attachable` para logos y archivos. Es referenciado por casi todos los dominios para aislamiento. El `codigo` es clave de ruta y clave foránea heredada; no debe sustituirse por `id` sin una migración integral.