Files
website/website/app/Console/Commands/SyncExchangeRatesCommand.php
Claude Dev de8ec69ea0 feat: add advanced features — KB, tickets v2, multi-currency, cart, quotes, affiliates, credits, staff RBAC, fraud detection, service panels
Major additions:
- Knowledge base with categories, articles, revisions, and voting
- Enhanced ticket system: departments, SLA policies, canned responses, tags, custom fields, satisfaction ratings, internal notes
- Multi-currency support with exchange rate sync
- Shopping cart and quote system with PDF generation
- Affiliate program with referrals, commissions, and payouts
- Account credits, credit notes, and debit notes
- Staff management with granular role-based permissions
- Fraud detection and order risk assessment
- ServerHunter SEO integration
- Service lifecycle events (suspend/unsuspend/terminate)
- Service management panels for VPS, Dedicated, Hosting, and Game servers
- Plan lifecycle fields and per-customer overrides
- 30+ migrations, 17 factories, 8 feature test suites

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 07:35:10 -04:00

84 lines
2.5 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Console\Commands;
use App\Models\Currency;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class SyncExchangeRatesCommand extends Command
{
protected $signature = 'currencies:sync-rates';
protected $description = 'Sync exchange rates from exchangerate.host API';
public function handle(): int
{
$baseCurrency = Currency::query()->base()->first();
if (! $baseCurrency) {
$this->error('No base currency configured.');
return self::FAILURE;
}
$this->info("Syncing exchange rates relative to {$baseCurrency->code}...");
try {
$response = Http::timeout(15)->get('https://api.exchangerate.host/latest', [
'base' => $baseCurrency->code,
]);
if (! $response->successful()) {
$this->error('Failed to fetch exchange rates: HTTP '.$response->status());
Log::error('Exchange rate sync failed', [
'status' => $response->status(),
'body' => $response->body(),
]);
return self::FAILURE;
}
$data = $response->json();
$rates = $data['rates'] ?? [];
if (empty($rates)) {
$this->warn('No rates returned from API.');
return self::FAILURE;
}
$currencies = Currency::query()->where('is_base', false)->get();
$updated = 0;
foreach ($currencies as $currency) {
if (isset($rates[$currency->code])) {
$currency->update([
'exchange_rate' => $rates[$currency->code],
'last_synced_at' => now(),
]);
$updated++;
$this->line(" {$currency->code}: {$rates[$currency->code]}");
}
}
// Clear currency cache
Cache::forget('currencies:enabled');
Cache::forget('currencies:base');
$this->info("Updated {$updated} exchange rates.");
return self::SUCCESS;
} catch (\Throwable $e) {
$this->error('Exchange rate sync error: '.$e->getMessage());
Log::error('Exchange rate sync exception', ['error' => $e->getMessage()]);
return self::FAILURE;
}
}
}