ifnex/04_Laravel/app/Services/ExchangeRateService.php
Kazem Alghasi f61de6f3a5 refactor(ui): redesign admin dashboard widgets and exchange service
Refactor the Filament dashboard by replacing the legacy FinanceOverviewWidget
with a new set of specialized widgets:
- DashboardInfoWidget for general information
- ExchangeRateWidget for real-time rate monitoring
- WalletStats for financial overview

Additionally, refactor the ExchangeRateService to improve encapsulation
and clean up the ExchangeRateHistory model by moving business logic
(change calculation and recording) from the model to the service layer.

Changes include:
- Removing deprecated helper methods from ExchangeRateHistory model
- Implementing direct queries in ExchangeRateService to replace model scopes
- Adding support for rate chart data retrieval
- Reordering and updating widget sorting in AdminPanelProvider
2026-08-10 04:08:29 +03:30

137 lines
3.8 KiB
PHP

<?php
namespace App\Services;
use App\Models\SystemSetting;
use App\Models\ExchangeRateHistory;
class ExchangeRateService
{
/**
* دریافت نرخ فعلی
*/
public function getCurrentRate(string $from = 'AED', string $to = 'IRR'): float
{
$key = strtolower("{$from}_to_{$to}");
$setting = SystemSetting::where('key', $key)->first();
if (!$setting) {
return config('ifnex.financial_defaults.aed_to_irr', 455000);
}
return (float) $setting->value;
}
/**
* تنظیم نرخ جدید (توسط کاربر)
*/
public function setRate(
string $from,
string $to,
float $newRate,
?int $userId = null,
?string $notes = null
): ExchangeRateHistory {
$key = strtolower("{$from}_to_{$to}");
$oldRate = $this->getCurrentRate($from, $to);
SystemSetting::updateOrCreate(
['key' => $key],
[
'value' => (string) $newRate,
'type' => 'number',
'description' => "{$from} to {$to} exchange rate",
]
);
return $this->recordChange(
from: $from,
to: $to,
oldRate: $oldRate,
newRate: $newRate,
source: 'manual',
userId: $userId,
notes: $notes
);
}
/**
* دریافت آخرین تغییرات
*/
public function getLatestChanges(int $limit = 10)
{
return ExchangeRateHistory::with('changedBy')
->orderBy('created_at', 'desc')
->limit($limit)
->get();
}
/**
* دریافت اطلاعات آخرین نرخ برای Widget
* ⚠️ بدون استفاده از scope - کوئری مستقیم
*/
public function getLatestRateInfo(string $from = 'AED', string $to = 'IRR'): array
{
// ✅ کوئری مستقیم بدون scope
$latest = ExchangeRateHistory::where('currency_from', $from)
->where('currency_to', $to)
->orderBy('created_at', 'desc')
->with('changedBy')
->first();
$currentRate = $this->getCurrentRate($from, $to);
return [
'current_rate' => $currentRate,
'last_change' => $latest,
'last_updated' => $latest?->created_at,
'changed_by' => $latest?->changedBy?->name,
'source' => $latest?->change_source,
'change_percent' => $latest?->change_percent,
];
}
/**
* دریافت آخرین N نرخ برای Chart
*/
public function getRateChart(string $from = 'AED', string $to = 'IRR', int $limit = 7): array
{
return ExchangeRateHistory::where('currency_from', $from)
->where('currency_to', $to)
->orderBy('created_at', 'asc')
->limit($limit)
->pluck('new_rate')
->toArray();
}
/**
* ثبت تغییر نرخ
*/
private function recordChange(
string $from,
string $to,
float $oldRate,
float $newRate,
string $source = 'manual',
?int $userId = null,
?string $apiSource = null,
?string $notes = null
): ExchangeRateHistory {
$changePercent = null;
if ($oldRate > 0) {
$changePercent = round((($newRate - $oldRate) / $oldRate) * 100, 4);
}
return ExchangeRateHistory::create([
'currency_from' => $from,
'currency_to' => $to,
'old_rate' => $oldRate,
'new_rate' => $newRate,
'change_percent' => $changePercent,
'change_source' => $source,
'changed_by' => $userId,
'api_source' => $apiSource,
'notes' => $notes,
]);
}
}