Teren-app/app/Http/Controllers/FieldJobController.php
Simon Pocrnjič fe91c7e4bc Mass changes
2025-10-04 23:36:18 +02:00

234 lines
9.1 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Activity;
use App\Models\Contract;
use App\Models\FieldJob;
use App\Models\FieldJobSetting;
use App\Models\User;
use Exception;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
class FieldJobController extends Controller
{
public function index(Request $request)
{
$setting = FieldJobSetting::query()->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',
]);
try {
DB::transaction(function () use ($data) {
$setting = FieldJobSetting::query()->latest('id')->first();
if (! $setting) {
throw new Exception('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
if ($setting->action_id && $setting->assign_decision_id) {
$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' => $setting->action_id,
'decision_id' => $setting->assign_decision_id,
'client_case_id' => $contract->client_case_id,
'contract_id' => $contract->id,
]);
// Move contract to the configured segment for field jobs
$job->moveContractToSegment($setting->segment_id);
} else {
throw new Exception('The current Field Job Setting is missing an action or assign decision. Please update it in Settings → Field Job Settings.');
}
});
return back()->with('success', 'Field job assigned.');
} catch (QueryException $e) {
return back()->withErrors(['database' => 'Database error: '.$e->getMessage()]);
} catch (Exception $e) {
return back()->withErrors(['error' => 'Error: '.$e->getMessage()]);
}
}
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');
$actionId = optional($job->setting)->action_id;
$decisionId = optional($job->setting)->cancel_decision_id;
// If no decision configured, skip logging
if ($actionId && $decisionId) {
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 = $setting->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');
}
}