A add example products command, I cleanup
This commit is contained in:
parent
8fa194e7e6
commit
ce41dea486
25
README.md
25
README.md
|
|
@ -141,6 +141,31 @@ return [
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
|
### Add Example Products
|
||||||
|
|
||||||
|
Create example products for testing and demonstration purposes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create 2 products of each type (default)
|
||||||
|
php artisan shop:add-example-products
|
||||||
|
|
||||||
|
# Create 5 products of each type
|
||||||
|
php artisan shop:add-example-products --count=5
|
||||||
|
|
||||||
|
# Clean existing example products first
|
||||||
|
php artisan shop:add-example-products --clean
|
||||||
|
```
|
||||||
|
|
||||||
|
This command creates:
|
||||||
|
- ✅ All 4 product types (simple, variable, grouped, external)
|
||||||
|
- ✅ Product categories
|
||||||
|
- ✅ Product attributes (material, size, color, etc.)
|
||||||
|
- ✅ Multiple pricing options (multi-currency, subscriptions)
|
||||||
|
- ✅ Example product actions (email notifications, stats updates)
|
||||||
|
- ✅ Variations for variable products
|
||||||
|
- ✅ Child products for grouped products
|
||||||
|
- ✅ Realistic data using Faker
|
||||||
|
|
||||||
### Reinstall Shop Tables
|
### Reinstall Shop Tables
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,407 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Blax\Shop\Console\Commands;
|
||||||
|
|
||||||
|
use Blax\Shop\Models\Product;
|
||||||
|
use Blax\Shop\Models\ProductAction;
|
||||||
|
use Blax\Shop\Models\ProductAttribute;
|
||||||
|
use Blax\Shop\Models\ProductCategory;
|
||||||
|
use Blax\Shop\Models\ProductPrice;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Faker\Factory as Faker;
|
||||||
|
|
||||||
|
class ShopAddExampleProducts extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'shop:add-example-products
|
||||||
|
{--clean : Remove existing example products first}
|
||||||
|
{--count=2 : Number of products per type}';
|
||||||
|
|
||||||
|
protected $description = 'Adds all possible example products to the shop for demonstration purposes.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Available product types in the shop system
|
||||||
|
*/
|
||||||
|
const PRODUCT_TYPES = [
|
||||||
|
'simple' => [
|
||||||
|
'name' => 'Simple Product',
|
||||||
|
'description' => 'A standalone product with no variations (e.g., a book, a service)',
|
||||||
|
],
|
||||||
|
'variable' => [
|
||||||
|
'name' => 'Variable Product',
|
||||||
|
'description' => 'A product with variations/options (e.g., a t-shirt with different sizes and colors)',
|
||||||
|
],
|
||||||
|
'grouped' => [
|
||||||
|
'name' => 'Grouped Product',
|
||||||
|
'description' => 'A collection of related products sold together (e.g., a product bundle)',
|
||||||
|
],
|
||||||
|
'external' => [
|
||||||
|
'name' => 'External Product',
|
||||||
|
'description' => 'A product that links to an external site for purchase',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $faker;
|
||||||
|
protected $categories = [];
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$this->faker = Faker::create();
|
||||||
|
|
||||||
|
if ($this->option('clean')) {
|
||||||
|
$this->cleanExampleProducts();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info('Creating example products for Laravel Shop Package...');
|
||||||
|
$this->newLine();
|
||||||
|
|
||||||
|
// Create categories first
|
||||||
|
$this->createCategories();
|
||||||
|
|
||||||
|
$count = (int) $this->option('count');
|
||||||
|
$totalCreated = 0;
|
||||||
|
|
||||||
|
foreach (self::PRODUCT_TYPES as $type => $details) {
|
||||||
|
$this->line("<fg=cyan>Creating {$count} {$details['name']}(s)...</>");
|
||||||
|
|
||||||
|
for ($i = 1; $i <= $count; $i++) {
|
||||||
|
$product = $this->createProduct($type, $i);
|
||||||
|
$totalCreated++;
|
||||||
|
|
||||||
|
$this->line(" <fg=green>✓</> {$product->slug}");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info("✓ Successfully created {$totalCreated} example products!");
|
||||||
|
$this->line(" - Products: {$totalCreated}");
|
||||||
|
$this->line(" - Categories: " . count($this->categories));
|
||||||
|
$this->newLine();
|
||||||
|
$this->info("You can view them in your shop or use them for testing.");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function cleanExampleProducts(): void
|
||||||
|
{
|
||||||
|
$this->warn('Cleaning existing example products...');
|
||||||
|
|
||||||
|
Product::where('slug', 'like', 'example-%')->delete();
|
||||||
|
ProductCategory::where('slug', 'like', 'example-%')->delete();
|
||||||
|
|
||||||
|
$this->info('✓ Cleaned existing example products');
|
||||||
|
$this->newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createCategories(): void
|
||||||
|
{
|
||||||
|
$categoryNames = [
|
||||||
|
'Electronics' => 'Electronic devices and gadgets',
|
||||||
|
'Clothing' => 'Apparel and fashion items',
|
||||||
|
'Books' => 'Books and publications',
|
||||||
|
'Home & Garden' => 'Home improvement and garden supplies',
|
||||||
|
'Sports' => 'Sports equipment and accessories',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($categoryNames as $name => $description) {
|
||||||
|
$category = ProductCategory::firstOrCreate(
|
||||||
|
['slug' => 'example-' . \Illuminate\Support\Str::slug($name)],
|
||||||
|
[
|
||||||
|
'name' => $name,
|
||||||
|
'description' => $description,
|
||||||
|
'visible' => true,
|
||||||
|
'sort_order' => 0,
|
||||||
|
'meta' => json_encode((object)[]),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->categories[] = $category;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function createProduct(string $type, int $index): Product
|
||||||
|
{
|
||||||
|
$productName = $this->generateProductName($type);
|
||||||
|
$slug = 'example-' . \Illuminate\Support\Str::slug($productName) . '-' . $this->faker->unique()->numberBetween(1000, 9999);
|
||||||
|
|
||||||
|
$regularPrice = $this->faker->randomFloat(2, 10, 500);
|
||||||
|
$onSale = $this->faker->boolean(30); // 30% chance of being on sale
|
||||||
|
|
||||||
|
$product = Product::create([
|
||||||
|
'slug' => $slug,
|
||||||
|
'sku' => 'EX-' . strtoupper($this->faker->bothify('??-####')),
|
||||||
|
'type' => $type,
|
||||||
|
'status' => $this->faker->randomElement(['published', 'published', 'published', 'draft']), // mostly published
|
||||||
|
'visible' => true,
|
||||||
|
'featured' => $this->faker->boolean(20), // 20% featured
|
||||||
|
'price' => $onSale ? $regularPrice * 0.8 : $regularPrice,
|
||||||
|
'regular_price' => $regularPrice,
|
||||||
|
'sale_price' => $onSale ? $regularPrice * $this->faker->randomFloat(2, 0.6, 0.9) : null,
|
||||||
|
'sale_start' => $onSale ? now()->subDays($this->faker->numberBetween(1, 30)) : null,
|
||||||
|
'sale_end' => $onSale ? now()->addDays($this->faker->numberBetween(7, 60)) : null,
|
||||||
|
'manage_stock' => $type !== 'external',
|
||||||
|
'stock_quantity' => $type !== 'external' ? $this->faker->numberBetween(0, 100) : 0,
|
||||||
|
'low_stock_threshold' => $type !== 'external' ? 5 : null,
|
||||||
|
'in_stock' => true,
|
||||||
|
'stock_status' => 'instock',
|
||||||
|
'weight' => $type === 'virtual' ? null : $this->faker->randomFloat(2, 0.1, 50),
|
||||||
|
'length' => $type === 'virtual' ? null : $this->faker->randomFloat(2, 5, 100),
|
||||||
|
'width' => $type === 'virtual' ? null : $this->faker->randomFloat(2, 5, 100),
|
||||||
|
'height' => $type === 'virtual' ? null : $this->faker->randomFloat(2, 5, 100),
|
||||||
|
'virtual' => $type === 'variable' ? $this->faker->boolean(20) : false,
|
||||||
|
'downloadable' => $type === 'simple' ? $this->faker->boolean(15) : false,
|
||||||
|
'published_at' => now(),
|
||||||
|
'sort_order' => $this->faker->numberBetween(0, 100),
|
||||||
|
'tax_class' => $this->faker->randomElement(['standard', 'reduced', 'zero']),
|
||||||
|
'meta' => json_encode((object)[
|
||||||
|
'description' => $this->faker->paragraph(3),
|
||||||
|
'short_description' => $this->faker->sentence(10),
|
||||||
|
'example' => true,
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Set localized name
|
||||||
|
$product->setLocalized('name', $productName, null, true);
|
||||||
|
|
||||||
|
// Add to random categories
|
||||||
|
$randomCategories = $this->faker->randomElements($this->categories, $this->faker->numberBetween(1, 3));
|
||||||
|
$product->categories()->attach(collect($randomCategories)->pluck('id'));
|
||||||
|
|
||||||
|
// Add attributes
|
||||||
|
$this->addAttributes($product, $type);
|
||||||
|
|
||||||
|
// Add additional prices (multi-currency or subscription)
|
||||||
|
if ($type === 'simple' || $type === 'variable') {
|
||||||
|
$this->addAdditionalPrices($product);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add example actions
|
||||||
|
$this->addExampleActions($product);
|
||||||
|
|
||||||
|
// For variable products, add variations
|
||||||
|
if ($type === 'variable') {
|
||||||
|
$this->addVariations($product);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For grouped products, add child products
|
||||||
|
if ($type === 'grouped') {
|
||||||
|
$this->addGroupedProducts($product);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $product;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function generateProductName(string $type): string
|
||||||
|
{
|
||||||
|
$names = [
|
||||||
|
'simple' => [
|
||||||
|
'Premium Wireless Headphones',
|
||||||
|
'Organic Cotton T-Shirt',
|
||||||
|
'Stainless Steel Water Bottle',
|
||||||
|
'Leather Wallet',
|
||||||
|
'Bamboo Cutting Board',
|
||||||
|
'Yoga Mat Pro',
|
||||||
|
'Coffee Mug Set',
|
||||||
|
'Digital Course: Web Development',
|
||||||
|
],
|
||||||
|
'variable' => [
|
||||||
|
'Classic Running Shoes',
|
||||||
|
'Designer Hoodie',
|
||||||
|
'Smart Watch Ultra',
|
||||||
|
'Backpack Collection',
|
||||||
|
'Sunglasses Elite',
|
||||||
|
'Fitness Tracker Band',
|
||||||
|
],
|
||||||
|
'grouped' => [
|
||||||
|
'Home Office Starter Kit',
|
||||||
|
'Camping Essentials Bundle',
|
||||||
|
'Kitchen Utensil Set',
|
||||||
|
'Travel Accessories Pack',
|
||||||
|
'Gaming Setup Bundle',
|
||||||
|
],
|
||||||
|
'external' => [
|
||||||
|
'External Brand Laptop',
|
||||||
|
'Partner Store Gift Card',
|
||||||
|
'Affiliate Product Link',
|
||||||
|
'Third-Party Service',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->faker->randomElement($names[$type] ?? $names['simple']);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addAttributes(Product $product, string $type): void
|
||||||
|
{
|
||||||
|
$attributes = [];
|
||||||
|
|
||||||
|
switch ($type) {
|
||||||
|
case 'simple':
|
||||||
|
$attributes = [
|
||||||
|
['name' => 'Material', 'value' => $this->faker->randomElement(['Cotton', 'Polyester', 'Leather', 'Metal', 'Plastic', 'Wood'])],
|
||||||
|
['name' => 'Brand', 'value' => $this->faker->company()],
|
||||||
|
['name' => 'Country of Origin', 'value' => $this->faker->country()],
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'variable':
|
||||||
|
$attributes = [
|
||||||
|
['name' => 'Size', 'value' => $this->faker->randomElement(['S, M, L, XL', 'One Size', '6-12'])],
|
||||||
|
['name' => 'Color', 'value' => $this->faker->randomElement(['Red, Blue, Green', 'Black, White', 'Multi-Color'])],
|
||||||
|
['name' => 'Material', 'value' => $this->faker->randomElement(['Cotton', 'Polyester', 'Blend'])],
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'grouped':
|
||||||
|
$attributes = [
|
||||||
|
['name' => 'Items Included', 'value' => $this->faker->numberBetween(3, 10) . ' pieces'],
|
||||||
|
['name' => 'Bundle Type', 'value' => 'Curated Collection'],
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'external':
|
||||||
|
$attributes = [
|
||||||
|
['name' => 'External URL', 'value' => 'https://example.com/product'],
|
||||||
|
['name' => 'Affiliate Link', 'value' => 'Yes'],
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($attributes as $index => $attr) {
|
||||||
|
ProductAttribute::create([
|
||||||
|
'product_id' => $product->id,
|
||||||
|
'name' => $attr['name'],
|
||||||
|
'value' => $attr['value'],
|
||||||
|
'sort_order' => $index,
|
||||||
|
'meta' => json_encode((object)[]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addAdditionalPrices(Product $product): void
|
||||||
|
{
|
||||||
|
// Add a subscription price option
|
||||||
|
if ($this->faker->boolean(30)) {
|
||||||
|
ProductPrice::create([
|
||||||
|
'product_id' => $product->id,
|
||||||
|
'active' => true,
|
||||||
|
'name' => 'Monthly Subscription',
|
||||||
|
'type' => 'recurring',
|
||||||
|
'price' => (int)($product->price * 100 * 0.3), // 30% of regular price monthly
|
||||||
|
'billing_scheme' => 'per_unit',
|
||||||
|
'interval' => 'month',
|
||||||
|
'interval_count' => 1,
|
||||||
|
'trial_period_days' => $this->faker->randomElement([0, 7, 14, 30]),
|
||||||
|
'currency' => 'usd',
|
||||||
|
'is_default' => false,
|
||||||
|
'meta' => json_encode((object)['example' => true]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add EUR price
|
||||||
|
if ($this->faker->boolean(40)) {
|
||||||
|
ProductPrice::create([
|
||||||
|
'product_id' => $product->id,
|
||||||
|
'active' => true,
|
||||||
|
'name' => 'EUR Price',
|
||||||
|
'type' => 'one_time',
|
||||||
|
'price' => (int)($product->price * 100 * 0.92), // Convert to cents and EUR rate
|
||||||
|
'billing_scheme' => 'per_unit',
|
||||||
|
'currency' => 'eur',
|
||||||
|
'is_default' => false,
|
||||||
|
'meta' => json_encode((object)['example' => true]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addExampleActions(Product $product): void
|
||||||
|
{
|
||||||
|
$actions = [
|
||||||
|
[
|
||||||
|
'event' => 'purchased',
|
||||||
|
'action_type' => 'SendThankYouEmail',
|
||||||
|
'config' => ['template' => 'thank-you', 'delay' => 0],
|
||||||
|
'description' => 'Send thank you email after purchase',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'event' => 'purchased',
|
||||||
|
'action_type' => 'UpdateCustomerStats',
|
||||||
|
'config' => ['increment' => 'total_purchases'],
|
||||||
|
'description' => 'Update customer purchase statistics',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'event' => 'low_stock',
|
||||||
|
'action_type' => 'NotifyAdmin',
|
||||||
|
'config' => ['threshold' => 5],
|
||||||
|
'description' => 'Notify admin when stock is low',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($actions as $index => $actionData) {
|
||||||
|
ProductAction::create([
|
||||||
|
'product_id' => $product->id,
|
||||||
|
'event' => $actionData['event'],
|
||||||
|
'action_type' => $actionData['action_type'],
|
||||||
|
'config' => $actionData['config'],
|
||||||
|
'active' => $this->faker->boolean(70), // 70% active
|
||||||
|
'sort_order' => $index,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addVariations(Product $product): void
|
||||||
|
{
|
||||||
|
$variations = ['Small', 'Medium', 'Large'];
|
||||||
|
|
||||||
|
foreach ($variations as $index => $variation) {
|
||||||
|
$variationProduct = Product::create([
|
||||||
|
'slug' => $product->slug . '-' . \Illuminate\Support\Str::slug($variation),
|
||||||
|
'sku' => $product->sku . '-' . strtoupper(substr($variation, 0, 1)),
|
||||||
|
'type' => 'simple',
|
||||||
|
'parent_id' => $product->id,
|
||||||
|
'status' => 'published',
|
||||||
|
'visible' => false, // Variations are not directly visible
|
||||||
|
'price' => $product->price + ($index * 5), // Slight price increase per size
|
||||||
|
'regular_price' => $product->regular_price + ($index * 5),
|
||||||
|
'manage_stock' => true,
|
||||||
|
'stock_quantity' => $this->faker->numberBetween(5, 50),
|
||||||
|
'in_stock' => true,
|
||||||
|
'stock_status' => 'instock',
|
||||||
|
'published_at' => now(),
|
||||||
|
'meta' => json_encode((object)['variation' => $variation, 'example' => true]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$variationProduct->setLocalized('name', $product->name . ' - ' . $variation, null, true);
|
||||||
|
|
||||||
|
ProductAttribute::create([
|
||||||
|
'product_id' => $variationProduct->id,
|
||||||
|
'name' => 'Size',
|
||||||
|
'value' => $variation,
|
||||||
|
'sort_order' => 0,
|
||||||
|
'meta' => json_encode((object)[]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addGroupedProducts(Product $product): void
|
||||||
|
{
|
||||||
|
$groupSize = $this->faker->numberBetween(2, 4);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $groupSize; $i++) {
|
||||||
|
$childProduct = Product::create([
|
||||||
|
'slug' => $product->slug . '-item-' . ($i + 1),
|
||||||
|
'sku' => $product->sku . '-' . ($i + 1),
|
||||||
|
'type' => 'simple',
|
||||||
|
'parent_id' => $product->id,
|
||||||
|
'status' => 'published',
|
||||||
|
'visible' => false,
|
||||||
|
'price' => $this->faker->randomFloat(2, 10, 100),
|
||||||
|
'manage_stock' => true,
|
||||||
|
'stock_quantity' => $this->faker->numberBetween(10, 50),
|
||||||
|
'in_stock' => true,
|
||||||
|
'stock_status' => 'instock',
|
||||||
|
'published_at' => now(),
|
||||||
|
'meta' => json_encode((object)['grouped_item' => true, 'example' => true]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$childProduct->setLocalized('name', $this->faker->words(3, true), null, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Blax\Shop\Console\Commands;
|
|
||||||
|
|
||||||
use Blax\Shop\Models\ProductAction;
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
|
|
||||||
class ShopAvailableActionsCommand extends Command
|
|
||||||
{
|
|
||||||
protected $signature = 'shop:available-actions';
|
|
||||||
|
|
||||||
protected $description = 'List all available action classes that can be used';
|
|
||||||
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
$actions = ProductAction::getAvailableActions();
|
|
||||||
|
|
||||||
if (empty($actions)) {
|
|
||||||
$this->warn('No action classes found.');
|
|
||||||
$this->info('Make sure auto_discover is enabled in config/shop.php');
|
|
||||||
$this->info('Path: ' . config('shop.actions.path', app_path('Jobs/ProductAction')));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->info('Available Action Classes:');
|
|
||||||
$this->newLine();
|
|
||||||
|
|
||||||
foreach ($actions as $className => $parameters) {
|
|
||||||
$this->line("• <fg=green>{$className}</>");
|
|
||||||
|
|
||||||
if (!empty($parameters)) {
|
|
||||||
$this->line(' Parameters:');
|
|
||||||
foreach ($parameters as $param => $description) {
|
|
||||||
$this->line(" - {$param}: {$description}");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->line(' No parameters');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->newLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->info("Total: " . count($actions) . " action class(es)");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Blax\Shop\Console\Commands;
|
|
||||||
|
|
||||||
use Blax\Shop\Models\ProductAction;
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
|
|
||||||
class ShopListActionsCommand extends Command
|
|
||||||
{
|
|
||||||
protected $signature = 'shop:list-actions
|
|
||||||
{product? : Product ID to filter by}
|
|
||||||
{--event= : Filter by event type}
|
|
||||||
{--enabled : Only show enabled actions}
|
|
||||||
{--disabled : Only show disabled actions}';
|
|
||||||
|
|
||||||
protected $description = 'List all product actions';
|
|
||||||
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
$query = ProductAction::with('product');
|
|
||||||
|
|
||||||
if ($productId = $this->argument('product')) {
|
|
||||||
$query->where('product_id', $productId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($event = $this->option('event')) {
|
|
||||||
$query->where('event', $event);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->option('enabled')) {
|
|
||||||
$query->where('enabled', true);
|
|
||||||
} elseif ($this->option('disabled')) {
|
|
||||||
$query->where('enabled', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
$actions = $query->orderBy('product_id')->orderBy('priority')->get();
|
|
||||||
|
|
||||||
if ($actions->isEmpty()) {
|
|
||||||
$this->info('No actions found.');
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$headers = ['ID', 'Product', 'Event', 'Action Class', 'Priority', 'Enabled', 'Parameters'];
|
|
||||||
|
|
||||||
$rows = $actions->map(function ($action) {
|
|
||||||
return [
|
|
||||||
$action->id,
|
|
||||||
$action->product->name ?? "ID: {$action->product_id}",
|
|
||||||
$action->event,
|
|
||||||
$action->action_class,
|
|
||||||
$action->priority,
|
|
||||||
$action->enabled ? '✓' : '✗',
|
|
||||||
json_encode($action->parameters),
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->table($headers, $rows);
|
|
||||||
$this->info("Total actions: {$actions->count()}");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -37,36 +37,6 @@ class ProductAction extends Model
|
||||||
return $this->belongsTo(config('shop.models.product', Product::class));
|
return $this->belongsTo(config('shop.models.product', Product::class));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getAvailableActions(): array
|
|
||||||
{
|
|
||||||
if (!config('shop.actions.auto_discover')) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$path = config('shop.actions.path', app_path('Jobs/ProductAction'));
|
|
||||||
$namespace = config('shop.actions.namespace', 'App\\Jobs\\ProductAction');
|
|
||||||
|
|
||||||
if (!file_exists($path)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$actions = collect(glob($path . '/*.php'));
|
|
||||||
|
|
||||||
$actions = $actions->mapWithKeys(function ($filePath) use ($path, $namespace) {
|
|
||||||
$className = str_replace(['.php', $path . '/'], '', $filePath);
|
|
||||||
$class = $namespace . '\\' . $className;
|
|
||||||
|
|
||||||
if (!class_exists($class) || !method_exists($class, 'parameters')) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$params = $class::parameters();
|
|
||||||
return [$className => $params];
|
|
||||||
});
|
|
||||||
|
|
||||||
return $actions->toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function callForProduct(
|
public static function callForProduct(
|
||||||
Product $product,
|
Product $product,
|
||||||
string $event,
|
string $event,
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,11 @@ class ShopServiceProvider extends ServiceProvider
|
||||||
ShopReinstallCommand::class,
|
ShopReinstallCommand::class,
|
||||||
\Blax\Shop\Console\Commands\ReleaseExpiredStocks::class,
|
\Blax\Shop\Console\Commands\ReleaseExpiredStocks::class,
|
||||||
\Blax\Shop\Console\Commands\ShopListProductsCommand::class,
|
\Blax\Shop\Console\Commands\ShopListProductsCommand::class,
|
||||||
\Blax\Shop\Console\Commands\ShopListActionsCommand::class,
|
|
||||||
\Blax\Shop\Console\Commands\ShopToggleActionCommand::class,
|
\Blax\Shop\Console\Commands\ShopToggleActionCommand::class,
|
||||||
\Blax\Shop\Console\Commands\ShopTestActionCommand::class,
|
\Blax\Shop\Console\Commands\ShopTestActionCommand::class,
|
||||||
\Blax\Shop\Console\Commands\ShopListPurchasesCommand::class,
|
\Blax\Shop\Console\Commands\ShopListPurchasesCommand::class,
|
||||||
\Blax\Shop\Console\Commands\ShopAvailableActionsCommand::class,
|
|
||||||
\Blax\Shop\Console\Commands\ShopStatsCommand::class,
|
\Blax\Shop\Console\Commands\ShopStatsCommand::class,
|
||||||
|
\Blax\Shop\Console\Commands\ShopAddExampleProducts::class,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue