setRawAttributes([ 'is_required' => 1, 'metadata_schema' => '{"swatch":true}', 'type' => FieldType::Select->value, ]); $this->assertSame('attribute', $attribute->getTable()); $this->assertTrue($attribute->is_required); $this->assertSame(['swatch' => true], $attribute->metadata_schema); $this->assertSame(FieldType::Select, $attribute->type); $this->assertInstanceOf(Tenant::class, $attribute->tenant()->getRelated()); $this->assertInstanceOf(AttributeOption::class, $attribute->options()->getRelated()); } public function test_catalog_item_is_the_catalog_root(): void { $item = new CatalogItem; $item->setRawAttributes([ 'category_id' => '10', 'brand_id' => '20', 'inventory_id' => '30', 'type' => CatalogItemType::Standard->value, 'precio' => '12.50', 'inventory_policy' => InventoryPolicy::Tracked->value, 'has_tickets' => 1, ]); $this->assertSame('catalog_items', $item->getTable()); $this->assertFalse($item->usesTimestamps()); $this->assertSame(10, $item->category_id); $this->assertSame(20, $item->brand_id); $this->assertSame(30, $item->inventory_id); $this->assertSame(CatalogItemType::Standard, $item->type); $this->assertSame('12.50', $item->precio); $this->assertSame(InventoryPolicy::Tracked, $item->inventory_policy); $this->assertTrue($item->has_tickets); $this->assertInstanceOf(Tenant::class, $item->tenant()->getRelated()); $this->assertInstanceOf(Category::class, $item->category()->getRelated()); $this->assertInstanceOf(Brand::class, $item->brand()->getRelated()); $this->assertInstanceOf(Inventory::class, $item->inventory()->getRelated()); $this->assertInstanceOf(BundleComponent::class, $item->bundleComponents()->getRelated()); $this->assertInstanceOf(BundleComponent::class, $item->bundleComponentUsages()->getRelated()); $this->assertInstanceOf(Variant::class, $item->variants()->getRelated()); $this->assertInstanceOf(Attribute::class, $item->attributes()->getRelated()); $this->assertInstanceOf(ItemAttribute::class, $item->itemAttributes()->getRelated()); $this->assertInstanceOf(FeaturedItem::class, $item->featuredItems()->getRelated()); $this->assertInstanceOf(Attachment::class, $item->attachments()->getRelated()); $this->assertSame('catalog_items_attachments', $item->attachments()->getTable()); } public function test_featured_models_map_catalog_relations_and_layout(): void { $group = new FeaturedGroup; $group->setRawAttributes([ 'product_layout' => ProductLayout::ColumnWithImage->value, 'group_order' => '2', ]); $featuredItem = new FeaturedItem; $featuredItem->setRawAttributes([ 'featured_group_id' => '10', 'catalog_item_id' => '20', 'order' => '3', ]); $this->assertSame('featured_groups', $group->getTable()); $this->assertFalse($group->usesTimestamps()); $this->assertSame(ProductLayout::ColumnWithImage, $group->product_layout); $this->assertSame(2, $group->group_order); $this->assertInstanceOf(Tenant::class, $group->tenant()->getRelated()); $this->assertInstanceOf(FeaturedItem::class, $group->featuredItems()->getRelated()); $this->assertSame('featured_items', $featuredItem->getTable()); $this->assertFalse($featuredItem->usesTimestamps()); $this->assertSame(10, $featuredItem->featured_group_id); $this->assertSame(20, $featuredItem->catalog_item_id); $this->assertSame(3, $featuredItem->order); $this->assertInstanceOf(FeaturedGroup::class, $featuredItem->featuredGroup()->getRelated()); $this->assertInstanceOf(CatalogItem::class, $featuredItem->catalogItem()->getRelated()); } public function test_variant_has_direct_catalog_and_inventory_relations(): void { $variant = new Variant; $variant->setRawAttributes(['catalog_item_id' => '10', 'inventory_id' => '20']); $this->assertSame('variantes', $variant->getTable()); $this->assertSame(10, $variant->catalog_item_id); $this->assertSame(20, $variant->inventory_id); $this->assertInstanceOf(CatalogItem::class, $variant->catalogItem()->getRelated()); $this->assertInstanceOf(Inventory::class, $variant->inventory()->getRelated()); $this->assertInstanceOf(VariantDefinition::class, $variant->definitions()->getRelated()); $this->assertInstanceOf(Attachment::class, $variant->attachments()->getRelated()); $this->assertSame('catalog_items_attachments', $variant->attachments()->getTable()); } public function test_inventory_maps_stock_without_a_polymorphic_owner(): void { $inventory = $this->trackedInventory(realStock: 10, reservedStock: 3); $inventory->sold_units = '2'; $this->assertSame('inventories', $inventory->getTable()); $this->assertFalse($inventory->usesTimestamps()); $this->assertSame(2, $inventory->sold_units); $this->assertSame(7, $inventory->availableStock()); $this->assertInstanceOf(CatalogItem::class, $inventory->catalogItem()->getRelated()); $this->assertInstanceOf(Variant::class, $inventory->variant()->getRelated()); } public function test_catalog_item_aggregates_variant_inventory(): void { $first = (new Variant)->setRelation('inventory', $this->trackedInventory(10, 3)); $second = (new Variant)->setRelation('inventory', $this->trackedInventory(5, 1)); $item = new CatalogItem; $item->inventory_policy = InventoryPolicy::Tracked; $item->setRelation('variants', new EloquentCollection([$first, $second])); $item->setRelation('inventory', null); $this->assertSame(11, $item->availableStock()); $this->assertTrue($item->isAvailable()); } public function test_catalog_item_prioritizes_its_inventory_over_variants(): void { $item = new CatalogItem; $item->inventory_policy = InventoryPolicy::Tracked; $item->setRelation('variants', new EloquentCollection([ (new Variant)->setRelation('inventory', $this->trackedInventory(100, 0)), ])); $item->setRelation('inventory', $this->trackedInventory(8, 2)); $this->assertSame(6, $item->availableStock()); $this->assertTrue($item->isAvailable()); } public function test_item_attribute_and_variant_definition_use_catalog_keys(): void { $itemAttribute = new ItemAttribute; $definition = new VariantDefinition; $this->assertSame('item_attributes', $itemAttribute->getTable()); $this->assertInstanceOf(CatalogItem::class, $itemAttribute->catalogItem()->getRelated()); $this->assertInstanceOf(Attribute::class, $itemAttribute->attribute()->getRelated()); $this->assertInstanceOf(VariantDefinition::class, $itemAttribute->variantDefinitions()->getRelated()); $this->assertSame('variant_values', $definition->getTable()); $this->assertInstanceOf(Variant::class, $definition->variant()->getRelated()); $this->assertInstanceOf(ItemAttribute::class, $definition->itemAttribute()->getRelated()); } private function trackedInventory(int $realStock, int $reservedStock): Inventory { $inventory = new Inventory; $inventory->setRawAttributes([ 'real_stock' => $realStock, 'reserved_stock' => $reservedStock, ]); return $inventory; } }