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 (dedicated only) ───────────────────────── $serverMgmt = PlanConfigGroup::updateOrCreate( ['name' => 'Server Management'], [ 'description' => 'Add managed support to your server.', 'mode' => 'preset', 'service_type' => 'dedicated', '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 dedicated plans only (VPS plans use the dedicated VPS Managed Support group below) $dedicatedPlanIds = Plan::query() ->where('service_type', 'dedicated') ->whereIn('status', ['active', 'internal']) ->pluck('id'); $serverMgmt->plans()->sync($dedicatedPlanIds); // ─── VPS Managed Support ──────────────────────────────────────── // 4-tier radio: Self ($0) / Basic ($29) / Pro ($79) / Pilot ($99, VPS-8+). // Pilot tier gating (min plan tier 8) is enforced in the frontend. $vpsManaged = PlanConfigGroup::updateOrCreate( ['name' => 'VPS Managed Support'], [ 'description' => 'Choose how hands-on you want our team to be with your VPS.', 'mode' => 'preset', 'service_type' => 'vps', 'is_active' => true, 'sort_order' => 10, ], ); $vpsManagedOption = $this->seedRadioOption($vpsManaged, 'Managed Support', false, 1); $this->seedValues($vpsManagedOption, [ ['label' => 'Self-Managed', 'value' => 'self', 'monthly' => 0, 'is_default' => true], ['label' => 'Managed Basic', 'value' => 'basic', 'monthly' => 29.00], ['label' => 'Managed Pro', 'value' => 'pro', 'monthly' => 79.00], ['label' => 'Pilot', 'value' => 'pilot', 'monthly' => 99.00], ]); $vpsPlanIds = Plan::query() ->where('service_type', 'vps') ->whereIn('status', ['active', 'internal']) ->pluck('id'); $vpsManaged->plans()->syncWithoutDetaching($vpsPlanIds); // ─── Off-site Backup (VPS) ────────────────────────────────────── // 5-tier radio: None / Lite (7d, 200GB, $5) / Standard (30d, 500GB, $12) // / Extended (90d, 1TB, $25) / Vault (1yr, 2TB, $59). // StorJ-backed, encrypted at rest. Restores included (no egress charge). $vpsBackup = PlanConfigGroup::updateOrCreate( ['name' => 'Off-site Backup'], [ 'description' => 'Encrypted off-site backups stored on StorJ. Daily snapshots, free restores.', 'mode' => 'preset', 'service_type' => 'vps', 'is_active' => true, 'sort_order' => 12, ], ); $vpsBackupOption = $this->seedRadioOption($vpsBackup, 'Backup Tier', false, 1); $this->seedValues($vpsBackupOption, [ ['label' => 'None', 'value' => 'none', 'monthly' => 0, 'is_default' => true], ['label' => 'Lite (7-day, 200 GB)', 'value' => 'lite', 'monthly' => 5.00], ['label' => 'Standard (30-day, 500 GB)', 'value' => 'standard', 'monthly' => 12.00], ['label' => 'Extended (90-day, 1 TB)', 'value' => 'extended', 'monthly' => 25.00], ['label' => 'Vault (1-year, 2 TB)', 'value' => 'vault', 'monthly' => 59.00], ]); $vpsBackup->plans()->syncWithoutDetaching($vpsPlanIds); // ─── 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', 8.00, 1); // Drop the legacy Windows License option if it exists (BYOL is now communicated // via marketing copy + OS template selection at checkout). PlanConfigOption::query() ->where('group_id', $vpsAddons->id) ->where('name', 'Windows License') ->delete(); // 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); // ─── Dedicated 14th Gen — CPU Upgrade ─────────────────────────── $gen14CpuUpgrade = PlanConfigGroup::updateOrCreate( ['name' => 'Dedicated 14th Gen — CPU Upgrade'], [ 'description' => 'Upgrade from the 2× Xeon Gold 6230 baseline to a higher core count or clock speed.', 'mode' => 'preset', 'service_type' => 'dedicated', 'is_active' => true, 'sort_order' => 40, ], ); $gen14CpuOption = $this->seedRadioOption($gen14CpuUpgrade, 'CPU Upgrade', false, 1); $this->seedValues($gen14CpuOption, [ ['label' => 'Baseline: 2× Xeon Gold 6230 (40C / 2.10 GHz)', 'value' => 'gold-6230-baseline', 'monthly' => 0, 'is_default' => true], // High-clock SKU for per-core licensed workloads (Microsoft SQL, // Oracle, single-threaded compute). Fewer cores, higher base clock. ['label' => 'High-clock: 2× Xeon Gold 6244 (16C / 3.60 GHz)', 'value' => 'gold-6244', 'monthly' => 25.00], ['label' => 'Upgrade: 2× Xeon Gold 6248 (40C / 2.50 GHz)', 'value' => 'gold-6248', 'monthly' => 35.00], // Cascade Lake Refresh of the 6230 — same gen, more cores at the // same clock. Sweet-spot mid-tier between baseline and 6248R. ['label' => 'Mid-tier: 2× Xeon Gold 6230R (52C / 2.10 GHz)', 'value' => 'gold-6230r', 'monthly' => 50.00], ['label' => 'Upgrade: 2× Xeon Gold 6248R (48C / 3.00 GHz)', 'value' => 'gold-6248r', 'monthly' => 75.00], ['label' => 'Upgrade: 2× Xeon Gold 6258R (56C / 2.70 GHz)', 'value' => 'gold-6258r', 'monthly' => 145.00], ]); $gen14CpuPlanSlugs = ['r440-4lff', 'r540-8lff', 'r640-8sff', 'r740-16sff']; $gen14CpuPlans = Plan::query()->whereIn('slug', $gen14CpuPlanSlugs)->pluck('id'); $gen14CpuUpgrade->plans()->syncWithoutDetaching($gen14CpuPlans); // ─── Dedicated 14th Gen — CPU Upgrade (R740xd) ────────────────── $gen14CpuUpgradeXd = PlanConfigGroup::updateOrCreate( ['name' => 'Dedicated 14th Gen — CPU Upgrade (R740xd)'], [ 'description' => 'R740xd-specific CPU options. Higher TDP support than non-xd variants.', 'mode' => 'preset', 'service_type' => 'dedicated', 'is_active' => true, 'sort_order' => 41, ], ); $gen14CpuXdOption = $this->seedRadioOption($gen14CpuUpgradeXd, 'CPU Upgrade', false, 1); $this->seedValues($gen14CpuXdOption, [ ['label' => 'Baseline: 2× Xeon Gold 6230 (40C / 2.10 GHz)', 'value' => 'gold-6230-baseline', 'monthly' => 0, 'is_default' => true], ['label' => 'Upgrade: 2× Xeon Gold 6248R (48C / 3.00 GHz)', 'value' => 'gold-6248r', 'monthly' => 75.00], ['label' => 'Upgrade: 2× Xeon Gold 6258R (56C / 2.70 GHz)', 'value' => 'gold-6258r', 'monthly' => 145.00], ['label' => 'Upgrade: 2× Xeon Platinum 8280 (56C / 2.70 GHz)', 'value' => 'platinum-8280', 'monthly' => 285.00], ]); $gen14CpuXdPlanSlugs = ['r740xd-24sff', 'r740xd-12lff', 'r740xd-24nvme']; $gen14CpuXdPlans = Plan::query()->whereIn('slug', $gen14CpuXdPlanSlugs)->pluck('id'); $gen14CpuUpgradeXd->plans()->syncWithoutDetaching($gen14CpuXdPlans); // ─── Dedicated 14th Gen — RAM Upgrade ─────────────────────────── $gen14Ram = PlanConfigGroup::updateOrCreate( ['name' => 'Dedicated 14th Gen — RAM Upgrade'], [ 'description' => 'DDR4-2400 ECC. RDIMM up to 128 GB; LRDIMM at 256 GB and above.', 'mode' => 'preset', 'service_type' => 'dedicated', 'is_active' => true, 'sort_order' => 42, ], ); $gen14RamOption = $this->seedRadioOption($gen14Ram, 'RAM Upgrade', false, 1); $this->seedValues($gen14RamOption, [ ['label' => '32 GB DDR4-2400 ECC RDIMM (baseline)', 'value' => '32', 'monthly' => 0, 'is_default' => true], ['label' => '64 GB DDR4-2400 ECC RDIMM', 'value' => '64', 'monthly' => 35.00], ['label' => '128 GB DDR4-2400 ECC RDIMM', 'value' => '128', 'monthly' => 90.00], ['label' => '256 GB DDR4-2400 ECC LRDIMM', 'value' => '256', 'monthly' => 195.00], ['label' => '512 GB DDR4-2400 ECC LRDIMM', 'value' => '512', 'monthly' => 380.00], ['label' => '1 TB DDR4-2400 ECC LRDIMM', 'value' => '1024', 'monthly' => 580.00], ['label' => '1.5 TB DDR4-2400 ECC LRDIMM (R640/R740/R740xd only)', 'value' => '1536', 'monthly' => 780.00], ]); $gen14AllPlanSlugs = ['r440-4lff', 'r540-8lff', 'r640-8sff', 'r740-16sff', 'r740xd-24sff', 'r740xd-12lff', 'r640-10nvme', 'r740xd-24nvme']; $gen14AllPlans = Plan::query()->whereIn('slug', $gen14AllPlanSlugs)->pluck('id'); $gen14Ram->plans()->syncWithoutDetaching($gen14AllPlans); // ─── Dedicated 14th Gen — Operating System ────────────────────── $gen14Os = PlanConfigGroup::updateOrCreate( ['name' => 'Dedicated 14th Gen — Operating System'], [ 'description' => 'Choose the OS image installed at provisioning time. Windows requires your own license (BYOL).', 'mode' => 'preset', 'service_type' => 'dedicated', 'is_active' => true, 'sort_order' => 43, ], ); $gen14OsOption = $this->seedRadioOption($gen14Os, 'Operating System', false, 1); $this->seedValues($gen14OsOption, [ ['label' => 'No OS (BYO image / custom PXE)', 'value' => 'none', 'monthly' => 0, 'is_default' => true], ['label' => 'AlmaLinux 9', 'value' => 'alma9', 'monthly' => 0], ['label' => 'Ubuntu 24.04 LTS', 'value' => 'ubuntu24', 'monthly' => 0], ['label' => 'Debian 12', 'value' => 'debian12', 'monthly' => 0], ['label' => 'Rocky Linux 9', 'value' => 'rocky9', 'monthly' => 0], ['label' => 'Windows Server 2022 (BYOL)', 'value' => 'windows-2022-byol', 'monthly' => 0], ]); $gen14Os->plans()->syncWithoutDetaching($gen14AllPlans); // ─── Dedicated 14th Gen — Bandwidth ───────────────────────────── $gen14Bandwidth = PlanConfigGroup::updateOrCreate( ['name' => 'Dedicated 14th Gen — Bandwidth'], [ 'description' => 'Network port speed and bandwidth allocation. 10 Gbps tiers include traffic packages with overage protection.', 'mode' => 'preset', 'service_type' => 'dedicated', 'is_active' => true, 'sort_order' => 44, ], ); $gen14BandwidthOption = $this->seedRadioOption($gen14Bandwidth, 'Bandwidth', false, 1); $this->seedValues($gen14BandwidthOption, [ ['label' => '1 Gbps unmetered (baseline)', 'value' => '1g-unmetered', 'monthly' => 0, 'is_default' => true], ['label' => '10 Gbps + 10 TB included', 'value' => '10g-10tb', 'monthly' => 45.00], ['label' => '10 Gbps + 50 TB included', 'value' => '10g-50tb', 'monthly' => 95.00], ['label' => '10 Gbps + 100 TB included', 'value' => '10g-100tb', 'monthly' => 175.00], ['label' => '10 Gbps unmetered (fair-use AUP)', 'value' => '10g-unmetered-fair-use', 'monthly' => 295.00], ]); $gen14Bandwidth->plans()->syncWithoutDetaching($gen14AllPlans); // ─── Dedicated 14th Gen — IPv4 Block ──────────────────────────── $gen14Ipv4 = PlanConfigGroup::updateOrCreate( ['name' => 'Dedicated 14th Gen — IPv4 Block'], [ 'description' => 'Additional IPv4 addresses beyond the 1 included with every server. Blocks of /28 or larger require ARIN justification — we provide the template; you fill in your use case before the IPs are allocated.', 'mode' => 'preset', 'service_type' => 'dedicated', 'is_active' => true, 'sort_order' => 45, ], ); $gen14Ipv4Option = $this->seedRadioOption($gen14Ipv4, 'IPv4 Block', false, 1); // ARIN justification policy applies to anything above /29; the group // description (above) tells customers about it, so we don't repeat // it on every tier label. $this->seedValues($gen14Ipv4Option, [ ['label' => '1 included (no extra)', 'value' => '1', 'monthly' => 0, 'is_default' => true], ['label' => '/29 (5 usable)', 'value' => '5', 'monthly' => 12.00], ['label' => '/28 (13 usable) — justification required', 'value' => '13', 'monthly' => 36.00], ['label' => '/27 (29 usable) — justification required', 'value' => '29', 'monthly' => 80.00], ['label' => '/26 (61 usable) — justification required', 'value' => '61', 'monthly' => 145.00], ['label' => '/25 (125 usable) — justification required', 'value' => '125', 'monthly' => 275.00], ['label' => '/24 (253 usable) — justification required', 'value' => '253', 'monthly' => 499.00], ]); $gen14Ipv4->plans()->syncWithoutDetaching($gen14AllPlans); // ─── Dedicated 14th Gen — LFF Drive Bays ──────────────────────── $gen14Lff = PlanConfigGroup::updateOrCreate( ['name' => 'Dedicated 14th Gen — LFF Drive Bays'], [ 'description' => 'Pick a starter drive configuration for the 3.5" LFF bays. Customers needing a heterogeneous setup (mixed sizes per bay, hot spares, etc.) can request a custom layout via the post-order ticket flow.', 'mode' => 'preset', 'service_type' => 'dedicated', 'is_active' => true, 'sort_order' => 50, ], ); $gen14LffOption = $this->seedRadioOption($gen14Lff, 'LFF Drive Bays', false, 1); $this->seedValues($gen14LffOption, [ ['label' => 'No drives — configure via ticket', 'value' => 'none', 'monthly' => 0, 'is_default' => true], ['label' => '2× 4 TB SATA HDD', 'value' => '2x4tb-hdd', 'monthly' => 24.00], ['label' => '4× 4 TB SATA HDD', 'value' => '4x4tb-hdd', 'monthly' => 48.00], ['label' => '2× 8 TB SATA HDD', 'value' => '2x8tb-hdd', 'monthly' => 40.00], ['label' => '4× 8 TB SATA HDD', 'value' => '4x8tb-hdd', 'monthly' => 80.00], ['label' => '8× 8 TB SATA HDD (R540 / R740xd LFF only)', 'value' => '8x8tb-hdd', 'monthly' => 160.00], ['label' => '12× 8 TB SATA HDD (R740xd LFF only)', 'value' => '12x8tb-hdd', 'monthly' => 240.00], ]); $gen14LffPlanSlugs = ['r440-4lff', 'r540-8lff', 'r740xd-12lff']; $gen14LffPlans = Plan::query()->whereIn('slug', $gen14LffPlanSlugs)->pluck('id'); $gen14Lff->plans()->syncWithoutDetaching($gen14LffPlans); // ─── Dedicated 14th Gen — SFF Drive Bays ──────────────────────── $gen14Sff = PlanConfigGroup::updateOrCreate( ['name' => 'Dedicated 14th Gen — SFF Drive Bays'], [ 'description' => 'Pick a starter drive configuration for the 2.5" SFF bays. Mixed-size setups via post-order ticket.', 'mode' => 'preset', 'service_type' => 'dedicated', 'is_active' => true, 'sort_order' => 51, ], ); $gen14SffOption = $this->seedRadioOption($gen14Sff, 'SFF Drive Bays', false, 1); $this->seedValues($gen14SffOption, [ ['label' => 'No drives — configure via ticket', 'value' => 'none', 'monthly' => 0, 'is_default' => true], ['label' => '2× 480 GB SATA SSD', 'value' => '2x480gb-ssd', 'monthly' => 20.00], ['label' => '4× 480 GB SATA SSD', 'value' => '4x480gb-ssd', 'monthly' => 40.00], ['label' => '2× 1.92 TB SATA SSD', 'value' => '2x1920gb-ssd', 'monthly' => 36.00], ['label' => '4× 1.92 TB SATA SSD', 'value' => '4x1920gb-ssd', 'monthly' => 72.00], ['label' => '8× 1.92 TB SATA SSD', 'value' => '8x1920gb-ssd', 'monthly' => 144.00], ['label' => '16× 1.92 TB SATA SSD (R740 16-bay / R740xd 24-SFF only)', 'value' => '16x1920gb-ssd', 'monthly' => 288.00], ['label' => '24× 1.92 TB SATA SSD (R740xd 24-SFF only)', 'value' => '24x1920gb-ssd', 'monthly' => 432.00], ]); $gen14SffPlanSlugs = ['r640-8sff', 'r740-16sff', 'r740xd-24sff']; $gen14SffPlans = Plan::query()->whereIn('slug', $gen14SffPlanSlugs)->pluck('id'); $gen14Sff->plans()->syncWithoutDetaching($gen14SffPlans); // ─── Dedicated 14th Gen — NVMe Drive Bays ─────────────────────── $gen14Nvme = PlanConfigGroup::updateOrCreate( ['name' => 'Dedicated 14th Gen — NVMe Drive Bays'], [ 'description' => 'Pick a starter NVMe drive configuration. U.2 bays direct-attach to CPU PCIe lanes — no RAID controller in the data path; software RAID (ZFS / mdraid / btrfs) only.', 'mode' => 'preset', 'service_type' => 'dedicated', 'is_active' => true, 'sort_order' => 52, ], ); $gen14NvmeOption = $this->seedRadioOption($gen14Nvme, 'NVMe Drive Bays', false, 1); $this->seedValues($gen14NvmeOption, [ ['label' => 'No drives — configure via ticket', 'value' => 'none', 'monthly' => 0, 'is_default' => true], ['label' => '2× 1 TB U.2 NVMe', 'value' => '2x1tb-nvme', 'monthly' => 44.00], ['label' => '4× 1 TB U.2 NVMe', 'value' => '4x1tb-nvme', 'monthly' => 88.00], ['label' => '2× 2 TB U.2 NVMe', 'value' => '2x2tb-nvme', 'monthly' => 96.00], ['label' => '4× 2 TB U.2 NVMe', 'value' => '4x2tb-nvme', 'monthly' => 192.00], ['label' => '8× 2 TB U.2 NVMe (R640 NVMe 10-bay / R740xd NVMe 24-bay)', 'value' => '8x2tb-nvme', 'monthly' => 384.00], ['label' => '16× 2 TB U.2 NVMe (R740xd NVMe 24-bay only)', 'value' => '16x2tb-nvme', 'monthly' => 768.00], ]); $gen14NvmePlanSlugs = ['r640-10nvme', 'r740xd-24nvme']; $gen14NvmePlans = Plan::query()->whereIn('slug', $gen14NvmePlanSlugs)->pluck('id'); $gen14Nvme->plans()->syncWithoutDetaching($gen14NvmePlans); } /** * 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 $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); } }