feat(tenant): add categories relationship and structure to tenant resource and controller

This commit is contained in:
2026-07-28 10:57:00 -03:00
parent 89f6dab0c4
commit e16d91f3f9
4 changed files with 92 additions and 1 deletions

View File

@@ -16,7 +16,14 @@ class BootstrapTenantController extends Controller
return TenantResource::make(
Tenant::query()
->with(['headerLogo', 'footerLogo', 'mainCarouselImages', 'menues', 'socialMedia'])
->with([
'headerLogo',
'footerLogo',
'mainCarouselImages',
'menues',
'socialMedia',
'categories' => fn ($query) => $query->orderBy('nombre'),
])
->where('dominio', $dominio)
->firstOrFail()
);

View File

@@ -6,6 +6,7 @@ use App\Domains\Attachable\Models\Attachment;
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\Menu\Models\Menu;
use App\Domains\Menu\Models\TenantMenu;
use Illuminate\Database\Eloquent\Attributes\Fillable;
@@ -109,6 +110,14 @@ class Tenant extends Model
return $this->hasMany(CatalogItem::class, 'tenant_code', 'codigo');
}
/**
* @return HasMany<Category, $this>
*/
public function categories(): HasMany
{
return $this->hasMany(Category::class, 'tenant_code', 'codigo');
}
/**
* @return BelongsToMany<SocialMedia, $this>
*/

View File

@@ -2,6 +2,7 @@
namespace App\Domains\Tenant\Resources;
use App\Domains\Catalog\Models\Category;
use App\Domains\Menu\Models\Menu;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Http\Request;
@@ -64,9 +65,43 @@ class TenantResource extends JsonResource
'menues',
fn () => $this->menuTree($this->menues)
),
'categories' => $this->whenLoaded(
'categories',
fn () => $this->categoryTree($this->categories)
),
];
}
/**
* @param Collection<int, Category> $categories
* @return Collection<int, array<string, mixed>>
*/
private function categoryTree(Collection $categories): Collection
{
$categoryIds = $categories->pluck('id')->flip();
$childrenByParent = $categories
->filter(fn (Category $category) => $category->categoria_id !== null
&& $categoryIds->has($category->categoria_id))
->groupBy('categoria_id');
$formatCategory = function (Category $category) use (&$formatCategory, $childrenByParent): array {
return [
'id' => $category->id,
'nombre' => $category->nombre,
'subcategories' => $childrenByParent
->get($category->id, collect())
->map($formatCategory)
->values(),
];
};
return $categories
->filter(fn (Category $category) => $category->categoria_id === null
|| ! $categoryIds->has($category->categoria_id))
->map($formatCategory)
->values();
}
/**
* @param Collection<int, Menu> $menus
* @return Collection<int, array<string, mixed>>

View File

@@ -4,6 +4,7 @@ namespace Tests\Feature\Tenant;
use App\Domains\Attachable\Enums\AttachmentType;
use App\Domains\Attachable\Models\Attachment;
use App\Domains\Catalog\Models\Category;
use App\Domains\Menu\Models\Menu;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Foundation\Testing\RefreshDatabase;
@@ -95,6 +96,45 @@ class BootstrapTenantControllerTest extends TestCase
->assertJsonPath('data.dominio', 'acme.com');
}
public function test_it_returns_only_the_tenant_categories_in_the_bootstrap(): void
{
$tenant = $this->createTenant();
$otherTenant = $this->createTenant([
'codigo' => 'globex',
'nombre' => 'Globex',
'dominio' => 'globex.com',
]);
$parent = Category::query()->create([
'tenant_code' => $tenant->codigo,
'nombre' => 'Remeras',
]);
Category::query()->create([
'tenant_code' => $tenant->codigo,
'categoria_id' => $parent->id,
'nombre' => 'Manga corta',
]);
Category::query()->create([
'tenant_code' => $otherTenant->codigo,
'nombre' => 'Otra categoría',
]);
Category::query()->create([
'tenant_code' => null,
'nombre' => 'Global',
]);
$this->getJson('/api/tenants/bootstrap/acme.com')
->assertOk()
->assertJsonCount(1, 'data.categories')
->assertJsonPath('data.categories.0.nombre', 'Remeras')
->assertJsonCount(1, 'data.categories.0.subcategories')
->assertJsonPath('data.categories.0.subcategories.0.nombre', 'Manga corta')
->assertJsonPath('data.categories.0.subcategories.0.subcategories', [])
->assertJsonMissingPath('data.categories.0.categoria_id')
->assertJsonMissing(['nombre' => 'Otra categoría'])
->assertJsonMissing(['nombre' => 'Global']);
}
public function test_it_returns_not_found_when_the_domain_does_not_exist(): void
{
$response = $this->getJson('/api/tenants/bootstrap/missing.example');