From 5f879c9436ce01d73f4c9d20ab0e2649e7eb4bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Pocrnji=C4=8D?= Date: Fri, 31 Oct 2025 13:21:54 +0100 Subject: [PATCH] Field job changed permissions and other things --- app/Http/Controllers/PhoneViewController.php | 98 ++++++++++++++----- resources/js/Layouts/AppLayout.vue | 1 + resources/js/Pages/Phone/Case/Index.vue | 4 +- .../Pages/Settings/Partials/ActionTable.vue | 6 ++ routes/web.php | 45 +++++---- .../Feature/Phone/CaseCompletedTodayTest.php | 52 ++++++++++ 6 files changed, 160 insertions(+), 46 deletions(-) create mode 100644 tests/Feature/Phone/CaseCompletedTodayTest.php diff --git a/app/Http/Controllers/PhoneViewController.php b/app/Http/Controllers/PhoneViewController.php index f3c72ae..062a095 100644 --- a/app/Http/Controllers/PhoneViewController.php +++ b/app/Http/Controllers/PhoneViewController.php @@ -76,25 +76,41 @@ public function completedToday(Request $request) public function showCase(\App\Models\ClientCase $clientCase, Request $request) { $userId = $request->user()->id; + $completedMode = (bool) $request->boolean('completed'); // Eager load client case with person details $case = \App\Models\ClientCase::query() ->with(['person' => fn ($q) => $q->with(['addresses', 'phones', 'emails', 'bankAccounts'])]) ->findOrFail($clientCase->id); - // Determine contracts of this case assigned to the current user via FieldJobs and still active - $assignedContractIds = FieldJob::query() - ->where('assigned_user_id', $userId) - ->whereNull('completed_at') - ->whereNull('cancelled_at') - ->whereHas('contract', fn ($q) => $q->where('client_case_id', $case->id)) - ->pluck('contract_id') - ->unique() - ->values(); + // Determine contracts of this case relevant to the current user + // - Normal mode: contracts assigned to me and still active (not completed/cancelled) + // - Completed mode (?completed=1): contracts where my field job was completed today + if ($completedMode) { + $start = now()->startOfDay(); + $end = now()->endOfDay(); + $contractIds = FieldJob::query() + ->where('assigned_user_id', $userId) + ->whereNull('cancelled_at') + ->whereBetween('completed_at', [$start, $end]) + ->whereHas('contract', fn ($q) => $q->where('client_case_id', $case->id)) + ->pluck('contract_id') + ->unique() + ->values(); + } else { + $contractIds = FieldJob::query() + ->where('assigned_user_id', $userId) + ->whereNull('completed_at') + ->whereNull('cancelled_at') + ->whereHas('contract', fn ($q) => $q->where('client_case_id', $case->id)) + ->pluck('contract_id') + ->unique() + ->values(); + } $contracts = \App\Models\Contract::query() ->where('client_case_id', $case->id) - ->whereIn('id', $assignedContractIds) + ->whereIn('id', $contractIds) ->with(['type:id,name', 'account']) ->orderByDesc('created_at') ->get(); @@ -128,7 +144,7 @@ public function showCase(\App\Models\ClientCase $clientCase, Request $request) $contractDocs = \App\Models\Document::query() ->where('documentable_type', \App\Models\Contract::class) - ->whereIn('documentable_id', $assignedContractIds) + ->whereIn('documentable_id', $contractIds) ->orderByDesc('created_at') ->get() ->map(function ($d) use ($contractRefMap) { @@ -168,6 +184,51 @@ public function showCase(\App\Models\ClientCase $clientCase, Request $request) return $a; }); + // Determine segment filters from FieldJobSettings for this case/user context + $settingIds = FieldJob::query() + ->where('assigned_user_id', $userId) + ->whereHas('contract', fn ($q) => $q->where('client_case_id', $case->id)) + ->when( + $completedMode, + function ($q) { + $q->whereNull('cancelled_at') + ->whereBetween('completed_at', [now()->startOfDay(), now()->endOfDay()]); + }, + function ($q) { + $q->whereNull('completed_at')->whereNull('cancelled_at'); + } + ) + ->pluck('field_job_setting_id') + ->filter() + ->unique() + ->values(); + + $segmentIds = collect(); + if ($settingIds->isNotEmpty()) { + $segmentIds = \App\Models\FieldJobSetting::query() + ->whereIn('id', $settingIds) + ->pluck('segment_id') + ->filter() + ->unique() + ->values(); + } + + // Filter actions and their decisions by the derived segment ids (decisions.segment_id) + $actions = \App\Models\Action::query() + ->when($segmentIds->isNotEmpty(), function ($q) use ($segmentIds) { + // Filter actions by their segment_id matching the FieldJobSetting segment(s) + $q->whereIn('segment_id', $segmentIds); + }) + ->with([ + 'decisions' => function ($q) { + $q->select('decisions.id', 'decisions.name', 'decisions.color_tag', 'decisions.auto_mail', 'decisions.email_template_id'); + }, + 'decisions.emailTemplate' => function ($q) { + $q->select('id', 'name', 'entity_types', 'allow_attachments'); + }, + ]) + ->get(['id', 'name', 'color_tag', 'segment_id']); + return Inertia::render('Phone/Case/Index', [ 'client' => $case->client()->with('person', fn ($q) => $q->with(['addresses', 'phones', 'emails', 'bankAccounts']))->firstOrFail(), 'client_case' => $case, @@ -175,19 +236,10 @@ public function showCase(\App\Models\ClientCase $clientCase, Request $request) 'documents' => $documents, 'types' => $types, 'account_types' => \App\Models\AccountType::all(), - // Provide decisions with linked email template metadata (entity_types, allow_attachments) - 'actions' => \App\Models\Action::query() - ->with([ - 'decisions' => function ($q) { - $q->select('decisions.id', 'decisions.name', 'decisions.color_tag', 'decisions.auto_mail', 'decisions.email_template_id'); - }, - 'decisions.emailTemplate' => function ($q) { - $q->select('id', 'name', 'entity_types', 'allow_attachments'); - }, - ]) - ->get(['id', 'name', 'color_tag', 'segment_id']), + // Provide decisions (filtered by segment) with linked email template metadata (entity_types, allow_attachments) + 'actions' => $actions, 'activities' => $activities, - 'completed_mode' => (bool) $request->boolean('completed'), + 'completed_mode' => $completedMode, ]); } } diff --git a/resources/js/Layouts/AppLayout.vue b/resources/js/Layouts/AppLayout.vue index bb5f1db..081ae2b 100644 --- a/resources/js/Layouts/AppLayout.vue +++ b/resources/js/Layouts/AppLayout.vue @@ -186,6 +186,7 @@ const rawMenuGroups = [ }, { label: "Terensko delo", + requires: { permission: "field-job" }, items: [ { key: "fieldjobs", diff --git a/resources/js/Pages/Phone/Case/Index.vue b/resources/js/Pages/Phone/Case/Index.vue index b7ced51..eced2f6 100644 --- a/resources/js/Pages/Phone/Case/Index.vue +++ b/resources/js/Pages/Phone/Case/Index.vue @@ -130,9 +130,9 @@ const redirectIfNoContracts = () => { } }; -onMounted(() => { +/*onMounted(() => { redirectIfNoContracts(); -}); +});*/ watch( () => (Array.isArray(props.contracts) ? props.contracts.length : null), diff --git a/resources/js/Pages/Settings/Partials/ActionTable.vue b/resources/js/Pages/Settings/Partials/ActionTable.vue index 8ae983f..0c1b032 100644 --- a/resources/js/Pages/Settings/Partials/ActionTable.vue +++ b/resources/js/Pages/Settings/Partials/ActionTable.vue @@ -38,6 +38,7 @@ const columns = [ { key: "id", label: "#", sortable: true, class: "w-16" }, { key: "name", label: "Ime", sortable: true }, { key: "color_tag", label: "Barva", sortable: false }, + { key: "segment", label: "Segment", sortable: false }, { key: "decisions", label: "Odločitve", sortable: false, class: "w-32" }, ]; @@ -195,6 +196,11 @@ const destroyAction = () => { +