Integrate multi-currency debt visibility across the platform by adding support for foreign currency credits in the user profile shortcode, improving the admin dashboard with unsettled credits widgets, and enhancing the Filament admin panel with navigation badges and relation managers. - Add multi-currency debt table to WordPress user profile shortcode - Implement `UnsettledCreditsWidget` for Filament dashboard - Add navigation badge to `CustomerCreditResource` for open credits - Add `CreditsRelationManager` to `UserResource` - Update `CustomerOrderController` API to include `foreign_credits` - Add concurrency check in `CustomerCreditService` during settlement
81 lines
3.3 KiB
PHP
81 lines
3.3 KiB
PHP
<?php
|
||
|
||
namespace App\Filament\Widgets;
|
||
|
||
use App\Models\CustomerCredit;
|
||
use App\Models\User;
|
||
use Filament\Widgets\Widget;
|
||
use Illuminate\Support\Facades\DB;
|
||
|
||
/**
|
||
* ویجت داشبورد — هشدار بدهیهای ارزی تسویهنشده.
|
||
*
|
||
* نمایش:
|
||
* - مجموع بدهی به تفکیک ارز (EUR/USD/AED/CNY/...)
|
||
* - لیست ۵ بدهکار برتر (مشتریانی که بیشترین بدهی تسویهنشده دارند)
|
||
* - لینک به صفحه اعتبارها فیلترشده با status=open
|
||
*/
|
||
class UnsettledCreditsWidget extends Widget
|
||
{
|
||
protected static ?int $sort = 2;
|
||
|
||
protected static bool $isLazy = false;
|
||
|
||
protected int|string|array $columnSpan = 'full';
|
||
|
||
protected static string $view = 'filament.widgets.unsettled-credits';
|
||
|
||
protected function getViewData(): array
|
||
{
|
||
// ─── خلاصه به تفکیک ارز ───
|
||
$currencySummary = CustomerCredit::whereIn('status', ['open', 'partially_settled'])
|
||
->select('currency_code')
|
||
->selectRaw('SUM(amount) as total_amount')
|
||
->selectRaw('SUM(settled_amount) as total_settled')
|
||
->selectRaw('SUM(amount - settled_amount) as total_balance')
|
||
->selectRaw('COUNT(*) as credit_count')
|
||
->groupBy('currency_code')
|
||
->orderBy('total_balance', 'desc')
|
||
->get()
|
||
->map(fn ($r) => [
|
||
'currency_code' => $r->currency_code,
|
||
'total_amount' => (float) $r->total_amount,
|
||
'total_settled' => (float) $r->total_settled,
|
||
'total_balance' => (float) $r->total_balance,
|
||
'credit_count' => (int) $r->credit_count,
|
||
]);
|
||
|
||
// ─── تعداد کل اعتبارهای باز ───
|
||
$totalOpenCredits = CustomerCredit::whereIn('status', ['open', 'partially_settled'])->count();
|
||
|
||
// ─── تعداد مشتریان بدهکار ───
|
||
$totalDebtors = CustomerCredit::whereIn('status', ['open', 'partially_settled'])
|
||
->distinct('user_id')
|
||
->count('user_id');
|
||
|
||
// ─── ۵ بدهکار برتر (بر اساس مانده کل به ارز) ───
|
||
$topDebtors = CustomerCredit::whereIn('customer_credits.status', ['open', 'partially_settled'])
|
||
->join('users', 'customer_credits.user_id', '=', 'users.id')
|
||
->select(
|
||
'users.id as user_id',
|
||
'users.name as user_name',
|
||
'users.phone as user_phone',
|
||
DB::raw('COUNT(customer_credits.id) as credit_count'),
|
||
DB::raw('GROUP_CONCAT(DISTINCT customer_credits.currency_code) as currencies'),
|
||
DB::raw('SUM(customer_credits.amount - customer_credits.settled_amount) as total_balance_sum'),
|
||
DB::raw('MAX(customer_credits.granted_at) as latest_grant')
|
||
)
|
||
->groupBy('users.id', 'users.name', 'users.phone')
|
||
->orderBy('total_balance_sum', 'desc')
|
||
->limit(5)
|
||
->get();
|
||
|
||
return [
|
||
'currencySummary' => $currencySummary,
|
||
'totalOpenCredits' => $totalOpenCredits,
|
||
'totalDebtors' => $totalDebtors,
|
||
'topDebtors' => $topDebtors,
|
||
'hasDebts' => $currencySummary->isNotEmpty(),
|
||
];
|
||
}
|
||
} |