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.
119 lines
3.8 KiB
PHP
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");
|
|
}
|
|
} |