Introduce a comprehensive design system across WordPress and Laravel to ensure visual consistency. Implement new financial reporting capabilities and Excel export functionality within the Filament admin panel. - Add `DESIGN_SYSTEM.md` to define brand colors, typography, and spacing - Implement `FinancialReport` page in Filament for transaction and shipment summaries - Add Excel export support for `ShipmentResource` and `WalletTransactionResource` using Laravel Excel - Refactor WordPress plugin and Filament CSS to utilize the new design system variables - Update project status to reflect new reporting and design milestones
279 lines
11 KiB
PHP
279 lines
11 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Pages\Reports;
|
|
|
|
use App\Exports\ShipmentsExport;
|
|
use App\Exports\WalletTransactionsExport;
|
|
use Filament\Forms;
|
|
use Filament\Forms\Form;
|
|
use Filament\Pages\Page;
|
|
use Filament\Notifications\Notification;
|
|
use Maatwebsite\Excel\Facades\Excel;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class FinancialReport extends Page
|
|
{
|
|
protected static ?string $navigationIcon = 'heroicon-o-chart-bar';
|
|
protected static ?string $navigationLabel = 'گزارش مالی';
|
|
protected static ?string $navigationGroup = 'مالی';
|
|
protected static ?int $navigationSort = 5;
|
|
protected static ?string $slug = 'financial-report';
|
|
protected static string $view = 'filament.pages.reports.financial-report';
|
|
|
|
public ?array $data = [];
|
|
public ?array $reportData = null;
|
|
|
|
public function mount(): void
|
|
{
|
|
$this->form->fill();
|
|
}
|
|
|
|
public function form(Form $form): Form
|
|
{
|
|
return $form
|
|
->schema([
|
|
Forms\Components\Section::make('فیلترهای گزارش')
|
|
->schema([
|
|
Forms\Components\Select::make('report_type')
|
|
->label('نوع گزارش')
|
|
->options([
|
|
'transactions' => 'تراکنشهای کیف پول',
|
|
'shipments' => 'مرسولات',
|
|
'financial_summary' => 'خلاصه مالی',
|
|
])
|
|
->required()
|
|
->reactive()
|
|
->default('transactions'),
|
|
|
|
Forms\Components\DatePicker::make('from_date')
|
|
->label('از تاریخ')
|
|
->required()
|
|
->default(now()->subMonth()),
|
|
|
|
Forms\Components\DatePicker::make('to_date')
|
|
->label('تا تاریخ')
|
|
->required()
|
|
->default(now()),
|
|
|
|
Forms\Components\Select::make('transaction_type')
|
|
->label('نوع تراکنش')
|
|
->options([
|
|
'deposit' => 'واریزی',
|
|
'withdrawal' => 'برداشت',
|
|
'order_payment' => 'پرداخت سفارش',
|
|
'refund' => 'بازگشت وجه',
|
|
])
|
|
->visible(fn ($get) => $get('report_type') === 'transactions')
|
|
->placeholder('همه'),
|
|
|
|
Forms\Components\Select::make('shipment_status')
|
|
->label('وضعیت مرسوله')
|
|
->options([
|
|
'processed' => 'ثبت شده',
|
|
'picked_up' => 'تحویل به پست',
|
|
'in_transit' => 'در حال حمل',
|
|
'out_for_delivery' => 'آماده تحویل',
|
|
'delivered' => 'تحویل داده شده',
|
|
'failed' => 'ناموفق',
|
|
'returned' => 'بازگشته',
|
|
])
|
|
->visible(fn ($get) => $get('report_type') === 'shipments')
|
|
->placeholder('همه'),
|
|
])
|
|
->columns(2),
|
|
|
|
Forms\Components\Section::make('عملیات')
|
|
->schema([
|
|
Forms\Components\Actions::make([
|
|
Forms\Components\Actions\Action::make('generate')
|
|
->label('تولید گزارش')
|
|
->icon('heroicon-o-eye')
|
|
->color('primary')
|
|
->action('generateReport'),
|
|
|
|
Forms\Components\Actions\Action::make('export_excel')
|
|
->label('خروجی Excel')
|
|
->icon('heroicon-o-arrow-down-tray')
|
|
->color('success')
|
|
->action('exportExcel')
|
|
->visible(fn ($get) => $get('report_type') !== 'financial_summary'),
|
|
])
|
|
->fullWidth(),
|
|
]),
|
|
])
|
|
->statePath('data');
|
|
}
|
|
|
|
public function generateReport(): void
|
|
{
|
|
$this->validate();
|
|
|
|
$type = $this->data['report_type'];
|
|
$fromDate = $this->data['from_date'];
|
|
$toDate = $this->data['to_date'];
|
|
|
|
switch ($type) {
|
|
case 'transactions':
|
|
$this->generateTransactionsReport($fromDate, $toDate);
|
|
break;
|
|
case 'shipments':
|
|
$this->generateShipmentsReport($fromDate, $toDate);
|
|
break;
|
|
case 'financial_summary':
|
|
$this->generateFinancialSummary($fromDate, $toDate);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private function generateTransactionsReport($fromDate, $toDate): void
|
|
{
|
|
$query = DB::table('wallet_transactions')
|
|
->join('wallets', 'wallet_transactions.wallet_id', '=', 'wallets.id')
|
|
->join('users', 'wallets.user_id', '=', 'users.id')
|
|
->select(
|
|
'wallet_transactions.id',
|
|
'users.name as user_name',
|
|
'users.email as user_email',
|
|
'wallet_transactions.amount',
|
|
'wallet_transactions.type',
|
|
'wallet_transactions.status',
|
|
'wallet_transactions.gateway',
|
|
'wallet_transactions.description',
|
|
'wallet_transactions.created_at'
|
|
)
|
|
->whereBetween('wallet_transactions.created_at', [$fromDate, $toDate . ' 23:59:59'])
|
|
->orderByDesc('wallet_transactions.created_at');
|
|
|
|
if (!empty($this->data['transaction_type'])) {
|
|
$query->where('wallet_transactions.type', $this->data['transaction_type']);
|
|
}
|
|
|
|
$this->reportData = [
|
|
'type' => 'transactions',
|
|
'data' => $query->get(),
|
|
'summary' => [
|
|
'total_count' => $query->count(),
|
|
'total_amount' => $query->sum('amount'),
|
|
'deposits' => $query->where('type', 'deposit')->sum('amount'),
|
|
'withdrawals' => $query->whereIn('type', ['withdrawal', 'order_payment'])->sum('amount'),
|
|
],
|
|
];
|
|
}
|
|
|
|
private function generateShipmentsReport($fromDate, $toDate): void
|
|
{
|
|
$query = DB::table('shipments')
|
|
->join('countries as from_country', 'shipments.from_country_id', '=', 'from_country.id')
|
|
->join('countries as to_country', 'shipments.to_country_id', '=', 'to_country.id')
|
|
->select(
|
|
'shipments.awb_no',
|
|
'shipments.direction',
|
|
'shipments.type',
|
|
'shipments.status',
|
|
'from_country.name as from_country',
|
|
'to_country.name as to_country',
|
|
'shipments.weight',
|
|
'shipments.chargeable_weight',
|
|
'shipments.shipping_price',
|
|
'shipments.total_fee',
|
|
'shipments.sender_name',
|
|
'shipments.receiver_name',
|
|
'shipments.created_at'
|
|
)
|
|
->whereBetween('shipments.created_at', [$fromDate, $toDate . ' 23:59:59'])
|
|
->orderByDesc('shipments.created_at');
|
|
|
|
if (!empty($this->data['shipment_status'])) {
|
|
$query->where('shipments.status', $this->data['shipment_status']);
|
|
}
|
|
|
|
$this->reportData = [
|
|
'type' => 'shipments',
|
|
'data' => $query->get(),
|
|
'summary' => [
|
|
'total_count' => $query->count(),
|
|
'total_fee' => $query->sum('total_fee'),
|
|
'total_weight' => $query->sum('chargeable_weight'),
|
|
],
|
|
];
|
|
}
|
|
|
|
private function generateFinancialSummary($fromDate, $toDate): void
|
|
{
|
|
// Total deposits
|
|
$deposits = DB::table('wallet_transactions')
|
|
->where('type', 'deposit')
|
|
->where('status', 'completed')
|
|
->whereBetween('created_at', [$fromDate, $toDate . ' 23:59:59'])
|
|
->sum('amount');
|
|
|
|
// Total withdrawals/order payments
|
|
$withdrawals = DB::table('wallet_transactions')
|
|
->whereIn('type', ['withdrawal', 'order_payment'])
|
|
->where('status', 'completed')
|
|
->whereBetween('created_at', [$fromDate, $toDate . ' 23:59:59'])
|
|
->sum('amount');
|
|
|
|
// Total shipments revenue
|
|
$shipmentsRevenue = DB::table('shipments')
|
|
->whereBetween('created_at', [$fromDate, $toDate . ' 23:59:59'])
|
|
->sum('total_fee');
|
|
|
|
// Total discount codes used
|
|
$discounts = DB::table('discount_codes')
|
|
->where('is_active', true)
|
|
->whereBetween('updated_at', [$fromDate, $toDate . ' 23:59:59'])
|
|
->sum('used_count');
|
|
|
|
// Wallet balances
|
|
$totalBalance = DB::table('wallets')->sum('balance');
|
|
$totalDeposited = DB::table('wallets')->sum('total_deposited');
|
|
$totalWithdrawn = DB::table('wallets')->sum('total_withdrawn');
|
|
|
|
$this->reportData = [
|
|
'type' => 'financial_summary',
|
|
'summary' => [
|
|
'deposits' => $deposits,
|
|
'withdrawals' => abs($withdrawals),
|
|
'shipments_revenue' => $shipmentsRevenue,
|
|
'discounts_used' => $discounts,
|
|
'total_balance' => $totalBalance,
|
|
'total_deposited' => $totalDeposited,
|
|
'total_withdrawn' => $totalWithdrawn,
|
|
'net_profit' => $shipmentsRevenue - $withdrawals,
|
|
],
|
|
];
|
|
}
|
|
|
|
public function exportExcel(): \Symfony\Component\HttpFoundation\BinaryFileResponse
|
|
{
|
|
$this->validate();
|
|
|
|
$type = $this->data['report_type'];
|
|
$filters = [
|
|
'from_date' => $this->data['from_date'],
|
|
'to_date' => $this->data['to_date'],
|
|
];
|
|
|
|
if ($type === 'transactions') {
|
|
$filters['type'] = $this->data['transaction_type'] ?? null;
|
|
$export = new WalletTransactionsExport($filters);
|
|
$fileName = 'transactions_' . now()->format('Y-m-d_H-i') . '.xlsx';
|
|
} elseif ($type === 'shipments') {
|
|
$filters['status'] = $this->data['shipment_status'] ?? null;
|
|
$export = new ShipmentsExport($filters);
|
|
$fileName = 'shipments_' . now()->format('Y-m-d_H-i') . '.xlsx';
|
|
} else {
|
|
Notification::make()
|
|
->title('خطا')
|
|
->body('برای خلاصه مالی خروجی Excel موجود نیست.')
|
|
->danger()
|
|
->send();
|
|
|
|
return redirect()->back();
|
|
}
|
|
|
|
return Excel::download($export, $fileName);
|
|
}
|
|
}
|