authorize('viewAny', Expense::class); $query = Expense::with(['project', 'currency', 'requestedBy', 'approvedBy']); // Filter by project if ($request->filled('project_id')) { $query->where('project_id', $request->project_id); } // Filter by category if ($request->filled('category')) { $query->byCategory($request->category); } // Filter by status if ($request->filled('status')) { $query->byStatus($request->status); } // Filter by date range if ($request->filled('from_date')) { $query->where('expense_date', '>=', $request->from_date); } if ($request->filled('to_date')) { $query->where('expense_date', '<=', $request->to_date); } $query->orderBy('expense_date', 'desc'); $expenses = $query->paginate(20)->appends($request->query()); $projects = Project::whereIn('status', ['planning', 'active'])->get(); $categories = ['materials', 'labor', 'equipment', 'transport', 'services', 'food', 'accommodation', 'other']; $statuses = ['pending', 'approved', 'rejected', 'paid']; return view('expenses.index', compact('expenses', 'projects', 'categories', 'statuses')); } /** * Show the form for creating a new expense (multi-currency aware). */ public function create() { $this->authorize('create', Expense::class); $expense = null; // ← این خط اضافه بشه $projects = Project::whereIn('status', ['planning', 'active'])->get(); $currencies = Currency::where('is_active', true)->get(); $categories = ['materials', 'labor', 'equipment', 'transport', 'services', 'food', 'accommodation', 'other']; $baseCurrency = CurrencyHelper::getBaseCurrency(); return view('expenses.form', compact('expense', 'projects', 'currencies', 'categories', 'baseCurrency')); } /** * Store a newly created expense in storage. */ public function store(StoreExpenseRequest $request) { $this->authorize('create', Expense::class); $data = $request->validated(); $data['tenant_id'] = $this->getTenantId(); $data['requested_by'] = Auth::id(); // Convert jalali date if needed if (!empty($data['expense_date'])) { $data['expense_date'] = \App\Helpers\CalendarHelper::parseDate($data['expense_date']); } // Handle currency conversion $baseCurrency = CurrencyHelper::getBaseCurrency(); $selectedCurrency = Currency::find($data['currency_id']); if ($selectedCurrency && $baseCurrency && $selectedCurrency->id !== $baseCurrency->id) { $data['original_amount'] = $data['amount']; $data['amount'] = CurrencyHelper::convert( (float) $data['amount'], $selectedCurrency->code, $baseCurrency->code ); } // Handle receipt upload if ($request->hasFile('receipt')) { $data['receipt_path'] = $request->file('receipt')->store('receipts', 'public'); } $expense = Expense::create($data); // Handle multiple file attachments if ($request->hasFile('attachments')) { $expense->attachFiles($request->file('attachments'), 'receipt'); } return redirect() ->route('expenses.show', $expense) ->with('success', __('expense.created_successfully')); } /** * Display the specified expense. */ public function show(Expense $expense) { $this->authorize('view', $expense); $expense->load(['project', 'currency', 'requestedBy', 'approvedBy', 'pettyCash']); return view('expenses.show', compact('expense')); } /** * Show the form for editing the specified expense. */ public function edit(Expense $expense) { $this->authorize('update', $expense); $projects = Project::whereIn('status', ['planning', 'active'])->get(); $currencies = Currency::where('is_active', true)->get(); $categories = ['materials', 'labor', 'equipment', 'transport', 'services', 'food', 'accommodation', 'other']; $baseCurrency = CurrencyHelper::getBaseCurrency(); return view('expenses.form', compact('expense', 'projects', 'currencies', 'categories', 'baseCurrency')); } /** * Update the specified expense in storage. */ public function update(StoreExpenseRequest $request, Expense $expense) { $this->authorize('update', $expense); $data = $request->validated(); // Convert jalali date if needed if (!empty($data['expense_date'])) { $data['expense_date'] = \App\Helpers\CalendarHelper::parseDate($data['expense_date']); } // Handle currency conversion $baseCurrency = CurrencyHelper::getBaseCurrency(); $selectedCurrency = Currency::find($data['currency_id']); if ($selectedCurrency && $baseCurrency && $selectedCurrency->id !== $baseCurrency->id) { $data['original_amount'] = $data['amount']; $data['amount'] = CurrencyHelper::convert( (float) $data['amount'], $selectedCurrency->code, $baseCurrency->code ); } // Handle receipt upload if ($request->hasFile('receipt')) { // Delete old receipt if ($expense->receipt_path) { \Illuminate\Support\Facades\Storage::disk('public')->delete($expense->receipt_path); } $data['receipt_path'] = $request->file('receipt')->store('receipts', 'public'); } $expense->update($data); // Handle multiple file attachments if ($request->hasFile('attachments')) { $expense->attachFiles($request->file('attachments'), 'receipt'); } return redirect() ->route('expenses.show', $expense) ->with('success', __('expense.updated_successfully')); } /** * Remove the specified expense from storage. */ public function destroy(Expense $expense) { $this->authorize('delete', $expense); $expense->delete(); return redirect() ->route('expenses.index') ->with('success', __('expense.deleted_successfully')); } /** * Approve an expense via AJAX. */ public function approve(Expense $expense) { $this->authorize('approve', $expense); $expense->update([ 'status' => 'approved', 'approved_by' => Auth::id(), 'approval_date' => now(), ]); // Update petty cash remaining if linked if ($expense->petty_cash_id && $expense->pettyCash) { $expense->pettyCash->updateRemaining(); } return response()->json([ 'success' => true, 'message' => __('expense.approved_successfully'), 'status' => $expense->status, ]); } /** * Reject an expense via AJAX. */ public function reject(Expense $expense) { $this->authorize('approve', $expense); $expense->update([ 'status' => 'rejected', 'approved_by' => Auth::id(), 'approval_date' => now(), ]); // Update petty cash remaining if linked if ($expense->petty_cash_id && $expense->pettyCash) { $expense->pettyCash->updateRemaining(); } return response()->json([ 'success' => true, 'message' => __('expense.rejected_successfully'), 'status' => $expense->status, ]); } }