feat: implement product controller, service, and feature tests with updated API collection.

This commit is contained in:
2026-06-29 17:01:21 -03:00
parent 14f3906ef0
commit 46e7c27ae7
3 changed files with 168 additions and 11 deletions

View File

@@ -15,19 +15,10 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class ProductController extends Controller
{
public function index(Tenant $tenant): JsonResponse
public function index(Tenant $tenant, ProductService $productService): JsonResponse
{
return ProductResource::collection(
Product::query()
->where('tenant_codigo', $tenant->codigo)
->with([
'attachments' => fn ($query) => $query->orderBy('attachments.id')->limit(1),
'brand',
'category',
'attributes.options',
])
->latest()
->paginateFromRequest()
$productService->getProductos($tenant)
)->response();
}

View File

@@ -244,4 +244,37 @@ class ProductService
Product::deleteAttribute($attribute);
});
}
/**
* Get products for a tenant with resolved first image (with fallback to first variant's first image).
*/
public function getProductos(Tenant $tenant): \Illuminate\Contracts\Pagination\LengthAwarePaginator
{
$products = Product::query()
->where('tenant_codigo', $tenant->codigo)
->with([
'attachments' => fn ($query) => $query->orderBy('attachments.id'),
'brand',
'category',
'variants.attachments' => fn ($query) => $query->orderBy('attachments.id'),
])
->latest()
->paginateFromRequest();
foreach ($products as $product) {
$resolvedAttachment = null;
if ($product->attachments->isNotEmpty()) {
$resolvedAttachment = $product->attachments->first();
} else {
$firstVariant = $product->variants->sortBy('id')->first();
if ($firstVariant && $firstVariant->attachments->isNotEmpty()) {
$resolvedAttachment = $firstVariant->attachments->first();
}
}
$product->setRelation('attachments', $resolvedAttachment ? collect([$resolvedAttachment]) : collect());
}
return $products;
}
}