feat: add filtering for product detail attribute options based on available variant values

This commit is contained in:
2026-07-01 08:55:27 -03:00
parent 46685a7141
commit 35384b48ab
2 changed files with 55 additions and 0 deletions

View File

@@ -293,6 +293,8 @@ class ProductService
'variants.definitions.productAttribute.attribute.options', 'variants.definitions.productAttribute.attribute.options',
]); ]);
$this->filterProductDetailAttributeOptions($product);
$selectedVariant = $variantId !== null $selectedVariant = $variantId !== null
? $product->variants->firstWhere('id', $variantId) ? $product->variants->firstWhere('id', $variantId)
: $product->variants->first(fn (ProductVariant $variant) => $variant->stock > 0); : $product->variants->first(fn (ProductVariant $variant) => $variant->stock > 0);
@@ -313,4 +315,36 @@ class ProductService
return $product; return $product;
} }
protected function filterProductDetailAttributeOptions(Product $product): void
{
$availableValuesByAttributeId = [];
foreach ($product->variants as $variant) {
foreach ($variant->definitions as $definition) {
$attributeId = $definition->productAttribute?->attribute_id;
if ($attributeId === null || $definition->value === null) {
continue;
}
$availableValuesByAttributeId[$attributeId][$definition->value] = true;
}
}
foreach ($product->attributes as $attribute) {
if (! $attribute->relationLoaded('options')) {
continue;
}
$availableValues = $availableValuesByAttributeId[$attribute->id] ?? [];
$attribute->setRelation(
'options',
$attribute->options
->filter(fn ($option): bool => array_key_exists($option->value, $availableValues))
->values()
);
}
}
} }

View File

@@ -405,6 +405,10 @@ class ProductControllerTest extends TestCase
'precio' => 100.00, 'precio' => 100.00,
]); ]);
$productAttributes = $this->syncVariantAttributes($product); $productAttributes = $this->syncVariantAttributes($product);
$this->colorAttr->options()->create([
'value' => 'Verde',
'label' => 'Verde',
]);
$variant = $product->createVariant([ $variant = $product->createVariant([
'stock' => 0, 'stock' => 0,
@@ -479,6 +483,23 @@ class ProductControllerTest extends TestCase
$response->assertJsonPath('data.variant.definitions.color', 'Rojo'); $response->assertJsonPath('data.variant.definitions.color', 'Rojo');
$response->assertJsonCount(1, 'data.variant.images'); $response->assertJsonCount(1, 'data.variant.images');
$this->assertStringContainsString($variantAttachment->path, $response->json('data.variant.images.0')); $this->assertStringContainsString($variantAttachment->path, $response->json('data.variant.images.0'));
$colorAttribute = collect($response->json('data.attributes'))->firstWhere('codigo', 'color');
$this->assertNotNull($colorAttribute);
$this->assertEqualsCanonicalizing(
['Azul', 'Rojo'],
collect($colorAttribute['options'])->pluck('value')->all()
);
$attributesResponse = $this->getJson("/api/tenants/{$this->tenant->codigo}/attributes");
$attributesResponse->assertOk();
$masterColorAttribute = collect($attributesResponse->json('data'))->firstWhere('codigo', 'color');
$this->assertNotNull($masterColorAttribute);
$this->assertEqualsCanonicalizing(
['Azul', 'Rojo', 'Verde'],
collect($masterColorAttribute['options'])->pluck('value')->all()
);
} }
public function test_it_returns_requested_variant_in_product_detail(): void public function test_it_returns_requested_variant_in_product_detail(): void