cashFlowService = $cashFlowService; $this->predictionService = $predictionService; } /** * checkPermission - Check if user has permission * * @param string $permission * @return void */ protected function checkPermission(string $permission) { $user = $this->getCurrentUser(); if (!$user || !$user->hasPermission($permission)) { $this->addFlash('error', 'Você não tem permissão para acessar esta área.'); $this->redirect('admin/dashboard')->send(); exit; } } /** * Display the Cash Flow Dashboard. */ public function index(Request $request) { $this->checkPermission('fluxocaixapro.view'); $startDate = $request->query->get('start_date', Carbon::now()->startOfMonth()->toDateString()); $endDate = $request->query->get('end_date', Carbon::now()->endOfMonth()->toDateString()); $statusFilter = $request->query->get('status'); $typeFilter = $request->query->get('type'); $entityFilter = $request->query->get('entity'); $summary = $this->cashFlowService->getSummary($startDate, $endDate); $monthlyBreakdown = $this->cashFlowService->getMonthlyBreakdown(); $categoryDistribution = $this->cashFlowService->getCategoryDistribution('expense'); $projections = $this->cashFlowService->getProjections(); $latestAnalysis = CashFlowAnalysis::orderBy('created_at', 'desc')->first(); $query = Transaction::with('category'); // The global scope 'company' already handles idbus filtering if ($startDate) { $query->where('transaction_date', '>=', $startDate); } if ($endDate) { $query->where('transaction_date', '<=', $endDate); } if ($statusFilter) { $query->where('status', $statusFilter); } if ($typeFilter) { $query->where('type', $typeFilter); } if ($entityFilter !== null && $entityFilter !== '') { $query->where('is_personal', $entityFilter == 'personal'); } $latestTransactions = $query->orderBy('transaction_date', 'desc') ->limit(50) ->get(); $categoriesAll = Category::where('is_active', true)->orderBy('name')->get(); return $this->renderAdminView('@fluxocaixapro/admin/index.twig', [ 'title' => 'Dashboard Fluxo de Caixa Pró', 'summary' => $summary, 'monthlyBreakdown' => json_encode($monthlyBreakdown), 'categoryDistribution' => json_encode($categoryDistribution), 'projections' => json_encode($projections), 'latestAnalysis' => $latestAnalysis, 'latestTransactions' => $latestTransactions, 'categories_all' => $categoriesAll, 'startDate' => $startDate, 'endDate' => $endDate, 'filters' => [ 'status' => $statusFilter, 'type' => $typeFilter, 'entity' => $entityFilter ] ]); } /** * storeTransaction - Store a new transaction * * @return Response */ public function storeTransaction(Request $request) { $this->checkPermission('fluxocaixapro.manage'); $data = $request->request->all(); // idbus and iduser are handled by Transaction::booted() static::creating Transaction::create([ 'category_id' => $data['category_id'], 'description' => $data['description'], 'amount' => str_replace(',', '.', $data['amount']), 'type' => $data['type'], 'status' => $data['status'] ?? 'pending', 'transaction_date' => $data['transaction_date'] ?? date('Y-m-d'), 'due_date' => !empty($data['due_date']) ? $data['due_date'] : null, 'is_personal' => isset($data['is_personal']) && $data['is_personal'] == '1', 'notes' => $data['notes'] ?? null ]); $this->addFlash('success', 'Transação registrada com sucesso!'); return $this->redirect('/admin/fluxo-caixa'); } /** * Update an existing transaction. */ public function updateTransaction(Request $request, $id) { $this->checkPermission('fluxocaixapro.manage'); $transaction = Transaction::findOrFail($id); $data = $request->request->all(); $transaction->update([ 'category_id' => $data['category_id'], 'description' => $data['description'], 'amount' => str_replace(',', '.', $data['amount']), 'transaction_date' => $data['transaction_date'], 'due_date' => !empty($data['due_date']) ? $data['due_date'] : null, 'payment_date' => ($data['status'] === 'paid') ? (!empty($data['payment_date']) ? $data['payment_date'] : $data['transaction_date']) : null, 'type' => $data['type'], 'status' => $data['status'] ?? 'paid', 'is_personal' => isset($data['is_personal']) && $data['is_personal'] == '1', 'notes' => $data['notes'] ?? null ]); $this->addFlash('success', 'Transação atualizada com sucesso!'); return $this->redirect('/admin/fluxo-caixa'); } /** * Delete a transaction. */ public function deleteTransaction(Request $request, $id) { $this->checkPermission('fluxocaixapro.manage'); $transaction = Transaction::findOrFail($id); $transaction->delete(); $this->addFlash('success', 'Transação excluída com sucesso!'); return $this->redirect('/admin/fluxo-caixa'); } /** * Mark a transaction as paid. */ public function markAsPaid(Request $request, $id) { $this->checkPermission('fluxocaixapro.manage'); $transaction = Transaction::findOrFail($id); $transaction->update([ 'status' => 'paid', 'payment_date' => Carbon::now()->toDateString() ]); $this->addFlash('success', 'Transação marcada como paga!'); return $this->redirect('/admin/fluxo-caixa'); } /** * Export cash flow to Excel. */ public function exportToExcel(Request $request) { $this->checkPermission('fluxocaixapro.manage'); $transactions = Transaction::with('category')->orderBy('transaction_date', 'desc')->get(); $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle('Fluxo de Caixa'); // Header $headers = ['Data', 'Vencimento', 'Pagamento', 'Descrição', 'Categoria', 'Valor', 'Tipo', 'Status', 'Empresa/Pessoal']; foreach ($headers as $col => $text) { $sheet->setCellValue([$col + 1, 1], $text); } // Data $row = 2; foreach ($transactions as $t) { $sheet->setCellValue([1, $row], $t->transaction_date ? $t->transaction_date->format('d/m/Y') : ''); $sheet->setCellValue([2, $row], $t->due_date ? $t->due_date->format('d/m/Y') : ''); $sheet->setCellValue([3, $row], $t->payment_date ? $t->payment_date->format('d/m/Y') : ''); $sheet->setCellValue([4, $row], $t->description); $sheet->setCellValue([5, $row], $t->category->name ?? 'N/A'); $sheet->setCellValue([6, $row], $t->amount); $sheet->setCellValue([7, $row], $t->type === 'income' ? 'Entrada' : 'Saída'); $sheet->setCellValue([8, $row], $t->status === 'paid' ? 'Pago' : 'Pendente'); $sheet->setCellValue([9, $row], $t->is_personal ? 'Pessoal' : 'Empresa'); $row++; } // Style header $sheet->getStyle('A1:I1')->getFont()->setBold(true); $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet); $filename = 'fluxo_caixa_' . date('Y-m-d') . '.xlsx'; header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Content-Disposition: attachment; filename="' . $filename . '"'); $writer->save('php://output'); exit; } /** * Run a new AI analysis. */ public function runAnalysis(Request $request) { $this->checkPermission('fluxocaixapro.manage'); try { $this->predictionService->generateAnalysis(); $this->addFlash('success', 'Análise inteligente concluída com sucesso!'); } catch (\Exception $e) { $this->addFlash('error', 'Erro ao gerar análise: ' . $e->getMessage()); } return $this->redirect('/admin/fluxo-caixa'); } /** * Perform bank reconciliation. */ public function reconcile(Request $request) { $this->checkPermission('fluxocaixapro.manage'); $bankBalance = (float) $request->request->get('bank_balance', 0); $summary = $this->cashFlowService->getSummary(); $systemBalance = $summary['net_balance']; $difference = $bankBalance - $systemBalance; return $this->renderAdminView('@fluxocaixapro/admin/reconciliation_result.twig', [ 'title' => 'Resultado da Conciliação Bancária', 'bankBalance' => $bankBalance, 'systemBalance' => $systemBalance, 'difference' => $difference, 'summary' => $summary ]); } }