period) { 'today' => [Carbon::today(), Carbon::today()->endOfDay()], 'this_week' => [Carbon::now()->startOfWeek(), Carbon::now()->endOfWeek()], 'this_month' => [Carbon::now()->startOfMonth(), Carbon::now()->endOfMonth()], 'last_month' => [Carbon::now()->subMonthNoOverflow()->startOfMonth(), Carbon::now()->subMonthNoOverflow()->endOfMonth()], 'this_year' => [Carbon::now()->startOfYear(), Carbon::now()->endOfYear()], default => [Carbon::now()->subYear(), Carbon::now()], }; } public function periods(): array { return [ 'today' => 'Astăzi', 'this_week' => 'Săptămâna curentă', 'this_month' => 'Luna curentă', 'last_month' => 'Luna trecută', 'this_year' => 'Anul curent', ]; } public function tabs(): array { return [ 'finance' => '💰 Finanțe', 'workload' => '📊 Încărcare', 'masters' => '👨‍🔧 Mecanici', 'works' => '🔧 Manopere top', 'parts' => '📦 Piese', 'clients' => '👥 Clienți', ]; } public function setPeriod(string $period): void { $this->period = $period; } public function setTab(string $tab): void { $this->tab = $tab; } public function data(): array { [$start, $end] = $this->dateRange(); return match ($this->tab) { 'finance' => $this->financeReport($start, $end), 'workload' => $this->workloadReport($start, $end), 'masters' => $this->mastersReport($start, $end), 'works' => $this->popularWorksReport($start, $end), 'parts' => $this->partsReport($start, $end), 'clients' => $this->clientsReport($start, $end), default => [], }; } protected function financeReport($start, $end): array { $income = (float) Payment::whereBetween('paid_at', [$start, $end])->sum('amount'); $expenses = (float) Expense::whereBetween('paid_at', [$start, $end])->sum('amount'); $byMethod = Payment::whereBetween('paid_at', [$start, $end]) ->selectRaw('method, COUNT(*) as cnt, SUM(amount) as total') ->groupBy('method')->get(); $byCategory = Expense::whereBetween('paid_at', [$start, $end]) ->selectRaw('category, COUNT(*) as cnt, SUM(amount) as total') ->groupBy('category')->orderByDesc('total')->get(); $debt = (float) WorkOrder::where('pay_status', '!=', 'paid') ->whereNotIn('status', ['cancelled']) ->get() ->sum(fn ($w) => $w->balanceDue()); return [ 'income' => $income, 'expenses' => $expenses, 'profit' => $income - $expenses, 'margin_pct' => $income > 0 ? round((($income - $expenses) / $income) * 100, 1) : 0, 'by_method' => $byMethod, 'by_category' => $byCategory, 'debt' => $debt, ]; } protected function workloadReport($start, $end): array { $opened = WorkOrder::whereBetween('opened_at', [$start, $end])->count(); $closed = WorkOrder::whereBetween('closed_at', [$start, $end])->count(); $byStatus = WorkOrder::selectRaw('status, COUNT(*) as cnt') ->whereBetween('opened_at', [$start, $end]) ->groupBy('status')->get(); $byDay = WorkOrder::selectRaw('DATE(opened_at) as day, COUNT(*) as cnt') ->whereBetween('opened_at', [$start, $end]) ->groupBy('day')->orderBy('day')->get(); return [ 'opened' => $opened, 'closed' => $closed, 'by_status' => $byStatus, 'by_day' => $byDay, ]; } protected function mastersReport($start, $end): array { $rows = User::where('role', 'mechanic')->get()->map(function ($u) use ($start, $end) { $works = WorkOrderWork::where('master_id', $u->id) ->whereHas('workOrder', fn ($q) => $q->whereBetween('opened_at', [$start, $end])) ->get(); $hoursTotal = (float) $works->sum('hours'); $revenueTotal = (float) $works->sum('total'); $worksCount = $works->count(); return [ 'id' => $u->id, 'name' => $u->name, 'specialization' => $u->specialization, 'hours' => $hoursTotal, 'works' => $worksCount, 'revenue' => $revenueTotal, ]; })->sortByDesc('revenue')->values(); return ['rows' => $rows]; } protected function popularWorksReport($start, $end): array { $rows = WorkOrderWork::selectRaw('name, COUNT(*) as cnt, SUM(hours) as hours, SUM(total) as revenue') ->whereHas('workOrder', fn ($q) => $q->whereBetween('opened_at', [$start, $end])) ->groupBy('name') ->orderByDesc('cnt') ->limit(20) ->get(); return ['rows' => $rows]; } protected function partsReport($start, $end): array { $sold = WorkOrderPart::selectRaw('name, brand, SUM(qty) as qty, SUM(total) as revenue, SUM((sell_price - buy_price) * qty) as margin') ->whereHas('workOrder', fn ($q) => $q->whereBetween('opened_at', [$start, $end])) ->where('status', 'installed') ->groupBy('name', 'brand') ->orderByDesc('revenue') ->limit(20) ->get(); $low = Part::where('is_active', true) ->whereColumn('qty', '<=', 'min_qty') ->orderBy('qty') ->get(); return ['sold' => $sold, 'low' => $low]; } protected function clientsReport($start, $end): array { $top = Client::withCount(['vehicles']) ->withSum(['workOrders' => fn ($q) => $q->whereBetween('opened_at', [$start, $end])], 'total') ->orderByDesc('work_orders_sum_total') ->limit(20) ->get(); // Fallback: if relation doesn't exist on Client if ($top->isEmpty() || ! $top->first()->relationLoaded('workOrders')) { $top = Client::withCount('vehicles')->limit(20)->get(); } $newCount = Client::whereBetween('created_at', [$start, $end])->count(); $bySource = Lead::selectRaw('source, COUNT(*) as cnt') ->whereBetween('created_at', [$start, $end]) ->groupBy('source') ->orderByDesc('cnt') ->get(); return ['top' => $top, 'new_count' => $newCount, 'by_source' => $bySource]; } }