latest('id')->first(); // Only fetch contracts that are currently in either the primary segment // or the optional queue segment defined on the latest FieldJobSetting. $segmentIds = collect([ optional($setting)->queue_segment_id, optional($setting)->segment_id, ])->filter()->unique()->values(); $contracts = Contract::query() ->with(['clientCase.person', 'clientCase.client.person', 'type', 'account']) ->when($segmentIds->isNotEmpty(), function ($q) use ($segmentIds) { $q->whereHas('segments', function ($sq) use ($segmentIds) { // Relation already filters on active pivots $sq->whereIn('segments.id', $segmentIds); }); }, function ($q) { // No segments configured on FieldJobSetting -> return none $q->whereRaw('1 = 0'); }) ->latest('id') ->limit(50) ->get(); // Mirror client onto the contract for simpler frontend access: c.client.person.full_name $contracts->each(function (Contract $contract): void { if ($contract->relationLoaded('clientCase') && $contract->clientCase) { $contract->setRelation('client', $contract->clientCase->client); } }); // Build active assignment map keyed by contract uuid for quicker UI checks $assignments = collect(); if ($contracts->isNotEmpty()) { $activeJobs = FieldJob::query() ->whereIn('contract_id', $contracts->pluck('id')) ->whereNull('completed_at') ->whereNull('cancelled_at') ->with(['assignedUser:id,name', 'user:id,name', 'contract:id,uuid']) ->get(); $assignments = $activeJobs->mapWithKeys(function (FieldJob $job) { return [ optional($job->contract)->uuid => [ 'assigned_to' => $job->assignedUser ? ['id' => $job->assignedUser->id, 'name' => $job->assignedUser->name] : null, 'assigned_by' => $job->user ? ['id' => $job->user->id, 'name' => $job->user->name] : null, 'assigned_at' => $job->assigned_at, ], ]; })->filter(); } $users = User::query()->orderBy('name')->get(['id', 'name']); return Inertia::render('FieldJob/Index', [ 'setting' => $setting, 'contracts' => $contracts, 'users' => $users, 'assignments' => $assignments, ]); } public function assign(Request $request) { $data = $request->validate([ 'contract_uuid' => 'required|string|exists:contracts,uuid', 'assigned_user_id' => 'required|integer|exists:users,id', ]); $setting = FieldJobSetting::query()->latest('id')->first(); if (! $setting) { return back()->withErrors(['setting' => 'No Field Job Setting found. Create one in Settings → Field Job Settings.']); } $contract = Contract::query()->where('uuid', $data['contract_uuid'])->firstOrFail(); $job = FieldJob::create([ 'field_job_setting_id' => $setting->id, 'assigned_user_id' => $data['assigned_user_id'], 'contract_id' => $contract->id, 'assigned_at' => now(), ]); // Create an activity for the assignment // Find the first action linked to the assign decision via pivot; also prefer actions within the same segment as the setting $decisionId = $setting->assign_decision_id; $actionId = null; if ($decisionId) { // Strictly use the action_decision pivot: take the first action mapped to this decision $actionId = DB::table('action_decision') ->where('decision_id', $decisionId) ->orderBy('id') ->value('action_id'); } if ($actionId) { $assigneeName = User::query()->where('id', $data['assigned_user_id'])->value('name'); // Localized note: "Terensko opravilo dodeljeno" + assignee when present $note = 'Terensko opravilo dodeljeno'.($assigneeName ? ' uporabniku '.$assigneeName : ''); Activity::create([ 'due_date' => null, 'amount' => null, 'note' => $note, 'action_id' => $actionId, 'decision_id' => $decisionId, 'client_case_id' => $contract->client_case_id, 'contract_id' => $contract->id, ]); } return back()->with('success', 'Field job assigned.'); } public function cancel(Request $request) { $data = $request->validate([ 'contract_uuid' => 'required|string|exists:contracts,uuid', ]); $contract = Contract::query()->where('uuid', $data['contract_uuid'])->firstOrFail(); $job = FieldJob::query() ->where('contract_id', $contract->id) ->whereNull('completed_at') ->whereNull('cancelled_at') ->latest('id') ->first(); if ($job) { $job->cancelled_at = now(); $job->save(); // Create an activity for the cancellation, mirroring the assign flow // Prefer the job's setting for a consistent decision $job->loadMissing('setting'); $decisionId = optional($job->setting)->cancel_decision_id; if ($decisionId) { $actionId = DB::table('action_decision') ->where('decision_id', $decisionId) ->orderBy('id') ->value('action_id'); if ($actionId) { Activity::create([ 'due_date' => null, 'amount' => null, 'note' => 'Terensko opravilo preklicano', 'action_id' => $actionId, 'decision_id' => $decisionId, 'client_case_id' => $contract->client_case_id, 'contract_id' => $contract->id, ]); } } } return back()->with('success', 'Field job cancelled.'); } public function complete(Request $request, \App\Models\ClientCase $clientCase) { // Complete all active field jobs for contracts of this case assigned to current user $userId = optional($request->user())->id; $setting = FieldJobSetting::query()->latest('id')->first(); if (! $setting) { return back()->withErrors(['setting' => 'No Field Job Setting found.']); } $decisionId = $setting->complete_decision_id; $actionId = null; if ($decisionId) { $actionId = DB::table('action_decision') ->where('decision_id', $decisionId) ->orderBy('id') ->value('action_id'); } // Find all active jobs for this case for the current user $jobs = FieldJob::query() ->whereHas('contract', function ($q) use ($clientCase) { $q->where('client_case_id', $clientCase->id); }) ->where(function ($q) use ($userId) { if ($userId) { $q->where('assigned_user_id', $userId); } }) ->whereNull('completed_at') ->whereNull('cancelled_at') ->with(['contract:id,client_case_id', 'setting']) ->get(); DB::transaction(function () use ($jobs, $decisionId, $actionId) { foreach ($jobs as $job) { // Mark job complete $job->completed_at = now(); $job->save(); // Log completion activity on the contract/case if ($actionId && $decisionId) { Activity::create([ 'due_date' => null, 'amount' => null, 'note' => 'Terensko opravilo zaključeno', 'action_id' => $actionId, 'decision_id' => $decisionId, 'client_case_id' => $job->contract->client_case_id, 'contract_id' => $job->contract_id, ]); } // Move contract to configured return segment $job->returnContractToConfiguredSegment(); } }); // Redirect back to phone index return to_route('phone.index'); } }