feat: Implement inventory policy for product variants

- Introduced InventoryPolicy enum to manage tracked and unlimited inventory types.
- Updated ProductVariant model to include inventory_policy and cantidad_vendida attributes.
- Modified addItem and updateItem methods in Cart to check available quantity based on inventory policy.
- Added migration to include inventory_policy and cantidad_vendida in productos_variantes table.
- Enhanced tests to validate inventory behavior for both tracked and unlimited policies.
- Updated various request and resource classes to handle new inventory fields.
This commit is contained in:
2026-07-16 08:36:59 -03:00
parent 716d8e447c
commit 10157d7c63
16 changed files with 547 additions and 73 deletions

View File

@@ -4,6 +4,7 @@ namespace Tests\Feature\Catalog;
use App\Domains\Attachable\Enums\AttachmentType;
use App\Domains\Attachable\Models\Attachment;
use App\Domains\Catalog\Enums\InventoryPolicy;
use App\Domains\Catalog\Models\Attribute;
use App\Domains\Catalog\Models\Brand;
use App\Domains\Catalog\Models\Product;
@@ -768,6 +769,67 @@ class ProductControllerTest extends TestCase
$response->assertJsonValidationErrors(['variant_id']);
}
public function test_it_creates_an_unlimited_default_variant_and_exposes_inventory_fields(): void
{
$response = $this->postJson("/api/tenants/{$this->tenant->codigo}/productos", [
'categoria_id' => 1,
'brand_id' => $this->brand->id,
'slug' => 'unlimited-product',
'nombre' => 'Unlimited Product',
'precio' => 100,
'stock' => 0,
'inventory_policy' => InventoryPolicy::Unlimited->value,
]);
$response->assertCreated();
$product = Product::query()->where('slug', 'unlimited-product')->firstOrFail();
$variant = $product->variants()->firstOrFail();
$this->assertSame(InventoryPolicy::Unlimited, $variant->inventory_policy);
$this->getJson("/api/tenants/{$this->tenant->codigo}/productos/{$product->id}")
->assertOk()
->assertJsonPath('data.variant.id', $variant->id)
->assertJsonPath('data.variant.inventory_policy', InventoryPolicy::Unlimited->value)
->assertJsonPath('data.variant.cantidad_maxima', null)
->assertJsonPath('data.variant.cantidad_vendida', 0)
->assertJsonPath('data.variants_map.0.inventory_policy', InventoryPolicy::Unlimited->value)
->assertJsonPath('data.variants_map.0.cantidad_maxima', null)
->assertJsonPath('data.variants_map.0.cantidad_vendida', 0);
}
public function test_it_rejects_invalid_or_updated_inventory_policies(): void
{
$this->postJson("/api/tenants/{$this->tenant->codigo}/productos", [
'categoria_id' => 1,
'brand_id' => $this->brand->id,
'slug' => 'invalid-policy',
'nombre' => 'Invalid Policy',
'precio' => 100,
'inventory_policy' => 'sometimes',
])->assertUnprocessable()->assertJsonValidationErrors(['inventory_policy']);
$product = Product::query()->create([
'tenant_codigo' => $this->tenant->codigo,
'categoria_id' => 1,
'brand_id' => $this->brand->id,
'slug' => 'immutable-policy',
'nombre' => 'Immutable Policy',
'precio' => 100,
]);
$variant = $product->variants()->create([
'stock' => 0,
'inventory_policy' => InventoryPolicy::Unlimited->value,
]);
$this->putJson(
"/api/tenants/{$this->tenant->codigo}/productos/{$product->id}/variants/{$variant->id}",
['inventory_policy' => InventoryPolicy::Tracked->value],
)->assertUnprocessable()->assertJsonValidationErrors(['inventory_policy']);
$this->assertSame(InventoryPolicy::Unlimited, $variant->fresh()->inventory_policy);
}
private function createAttachment(string $path): Attachment
{
return Attachment::create([