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.
100 lines
4.2 KiB
PHP
100 lines
4.2 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Widgets;
|
|
|
|
use App\Models\ExchangeRateHistory;
|
|
use App\Services\ExchangeRateService;
|
|
use Filament\Widgets\StatsOverviewWidget as BaseWidget;
|
|
use Filament\Widgets\StatsOverviewWidget\Stat;
|
|
|
|
/**
|
|
* Layer 2 (right) — live exchange-rate summary, spanning 4/12 of the body grid.
|
|
*/
|
|
class ExchangeRateWidget extends BaseWidget
|
|
{
|
|
protected static ?int $sort = 3;
|
|
|
|
protected static bool $isLazy = false;
|
|
|
|
protected int|string|array $columnSpan = 12;
|
|
|
|
/**
|
|
* Stat cards inside the rate widget: 1 column on the narrow lg+ column,
|
|
* 2 on mobile so they don't all stack vertically on tiny screens.
|
|
*/
|
|
protected int|string|array $columns = 1;
|
|
|
|
protected function getStats(): array
|
|
{
|
|
$service = app(ExchangeRateService::class);
|
|
|
|
$aedInfo = $service->getLatestRateInfo('AED');
|
|
$usdInfo = $service->getLatestRateInfo('USD');
|
|
|
|
$aedChangePercent = $aedInfo['change_percent'];
|
|
$usdChangePercent = $usdInfo['change_percent'];
|
|
|
|
$aedChart = $service->getRateChart('AED', 7);
|
|
$usdChart = $service->getRateChart('USD', 7);
|
|
|
|
return [
|
|
Stat::make('نرخ درهم (AED)', ifnex_format_number($aedInfo['current_rate'] ?? 0))
|
|
->description(
|
|
$aedChangePercent !== null
|
|
? sprintf('%s %s — %s',
|
|
$aedChangePercent > 0 ? '↑' : ($aedChangePercent < 0 ? '↓' : '—'),
|
|
ifnex_persian_digits(number_format(abs((float) $aedChangePercent), 2)) . '%',
|
|
($aedInfo['changed_by'] ?? 'سیستم'))
|
|
: 'آخرین تغییر: ' . ($aedInfo['last_updated']?->format('Y/m/d H:i') ?? '—')
|
|
)
|
|
->descriptionIcon(
|
|
$aedChangePercent > 0 ? 'heroicon-m-arrow-trending-up' :
|
|
($aedChangePercent < 0 ? 'heroicon-m-arrow-trending-down' : 'heroicon-m-minus')
|
|
)
|
|
->icon('heroicon-o-currency-dollar')
|
|
->color(
|
|
$aedChangePercent > 0 ? 'danger' :
|
|
($aedChangePercent < 0 ? 'success' : 'gray')
|
|
)
|
|
->chart(!empty($aedChart) ? $aedChart : [0]),
|
|
|
|
Stat::make('نرخ دلار (USD)', ifnex_format_number($usdInfo['current_rate'] ?? 0))
|
|
->description(
|
|
$usdChangePercent !== null
|
|
? sprintf('%s %s — %s',
|
|
$usdChangePercent > 0 ? '↑' : ($usdChangePercent < 0 ? '↓' : '—'),
|
|
ifnex_persian_digits(number_format(abs((float) $usdChangePercent), 2)) . '%',
|
|
($usdInfo['changed_by'] ?? 'سیستم'))
|
|
: 'آخرین تغییر: ' . ($usdInfo['last_updated']?->format('Y/m/d H:i') ?? '—')
|
|
)
|
|
->descriptionIcon(
|
|
$usdChangePercent > 0 ? 'heroicon-m-arrow-trending-up' :
|
|
($usdChangePercent < 0 ? 'heroicon-m-arrow-trending-down' : 'heroicon-m-minus')
|
|
)
|
|
->icon('heroicon-o-banknotes')
|
|
->color(
|
|
$usdChangePercent > 0 ? 'danger' :
|
|
($usdChangePercent < 0 ? 'success' : 'gray')
|
|
)
|
|
->chart(!empty($usdChart) ? $usdChart : [0]),
|
|
|
|
Stat::make('تغییرات امروز',
|
|
ifnex_persian_digits(number_format(
|
|
ExchangeRateHistory::whereDate('created_at', today())->count()
|
|
))
|
|
)
|
|
->description('تغییرات نرخ ثبتشده در امروز')
|
|
->descriptionIcon('heroicon-m-arrow-path')
|
|
->icon('heroicon-o-arrow-path')
|
|
->color('info'),
|
|
|
|
Stat::make('در انتظار تأیید',
|
|
ifnex_persian_digits(number_format($service->getPendingCount()))
|
|
)
|
|
->description('نرخهای پیشنهادی API — منتظر تأیید مدیر')
|
|
->descriptionIcon('heroicon-m-clock')
|
|
->icon('heroicon-o-clock')
|
|
->color('warning'),
|
|
];
|
|
}
|
|
} |