where('active', true) ->withCount(['contracts as contracts_count' => function ($q) { // On some drivers, wherePivot can compile oddly inside withCount; target the pivot table directly $q->where('contract_segment.active', '=', 1); }]) ->get(['id', 'name', 'description']); // Compute total balance per segment for active contracts $balances = DB::table('segments') ->join('contract_segment', 'contract_segment.segment_id', '=', 'segments.id') ->join('contracts', 'contracts.id', '=', 'contract_segment.contract_id') ->leftJoin('accounts', 'accounts.contract_id', '=', 'contracts.id') ->where('segments.active', '=', 1) ->where('contract_segment.active', '=', 1) ->groupBy('segments.id') ->pluck(DB::raw('COALESCE(SUM(accounts.balance_amount),0) as total_balance'), 'segments.id'); $segments = $segments->map(function ($seg) use ($balances) { $seg->total_balance = (string) ($balances[$seg->id] ?? 0); return $seg; }); return Inertia::render('Segments/Index', [ 'segments' => $segments, ]); } public function show(Segment $segment) { $search = request('search'); $clientFilter = request('client') ?? request('client_id'); $perPage = request()->integer('perPage', request()->integer('per_page', 15)); $perPage = max(1, min(200, $perPage)); $contracts = $this->buildContractsQuery($segment, $search, $clientFilter) ->paginate($perPage) ->withQueryString(); $contracts = $this->hydrateClientShortcut($contracts); $clients = Client::query() ->whereHas('clientCases.contracts.segments', function ($q) use ($segment) { $q->where('segments.id', $segment->id) ->where('contract_segment.active', '=', 1); }) ->with(['person:id,full_name']) ->get(['uuid', 'person_id']) ->map(function ($c) { return [ 'uuid' => (string) $c->uuid, 'name' => (string) optional($c->person)->full_name, ]; }) ->sortBy('name', SORT_NATURAL | SORT_FLAG_CASE) ->values(); return Inertia::render('Segments/Show', [ 'segment' => $segment->only(['id', 'name', 'description']), 'contracts' => $contracts, 'clients' => $clients, ]); } public function export(ExportSegmentContractsRequest $request, Segment $segment) { $data = $request->validated(); $client = $this->resolveClient($data['client'] ?? null); $columns = array_values(array_unique($data['columns'])); $query = $this->buildContractsQuery( $segment, $data['search'] ?? null, $data['client'] ?? null ); if (($data['scope'] ?? ExportSegmentContractsRequest::SCOPE_ALL) === ExportSegmentContractsRequest::SCOPE_CURRENT) { $page = max(1, (int) ($data['page'] ?? 1)); $perPage = max(1, min(200, (int) ($data['per_page'] ?? 15))); $query->forPage($page, $perPage); } $filename = $this->buildExportFilename($segment, $client); return Excel::download(new SegmentContractsExport($query, $columns), $filename); } private function resolveClient(?string $identifier): ?Client { if (empty($identifier)) { return null; } $query = Client::query()->with(['person:id,full_name']); if (Str::isUuid($identifier)) { $query->where('uuid', $identifier); } elseif (is_numeric($identifier)) { $query->where('id', (int) $identifier); } else { $query->where('uuid', $identifier); } return $query->first(); } private function buildExportFilename(Segment $segment, ?Client $client): string { $datePrefix = now()->format('dmy'); $segmentName = $this->slugify($segment->name ?? 'segment'); $base = sprintf('%s_%s-Pogodbe', $datePrefix, $segmentName); if ($client && $client->person?->full_name) { $clientName = $this->slugify($client->person->full_name); return sprintf('%s_%s.xlsx', $base, $clientName); } return sprintf('%s.xlsx', $base); } private function slugify(string $value): string { $slug = trim(preg_replace('/[^a-zA-Z0-9]+/', '-', $value), '-'); return $slug !== '' ? $slug : 'data'; } public function settings(Request $request) { return Inertia::render('Settings/Segments/Index', [ 'segments' => Segment::query()->get(), ]); } public function store(StoreSegmentRequest $request) { $data = $request->validated(); Segment::create([ 'name' => $data['name'], 'description' => $data['description'] ?? null, 'active' => $data['active'] ?? true, ]); return to_route('settings.segments')->with('success', 'Segment created'); } public function update(UpdateSegmentRequest $request, Segment $segment) { $data = $request->validated(); $segment->update([ 'name' => $data['name'], 'description' => $data['description'] ?? null, 'active' => $data['active'] ?? $segment->active, 'exclude' => $data['exclude'] ?? $segment->exclude, ]); return to_route('settings.segments')->with('success', 'Segment updated'); } private function buildContractsQuery(Segment $segment, ?string $search, ?string $clientFilter): Builder { $query = Contract::query() ->whereHas('segments', function ($q) use ($segment) { $q->where('segments.id', $segment->id) ->where('contract_segment.active', '=', 1); }) ->with([ 'clientCase.person', 'clientCase.client.person', 'type', 'account', ]) ->latest('id'); if (! empty($clientFilter)) { $query->whereHas('clientCase.client', function ($q) use ($clientFilter) { if (is_numeric($clientFilter)) { $q->where('clients.id', (int) $clientFilter); } else { $q->where('clients.uuid', $clientFilter); } }); } if (! empty($search)) { $query->where(function ($qq) use ($search) { $qq->where('contracts.reference', 'ilike', '%'.$search.'%') ->orWhereHas('clientCase.person', function ($p) use ($search) { $p->where('full_name', 'ilike', '%'.$search.'%'); }) ->orWhereHas('clientCase.client.person', function ($p) use ($search) { $p->where('full_name', 'ilike', '%'.$search.'%'); }); }); } return $query; } private function hydrateClientShortcut(LengthAwarePaginator $contracts): LengthAwarePaginator { $items = collect($contracts->items()); $items->each(function (Contract $contract) { if ($contract->relationLoaded('clientCase') && $contract->clientCase) { $contract->setRelation('client', $contract->clientCase->client); } }); if (method_exists($contracts, 'setCollection')) { $contracts->setCollection($items); } return $contracts; } }