R product columns

This commit is contained in:
a6a2f5842 2025-11-22 09:55:58 +01:00
parent b65706e029
commit afe7359ea4
8 changed files with 29 additions and 27 deletions

View File

@ -20,7 +20,7 @@ class ProductFactory extends Factory
'sku' => strtoupper($this->faker->bothify('??-####')), 'sku' => strtoupper($this->faker->bothify('??-####')),
'type' => 'simple', 'type' => 'simple',
'status' => 'published', 'status' => 'published',
'visible' => true, 'is_visible' => true,
'featured' => false, 'featured' => false,
'price' => $this->faker->randomFloat(2, 10, 1000), 'price' => $this->faker->randomFloat(2, 10, 1000),
'regular_price' => $this->faker->randomFloat(2, 10, 1000), 'regular_price' => $this->faker->randomFloat(2, 10, 1000),

View File

@ -15,7 +15,7 @@ return new class extends Migration
if (!Schema::hasTable(config('shop.tables.products', 'products'))) { if (!Schema::hasTable(config('shop.tables.products', 'products'))) {
Schema::create(config('shop.tables.products', 'products'), function (Blueprint $table) { Schema::create(config('shop.tables.products', 'products'), function (Blueprint $table) {
$table->uuid('id')->primary(); $table->uuid('id')->primary();
$table->string('name'); $table->string('name')->nullable();
$table->string('slug')->unique(); $table->string('slug')->unique();
$table->string('sku')->nullable()->unique(); $table->string('sku')->nullable()->unique();
$table->text('short_description')->nullable(); $table->text('short_description')->nullable();
@ -40,7 +40,7 @@ return new class extends Migration
$table->boolean('downloadable')->default(false); $table->boolean('downloadable')->default(false);
$table->uuid('parent_id')->nullable(); $table->uuid('parent_id')->nullable();
$table->boolean('featured')->default(false); $table->boolean('featured')->default(false);
$table->boolean('visible')->default(true); $table->boolean('is_visible')->default(true);
$table->string('status')->default('draft'); // draft, published, archived $table->string('status')->default('draft'); // draft, published, archived
$table->timestamp('published_at')->nullable(); $table->timestamp('published_at')->nullable();
$table->integer('sort_order')->default(0); $table->integer('sort_order')->default(0);
@ -50,7 +50,7 @@ return new class extends Migration
$table->softDeletes(); $table->softDeletes();
$table->index(['slug', 'status']); $table->index(['slug', 'status']);
$table->index(['featured', 'visible', 'status']); $table->index(['featured', 'is_visible', 'status']);
$table->index('parent_id'); $table->index('parent_id');
$table->foreign('parent_id')->references('id')->on(config('shop.tables.products', 'products'))->onDelete('cascade'); $table->foreign('parent_id')->references('id')->on(config('shop.tables.products', 'products'))->onDelete('cascade');
}); });
@ -87,13 +87,13 @@ return new class extends Migration
$table->text('description')->nullable(); $table->text('description')->nullable();
$table->uuid('parent_id')->nullable(); $table->uuid('parent_id')->nullable();
$table->integer('sort_order')->default(0); $table->integer('sort_order')->default(0);
$table->boolean('visible')->default(true); $table->boolean('is_visible')->default(true);
$table->json('meta')->nullable(); $table->json('meta')->nullable();
$table->timestamps(); $table->timestamps();
$table->softDeletes(); $table->softDeletes();
$table->index(['parent_id', 'visible']); $table->index(['parent_id', 'is_visible']);
$table->index(['slug', 'visible']); $table->index(['slug', 'is_visible']);
$table->foreign('parent_id')->references('id')->on(config('shop.tables.product_categories', 'product_categories'))->onDelete('cascade'); $table->foreign('parent_id')->references('id')->on(config('shop.tables.product_categories', 'product_categories'))->onDelete('cascade');
}); });
} }

View File

@ -30,7 +30,7 @@ $product = Product::create([
'price' => 49.99, 'price' => 49.99,
'regular_price' => 49.99, 'regular_price' => 49.99,
'status' => 'published', 'status' => 'published',
'visible' => true, 'is_visible' => true,
'featured' => false, 'featured' => false,
]); ]);
@ -49,7 +49,7 @@ $product = Product::create([
'sku' => 'HEAD-PREM-001', 'sku' => 'HEAD-PREM-001',
'type' => 'simple', 'type' => 'simple',
'status' => 'published', 'status' => 'published',
'visible' => true, 'is_visible' => true,
'featured' => true, 'featured' => true,
'published_at' => now(), 'published_at' => now(),
'sort_order' => 10, 'sort_order' => 10,

View File

@ -107,7 +107,7 @@ class ShopAddExampleProducts extends Command
[ [
'name' => $name, 'name' => $name,
'description' => $description, 'description' => $description,
'visible' => true, 'is_visible' => true,
'sort_order' => 0, 'sort_order' => 0,
'meta' => json_encode((object)[]), 'meta' => json_encode((object)[]),
] ]
@ -131,7 +131,7 @@ class ShopAddExampleProducts extends Command
'sku' => 'EX-' . strtoupper($this->faker->bothify('??-####')), 'sku' => 'EX-' . strtoupper($this->faker->bothify('??-####')),
'type' => $type, 'type' => $type,
'status' => $this->faker->randomElement(['published', 'published', 'published', 'draft']), // mostly published 'status' => $this->faker->randomElement(['published', 'published', 'published', 'draft']), // mostly published
'visible' => true, 'is_visible' => true,
'featured' => $this->faker->boolean(20), // 20% featured 'featured' => $this->faker->boolean(20), // 20% featured
'price' => $onSale ? $regularPrice * 0.8 : $regularPrice, 'price' => $onSale ? $regularPrice * 0.8 : $regularPrice,
'regular_price' => $regularPrice, 'regular_price' => $regularPrice,
@ -353,12 +353,13 @@ class ShopAddExampleProducts extends Command
foreach ($variations as $index => $variation) { foreach ($variations as $index => $variation) {
$variationProduct = Product::create([ $variationProduct = Product::create([
'name' => $product->name . ' - ' . $variation,
'slug' => $product->slug . '-' . \Illuminate\Support\Str::slug($variation), 'slug' => $product->slug . '-' . \Illuminate\Support\Str::slug($variation),
'sku' => $product->sku . '-' . strtoupper(substr($variation, 0, 1)), 'sku' => $product->sku . '-' . strtoupper(substr($variation, 0, 1)),
'type' => 'simple', 'type' => 'simple',
'parent_id' => $product->id, 'parent_id' => $product->id,
'status' => 'published', 'status' => 'published',
'visible' => false, // Variations are not directly visible 'is_visible' => false, // Variations are not directly visible
'price' => $product->price + ($index * 5), // Slight price increase per size 'price' => $product->price + ($index * 5), // Slight price increase per size
'regular_price' => $product->regular_price + ($index * 5), 'regular_price' => $product->regular_price + ($index * 5),
'manage_stock' => true, 'manage_stock' => true,
@ -373,7 +374,7 @@ class ShopAddExampleProducts extends Command
ProductAttribute::create([ ProductAttribute::create([
'product_id' => $variationProduct->id, 'product_id' => $variationProduct->id,
'name' => 'Size', 'key' => 'Size',
'value' => $variation, 'value' => $variation,
'sort_order' => 0, 'sort_order' => 0,
'meta' => json_encode((object)[]), 'meta' => json_encode((object)[]),
@ -387,12 +388,13 @@ class ShopAddExampleProducts extends Command
for ($i = 0; $i < $groupSize; $i++) { for ($i = 0; $i < $groupSize; $i++) {
$childProduct = Product::create([ $childProduct = Product::create([
'name' => $product->name . ' Item ' . ($i + 1),
'slug' => $product->slug . '-item-' . ($i + 1), 'slug' => $product->slug . '-item-' . ($i + 1),
'sku' => $product->sku . '-' . ($i + 1), 'sku' => $product->sku . '-' . ($i + 1),
'type' => 'simple', 'type' => 'simple',
'parent_id' => $product->id, 'parent_id' => $product->id,
'status' => 'published', 'status' => 'published',
'visible' => false, 'is_visible' => false,
'price' => $this->faker->randomFloat(2, 10, 100), 'price' => $this->faker->randomFloat(2, 10, 100),
'manage_stock' => true, 'manage_stock' => true,
'stock_quantity' => $this->faker->numberBetween(10, 50), 'stock_quantity' => $this->faker->numberBetween(10, 50),

View File

@ -43,7 +43,7 @@ class Product extends Model implements Purchasable
'downloadable', 'downloadable',
'parent_id', 'parent_id',
'featured', 'featured',
'visible', 'is_visible',
'status', 'status',
'published_at', 'published_at',
'meta', 'meta',
@ -62,7 +62,7 @@ class Product extends Model implements Purchasable
'sale_end' => 'datetime', 'sale_end' => 'datetime',
'published_at' => 'datetime', 'published_at' => 'datetime',
'featured' => 'boolean', 'featured' => 'boolean',
'visible' => 'boolean', 'is_visible' => 'boolean',
'low_stock_threshold' => 'integer', 'low_stock_threshold' => 'integer',
'sort_order' => 'integer', 'sort_order' => 'integer',
]; ];
@ -348,7 +348,7 @@ class Product extends Model implements Purchasable
public function scopeVisible($query) public function scopeVisible($query)
{ {
return $query->where('visible', true) return $query->where('is_visible', true)
->where('status', 'published') ->where('status', 'published')
->where(function ($q) { ->where(function ($q) {
$q->whereNull('published_at') $q->whereNull('published_at')
@ -405,7 +405,7 @@ class Product extends Model implements Purchasable
public function isVisible(): bool public function isVisible(): bool
{ {
if (!$this->visible || $this->status !== 'published') { if (!$this->is_visible || $this->status !== 'published') {
return false; return false;
} }

View File

@ -20,12 +20,12 @@ class ProductCategory extends Model
'description', 'description',
'parent_id', 'parent_id',
'sort_order', 'sort_order',
'visible', 'is_visible',
'meta', 'meta',
]; ];
protected $casts = [ protected $casts = [
'visible' => 'boolean', 'is_visible' => 'boolean',
'meta' => 'object', 'meta' => 'object',
]; ];
@ -82,7 +82,7 @@ class ProductCategory extends Model
public function children(): HasMany public function children(): HasMany
{ {
return $this->hasMany(self::class, 'parent_id') return $this->hasMany(self::class, 'parent_id')
->where('visible', true) ->where('is_visible', true)
->orderBy('sort_order'); ->orderBy('sort_order');
} }
@ -94,7 +94,7 @@ class ProductCategory extends Model
public function scopeVisible($query) public function scopeVisible($query)
{ {
return $query->where('visible', true); return $query->where('is_visible', true);
} }
public function scopeRoots($query) public function scopeRoots($query)
@ -105,7 +105,7 @@ class ProductCategory extends Model
// Backward compatibility accessor // Backward compatibility accessor
public function getIsVisibleAttribute(): bool public function getIsVisibleAttribute(): bool
{ {
return $this->attributes['visible'] ?? true; return $this->attributes['is_visible'] ?? true;
} }
public function getProductCountAttribute(): int public function getProductCountAttribute(): int

View File

@ -92,11 +92,11 @@ class ProductCategoryTest extends TestCase
public function it_can_check_visibility() public function it_can_check_visibility()
{ {
$visibleCategory = ProductCategory::factory()->create([ $visibleCategory = ProductCategory::factory()->create([
'visible' => true, 'is_visible' => true,
]); ]);
$hiddenCategory = ProductCategory::factory()->create([ $hiddenCategory = ProductCategory::factory()->create([
'visible' => false, 'is_visible' => false,
]); ]);
$this->assertTrue($visibleCategory->is_visible); $this->assertTrue($visibleCategory->is_visible);

View File

@ -275,12 +275,12 @@ class ProductManagementTest extends TestCase
public function it_can_scope_visible_products() public function it_can_scope_visible_products()
{ {
Product::factory()->create([ Product::factory()->create([
'visible' => true, 'is_visible' => true,
'status' => 'published', 'status' => 'published',
]); ]);
Product::factory()->create([ Product::factory()->create([
'visible' => false, 'is_visible' => false,
'status' => 'published', 'status' => 'published',
]); ]);