diff --git a/Modules/AuditTrail/Database/Seeders/AuditTrailDatabaseSeeder.php b/Modules/AuditTrail/Database/Seeders/AuditTrailDatabaseSeeder.php index ede190ef..36bfad37 100644 --- a/Modules/AuditTrail/Database/Seeders/AuditTrailDatabaseSeeder.php +++ b/Modules/AuditTrail/Database/Seeders/AuditTrailDatabaseSeeder.php @@ -14,8 +14,5 @@ class AuditTrailDatabaseSeeder extends Seeder */ public function run() { - Model::unguard(); - - // $this->call("OthersTableSeeder"); } } diff --git a/Modules/Countries/Database/Seeders/CountriesDatabaseSeeder.php b/Modules/Countries/Database/Seeders/CountriesDatabaseSeeder.php index 331b289e..e8a77462 100644 --- a/Modules/Countries/Database/Seeders/CountriesDatabaseSeeder.php +++ b/Modules/Countries/Database/Seeders/CountriesDatabaseSeeder.php @@ -11,6 +11,7 @@ class CountriesDatabaseSeeder extends Seeder */ public function run(): void { + $this->command?->info('Running CountriesDatabaseSeeder'); $this->call([ IsoCountriesSeeder::class, IsoCountrySubdivisionsSeeder::class, diff --git a/Modules/Helpdesk/Concerns/HasHelpdeskTickets.php b/Modules/Helpdesk/Concerns/HasHelpdeskTickets.php index c5346eb1..31c9ecc8 100644 --- a/Modules/Helpdesk/Concerns/HasHelpdeskTickets.php +++ b/Modules/Helpdesk/Concerns/HasHelpdeskTickets.php @@ -7,6 +7,9 @@ namespace Modules\Helpdesk\Concerns; use Illuminate\Database\Eloquent\Relations\HasMany; use Modules\Helpdesk\Models\Ticket; +/** + * @method hasMany(string $class, string $string) + */ trait HasHelpdeskTickets { /** @return HasMany */ diff --git a/Modules/Pricing/Database/Seeders/PricingDatabaseSeeder.php b/Modules/Pricing/Database/Seeders/PricingDatabaseSeeder.php index 6d10b400..16b52750 100644 --- a/Modules/Pricing/Database/Seeders/PricingDatabaseSeeder.php +++ b/Modules/Pricing/Database/Seeders/PricingDatabaseSeeder.php @@ -1,20 +1,20 @@ insert([ + $plans = [ [ 'code' => 'basic', 'name' => 'Basic', @@ -24,12 +24,15 @@ class PricingDatabaseSeeder extends Seeder 'annual_amount' => 49000, 'currency' => 'gbp', 'badge_label' => 'Starter', - 'features' => json_encode(['Warehouse dashboard', 'Inventory overview', 'Basic audit trail', 'Email support']), + 'features' => [ + 'Warehouse dashboard', + 'Inventory overview', + 'Basic audit trail', + 'Email support', + ], 'sort_order' => 10, 'is_featured' => false, 'is_active' => true, - 'created_at' => now(), - 'updated_at' => now(), ], [ 'code' => 'advanced', @@ -40,12 +43,16 @@ class PricingDatabaseSeeder extends Seeder 'annual_amount' => 99000, 'currency' => 'gbp', 'badge_label' => 'Popular', - 'features' => json_encode(['Everything in Basic', 'Replenishment workflows', 'Reporting workspace', 'M3 integration status', 'Priority support']), + 'features' => [ + 'Everything in Basic', + 'Replenishment workflows', + 'Reporting workspace', + 'M3 integration status', + 'Priority support', + ], 'sort_order' => 20, 'is_featured' => true, 'is_active' => true, - 'created_at' => now(), - 'updated_at' => now(), ], [ 'code' => 'pro', @@ -56,29 +63,69 @@ class PricingDatabaseSeeder extends Seeder 'annual_amount' => 199000, 'currency' => 'gbp', 'badge_label' => 'Enterprise', - 'features' => json_encode(['Everything in Advanced', 'Multi-company administration', 'Security and audit controls', 'Document archive', 'Carrier management', 'Dedicated support']), + 'features' => [ + 'Everything in Advanced', + 'Multi-company administration', + 'Security and audit controls', + 'Document archive', + 'Carrier management', + 'Dedicated support', + ], 'sort_order' => 30, 'is_featured' => false, 'is_active' => true, - 'created_at' => now(), - 'updated_at' => now(), ], [ 'code' => 'ultimate', 'name' => 'Ultimate', 'strapline' => 'Ultimate Enterprise Grade Administration', - 'description' => 'Full platform administration for regulated warehouse,unlimited warehouses and users, carrier and document operations.', + 'description' => 'Full platform administration for regulated warehouse, unlimited warehouses and users, carrier and document operations.', 'monthly_amount' => 1009900, 'annual_amount' => 1000000, 'currency' => 'gbp', 'badge_label' => 'Enterprise', - 'features' => json_encode(['Everything in pro', 'Multi-company administration', 'Security and audit controls', 'Document archive', 'Carrier management', 'Dedicated support']), + 'features' => [ + 'Everything in Pro', + 'Multi-company administration', + 'Security and audit controls', + 'Document archive', + 'Carrier management', + 'Dedicated support', + ], 'sort_order' => 50, 'is_featured' => false, 'is_active' => true, - 'created_at' => now(), - 'updated_at' => now(), ], - ]); + ]; + + foreach ($plans as $plan) { + $exists = DB::table('platform_prices') + ->where('code', $plan['code']) + ->exists(); + + $payload = [ + 'name' => $plan['name'], + 'strapline' => $plan['strapline'], + 'description' => $plan['description'], + 'monthly_amount' => $plan['monthly_amount'], + 'annual_amount' => $plan['annual_amount'], + 'currency' => $plan['currency'], + 'badge_label' => $plan['badge_label'], + 'features' => json_encode($plan['features'], JSON_THROW_ON_ERROR), + 'sort_order' => $plan['sort_order'], + 'is_featured' => $plan['is_featured'], + 'is_active' => $plan['is_active'], + 'updated_at' => now(), + ]; + + if (! $exists) { + $payload['created_at'] = now(); + } + + DB::table('platform_prices')->updateOrInsert( + ['code' => $plan['code']], + $payload + ); + } } } diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 8ff55821..a96c353a 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -15,5 +15,6 @@ class DatabaseSeeder extends Seeder { $this->call(PlatformSeeder::class); $this->call(PricingDatabaseSeeder::class); + $this->call(ModuleDatabaseSeeder::class); } } diff --git a/database/seeders/ModuleDatabaseSeeder.php b/database/seeders/ModuleDatabaseSeeder.php new file mode 100644 index 00000000..9a4da273 --- /dev/null +++ b/database/seeders/ModuleDatabaseSeeder.php @@ -0,0 +1,85 @@ + + */ + private const SKIP_MODULES = [ + // 'Platform', + // 'Pricing', + ]; + + /** + * Seed all enabled Laravel modules that expose a module database seeder. + */ + public function run(): void + { + foreach (Module::allEnabled() as $module) { + $moduleName = $module->getName(); + + if (in_array($moduleName, self::SKIP_MODULES, true)) { + $this->command?->warn("Skipping module: {$moduleName} - excluded from automatic module seeding"); + + continue; + } + + $seederClass = $this->resolveSeederClass($moduleName); + + if ($seederClass === null) { + $this->command?->warn("Skipping module: {$moduleName} - no module seeder found"); + + continue; + } + + $this->command?->info("Seeding module: {$moduleName}"); + $this->command?->line("Seeder class: {$seederClass}"); + + try { + $this->call($seederClass); + } catch (Throwable $exception) { + $this->command?->error("Module seed failed: {$moduleName}"); + $this->command?->error($exception->getMessage()); + + throw $exception; + } + + $this->command?->info("Seeded module: {$moduleName}"); + } + } + + /** + * Resolve the module database seeder class using supported project patterns. + */ + private function resolveSeederClass(string $moduleName): ?string + { + $candidates = [ + "Modules\\{$moduleName}\\Database\\Seeders\\{$moduleName}DatabaseSeeder", + "Modules\\{$moduleName}\\Database\\Seeders\\{$moduleName}Seeder", + "Modules\\{$moduleName}\\Database\\Seeders\\DatabaseSeeder", + + // Legacy lowercase namespace variants used by some existing modules. + "Modules\\{$moduleName}\\database\\seeders\\{$moduleName}DatabaseSeeder", + "Modules\\{$moduleName}\\database\\seeders\\{$moduleName}Seeder", + "Modules\\{$moduleName}\\database\\seeders\\DatabaseSeeder", + ]; + + foreach ($candidates as $candidate) { + if (class_exists($candidate)) { + return $candidate; + } + } + + return null; + } +}