ifnex/04_Laravel/app/Console/Commands/UpdateExchangeRates.php
Kazem Alghasi ed5bae9997 feat(exchange): implement exchange rate history tracking
Introduce a mechanism to track and audit changes in exchange rates.
This includes:
- Creating `ExchangeRateHistory` model and migration to store rate changes.
- Implementing `ExchangeRateService` to encapsulate rate logic.
- Updating `UpdateExchangeRates` command to record history when rates change.
- Adding `ExchangeRateHistoryResource` to the Filament admin panel for monitoring.
2026-08-10 03:04:18 +03:30

119 lines
3.8 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Models\SystemSetting;
use App\Models\ExchangeRateHistory;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
class UpdateExchangeRates extends Command
{
protected $signature = 'ifnex:update-rates {--source=ecb : Data source for exchange rates (ecb or freecurrencyapi)}';
protected $description = 'Update exchange rates from external APIs and record history';
public function handle(): int
{
$source = $this->option('source');
$this->info("Fetching exchange rates from source: {$source}...");
try {
$rates = match ($source) {
'freecurrencyapi' => $this->fetchFromFreeCurrencyApi(),
default => $this->fetchFromEcb(),
};
} catch (\Throwable $e) {
$this->error("Failed to fetch rates: {$e->getMessage()}");
return Command::FAILURE;
}
if ($rates) {
$this->updateRate('aed_to_irr', $rates['aed_to_irr'], 'api', null, $source);
$this->updateRate('usd_to_irr', $rates['usd_to_irr'], 'api', null, $source);
$this->info("✅ Exchange rates updated successfully:");
$this->line(" AED/IRR: " . number_format($rates['aed_to_irr']));
$this->line(" USD/IRR: " . number_format($rates['usd_to_irr']));
} else {
$this->warn("⚠️ No rates were updated. Using fallback values.");
$this->setFallbackRates();
}
return Command::SUCCESS;
}
private function updateRate(string $key, float $newRate, string $source, ?int $userId, ?string $apiSource = null): void
{
$setting = SystemSetting::where('key', $key)->first();
$oldRate = $setting ? (float) $setting->value : 0;
// Update در system_settings
SystemSetting::updateOrCreate(
['key' => $key],
['value' => (string) $newRate]
);
// ثبت در تاریخچه فقط اگر تغییر کرده باشد
if ($oldRate != $newRate && $oldRate > 0) {
$currencyFrom = str_starts_with($key, 'aed') ? 'AED' : 'USD';
ExchangeRateHistory::recordChange(
from: $currencyFrom,
to: 'IRR',
oldRate: $oldRate,
newRate: $newRate,
source: $source,
userId: $userId,
apiSource: $apiSource
);
}
}
private function fetchFromEcb(): ?array
{
$response = Http::timeout(10)->get('https://api.exchangerate-api.com/v4/latest/AED');
if ($response->failed()) {
return null;
}
$data = $response->json();
return [
'aed_to_irr' => round($data['rates']['IRR'] ?? 455000, 2),
'usd_to_irr' => round(($data['rates']['IRR'] ?? 425000) / 1.07, 2), // USD از AED محاسبه می‌شود
];
}
private function fetchFromFreeCurrencyApi(): ?array
{
$response = Http::timeout(10)->get('https://api.freecurrencyapi.com/v1/latest', [
'apikey' => config('ifnex.currency.api_key'),
'base_currency' => 'AED',
]);
if ($response->failed()) {
return null;
}
$data = $response->json();
if (!isset($data['data'])) {
return null;
}
return [
'aed_to_irr' => round(($data['data']['IRR'] ?? 455000), 2),
'usd_to_irr' => round(($data['data']['IRR'] ?? 425000) / 1.07, 2),
];
}
private function setFallbackRates(): void
{
$this->updateRate('aed_to_irr', 455000, 'api', null, 'fallback');
$this->updateRate('usd_to_irr', 425000, 'api', null, 'fallback');
$this->info("Fallback rates set: AED/IRR=455000, USD/IRR=425000");
}
}