ifnex/04_Laravel/app/Console/Commands/UpdateExchangeRates.php
Kazem Alghasi 4fac1dae01 refactor(currency): simplify exchange rate logic to use Rial as base
Refactor the currency management system to eliminate the redundant
`rate_to_aed` field and transition to a single-base model where all
rates are stored relative to the Iranian Rial (IRR).

Key changes:
- Removed `rate_to_aed` from `currencies` table via new migration.
- Updated `ExchangeRateService` to handle rates using a single
  `currency_code` parameter instead of currency pairs.
- Refactored `UpdateExchangeRates` command to fetch rates from the
  Exir.io API and support multiple currencies (AED, USD, EUR, CNY).
- Updated Filament resources (`CurrencyResource`,
  `ExchangeRateHistoryResource`) and widgets to reflect the new
  single-base architecture.
- Improved `PriceCalculatorService` to use the updated service
  methodology for fetching the AED/IRR conversion rate.
- Localized console command output to Persian.
2026-10-29 03:54:02 +03:30

106 lines
3.8 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Models\Currency;
use App\Models\ExchangeRateHistory;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
class UpdateExchangeRates extends Command
{
protected $signature = 'ifnex:update-rates';
protected $description = 'دریافت نرخ ارز از API ایرانی (Exir.io) و ایجاد پیشنهاد در انتظار تأیید مدیر';
public function handle(): int
{
$this->info('در حال دریافت نرخ از API ایرانی (Exir.io)...');
try {
$rates = $this->fetchFromExir();
} catch (\Throwable $e) {
$this->error("خطا در دریافت نرخ: {$e->getMessage()}");
return Command::FAILURE;
}
if ($rates && count($rates) > 0) {
foreach ($rates as $currencyCode => $rate) {
$this->updateRate($currencyCode, $rate);
}
$this->info('✅ پیشنهاد نرخ ارز ایجاد شد (منتظر تأیید مدیر در پنل).');
} else {
$this->warn('⚠️ دریافت نرخ ناموفق بود. نرخ زنده تغییر نکرد.');
}
return Command::SUCCESS;
}
private function updateRate(string $currencyCode, float $newRate): void
{
$currency = Currency::where('code', $currencyCode)->first();
if (!$currency) {
return;
}
$oldRate = (float) $currency->rate_to_rial;
// فقط اگه اختلاف نرخ بیشتر از 0.5% باشه، پیشنهاد ثبت کن
if ($oldRate > 0 && abs($newRate - $oldRate) / $oldRate > 0.005) {
$changePercent = round((($newRate - $oldRate) / $oldRate) * 100, 4);
ExchangeRateHistory::create([
'currency_from' => $currencyCode,
'currency_to' => 'IRR',
'old_rate' => $oldRate,
'new_rate' => $newRate,
'change_percent' => $changePercent,
'change_source' => 'api',
'api_source' => 'exir.io',
'status' => 'pending',
]);
}
}
private function fetchFromExir(): ?array
{
// دریافت لیست جفت‌ارزها از اکسیر
$response = Http::timeout(15)->get('https://api.exir.io/v2/minicharts');
if ($response->failed()) {
return null;
}
$data = $response->json();
$rates = [];
// نگاشت جفت‌ارزهای اکسیر به کدهای استاندارد ما
// اکسیر قیمت‌ها رو بر اساس تتر (USDT) می‌ده، که در ایران معادل دلار نقدی هست
$symbolMap = [
'usdt-rls' => 'USD', // 1 دلار = X ریال
'usdt-aed' => 'AED', // 1 درهم = X تتر (باید در ریال ضرب بشه)
// اکسیر یورو و یوان مستقیم نداره، پس فقط دلار و درهم رو می‌گیریم
];
foreach ($data as $symbol => $info) {
if (!isset($symbolMap[$symbol])) {
continue;
}
$currencyCode = $symbolMap[$symbol];
$price = (float) ($info['price'] ?? 0);
if ($price > 0) {
// برای دلار: قیمت مستقیم ریاله
if ($currencyCode === 'USD') {
$rates['USD'] = round($price, 2);
}
// برای درهم: قیمت بر اساس تتره، باید در نرخ دلار ضرب بشه تا ریال بشه
if ($currencyCode === 'AED' && isset($rates['USD'])) {
$rates['AED'] = round($price * $rates['USD'], 2);
}
}
}
return $rates;
}
}