feat(categories): add category retrieval and pagination for tenant-specific products

This commit is contained in:
2026-07-28 12:20:17 -03:00
parent ff9d7728e8
commit 8dc80411d7
14 changed files with 355 additions and 8 deletions

View File

@@ -0,0 +1,123 @@
<?php
namespace Tests\Feature\Catalog;
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\Catalog\Models\Inventory;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class CategoryDetailTest extends TestCase
{
use RefreshDatabase;
public function test_it_returns_category_products_paginated_with_the_tenant_search_layout(): void
{
$tenant = $this->createTenant('category-detail');
$tenant->update([
'search_product_layout' => ProductLayout::Row->value,
'search_group_layout' => GroupLayout::SimpleVertical->value,
'search_items_per_page' => 2,
]);
$category = $this->createCategory($tenant, 'Remeras');
$otherCategory = $this->createCategory($tenant, 'Pantalones');
$this->createCatalogItem($tenant, $category, 'Remera C');
$firstItem = $this->createCatalogItem($tenant, $category, 'Remera A');
$secondItem = $this->createCatalogItem($tenant, $category, 'Remera B');
$this->createCatalogItem($tenant, $otherCategory, 'Pantalón');
$this->getJson("/api/tenants/{$tenant->codigo}/categories/{$category->id}")
->assertOk()
->assertJsonPath('category.id', $category->id)
->assertJsonPath('category.nombre', 'Remeras')
->assertJsonPath('category.categoria_id', null)
->assertJsonPath('layout', ProductLayout::Row->value)
->assertJsonPath('group_layout', GroupLayout::SimpleVertical->value)
->assertJsonPath('meta.current_page', 1)
->assertJsonPath('meta.per_page', 2)
->assertJsonPath('meta.total', 3)
->assertJsonCount(2, 'data')
->assertJsonPath('data.0.id', $firstItem->id)
->assertJsonPath('data.1.id', $secondItem->id)
->assertJsonMissing(['nombre' => 'Pantalón']);
}
public function test_it_returns_an_empty_paginated_response_for_a_category_without_products(): void
{
$tenant = $this->createTenant('empty-category');
$category = $this->createCategory($tenant, 'Sin productos');
$this->getJson("/api/tenants/{$tenant->codigo}/categories/{$category->id}")
->assertOk()
->assertJsonPath('category.id', $category->id)
->assertJsonPath('meta.total', 0)
->assertJsonPath('meta.current_page', 1)
->assertJsonCount(0, 'data');
}
public function test_it_rejects_categories_from_another_tenant(): void
{
$tenant = $this->createTenant('category-owner');
$otherTenant = $this->createTenant('category-foreign');
$foreignCategory = $this->createCategory($otherTenant, 'Ajena');
$this->getJson("/api/tenants/{$tenant->codigo}/categories/{$foreignCategory->id}")
->assertNotFound();
}
public function test_it_validates_the_page(): void
{
$tenant = $this->createTenant('category-page');
$category = $this->createCategory($tenant, 'Remeras');
$this->getJson("/api/tenants/{$tenant->codigo}/categories/{$category->id}?page=0")
->assertUnprocessable()
->assertJsonValidationErrors('page');
}
private function createTenant(string $code): Tenant
{
return Tenant::query()->create([
'codigo' => $code,
'nombre' => ucfirst($code),
'dominio' => "{$code}.local",
'primary_color' => '#000000',
'secondary_color' => '#000000',
'danger_color' => '#000000',
'success_color' => '#000000',
'header_bg_color' => '#000000',
'footer_bg_color' => '#000000',
]);
}
private function createCategory(Tenant $tenant, string $name): Category
{
return Category::query()->create([
'tenant_code' => $tenant->codigo,
'nombre' => $name,
]);
}
private function createCatalogItem(
Tenant $tenant,
Category $category,
string $name,
): CatalogItem {
$inventory = Inventory::query()->create(['real_stock' => 10]);
return CatalogItem::query()->create([
'tenant_code' => $tenant->codigo,
'category_id' => $category->id,
'inventory_id' => $inventory->id,
'slug' => str($name)->slug()->toString(),
'nombre' => $name,
'descripcion' => "{$name} description",
'precio' => 100,
]);
}
}