feat: complete pre-launch audit — frontend polish, churn prevention, login history, financial reports, configurable checkout
Includes all work from phases 6-9+ and frontend polish rounds 1 & 2: - Login history with device trust, new device notifications, session management - Churn prevention: cancellation surveys, winback campaigns with email sequences - Financial reports: revenue, P&L, tax, aging, refund, subscription reports with PDF/CSV/JSON export - Configurable checkout: plan config groups/options, build-your-own VPS - Frontend polish: fix broken legal links, add SEO meta tags, favicon, font display=swap, Head titles on all 14 marketing pages, mobile responsive fixes, AuthLayout legal footer, remove false 24/7 claims, hide empty stats, correct uptime SLA to 99.9%, GameServers notify buttons linked to /contact, 301 redirects for /terms and /privacy - WHMCS migration scripts - Update legal page effective dates to March 16, 2026 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
473
website/database/seeders/ConfigOptionSeeder.php
Normal file
473
website/database/seeders/ConfigOptionSeeder.php
Normal file
@@ -0,0 +1,473 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Plan;
|
||||
use App\Models\PlanConfigGroup;
|
||||
use App\Models\PlanConfigOption;
|
||||
use App\Models\PlanConfigValue;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class ConfigOptionSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
$this->seedBuildYourOwnGroups();
|
||||
$this->seedPresetGroups();
|
||||
}
|
||||
|
||||
private function seedBuildYourOwnGroups(): void
|
||||
{
|
||||
// ─── VPS Builder ────────────────────────────────────────────────
|
||||
$vpsBuilder = PlanConfigGroup::updateOrCreate(
|
||||
['name' => 'VPS Builder'],
|
||||
[
|
||||
'description' => 'Build your own custom VPS with the exact resources you need.',
|
||||
'mode' => 'build_your_own',
|
||||
'service_type' => 'vps',
|
||||
'is_active' => true,
|
||||
'sort_order' => 1,
|
||||
],
|
||||
);
|
||||
|
||||
$this->seedSliderOption($vpsBuilder, 'CPU Cores', 'cpu_cores', 1, 16, 1, 'cores', 0.003, 2.00, 1);
|
||||
$this->seedSliderOption($vpsBuilder, 'RAM', 'ram_gb', 1, 64, 1, 'GB', 0.0015, 1.00, 2);
|
||||
$this->seedSliderOption($vpsBuilder, 'SSD Storage', 'disk_gb', 25, 1000, 25, 'GB', 0.0001, 0.05, 3);
|
||||
|
||||
// ─── MySQL Builder ──────────────────────────────────────────────
|
||||
$mysqlBuilder = PlanConfigGroup::updateOrCreate(
|
||||
['name' => 'MySQL Builder'],
|
||||
[
|
||||
'description' => 'Build your own managed MySQL instance.',
|
||||
'mode' => 'build_your_own',
|
||||
'service_type' => 'mysql',
|
||||
'is_active' => true,
|
||||
'sort_order' => 2,
|
||||
],
|
||||
);
|
||||
|
||||
$this->seedSliderOption($mysqlBuilder, 'Storage', 'storage_gb', 5, 500, 5, 'GB', 0.0003, 0.20, 1);
|
||||
$this->seedSliderOption($mysqlBuilder, 'Max Connections', 'max_connections', 50, 1000, 50, 'connections', 0.0001, 0.05, 2);
|
||||
|
||||
// ─── Game Server Builder ────────────────────────────────────────
|
||||
$gameBuilder = PlanConfigGroup::updateOrCreate(
|
||||
['name' => 'Game Server Builder'],
|
||||
[
|
||||
'description' => 'Build your own custom game server.',
|
||||
'mode' => 'build_your_own',
|
||||
'service_type' => 'game',
|
||||
'is_active' => true,
|
||||
'sort_order' => 3,
|
||||
],
|
||||
);
|
||||
|
||||
$this->seedSliderOption($gameBuilder, 'RAM', 'ram_gb', 1, 16, 1, 'GB', 0.002, 1.50, 1);
|
||||
$this->seedSliderOption($gameBuilder, 'Storage', 'disk_gb', 10, 200, 10, 'GB', 0.0001, 0.08, 2);
|
||||
$this->seedSliderOption($gameBuilder, 'Player Slots', 'player_slots', 10, 200, 10, 'slots', 0.0001, 0.05, 3);
|
||||
}
|
||||
|
||||
private function seedPresetGroups(): void
|
||||
{
|
||||
// ─── Server Management (all dedicated + VPS plans) ──────────────
|
||||
$serverMgmt = PlanConfigGroup::updateOrCreate(
|
||||
['name' => 'Server Management'],
|
||||
[
|
||||
'description' => 'Add managed support to your server.',
|
||||
'mode' => 'preset',
|
||||
'service_type' => null,
|
||||
'is_active' => true,
|
||||
'sort_order' => 10,
|
||||
],
|
||||
);
|
||||
|
||||
$mgmtOption = $this->seedDropdownOption($serverMgmt, 'Server Management', null, false, 1);
|
||||
$this->seedValues($mgmtOption, [
|
||||
['label' => 'None', 'value' => 'none', 'monthly' => 0, 'is_default' => true],
|
||||
['label' => 'Semi-Managed', 'value' => 'semi_managed', 'monthly' => 25.00],
|
||||
['label' => 'Fully Managed', 'value' => 'fully_managed', 'monthly' => 60.00],
|
||||
]);
|
||||
|
||||
// Attach to all active dedicated AND vps plans
|
||||
$dedicatedAndVpsPlans = Plan::query()
|
||||
->whereIn('service_type', ['dedicated', 'vps'])
|
||||
->whereIn('status', ['active', 'internal'])
|
||||
->pluck('id');
|
||||
$serverMgmt->plans()->syncWithoutDetaching($dedicatedAndVpsPlans);
|
||||
|
||||
// ─── VPS Add-ons ────────────────────────────────────────────────
|
||||
$vpsAddons = PlanConfigGroup::updateOrCreate(
|
||||
['name' => 'VPS Add-ons'],
|
||||
[
|
||||
'description' => 'Additional options for your VPS.',
|
||||
'mode' => 'preset',
|
||||
'service_type' => 'vps',
|
||||
'is_active' => true,
|
||||
'sort_order' => 11,
|
||||
],
|
||||
);
|
||||
|
||||
// IPv4 Addresses (quantity)
|
||||
$ipv4Option = $this->seedQuantityOption($vpsAddons, 'IPv4 Addresses', 1, 8, 'addresses', 3.00, 1);
|
||||
|
||||
// Windows License (checkbox)
|
||||
$winOption = $this->seedCheckboxOption($vpsAddons, 'Windows License', 2);
|
||||
$this->seedValues($winOption, [
|
||||
['label' => 'Yes (Free BYOL)', 'value' => 'yes', 'monthly' => 0, 'is_default' => false],
|
||||
]);
|
||||
|
||||
// Attach to all active VPS plans
|
||||
$vpsSlugs = ['vps-1', 'vps-2', 'vps-3-custom', 'vps-4', 'vps-8', 'vps-16', 'vps-32', 'stor-500', 'stor-1tb'];
|
||||
$vpsPlans = Plan::query()->whereIn('slug', $vpsSlugs)->pluck('id');
|
||||
$vpsAddons->plans()->syncWithoutDetaching($vpsPlans);
|
||||
|
||||
// ─── Dedicated RAM - DDR4 ──────────────────────────────────────
|
||||
$ddr4Ram = PlanConfigGroup::updateOrCreate(
|
||||
['name' => 'Dedicated RAM - DDR4'],
|
||||
[
|
||||
'description' => 'Choose the DDR4 ECC RAM configuration for your dedicated server.',
|
||||
'mode' => 'preset',
|
||||
'service_type' => 'dedicated',
|
||||
'is_active' => true,
|
||||
'sort_order' => 20,
|
||||
],
|
||||
);
|
||||
|
||||
$ramOption = $this->seedDropdownOption($ddr4Ram, 'DDR4 ECC RAM', null, true, 1);
|
||||
$this->seedValues($ramOption, [
|
||||
['label' => '32 GB', 'value' => '32', 'monthly' => 0, 'is_default' => true],
|
||||
['label' => '64 GB', 'value' => '64', 'monthly' => 15.00],
|
||||
['label' => '96 GB', 'value' => '96', 'monthly' => 20.00],
|
||||
['label' => '128 GB', 'value' => '128', 'monthly' => 28.00],
|
||||
['label' => '192 GB', 'value' => '192', 'monthly' => 40.00],
|
||||
['label' => '256 GB', 'value' => '256', 'monthly' => 55.00],
|
||||
['label' => '384 GB', 'value' => '384', 'monthly' => 80.00],
|
||||
['label' => '512 GB', 'value' => '512', 'monthly' => 120.00],
|
||||
]);
|
||||
|
||||
$ramPlanSlugs = ['dell-r440', 'dell-r640', 'dell-r540', 'dell-r740'];
|
||||
$ramPlans = Plan::query()->whereIn('slug', $ramPlanSlugs)->pluck('id');
|
||||
$ddr4Ram->plans()->syncWithoutDetaching($ramPlans);
|
||||
|
||||
// ─── Dedicated Network ──────────────────────────────────────────
|
||||
$dedicatedNetwork = PlanConfigGroup::updateOrCreate(
|
||||
['name' => 'Dedicated Network'],
|
||||
[
|
||||
'description' => 'Network configuration for your dedicated server.',
|
||||
'mode' => 'preset',
|
||||
'service_type' => 'dedicated',
|
||||
'is_active' => true,
|
||||
'sort_order' => 21,
|
||||
],
|
||||
);
|
||||
|
||||
// Network Port Speed (radio, required)
|
||||
$portSpeedOption = $this->seedRadioOption($dedicatedNetwork, 'Network Port Speed', true, 1);
|
||||
$this->seedValues($portSpeedOption, [
|
||||
['label' => 'Unmetered 100Mbit', 'value' => '100mbit_unmetered', 'monthly' => 0, 'is_default' => true],
|
||||
['label' => 'Metered 1Gbit', 'value' => '1gbit_metered', 'monthly' => 0],
|
||||
['label' => 'Unmetered 2Gbit', 'value' => '2gbit_unmetered', 'monthly' => 150.00],
|
||||
['label' => 'Unmetered 5Gbit', 'value' => '5gbit_unmetered', 'monthly' => 325.00],
|
||||
['label' => 'Unmetered 10Gbit', 'value' => '10gbit_unmetered', 'monthly' => 650.00],
|
||||
]);
|
||||
|
||||
// Public Bandwidth (dropdown)
|
||||
$publicBwOption = $this->seedDropdownOption($dedicatedNetwork, 'Public Bandwidth', null, false, 2);
|
||||
$this->seedValues($publicBwOption, [
|
||||
['label' => '20TB', 'value' => '20tb', 'monthly' => 0, 'is_default' => true],
|
||||
['label' => '50TB', 'value' => '50tb', 'monthly' => 45.00],
|
||||
['label' => '100TB', 'value' => '100tb', 'monthly' => 100.00],
|
||||
['label' => 'Unmetered 1Gbps', 'value' => 'unmetered_1gbps', 'monthly' => 150.00],
|
||||
]);
|
||||
|
||||
// Private Bandwidth (radio)
|
||||
$privateBwOption = $this->seedRadioOption($dedicatedNetwork, 'Private Bandwidth', false, 3);
|
||||
$this->seedValues($privateBwOption, [
|
||||
['label' => '1Gbit', 'value' => '1gbit', 'monthly' => 0, 'is_default' => true],
|
||||
['label' => '10Gbit', 'value' => '10gbit', 'monthly' => 85.00],
|
||||
]);
|
||||
|
||||
$allDedicatedPlans = Plan::query()
|
||||
->where('service_type', 'dedicated')
|
||||
->whereIn('status', ['active', 'internal'])
|
||||
->pluck('id');
|
||||
$dedicatedNetwork->plans()->syncWithoutDetaching($allDedicatedPlans);
|
||||
|
||||
// ─── M.2 NVMe ──────────────────────────────────────────────────
|
||||
$nvme = PlanConfigGroup::updateOrCreate(
|
||||
['name' => 'M.2 NVMe'],
|
||||
[
|
||||
'description' => 'Add M.2 NVMe storage to your dedicated server.',
|
||||
'mode' => 'preset',
|
||||
'service_type' => 'dedicated',
|
||||
'is_active' => true,
|
||||
'sort_order' => 23,
|
||||
],
|
||||
);
|
||||
|
||||
$nvmeOption = $this->seedDropdownOption($nvme, 'M.2 NVMe', null, false, 1);
|
||||
$this->seedValues($nvmeOption, [
|
||||
['label' => 'None', 'value' => 'none', 'monthly' => 0, 'is_default' => true],
|
||||
['label' => '2x 500GB', 'value' => '2x500gb', 'monthly' => 18.00],
|
||||
['label' => '2x 1TB', 'value' => '2x1tb', 'monthly' => 30.00],
|
||||
['label' => '2x 2TB', 'value' => '2x2tb', 'monthly' => 75.00],
|
||||
]);
|
||||
|
||||
$nvme->plans()->syncWithoutDetaching($ramPlans);
|
||||
|
||||
// ─── Veeam Enterprise Plus Options ─────────────────────────────
|
||||
$veeamEntPlus = PlanConfigGroup::updateOrCreate(
|
||||
['name' => 'Veeam Enterprise Plus Options'],
|
||||
[
|
||||
'description' => 'Configure your Veeam Enterprise Plus backup solution.',
|
||||
'mode' => 'preset',
|
||||
'service_type' => 'backups',
|
||||
'is_active' => true,
|
||||
'sort_order' => 30,
|
||||
],
|
||||
);
|
||||
|
||||
$this->seedQuantityOption($veeamEntPlus, 'Virtual Machines', 0, 100, 'VMs', 15.00, 1);
|
||||
$this->seedQuantityOption($veeamEntPlus, 'Server Agents', 0, 50, 'agents', 15.00, 2);
|
||||
$this->seedQuantityOption($veeamEntPlus, 'Workstation Agents', 0, 100, 'agents', 6.00, 3);
|
||||
$this->seedQuantityOption($veeamEntPlus, 'NAS (per 500GB)', 0, 50, 'units', 14.00, 4);
|
||||
$this->seedQuantityOption($veeamEntPlus, 'Office 365 Users', 0, 500, 'users', 3.00, 5);
|
||||
|
||||
$veeamEntPlusPlan = Plan::query()->where('slug', 'veeam-enterprise-plus')->pluck('id');
|
||||
$veeamEntPlus->plans()->syncWithoutDetaching($veeamEntPlusPlan);
|
||||
|
||||
// ─── Veeam Standard Options ────────────────────────────────────
|
||||
$veeamStandard = PlanConfigGroup::updateOrCreate(
|
||||
['name' => 'Veeam Standard Options'],
|
||||
[
|
||||
'description' => 'Configure your Veeam Standard backup solution.',
|
||||
'mode' => 'preset',
|
||||
'service_type' => 'backups',
|
||||
'is_active' => true,
|
||||
'sort_order' => 31,
|
||||
],
|
||||
);
|
||||
|
||||
$this->seedQuantityOption($veeamStandard, 'Virtual Machines', 0, 100, 'VMs', 7.00, 1);
|
||||
$this->seedQuantityOption($veeamStandard, 'Server Agents', 0, 50, 'agents', 15.00, 2);
|
||||
$this->seedQuantityOption($veeamStandard, 'Workstation Agents', 0, 100, 'agents', 6.00, 3);
|
||||
$this->seedQuantityOption($veeamStandard, 'NAS (per 500GB)', 0, 50, 'units', 14.00, 4);
|
||||
$this->seedQuantityOption($veeamStandard, 'Office 365 Users', 0, 500, 'users', 3.00, 5);
|
||||
|
||||
$veeamStandardPlan = Plan::query()->where('slug', 'veeam-standard')->pluck('id');
|
||||
$veeamStandard->plans()->syncWithoutDetaching($veeamStandardPlan);
|
||||
|
||||
// ─── Veeam Cloud Connect Options ───────────────────────────────
|
||||
$veeamCloudConnect = PlanConfigGroup::updateOrCreate(
|
||||
['name' => 'Veeam Cloud Connect Options'],
|
||||
[
|
||||
'description' => 'Configure your Veeam Cloud Connect backup and replication solution.',
|
||||
'mode' => 'preset',
|
||||
'service_type' => 'backups',
|
||||
'is_active' => true,
|
||||
'sort_order' => 32,
|
||||
],
|
||||
);
|
||||
|
||||
$this->seedQuantityOption($veeamCloudConnect, 'Virtual Machines', 0, 100, 'VMs', 15.00, 1);
|
||||
$this->seedQuantityOption($veeamCloudConnect, 'Server Agents', 0, 50, 'agents', 15.00, 2);
|
||||
$this->seedQuantityOption($veeamCloudConnect, 'Workstation Agents', 0, 100, 'agents', 6.00, 3);
|
||||
$this->seedQuantityOption($veeamCloudConnect, 'NAS (per 500GB)', 0, 50, 'units', 14.00, 4);
|
||||
$this->seedQuantityOption($veeamCloudConnect, 'Office 365 Users', 0, 500, 'users', 3.00, 5);
|
||||
$this->seedQuantityOption($veeamCloudConnect, 'Capacity Storage', 1, 100, 'TB', 4.00, 6, required: true);
|
||||
$this->seedQuantityOption($veeamCloudConnect, 'Replicated VMs', 0, 50, 'VMs', 30.00, 7);
|
||||
|
||||
$supportOption = $this->seedDropdownOption($veeamCloudConnect, 'Support Level', null, true, 8);
|
||||
$this->seedValues($supportOption, [
|
||||
['label' => 'Basic', 'value' => 'basic', 'monthly' => 30.00, 'is_default' => true],
|
||||
['label' => 'Enhanced', 'value' => 'enhanced', 'monthly' => 60.00],
|
||||
['label' => 'Enhanced Plus', 'value' => 'enhanced_plus', 'monthly' => 200.00],
|
||||
]);
|
||||
|
||||
$veeamCloudConnectPlan = Plan::query()->where('slug', 'veeam-cloud-connect')->pluck('id');
|
||||
$veeamCloudConnect->plans()->syncWithoutDetaching($veeamCloudConnectPlan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create/update a slider option for BYO groups.
|
||||
*/
|
||||
private function seedSliderOption(
|
||||
PlanConfigGroup $group,
|
||||
string $name,
|
||||
string $provisioningKey,
|
||||
int $min,
|
||||
int $max,
|
||||
int $step,
|
||||
string $unit,
|
||||
float $hourly,
|
||||
float $monthly,
|
||||
int $sortOrder,
|
||||
): PlanConfigOption {
|
||||
return PlanConfigOption::updateOrCreate(
|
||||
['group_id' => $group->id, 'name' => $name],
|
||||
[
|
||||
'type' => 'slider',
|
||||
'provisioning_key' => $provisioningKey,
|
||||
'required' => true,
|
||||
'is_active' => true,
|
||||
'min_qty' => $min,
|
||||
'max_qty' => $max,
|
||||
'step' => $step,
|
||||
'unit_label' => $unit,
|
||||
'hourly_price' => $hourly,
|
||||
'monthly_price' => $monthly,
|
||||
'quarterly_price' => $this->quarterlyPrice($monthly),
|
||||
'semi_annual_price' => $this->semiAnnualPrice($monthly),
|
||||
'annual_price' => $this->annualPrice($monthly),
|
||||
'sort_order' => $sortOrder,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create/update a dropdown option.
|
||||
*/
|
||||
private function seedDropdownOption(
|
||||
PlanConfigGroup $group,
|
||||
string $name,
|
||||
?string $provisioningKey,
|
||||
bool $required,
|
||||
int $sortOrder,
|
||||
): PlanConfigOption {
|
||||
return PlanConfigOption::updateOrCreate(
|
||||
['group_id' => $group->id, 'name' => $name],
|
||||
[
|
||||
'type' => 'dropdown',
|
||||
'provisioning_key' => $provisioningKey,
|
||||
'required' => $required,
|
||||
'is_active' => true,
|
||||
'sort_order' => $sortOrder,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create/update a radio option.
|
||||
*/
|
||||
private function seedRadioOption(
|
||||
PlanConfigGroup $group,
|
||||
string $name,
|
||||
bool $required,
|
||||
int $sortOrder,
|
||||
): PlanConfigOption {
|
||||
return PlanConfigOption::updateOrCreate(
|
||||
['group_id' => $group->id, 'name' => $name],
|
||||
[
|
||||
'type' => 'radio',
|
||||
'provisioning_key' => null,
|
||||
'required' => $required,
|
||||
'is_active' => true,
|
||||
'sort_order' => $sortOrder,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create/update a checkbox option.
|
||||
*/
|
||||
private function seedCheckboxOption(
|
||||
PlanConfigGroup $group,
|
||||
string $name,
|
||||
int $sortOrder,
|
||||
): PlanConfigOption {
|
||||
return PlanConfigOption::updateOrCreate(
|
||||
['group_id' => $group->id, 'name' => $name],
|
||||
[
|
||||
'type' => 'checkbox',
|
||||
'provisioning_key' => null,
|
||||
'required' => false,
|
||||
'is_active' => true,
|
||||
'sort_order' => $sortOrder,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create/update a quantity option.
|
||||
*/
|
||||
private function seedQuantityOption(
|
||||
PlanConfigGroup $group,
|
||||
string $name,
|
||||
int $min,
|
||||
int $max,
|
||||
string $unit,
|
||||
float $monthly,
|
||||
int $sortOrder,
|
||||
bool $required = false,
|
||||
): PlanConfigOption {
|
||||
return PlanConfigOption::updateOrCreate(
|
||||
['group_id' => $group->id, 'name' => $name],
|
||||
[
|
||||
'type' => 'quantity',
|
||||
'provisioning_key' => null,
|
||||
'required' => $required,
|
||||
'is_active' => true,
|
||||
'min_qty' => $min,
|
||||
'max_qty' => $max,
|
||||
'step' => 1,
|
||||
'unit_label' => $unit,
|
||||
'monthly_price' => $monthly,
|
||||
'quarterly_price' => $this->quarterlyPrice($monthly),
|
||||
'semi_annual_price' => $this->semiAnnualPrice($monthly),
|
||||
'annual_price' => $this->annualPrice($monthly),
|
||||
'sort_order' => $sortOrder,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed values for a dropdown/radio/checkbox option.
|
||||
*
|
||||
* @param array<int, array{label: string, value: string, monthly: float, is_default?: bool}> $values
|
||||
*/
|
||||
private function seedValues(PlanConfigOption $option, array $values): void
|
||||
{
|
||||
foreach ($values as $index => $data) {
|
||||
$monthly = $data['monthly'];
|
||||
|
||||
PlanConfigValue::updateOrCreate(
|
||||
['option_id' => $option->id, 'label' => $data['label']],
|
||||
[
|
||||
'value' => $data['value'],
|
||||
'hourly_price' => 0,
|
||||
'monthly_price' => $monthly,
|
||||
'quarterly_price' => $this->quarterlyPrice($monthly),
|
||||
'semi_annual_price' => $this->semiAnnualPrice($monthly),
|
||||
'annual_price' => $this->annualPrice($monthly),
|
||||
'is_default' => $data['is_default'] ?? false,
|
||||
'sort_order' => $index,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* quarterly = monthly * 3 * 0.95
|
||||
*/
|
||||
private function quarterlyPrice(float $monthly): float
|
||||
{
|
||||
return round($monthly * 3 * 0.95, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* semi_annual = monthly * 6 * 0.90
|
||||
*/
|
||||
private function semiAnnualPrice(float $monthly): float
|
||||
{
|
||||
return round($monthly * 6 * 0.90, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* annual = monthly * 12 * 0.85
|
||||
*/
|
||||
private function annualPrice(float $monthly): float
|
||||
{
|
||||
return round($monthly * 12 * 0.85, 2);
|
||||
}
|
||||
}
|
||||
@@ -5,20 +5,37 @@ declare(strict_types=1);
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Plan;
|
||||
use App\Models\PlanPrice;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class PlanSeeder extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
// Archive old VPS plans instead of deleting (preserves foreign key relationships)
|
||||
// Archive old VPS plans (preserves foreign key relationships)
|
||||
Plan::query()
|
||||
->where('service_type', 'vps')
|
||||
->whereNotIn('slug', [
|
||||
'vps-1', 'vps-2', 'vps-4', 'vps-8', 'vps-16', 'vps-32',
|
||||
'vps-1', 'vps-2', 'vps-3-custom', 'vps-4', 'vps-8', 'vps-16', 'vps-32',
|
||||
'stor-500', 'stor-1tb',
|
||||
])
|
||||
->update(['status' => 'archived']);
|
||||
->update(['status' => 'inactive']);
|
||||
|
||||
// ─── Archive old dedicated server plans (12th/13th gen) ──────
|
||||
$oldDedicatedSlugs = [
|
||||
'dell-r330-lff',
|
||||
'dell-r420-lff',
|
||||
'dell-r620-sff-10-bay',
|
||||
'dell-r620-sff-8-bay',
|
||||
'dell-r520-lff',
|
||||
'dell-r430-lff',
|
||||
'dell-r630-sff',
|
||||
'dell-r730-lff',
|
||||
];
|
||||
|
||||
Plan::query()
|
||||
->whereIn('slug', $oldDedicatedSlugs)
|
||||
->update(['status' => 'hidden']);
|
||||
|
||||
$plans = [
|
||||
// ─── VPS Plans ─────────────────────────────────────────────────
|
||||
@@ -38,8 +55,8 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '/64 Included',
|
||||
'control_panel' => 'VirtFusion',
|
||||
'os' => 'Linux & Windows (BYOL)',
|
||||
'virtfusion_package_id' => 19,
|
||||
],
|
||||
'provisioning_config' => ['package_id' => 44, 'hypervisor_id' => 1],
|
||||
'sort_order' => 1,
|
||||
],
|
||||
[
|
||||
@@ -58,10 +75,31 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '/64 Included',
|
||||
'control_panel' => 'VirtFusion',
|
||||
'os' => 'Linux & Windows (BYOL)',
|
||||
'virtfusion_package_id' => 20,
|
||||
],
|
||||
'provisioning_config' => ['package_id' => 45, 'hypervisor_id' => 1],
|
||||
'sort_order' => 2,
|
||||
],
|
||||
[
|
||||
'name' => 'VPS-3 Custom',
|
||||
'slug' => 'vps-3-custom',
|
||||
'description' => 'Custom VPS plan for grandfathered customers. Not available for new signups.',
|
||||
'service_type' => 'vps',
|
||||
'price' => 0.00,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'cpu' => '2 vCPU',
|
||||
'ram' => '3 GB',
|
||||
'storage' => '60 GB SSD',
|
||||
'bandwidth' => 'Unmetered',
|
||||
'ipv4' => '1 Included',
|
||||
'ipv6' => '/64 Included',
|
||||
'control_panel' => 'VirtFusion',
|
||||
'os' => 'Linux & Windows (BYOL)',
|
||||
],
|
||||
'provisioning_config' => ['package_id' => 47, 'hypervisor_id' => 1],
|
||||
'status' => 'hidden',
|
||||
'sort_order' => 3,
|
||||
],
|
||||
[
|
||||
'name' => 'VPS-4',
|
||||
'slug' => 'vps-4',
|
||||
@@ -78,9 +116,9 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '/64 Included',
|
||||
'control_panel' => 'VirtFusion',
|
||||
'os' => 'Linux & Windows (BYOL)',
|
||||
'virtfusion_package_id' => 21,
|
||||
],
|
||||
'sort_order' => 3,
|
||||
'provisioning_config' => ['package_id' => 46, 'hypervisor_id' => 1],
|
||||
'sort_order' => 4,
|
||||
],
|
||||
[
|
||||
'name' => 'VPS-8',
|
||||
@@ -98,9 +136,9 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '/64 Included',
|
||||
'control_panel' => 'VirtFusion',
|
||||
'os' => 'Linux & Windows (BYOL)',
|
||||
'virtfusion_package_id' => 22,
|
||||
],
|
||||
'sort_order' => 4,
|
||||
'provisioning_config' => ['package_id' => 47, 'hypervisor_id' => 1],
|
||||
'sort_order' => 5,
|
||||
],
|
||||
[
|
||||
'name' => 'VPS-16',
|
||||
@@ -118,9 +156,9 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '/64 Included',
|
||||
'control_panel' => 'VirtFusion',
|
||||
'os' => 'Linux & Windows (BYOL)',
|
||||
'virtfusion_package_id' => 23,
|
||||
],
|
||||
'sort_order' => 5,
|
||||
'provisioning_config' => ['package_id' => 48, 'hypervisor_id' => 1],
|
||||
'sort_order' => 6,
|
||||
],
|
||||
[
|
||||
'name' => 'VPS-32',
|
||||
@@ -138,9 +176,9 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '/64 Included',
|
||||
'control_panel' => 'VirtFusion',
|
||||
'os' => 'Linux & Windows (BYOL)',
|
||||
'virtfusion_package_id' => 24,
|
||||
],
|
||||
'sort_order' => 6,
|
||||
'provisioning_config' => ['package_id' => 49, 'hypervisor_id' => 1],
|
||||
'sort_order' => 7,
|
||||
],
|
||||
[
|
||||
'name' => 'Storage 500',
|
||||
@@ -158,9 +196,9 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '/64 Included',
|
||||
'control_panel' => 'VirtFusion',
|
||||
'os' => 'Linux & Windows (BYOL)',
|
||||
'virtfusion_package_id' => 41,
|
||||
],
|
||||
'sort_order' => 7,
|
||||
'provisioning_config' => ['package_id' => 50, 'hypervisor_id' => 1],
|
||||
'sort_order' => 8,
|
||||
],
|
||||
[
|
||||
'name' => 'Storage 1TB',
|
||||
@@ -178,12 +216,12 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '/64 Included',
|
||||
'control_panel' => 'VirtFusion',
|
||||
'os' => 'Linux & Windows (BYOL)',
|
||||
'virtfusion_package_id' => 41,
|
||||
],
|
||||
'sort_order' => 8,
|
||||
'provisioning_config' => ['package_id' => 51, 'hypervisor_id' => 1],
|
||||
'sort_order' => 9,
|
||||
],
|
||||
|
||||
// ─── Dedicated Server Plans ──────────────────────────────────
|
||||
// ─── Dedicated Server Plans — OLD (12th/13th Gen, hidden) ───
|
||||
[
|
||||
'name' => 'Dell R330 LFF',
|
||||
'slug' => 'dell-r330-lff',
|
||||
@@ -201,8 +239,9 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '1 /64 IPv6',
|
||||
'management' => 'SynergyCP',
|
||||
],
|
||||
'status' => 'hidden',
|
||||
'stock_quantity' => 3,
|
||||
'sort_order' => 10,
|
||||
'sort_order' => 100,
|
||||
],
|
||||
[
|
||||
'name' => 'Dell R420 LFF',
|
||||
@@ -221,8 +260,9 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '1 /64 IPv6',
|
||||
'management' => 'SynergyCP',
|
||||
],
|
||||
'status' => 'hidden',
|
||||
'stock_quantity' => 0,
|
||||
'sort_order' => 11,
|
||||
'sort_order' => 101,
|
||||
],
|
||||
[
|
||||
'name' => 'Dell R620 SFF 10-Bay',
|
||||
@@ -241,8 +281,9 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '1 /64 IPv6',
|
||||
'management' => 'SynergyCP',
|
||||
],
|
||||
'status' => 'hidden',
|
||||
'stock_quantity' => 0,
|
||||
'sort_order' => 12,
|
||||
'sort_order' => 102,
|
||||
],
|
||||
[
|
||||
'name' => 'Dell R620 SFF 8-Bay',
|
||||
@@ -261,8 +302,9 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '1 /64 IPv6',
|
||||
'management' => 'SynergyCP',
|
||||
],
|
||||
'status' => 'hidden',
|
||||
'stock_quantity' => 0,
|
||||
'sort_order' => 13,
|
||||
'sort_order' => 103,
|
||||
],
|
||||
[
|
||||
'name' => 'Dell R520 LFF',
|
||||
@@ -281,8 +323,9 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '1 /64 IPv6',
|
||||
'management' => 'SynergyCP',
|
||||
],
|
||||
'status' => 'hidden',
|
||||
'stock_quantity' => 2,
|
||||
'sort_order' => 14,
|
||||
'sort_order' => 104,
|
||||
],
|
||||
[
|
||||
'name' => 'Dell R430 LFF',
|
||||
@@ -301,8 +344,9 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '1 /64 IPv6',
|
||||
'management' => 'SynergyCP',
|
||||
],
|
||||
'status' => 'hidden',
|
||||
'stock_quantity' => 1,
|
||||
'sort_order' => 15,
|
||||
'sort_order' => 105,
|
||||
],
|
||||
[
|
||||
'name' => 'Dell R630 SFF',
|
||||
@@ -321,8 +365,9 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '1 /64 IPv6',
|
||||
'management' => 'SynergyCP',
|
||||
],
|
||||
'status' => 'hidden',
|
||||
'stock_quantity' => 1,
|
||||
'sort_order' => 16,
|
||||
'sort_order' => 106,
|
||||
],
|
||||
[
|
||||
'name' => 'Dell R730 LFF',
|
||||
@@ -341,8 +386,101 @@ class PlanSeeder extends Seeder
|
||||
'ipv6' => '1 /64 IPv6',
|
||||
'management' => 'SynergyCP',
|
||||
],
|
||||
'status' => 'hidden',
|
||||
'stock_quantity' => 1,
|
||||
'sort_order' => 17,
|
||||
'sort_order' => 107,
|
||||
],
|
||||
|
||||
// ─── Dedicated Server Plans — NEW (14th Gen) ────────────────
|
||||
[
|
||||
'name' => 'Dell R440',
|
||||
'slug' => 'dell-r440',
|
||||
'description' => 'Entry-level dedicated server. Xeon Scalable, DDR4 ECC, 4x LFF drive bays. Perfect for small businesses, web hosting, and development.',
|
||||
'service_type' => 'dedicated',
|
||||
'price' => 79.00,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'cpu' => 'Intel Xeon Scalable',
|
||||
'ram' => 'DDR4 ECC',
|
||||
'storage_bays' => '4x LFF bays',
|
||||
'bandwidth' => '10 TB',
|
||||
'ipv4' => '1 IPv4',
|
||||
'ipv6' => '1 /64 IPv6',
|
||||
'management' => 'SynergyCP',
|
||||
],
|
||||
'sort_order' => 10,
|
||||
],
|
||||
[
|
||||
'name' => 'Dell R640',
|
||||
'slug' => 'dell-r640',
|
||||
'description' => 'High-performance 1U server. Xeon Scalable, DDR4 ECC, 8x SFF drive slots. Ideal for production applications, databases, and virtualization.',
|
||||
'service_type' => 'dedicated',
|
||||
'price' => 109.00,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'cpu' => 'Intel Xeon Scalable',
|
||||
'ram' => 'DDR4 ECC',
|
||||
'storage_bays' => '8x SFF slots',
|
||||
'bandwidth' => '10 TB',
|
||||
'ipv4' => '1 IPv4',
|
||||
'ipv6' => '1 /64 IPv6',
|
||||
'management' => 'SynergyCP',
|
||||
],
|
||||
'sort_order' => 11,
|
||||
],
|
||||
[
|
||||
'name' => 'Dell R540',
|
||||
'slug' => 'dell-r540',
|
||||
'description' => 'Storage-optimized 2U server. Xeon Scalable, DDR4 ECC, 8x LFF drive bays. Built for large databases, file servers, and storage-heavy workloads.',
|
||||
'service_type' => 'dedicated',
|
||||
'price' => 119.00,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'cpu' => 'Intel Xeon Scalable',
|
||||
'ram' => 'DDR4 ECC',
|
||||
'storage_bays' => '8x LFF bays',
|
||||
'bandwidth' => '10 TB',
|
||||
'ipv4' => '1 IPv4',
|
||||
'ipv6' => '1 /64 IPv6',
|
||||
'management' => 'SynergyCP',
|
||||
],
|
||||
'sort_order' => 12,
|
||||
],
|
||||
[
|
||||
'name' => 'Dell R740',
|
||||
'slug' => 'dell-r740',
|
||||
'description' => 'Enterprise 2U server. Xeon Scalable, DDR4 ECC, 16x SFF drive slots. Maximum expansion for high-density deployments and virtualization.',
|
||||
'service_type' => 'dedicated',
|
||||
'price' => 159.00,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'cpu' => 'Intel Xeon Scalable',
|
||||
'ram' => 'DDR4 ECC',
|
||||
'storage_bays' => '16x SFF slots',
|
||||
'bandwidth' => '10 TB',
|
||||
'ipv4' => '1 IPv4',
|
||||
'ipv6' => '1 /64 IPv6',
|
||||
'management' => 'SynergyCP',
|
||||
],
|
||||
'sort_order' => 13,
|
||||
],
|
||||
[
|
||||
'name' => 'Storage Server 36-Bay',
|
||||
'slug' => 'stor-36bay',
|
||||
'description' => 'High-capacity storage server. Dual Xeon E5-2695 v4, 256GB DDR4 ECC, 36x 3.5" drive bays. Massive raw storage for backups, archives, and data lakes.',
|
||||
'service_type' => 'dedicated',
|
||||
'price' => 449.00,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'cpu' => '2x Intel Xeon E5-2695 v4',
|
||||
'ram' => '256 GB DDR4 ECC',
|
||||
'storage_bays' => '36x 3.5" bays',
|
||||
'bandwidth' => '10 TB',
|
||||
'ipv4' => '1 IPv4',
|
||||
'ipv6' => '1 /64 IPv6',
|
||||
'management' => 'SynergyCP',
|
||||
],
|
||||
'sort_order' => 14,
|
||||
],
|
||||
|
||||
// ─── Web Hosting Plans ───────────────────────────────────────
|
||||
@@ -351,7 +489,7 @@ class PlanSeeder extends Seeder
|
||||
'slug' => 'hosting-small',
|
||||
'description' => 'Starter web hosting plan for personal sites and blogs.',
|
||||
'service_type' => 'hosting',
|
||||
'price' => 2.39,
|
||||
'price' => 3.99,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'storage' => '10 GB SSD',
|
||||
@@ -371,7 +509,7 @@ class PlanSeeder extends Seeder
|
||||
'slug' => 'hosting-medium',
|
||||
'description' => 'Mid-range hosting for small businesses and growing websites.',
|
||||
'service_type' => 'hosting',
|
||||
'price' => 3.99,
|
||||
'price' => 6.99,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'storage' => '25 GB SSD',
|
||||
@@ -391,7 +529,7 @@ class PlanSeeder extends Seeder
|
||||
'slug' => 'hosting-large',
|
||||
'description' => 'High-capacity hosting with unlimited databases and email for agencies and power users.',
|
||||
'service_type' => 'hosting',
|
||||
'price' => 7.19,
|
||||
'price' => 12.99,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'storage' => '100 GB SSD',
|
||||
@@ -411,7 +549,7 @@ class PlanSeeder extends Seeder
|
||||
'slug' => 'hosting-dedicated',
|
||||
'description' => 'Dedicated hosting resources with maximum performance and capacity.',
|
||||
'service_type' => 'hosting',
|
||||
'price' => 15.99,
|
||||
'price' => 29.99,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'storage' => '160 GB SSD',
|
||||
@@ -427,6 +565,64 @@ class PlanSeeder extends Seeder
|
||||
'sort_order' => 23,
|
||||
],
|
||||
|
||||
// ─── MySQL Hosting Plans ─────────────────────────────────────
|
||||
[
|
||||
'name' => 'Bronze',
|
||||
'slug' => 'mysql-bronze',
|
||||
'description' => 'Entry-level managed MySQL hosting with daily backups.',
|
||||
'service_type' => 'mysql',
|
||||
'price' => 7.99,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'storage' => '5 GB',
|
||||
'backups' => 'Daily',
|
||||
'ssl' => 'SSL Encrypted',
|
||||
],
|
||||
'sort_order' => 30,
|
||||
],
|
||||
[
|
||||
'name' => 'Silver',
|
||||
'slug' => 'mysql-silver',
|
||||
'description' => 'Mid-tier managed MySQL hosting for growing applications.',
|
||||
'service_type' => 'mysql',
|
||||
'price' => 14.99,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'storage' => '15 GB',
|
||||
'backups' => 'Daily',
|
||||
'ssl' => 'SSL Encrypted',
|
||||
],
|
||||
'sort_order' => 31,
|
||||
],
|
||||
[
|
||||
'name' => 'Gold',
|
||||
'slug' => 'mysql-gold',
|
||||
'description' => 'High-capacity managed MySQL hosting for production databases.',
|
||||
'service_type' => 'mysql',
|
||||
'price' => 22.99,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'storage' => '30 GB',
|
||||
'backups' => 'Daily',
|
||||
'ssl' => 'SSL Encrypted',
|
||||
],
|
||||
'sort_order' => 32,
|
||||
],
|
||||
[
|
||||
'name' => 'Platinum',
|
||||
'slug' => 'mysql-platinum',
|
||||
'description' => 'Enterprise managed MySQL hosting with 100 GB storage for large-scale databases.',
|
||||
'service_type' => 'mysql',
|
||||
'price' => 34.99,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'storage' => '100 GB',
|
||||
'backups' => 'Daily',
|
||||
'ssl' => 'SSL Encrypted',
|
||||
],
|
||||
'sort_order' => 33,
|
||||
],
|
||||
|
||||
// ─── Game Server Plans ──────────────────────────────────────
|
||||
[
|
||||
'name' => 'Minecraft',
|
||||
@@ -530,63 +726,64 @@ class PlanSeeder extends Seeder
|
||||
],
|
||||
'sort_order' => 45,
|
||||
],
|
||||
[
|
||||
'name' => 'Procon Layer',
|
||||
'slug' => 'procon-layer',
|
||||
'description' => 'Battlefield server management tool. Hosted on Pterodactyl with configurable memory and disk.',
|
||||
'service_type' => 'game',
|
||||
'price' => 2.99,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'ram' => 'Configurable',
|
||||
'storage' => 'Configurable',
|
||||
'platform' => 'Pterodactyl',
|
||||
'ddos' => 'DDoS Protection',
|
||||
],
|
||||
'sort_order' => 50,
|
||||
],
|
||||
|
||||
// ─── MySQL Hosting Plans ─────────────────────────────────────
|
||||
// ─── Backup Plans (Veeam) ────────────────────────────────────
|
||||
[
|
||||
'name' => 'Bronze',
|
||||
'slug' => 'mysql-bronze',
|
||||
'description' => 'Entry-level managed MySQL hosting with daily backups.',
|
||||
'service_type' => 'mysql',
|
||||
'price' => 6.00,
|
||||
'name' => 'Veeam Enterprise Plus',
|
||||
'slug' => 'veeam-enterprise-plus',
|
||||
'description' => 'Enterprise-grade backup and replication. Per-VM and per-agent licensing with full Veeam feature set.',
|
||||
'service_type' => 'backups',
|
||||
'price' => 0.00,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'storage' => '5 GB',
|
||||
'backups' => 'Daily',
|
||||
'ssl' => 'SSL Encrypted',
|
||||
'licensing' => 'Per-VM & Per-Agent',
|
||||
'tier' => 'Enterprise Plus',
|
||||
'replication' => 'Full Feature Set',
|
||||
],
|
||||
'sort_order' => 30,
|
||||
'sort_order' => 60,
|
||||
],
|
||||
[
|
||||
'name' => 'Silver',
|
||||
'slug' => 'mysql-silver',
|
||||
'description' => 'Mid-tier managed MySQL hosting for growing applications.',
|
||||
'service_type' => 'mysql',
|
||||
'price' => 12.00,
|
||||
'name' => 'Veeam Standard',
|
||||
'slug' => 'veeam-standard',
|
||||
'description' => 'Standard backup and replication. Per-VM and per-agent licensing for essential data protection.',
|
||||
'service_type' => 'backups',
|
||||
'price' => 0.00,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'storage' => '15 GB',
|
||||
'backups' => 'Daily',
|
||||
'ssl' => 'SSL Encrypted',
|
||||
'licensing' => 'Per-VM & Per-Agent',
|
||||
'tier' => 'Standard',
|
||||
'replication' => 'Essential Data Protection',
|
||||
],
|
||||
'sort_order' => 31,
|
||||
'sort_order' => 61,
|
||||
],
|
||||
[
|
||||
'name' => 'Gold',
|
||||
'slug' => 'mysql-gold',
|
||||
'description' => 'High-capacity managed MySQL hosting for production databases.',
|
||||
'service_type' => 'mysql',
|
||||
'price' => 18.00,
|
||||
'name' => 'Veeam Cloud Connect',
|
||||
'slug' => 'veeam-cloud-connect',
|
||||
'description' => 'Cloud-connected backup with off-site replication. Capacity-based storage with optional VM replication.',
|
||||
'service_type' => 'backups',
|
||||
'price' => 0.00,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'storage' => '30 GB',
|
||||
'backups' => 'Daily',
|
||||
'ssl' => 'SSL Encrypted',
|
||||
'licensing' => 'Capacity-Based',
|
||||
'tier' => 'Cloud Connect',
|
||||
'replication' => 'Off-Site VM Replication',
|
||||
],
|
||||
'sort_order' => 32,
|
||||
],
|
||||
[
|
||||
'name' => 'Platinum',
|
||||
'slug' => 'mysql-platinum',
|
||||
'description' => 'Enterprise managed MySQL hosting with 100 GB storage for large-scale databases.',
|
||||
'service_type' => 'mysql',
|
||||
'price' => 30.00,
|
||||
'billing_cycle' => 'monthly',
|
||||
'features' => [
|
||||
'storage' => '100 GB',
|
||||
'backups' => 'Daily',
|
||||
'ssl' => 'SSL Encrypted',
|
||||
],
|
||||
'sort_order' => 33,
|
||||
'sort_order' => 62,
|
||||
],
|
||||
];
|
||||
|
||||
@@ -600,8 +797,9 @@ class PlanSeeder extends Seeder
|
||||
);
|
||||
}
|
||||
|
||||
// ─── VPS Multi-Cycle Pricing ───────────────────────────────────
|
||||
$vpsPricing = [
|
||||
// ─── Multi-Cycle Pricing ─────────────────────────────────────
|
||||
$allPricing = [
|
||||
// VPS Plans
|
||||
'vps-1' => ['monthly' => 5.00, 'quarterly' => 14.25, 'semi_annual' => 27.00, 'annual' => 51.00],
|
||||
'vps-2' => ['monthly' => 8.00, 'quarterly' => 22.80, 'semi_annual' => 43.20, 'annual' => 81.60],
|
||||
'vps-4' => ['monthly' => 15.00, 'quarterly' => 42.75, 'semi_annual' => 81.00, 'annual' => 153.00],
|
||||
@@ -610,19 +808,77 @@ class PlanSeeder extends Seeder
|
||||
'vps-32' => ['monthly' => 99.00, 'quarterly' => 282.15, 'semi_annual' => 534.60, 'annual' => 1009.80],
|
||||
'stor-500' => ['monthly' => 18.00, 'quarterly' => 51.30, 'semi_annual' => 97.20, 'annual' => 183.60],
|
||||
'stor-1tb' => ['monthly' => 28.00, 'quarterly' => 79.80, 'semi_annual' => 151.20, 'annual' => 285.60],
|
||||
|
||||
// Dedicated Server Plans — NEW (14th Gen)
|
||||
'dell-r440' => ['monthly' => 79.00, 'quarterly' => 225.15, 'semi_annual' => 426.60, 'annual' => 805.80],
|
||||
'dell-r640' => ['monthly' => 109.00, 'quarterly' => 310.65, 'semi_annual' => 588.60, 'annual' => 1111.80],
|
||||
'dell-r540' => ['monthly' => 119.00, 'quarterly' => 339.15, 'semi_annual' => 642.60, 'annual' => 1213.80],
|
||||
'dell-r740' => ['monthly' => 159.00, 'quarterly' => 453.15, 'semi_annual' => 858.60, 'annual' => 1621.80],
|
||||
'stor-36bay' => ['monthly' => 449.00, 'quarterly' => 1279.65, 'semi_annual' => 2424.60, 'annual' => 4579.80],
|
||||
|
||||
// Web Hosting Plans
|
||||
'hosting-small' => ['monthly' => 3.99, 'annual' => 40.68],
|
||||
'hosting-medium' => ['monthly' => 6.99, 'annual' => 71.28],
|
||||
'hosting-large' => ['monthly' => 12.99, 'annual' => 132.48],
|
||||
'hosting-dedicated' => ['monthly' => 29.99, 'annual' => 305.88],
|
||||
|
||||
// MySQL Hosting Plans
|
||||
'mysql-bronze' => ['monthly' => 7.99, 'annual' => 81.48],
|
||||
'mysql-silver' => ['monthly' => 14.99, 'annual' => 152.88],
|
||||
'mysql-gold' => ['monthly' => 22.99, 'annual' => 234.48],
|
||||
'mysql-platinum' => ['monthly' => 34.99, 'annual' => 356.88],
|
||||
|
||||
// Game Server Plans
|
||||
'procon-layer' => ['monthly' => 2.99, 'annual' => 30.48],
|
||||
|
||||
// Backup Plans (base price $0, all pricing via configurable options)
|
||||
'veeam-enterprise-plus' => ['monthly' => 0.00],
|
||||
'veeam-standard' => ['monthly' => 0.00],
|
||||
'veeam-cloud-connect' => ['monthly' => 0.00],
|
||||
];
|
||||
|
||||
foreach ($vpsPricing as $slug => $prices) {
|
||||
foreach ($allPricing as $slug => $prices) {
|
||||
$plan = Plan::where('slug', $slug)->first();
|
||||
if (! $plan) {
|
||||
continue;
|
||||
}
|
||||
foreach ($prices as $cycle => $price) {
|
||||
\App\Models\PlanPrice::updateOrCreate(
|
||||
PlanPrice::updateOrCreate(
|
||||
['plan_id' => $plan->id, 'billing_cycle' => $cycle],
|
||||
['price' => $price],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Build Your Own (BYO) Custom Plans ─────────────────────────
|
||||
$byoPlans = [
|
||||
['name' => 'Custom VPS', 'slug' => 'vps-custom', 'service_type' => 'vps', 'sort_order' => 99],
|
||||
['name' => 'Custom MySQL', 'slug' => 'mysql-custom', 'service_type' => 'mysql', 'sort_order' => 99],
|
||||
['name' => 'Custom Game Server', 'slug' => 'game-custom', 'service_type' => 'game', 'sort_order' => 99],
|
||||
];
|
||||
|
||||
foreach ($byoPlans as $byoPlan) {
|
||||
Plan::updateOrCreate(
|
||||
['slug' => $byoPlan['slug']],
|
||||
array_merge($byoPlan, [
|
||||
'price' => 0.00,
|
||||
'billing_cycle' => 'monthly',
|
||||
'currency' => 'USD',
|
||||
'status' => 'internal',
|
||||
'description' => 'Custom Build Your Own plan.',
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
// Seed $0 PlanPrice rows for BYO plans so priceForCycle() returns valid results
|
||||
foreach ($byoPlans as $byoPlan) {
|
||||
$plan = Plan::where('slug', $byoPlan['slug'])->first();
|
||||
foreach (['monthly', 'quarterly', 'semi_annual', 'annual'] as $cycle) {
|
||||
PlanPrice::updateOrCreate(
|
||||
['plan_id' => $plan->id, 'billing_cycle' => $cycle],
|
||||
['price' => 0.00],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\Plan;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class UpdateVirtFusionPackageIds extends Seeder
|
||||
{
|
||||
public function run(): void
|
||||
{
|
||||
// Map Laravel plans to VirtFusion package IDs
|
||||
$mapping = [
|
||||
'Nano' => 43, // Base Package (will use custom specs)
|
||||
'Micro' => 19, // Micro
|
||||
'Mini' => 20, // Mini
|
||||
'Standard' => 22, // Standard
|
||||
'Plus' => 23, // Advanced
|
||||
'Pro' => 24, // Pro
|
||||
'Storage-500' => 41, // Storage Box
|
||||
'Storage-1TB' => 41, // Storage Box
|
||||
];
|
||||
|
||||
foreach ($mapping as $planName => $packageId) {
|
||||
$plan = Plan::where('name', $planName)->where('service_type', 'vps')->first();
|
||||
|
||||
if ($plan) {
|
||||
$features = $plan->features ?? [];
|
||||
$features['virtfusion_package_id'] = $packageId;
|
||||
|
||||
$plan->update(['features' => $features]);
|
||||
|
||||
$this->command->info("Updated {$planName} with VirtFusion package ID {$packageId}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user