Extract Ladill Servers as standalone app at servers.ladill.com.
VPS and dedicated server ordering, managed panels, SSO, billing, and launcher integration — forked from hosting infrastructure with server-focused routes and dashboard. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* Domain pricing overrides.
|
||||
*
|
||||
* When a TLD has an entry here with is_override=true, the manually set GHS price
|
||||
* will be used instead of the live-converted Dynadot price.
|
||||
*
|
||||
* Prices are stored in pesewas (minor units).
|
||||
*/
|
||||
class DomainPricing extends Model
|
||||
{
|
||||
/**
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private static array $columnExists = [];
|
||||
|
||||
protected $fillable = [
|
||||
'tld',
|
||||
'register_price',
|
||||
'renew_price',
|
||||
'transfer_price',
|
||||
'currency',
|
||||
'is_override',
|
||||
'is_featured',
|
||||
'is_active',
|
||||
'sort_order',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'register_price' => 'integer',
|
||||
'renew_price' => 'integer',
|
||||
'transfer_price' => 'integer',
|
||||
'is_override' => 'boolean',
|
||||
'is_featured' => 'boolean',
|
||||
'is_active' => 'boolean',
|
||||
'sort_order' => 'integer',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get active pricing override for a TLD.
|
||||
*/
|
||||
public static function forTld(string $tld): ?self
|
||||
{
|
||||
$tld = ltrim(strtolower(trim($tld)), '.');
|
||||
|
||||
return Cache::remember(
|
||||
"domain_pricing:{$tld}",
|
||||
now()->addHours(1),
|
||||
function () use ($tld) {
|
||||
$query = static::where('tld', $tld);
|
||||
|
||||
if (static::hasColumn('is_active')) {
|
||||
$query->where('is_active', true);
|
||||
}
|
||||
|
||||
return $query->first();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all active price overrides.
|
||||
*
|
||||
* @return array<string, array{register: int, renew: int, transfer: int, is_override: bool}>
|
||||
*/
|
||||
public static function getOverrides(): array
|
||||
{
|
||||
return Cache::remember(
|
||||
'domain_pricing:overrides',
|
||||
now()->addHours(1),
|
||||
function () {
|
||||
$query = static::query();
|
||||
|
||||
if (static::hasColumn('is_active')) {
|
||||
$query->where('is_active', true);
|
||||
}
|
||||
|
||||
// Older installs may have used this table only for manual overrides.
|
||||
if (static::hasColumn('is_override')) {
|
||||
$query->where('is_override', true);
|
||||
}
|
||||
|
||||
return $query->get()
|
||||
->keyBy('tld')
|
||||
->map(fn ($p) => [
|
||||
'register' => $p->register_price,
|
||||
'renew' => $p->renew_price,
|
||||
'transfer' => $p->transfer_price,
|
||||
'is_override' => static::hasColumn('is_override') ? (bool) $p->is_override : true,
|
||||
])
|
||||
->all();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all active TLDs with pricing.
|
||||
*/
|
||||
public static function activeTlds(): array
|
||||
{
|
||||
return Cache::remember(
|
||||
'domain_pricing:active_tlds',
|
||||
now()->addHours(1),
|
||||
function () {
|
||||
$query = static::query();
|
||||
|
||||
if (static::hasColumn('is_active')) {
|
||||
$query->where('is_active', true);
|
||||
}
|
||||
|
||||
if (static::hasColumn('sort_order')) {
|
||||
$query->orderBy('sort_order');
|
||||
}
|
||||
|
||||
return $query->orderBy('tld')->pluck('tld')->all();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get featured TLDs for search.
|
||||
*/
|
||||
public static function featuredTlds(): array
|
||||
{
|
||||
return Cache::remember(
|
||||
'domain_pricing:featured_tlds',
|
||||
now()->addHours(1),
|
||||
function () {
|
||||
$query = static::query();
|
||||
|
||||
if (static::hasColumn('is_active')) {
|
||||
$query->where('is_active', true);
|
||||
}
|
||||
|
||||
if (static::hasColumn('is_featured')) {
|
||||
$query->where('is_featured', true);
|
||||
}
|
||||
|
||||
if (static::hasColumn('sort_order')) {
|
||||
$query->orderBy('sort_order');
|
||||
}
|
||||
|
||||
$tlds = $query->orderBy('tld')->pluck('tld')->all();
|
||||
|
||||
return $tlds !== [] ? $tlds : static::activeTlds();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pricing map for multiple TLDs.
|
||||
*
|
||||
* @return array<string, array{register: int, renew: int, transfer: int, currency: string}>
|
||||
*/
|
||||
public static function pricingMap(array $tlds = []): array
|
||||
{
|
||||
$query = static::query();
|
||||
|
||||
if (static::hasColumn('is_active')) {
|
||||
$query->where('is_active', true);
|
||||
}
|
||||
|
||||
if (! empty($tlds)) {
|
||||
$query->whereIn('tld', array_map(fn ($t) => ltrim(strtolower($t), '.'), $tlds));
|
||||
}
|
||||
|
||||
return $query->get()->keyBy('tld')->map(fn ($p) => [
|
||||
'register' => $p->register_price,
|
||||
'renew' => $p->renew_price,
|
||||
'transfer' => $p->transfer_price,
|
||||
'currency' => $p->currency,
|
||||
])->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear pricing cache.
|
||||
*/
|
||||
public static function clearCache(): void
|
||||
{
|
||||
Cache::forget('domain_pricing:active_tlds');
|
||||
Cache::forget('domain_pricing:featured_tlds');
|
||||
Cache::forget('domain_pricing:overrides');
|
||||
|
||||
foreach (static::pluck('tld') as $tld) {
|
||||
Cache::forget("domain_pricing:{$tld}");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format price for display.
|
||||
*/
|
||||
public function formatRegisterPrice(): string
|
||||
{
|
||||
return $this->formatPrice($this->register_price);
|
||||
}
|
||||
|
||||
public function formatRenewPrice(): string
|
||||
{
|
||||
return $this->formatPrice($this->renew_price);
|
||||
}
|
||||
|
||||
public function formatTransferPrice(): string
|
||||
{
|
||||
return $this->formatPrice($this->transfer_price);
|
||||
}
|
||||
|
||||
private function formatPrice(int $amountMinor): string
|
||||
{
|
||||
$symbol = $this->currency === 'GHS' ? 'GH₵' : $this->currency;
|
||||
return $symbol . ' ' . number_format($amountMinor / 100, 2);
|
||||
}
|
||||
|
||||
private static function hasColumn(string $column): bool
|
||||
{
|
||||
$cacheKey = static::class . ':' . $column;
|
||||
|
||||
if (! array_key_exists($cacheKey, self::$columnExists)) {
|
||||
self::$columnExists[$cacheKey] = Schema::hasColumn((new static)->getTable(), $column);
|
||||
}
|
||||
|
||||
return self::$columnExists[$cacheKey];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user