OS list updated to reflect each project's actual current and supported versions as of 2026-04 (verified per project release calendars): Added: - AlmaLinux 10 (RHEL 10 rebuild, default) — was missing - Rocky Linux 10 — was missing - Ubuntu 26.04 LTS (Resolute Raccoon, released Apr 2026) — was missing - Debian 13 Trixie (current stable since Aug 2025) — was missing; bumped from oldstable Debian 12 - openSUSE Leap 16.0 (Oct 2025) — replaces 15.6 (EOLs Apr 30 2026) - FreeBSD 15.0 (Dec 2025) and 14.4 (Mar 2026) — was a generic "14" - Proxmox VE 9.1 (Nov 2025) — added alongside 8.4 (security maint through Aug 2026) Removed: - Debian 11 (LTS ends Aug 2026, dropped to avoid offering near-EOL) - openSUSE Leap 15.6 (EOLs in 4 days) Default OS flipped from AlmaLinux 9 → AlmaLinux 10 (current major). Proxmox logo color: the Wikimedia CoreUI Proxmox SVG was monochrome (inheriting black). Added fill="#E57000" so the brand orange is correct. 22 OS options total across 9 distro families. metaFor() in OsGroupSelector already handles all families via slug prefix — no component changes needed for the new versions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
900 lines
46 KiB
PHP
900 lines
46 KiB
PHP
<?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 (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,
|
||
],
|
||
);
|
||
|
||
// Platinum 8280 sits in this group but is filtered out at the route
|
||
// level for chassis where features.cpu_premium === false (R440/R540).
|
||
$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],
|
||
['label' => 'Premium: 2× Xeon Platinum 8280 (56C / 2.70 GHz)', 'value' => 'platinum-8280', 'monthly' => 285.00],
|
||
]);
|
||
|
||
$gen14CpuPlanSlugs = ['r440-4lff', 'r540-8lff', 'r640-8sff', 'r740-16sff', 'r740xd-24sff', 'r740xd-12lff', 'r640-10nvme', 'r740xd-24nvme'];
|
||
$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],
|
||
]);
|
||
|
||
// R740xd-specific group is now obsolete — all chassis use the
|
||
// standard CPU group above and the route-level cpu_premium filter
|
||
// controls Platinum visibility. Detach all plans; group + values
|
||
// remain seeded for backwards-compat with any historical references.
|
||
$gen14CpuUpgradeXd->plans()->sync([]);
|
||
|
||
// ─── 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, [
|
||
// Per-stick math at $65/64GB-equivalent, set to recoup 12-month
|
||
// hardware cost on $390/stick DDR4-2400 LRDIMM at 2026 Q2
|
||
// shortage prices + ~30% margin. Sits ~17% under Hetzner's
|
||
// $78/module pricing — small-provider positioning.
|
||
['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' => 65.00],
|
||
['label' => '128 GB DDR4-2400 ECC RDIMM', 'value' => '128', 'monthly' => 195.00],
|
||
['label' => '256 GB DDR4-2400 ECC LRDIMM', 'value' => '256', 'monthly' => 260.00],
|
||
['label' => '512 GB DDR4-2400 ECC LRDIMM', 'value' => '512', 'monthly' => 520.00],
|
||
['label' => '1 TB DDR4-2400 ECC LRDIMM', 'value' => '1024', 'monthly' => 1040.00],
|
||
// 1.5 TB hides for chassis with features.max_ram_gb < 1536.
|
||
['label' => '1.5 TB DDR4-2400 ECC LRDIMM', 'value' => '1536', 'monthly' => 1560.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);
|
||
// Order: enterprise Linux first (Alma / Rocky), then mainstream LTS
|
||
// (Ubuntu / Debian), then leading-edge / specialty (Fedora / openSUSE
|
||
// / FreeBSD / Proxmox), then Windows BYOL, with "No OS" last so the
|
||
// picker reads as a positive distro choice.
|
||
//
|
||
// Only versions in active or security maintenance as of 2026-04 are
|
||
// listed. Verified against each project's release calendar:
|
||
// Alma 10 (current, RHEL 10 rebuild), 9 (active), 8 (security only)
|
||
// Rocky 10 (released Jul 2025), 9, 8 (security only)
|
||
// Ubuntu 26.04 LTS (released Apr 2026), 24.04 LTS, 22.04 LTS
|
||
// Debian 13 trixie (current stable since Aug 2025), 12 (oldstable);
|
||
// 11 dropped — LTS ends Aug 2026
|
||
// Fedora 44 (released Apr 2026), 43 (released Oct 2025); 41 EOL
|
||
// openSUSE Leap 16.0 (Oct 2025); 15.6 dropped — EOL Apr 30 2026
|
||
// FreeBSD 15.0 (Dec 2025), 14.4 (Mar 2026)
|
||
// Proxmox VE 9.1 (Nov 2025), 8.4 (security through Aug 2026)
|
||
// Windows Server 2025 (Nov 2024), 2022, 2019
|
||
$this->seedValues($gen14OsOption, [
|
||
['label' => 'AlmaLinux 10', 'value' => 'alma10', 'monthly' => 0, 'is_default' => true],
|
||
['label' => 'AlmaLinux 9', 'value' => 'alma9', 'monthly' => 0],
|
||
['label' => 'AlmaLinux 8', 'value' => 'alma8', 'monthly' => 0],
|
||
['label' => 'Rocky Linux 10', 'value' => 'rocky10', 'monthly' => 0],
|
||
['label' => 'Rocky Linux 9', 'value' => 'rocky9', 'monthly' => 0],
|
||
['label' => 'Rocky Linux 8', 'value' => 'rocky8', 'monthly' => 0],
|
||
['label' => 'Ubuntu 26.04 LTS', 'value' => 'ubuntu26', 'monthly' => 0],
|
||
['label' => 'Ubuntu 24.04 LTS', 'value' => 'ubuntu24', 'monthly' => 0],
|
||
['label' => 'Ubuntu 22.04 LTS', 'value' => 'ubuntu22', 'monthly' => 0],
|
||
['label' => 'Debian 13 (Trixie)', 'value' => 'debian13', 'monthly' => 0],
|
||
['label' => 'Debian 12 (Bookworm)', 'value' => 'debian12', 'monthly' => 0],
|
||
['label' => 'Fedora Server 44', 'value' => 'fedora44', 'monthly' => 0],
|
||
['label' => 'Fedora Server 43', 'value' => 'fedora43', 'monthly' => 0],
|
||
['label' => 'openSUSE Leap 16.0', 'value' => 'opensuse-leap-160', 'monthly' => 0],
|
||
['label' => 'FreeBSD 15.0', 'value' => 'freebsd15', 'monthly' => 0],
|
||
['label' => 'FreeBSD 14.4', 'value' => 'freebsd14', 'monthly' => 0],
|
||
['label' => 'Proxmox VE 9.1', 'value' => 'proxmox9', 'monthly' => 0],
|
||
['label' => 'Proxmox VE 8.4', 'value' => 'proxmox8', 'monthly' => 0],
|
||
['label' => 'Windows Server 2025 (BYOL)', 'value' => 'windows-2025-byol', 'monthly' => 0],
|
||
['label' => 'Windows Server 2022 (BYOL)', 'value' => 'windows-2022-byol', 'monthly' => 0],
|
||
['label' => 'Windows Server 2019 (BYOL)', 'value' => 'windows-2019-byol', 'monthly' => 0],
|
||
['label' => 'No OS (BYO image / custom PXE)', 'value' => 'none', '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 + 500 TB included', 'value' => '10g-500tb', 'monthly' => 345.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 — Private Networking ────────────────────
|
||
// Separate from public bandwidth. Intra-rack private link with no
|
||
// bandwidth metering — traffic never traverses the public internet,
|
||
// so only the link speed itself is billable. Flat monthly, no setup.
|
||
$gen14PrivateNet = PlanConfigGroup::updateOrCreate(
|
||
['name' => 'Dedicated 14th Gen — Private Networking'],
|
||
[
|
||
'description' => 'Optional dedicated private network link for server-to-server traffic. Unmetered (traffic stays on our internal switch fabric).',
|
||
'mode' => 'preset',
|
||
'service_type' => 'dedicated',
|
||
'is_active' => true,
|
||
'sort_order' => 46,
|
||
],
|
||
);
|
||
|
||
$gen14PrivateNetOption = $this->seedRadioOption($gen14PrivateNet, 'Private Network', false, 1);
|
||
$this->seedValues($gen14PrivateNetOption, [
|
||
['label' => '1 Gbit private (included)', 'value' => '1g', 'monthly' => 0, 'is_default' => true],
|
||
['label' => '10 Gbit private', 'value' => '10g', 'monthly' => 25.00],
|
||
['label' => '40 Gbit private', 'value' => '40g', 'monthly' => 75.00],
|
||
]);
|
||
|
||
$gen14PrivateNet->plans()->syncWithoutDetaching($gen14AllPlans);
|
||
|
||
// ─── Dedicated 14th Gen — PCIe NVMe Add-in ──────────────────────
|
||
// Separate category from bay-attached drives — uses empty PCIe slots
|
||
// via Sabrent EC-PCIE (single-drive) or EC-P4BF (4-drive bifurcation
|
||
// x16) adapter cards. Customers can stack this on top of bay drives
|
||
// for fast scratch / cache / metadata storage.
|
||
// Pricing: 12-month payback × 1.5x markup on (Sabrent retail drive
|
||
// cost + adapter cost). Drive prices scraped from sabrent.com on
|
||
// 2026-04-26: Rocket 4 Plus 1TB \$249.99 / 2TB \$289.99 / 4TB \$879.99
|
||
// / 8TB \$3,699.99; Rocket 5 Gen5 1TB \$400 / 2TB \$499.99 / 4TB \$1,400.
|
||
// Adapters: EC-PCIE \$17.98, EC-P4BF \$99.99.
|
||
$gen14PciNvme = PlanConfigGroup::updateOrCreate(
|
||
['name' => 'Dedicated 14th Gen — PCIe NVMe Add-in'],
|
||
[
|
||
'description' => 'Add high-performance M.2 NVMe storage on top of your bay drives. Pick a single drive for fast scratch space or a 4-drive bundle for more capacity.',
|
||
'mode' => 'preset',
|
||
'service_type' => 'dedicated',
|
||
'is_active' => true,
|
||
'sort_order' => 47,
|
||
],
|
||
);
|
||
|
||
$gen14PciNvmeOption = $this->seedRadioOption($gen14PciNvme, 'PCIe NVMe Add-in', false, 1);
|
||
$this->seedValues($gen14PciNvmeOption, [
|
||
['label' => 'No PCIe NVMe add-in', 'value' => 'none', 'monthly' => 0, 'is_default' => true],
|
||
// Single-drive (Gen4)
|
||
['label' => '1× 1 TB M.2 NVMe (Gen4)', 'value' => '1x1tb-r4p-pcie', 'monthly' => 35.00],
|
||
['label' => '1× 2 TB M.2 NVMe (Gen4)', 'value' => '1x2tb-r4p-pcie', 'monthly' => 40.00],
|
||
['label' => '1× 4 TB M.2 NVMe (Gen4)', 'value' => '1x4tb-r4p-pcie', 'monthly' => 115.00],
|
||
['label' => '1× 8 TB M.2 NVMe (Gen4)', 'value' => '1x8tb-r4p-pcie', 'monthly' => 465.00],
|
||
// Single-drive (Gen5)
|
||
['label' => '1× 2 TB M.2 NVMe (Gen5)', 'value' => '1x2tb-r5-pcie', 'monthly' => 65.00],
|
||
['label' => '1× 4 TB M.2 NVMe (Gen5)', 'value' => '1x4tb-r5-pcie', 'monthly' => 180.00],
|
||
// 4-drive bundles (Gen4)
|
||
['label' => '4× 1 TB M.2 NVMe (Gen4 bundle)', 'value' => '4x1tb-r4p-p4bf', 'monthly' => 140.00],
|
||
['label' => '4× 2 TB M.2 NVMe (Gen4 bundle)', 'value' => '4x2tb-r4p-p4bf', 'monthly' => 160.00],
|
||
['label' => '4× 4 TB M.2 NVMe (Gen4 bundle)', 'value' => '4x4tb-r4p-p4bf', 'monthly' => 455.00],
|
||
['label' => '4× 8 TB M.2 NVMe (Gen4 bundle)', 'value' => '4x8tb-r4p-p4bf', 'monthly' => 1865.00],
|
||
]);
|
||
|
||
// Attach to LFF + SFF chassis (have free PCIe slots). Skip on the
|
||
// U.2 NVMe-native chassis since they don't have PCIe slots free
|
||
// for add-in cards (lanes are routed to the U.2 backplane).
|
||
$gen14PciNvmeSlugs = ['r440-4lff', 'r540-8lff', 'r640-8sff', 'r740-16sff', 'r740xd-24sff', 'r740xd-12lff'];
|
||
$gen14PciNvmePlans = Plan::query()->whereIn('slug', $gen14PciNvmeSlugs)->pluck('id');
|
||
$gen14PciNvme->plans()->syncWithoutDetaching($gen14PciNvmePlans);
|
||
|
||
// ─── Dedicated 14th Gen — LFF Drive Bays ────────────────────────
|
||
// New shape (Option B): two options per group — Drive Selection (radio,
|
||
// PER-DRIVE cost) + Drive Quantity (stepper). Total = drive × quantity,
|
||
// computed in the frontend. Per-drive economics keep the catalog short
|
||
// and let us add a new size or interface (SAS) without exploding into
|
||
// 4-N more flat-radio rows. SAS HDD/SSD variants offer a 12 Gb/s
|
||
// dual-port path for customers running clustered storage / HA pairs.
|
||
$gen14Lff = PlanConfigGroup::updateOrCreate(
|
||
['name' => 'Dedicated 14th Gen — LFF Drive Bays'],
|
||
[
|
||
'description' => 'Pick a drive type, then choose how many to populate. SATA covers the price-sensitive cases; SAS variants add 12 Gb/s + dual-port for clustered storage workloads.',
|
||
'mode' => 'preset',
|
||
'service_type' => 'dedicated',
|
||
'is_active' => true,
|
||
'sort_order' => 50,
|
||
],
|
||
);
|
||
|
||
$gen14LffDriveOption = $this->seedRadioOption($gen14Lff, 'Drive Selection', false, 1);
|
||
$this->seedValues($gen14LffDriveOption, [
|
||
['label' => 'No drives', 'value' => 'none', 'monthly' => 0, 'is_default' => true],
|
||
['label' => '4 TB SATA HDD', 'value' => 'sata-hdd-4tb', 'monthly' => 12.00],
|
||
['label' => '8 TB SATA HDD', 'value' => 'sata-hdd-8tb', 'monthly' => 20.00],
|
||
['label' => '12 TB Enterprise SATA HDD', 'value' => 'sata-hdd-12tb', 'monthly' => 45.00],
|
||
['label' => '20 TB Enterprise SATA HDD', 'value' => 'sata-hdd-20tb', 'monthly' => 55.00],
|
||
['label' => '24 TB Enterprise SATA HDD', 'value' => 'sata-hdd-24tb', 'monthly' => 75.00],
|
||
['label' => '12 TB Enterprise SAS HDD', 'value' => 'sas-hdd-12tb', 'monthly' => 50.00],
|
||
['label' => '16 TB Enterprise SAS HDD', 'value' => 'sas-hdd-16tb', 'monthly' => 55.00],
|
||
['label' => '480 GB SATA SSD', 'value' => 'sata-ssd-480gb-lff', 'monthly' => 10.00],
|
||
['label' => '1.92 TB SATA SSD', 'value' => 'sata-ssd-1920gb-lff', 'monthly' => 18.00],
|
||
['label' => '3.84 TB SATA SSD', 'value' => 'sata-ssd-3840gb-lff', 'monthly' => 45.00],
|
||
['label' => '7.68 TB SATA SSD', 'value' => 'sata-ssd-7680gb-lff', 'monthly' => 100.00],
|
||
['label' => '1.92 TB SAS SSD', 'value' => 'sas-ssd-1920gb-lff', 'monthly' => 40.00],
|
||
['label' => '3.84 TB SAS SSD', 'value' => 'sas-ssd-3840gb-lff', 'monthly' => 80.00],
|
||
['label' => '7.68 TB SAS SSD', 'value' => 'sas-ssd-7680gb-lff', 'monthly' => 200.00],
|
||
]);
|
||
|
||
// monthly_price = 0 on the stepper itself — actual cost is computed in
|
||
// the frontend as drive_selection.monthly_price × quantity. The route
|
||
// filter clamps max_qty down to chassis bay_count at request time.
|
||
$this->seedQuantityOption($gen14Lff, 'Drive Quantity', 0, 12, 'drives', 0.00, 2);
|
||
|
||
$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 2.5" drive type, then set quantity. SAS SSD variants add 12 Gb/s + dual-port for HA / clustered storage.',
|
||
'mode' => 'preset',
|
||
'service_type' => 'dedicated',
|
||
'is_active' => true,
|
||
'sort_order' => 51,
|
||
],
|
||
);
|
||
|
||
$gen14SffDriveOption = $this->seedRadioOption($gen14Sff, 'Drive Selection', false, 1);
|
||
$this->seedValues($gen14SffDriveOption, [
|
||
['label' => 'No drives', 'value' => 'none', 'monthly' => 0, 'is_default' => true],
|
||
['label' => '480 GB SATA SSD', 'value' => 'sata-ssd-480gb', 'monthly' => 10.00],
|
||
['label' => '1.92 TB SATA SSD', 'value' => 'sata-ssd-1920gb', 'monthly' => 18.00],
|
||
['label' => '3.84 TB SATA SSD', 'value' => 'sata-ssd-3840gb', 'monthly' => 45.00],
|
||
['label' => '7.68 TB SATA SSD', 'value' => 'sata-ssd-7680gb', 'monthly' => 100.00],
|
||
['label' => '1.92 TB SAS SSD', 'value' => 'sas-ssd-1920gb', 'monthly' => 40.00],
|
||
['label' => '3.84 TB SAS SSD', 'value' => 'sas-ssd-3840gb', 'monthly' => 80.00],
|
||
['label' => '7.68 TB SAS SSD', 'value' => 'sas-ssd-7680gb', 'monthly' => 200.00],
|
||
]);
|
||
|
||
$this->seedQuantityOption($gen14Sff, 'Drive Quantity', 0, 24, 'drives', 0.00, 2);
|
||
|
||
$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 U.2 NVMe size, then set quantity. 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,
|
||
],
|
||
);
|
||
|
||
$gen14NvmeDriveOption = $this->seedRadioOption($gen14Nvme, 'Drive Selection', false, 1);
|
||
$this->seedValues($gen14NvmeDriveOption, [
|
||
['label' => 'No drives', 'value' => 'none', 'monthly' => 0, 'is_default' => true],
|
||
['label' => '1.92 TB U.2 NVMe', 'value' => 'u2-nvme-1920gb', 'monthly' => 30.00],
|
||
['label' => '3.84 TB U.2 NVMe', 'value' => 'u2-nvme-3840gb', 'monthly' => 70.00],
|
||
['label' => '7.68 TB U.2 NVMe', 'value' => 'u2-nvme-7680gb', 'monthly' => 150.00],
|
||
]);
|
||
|
||
$this->seedQuantityOption($gen14Nvme, 'Drive Quantity', 0, 24, 'drives', 0.00, 2);
|
||
|
||
$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<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);
|
||
}
|
||
}
|