Field job changed permissions and other things
This commit is contained in:
parent
0d9c8c8b30
commit
5f879c9436
|
|
@ -76,14 +76,29 @@ 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()
|
||||
// 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')
|
||||
|
|
@ -91,10 +106,11 @@ public function showCase(\App\Models\ClientCase $clientCase, Request $request)
|
|||
->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,15 +184,41 @@ public function showCase(\App\Models\ClientCase $clientCase, Request $request)
|
|||
return $a;
|
||||
});
|
||||
|
||||
return Inertia::render('Phone/Case/Index', [
|
||||
'client' => $case->client()->with('person', fn ($q) => $q->with(['addresses', 'phones', 'emails', 'bankAccounts']))->firstOrFail(),
|
||||
'client_case' => $case,
|
||||
'contracts' => $contracts,
|
||||
'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()
|
||||
// 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');
|
||||
|
|
@ -185,9 +227,19 @@ public function showCase(\App\Models\ClientCase $clientCase, Request $request)
|
|||
$q->select('id', 'name', 'entity_types', 'allow_attachments');
|
||||
},
|
||||
])
|
||||
->get(['id', 'name', 'color_tag', 'segment_id']),
|
||||
->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,
|
||||
'contracts' => $contracts,
|
||||
'documents' => $documents,
|
||||
'types' => $types,
|
||||
'account_types' => \App\Models\AccountType::all(),
|
||||
// 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,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@ const rawMenuGroups = [
|
|||
},
|
||||
{
|
||||
label: "Terensko delo",
|
||||
requires: { permission: "field-job" },
|
||||
items: [
|
||||
{
|
||||
key: "fieldjobs",
|
||||
|
|
|
|||
|
|
@ -130,9 +130,9 @@ const redirectIfNoContracts = () => {
|
|||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
/*onMounted(() => {
|
||||
redirectIfNoContracts();
|
||||
});
|
||||
});*/
|
||||
|
||||
watch(
|
||||
() => (Array.isArray(props.contracts) ? props.contracts.length : null),
|
||||
|
|
|
|||
|
|
@ -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 = () => {
|
|||
<template #cell-decisions="{ row }">
|
||||
{{ row.decisions?.length ?? 0 }}
|
||||
</template>
|
||||
<template #cell-segment="{ row }">
|
||||
<span>
|
||||
{{ row.segment?.name || "" }}
|
||||
</span>
|
||||
</template>
|
||||
<template #actions="{ row }">
|
||||
<button class="px-2" @click="openEditDrawer(row)">
|
||||
<EditIcon size="md" css="text-gray-500" />
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@
|
|||
});
|
||||
|
||||
// Contract document generation (JSON) - protected by auth+verified; permission enforced inside controller service
|
||||
Route::post('contracts/{contract:uuid}/generate-document', \App\Http\Controllers\ContractDocumentGenerationController::class)->name('contracts.generate-document')->middleware("permission:create-docs");
|
||||
Route::post('contracts/{contract:uuid}/generate-document', \App\Http\Controllers\ContractDocumentGenerationController::class)->name('contracts.generate-document')->middleware('permission:create-docs');
|
||||
|
||||
// Phone page
|
||||
Route::get('phone', [PhoneViewController::class, 'index'])->name('phone.index');
|
||||
|
|
@ -303,7 +303,7 @@
|
|||
Route::get('clients/{client:uuid}', [ClientController::class, 'show'])->name('client.show');
|
||||
Route::get('clients/{client:uuid}/contracts', [ClientController::class, 'contracts'])->name('client.contracts');
|
||||
|
||||
Route::middleware('permission:client-edit')->group( function() {
|
||||
Route::middleware('permission:client-edit')->group(function () {
|
||||
Route::post('clients', [ClientController::class, 'store'])->name('client.store');
|
||||
Route::put('clients/{client:uuid}', [ClientController::class, 'update'])->name('client.update');
|
||||
Route::post('clients/{client:uuid}/emergency-person', [ClientController::class, 'emergencyCreatePerson'])->name('client.emergencyPerson');
|
||||
|
|
@ -320,7 +320,7 @@
|
|||
// client-case / contract
|
||||
Route::get('client-cases/{client_case:uuid}/contract/{uuid}/debug-accounts', [ClientCaseContoller::class, 'debugContractAccounts'])->name('clientCase.contract.debugAccounts');
|
||||
|
||||
Route::middleware('permission:contract-edit')->group( function () {
|
||||
Route::middleware('permission:contract-edit')->group(function () {
|
||||
Route::post('client-cases/{client_case:uuid}/contract', [ClientCaseContoller::class, 'storeContract'])->name('clientCase.contract.store');
|
||||
Route::put('client-cases/{client_case:uuid}/contract/{uuid}', [ClientCaseContoller::class, 'updateContract'])->name('clientCase.contract.update');
|
||||
Route::delete('client-cases/{client_case:uuid}/contract/{uuid}', [ClientCaseContoller::class, 'deleteContract'])->name('clientCase.contract.delete');
|
||||
|
|
@ -332,7 +332,7 @@
|
|||
Route::delete('client-cases/{client_case:uuid}/objects/{id}', [CaseObjectController::class, 'destroy'])->name('clientCase.object.delete');
|
||||
// client-case / activity
|
||||
Route::post('client-cases/{client_case:uuid}/activity', [ClientCaseContoller::class, 'storeActivity'])->name('clientCase.activity.store');
|
||||
Route::delete('client-cases/{client_case:uuid}/activity/{activity}', [ClientCaseContoller::class, 'deleteActivity'])->name('clientCase.activity.delete')->middleware("permission:activity-edit");
|
||||
Route::delete('client-cases/{client_case:uuid}/activity/{activity}', [ClientCaseContoller::class, 'deleteActivity'])->name('clientCase.activity.delete')->middleware('permission:activity-edit');
|
||||
// client-case / segments
|
||||
Route::post('client-cases/{client_case:uuid}/segments', [ClientCaseContoller::class, 'attachSegment'])->name('clientCase.segments.attach');
|
||||
// client-case / documents
|
||||
|
|
@ -340,7 +340,7 @@
|
|||
|
||||
Route::get('client-cases/{client_case:uuid}/documents/{document:uuid}/view', [ClientCaseContoller::class, 'viewDocument'])->name('clientCase.document.view');
|
||||
Route::get('client-cases/{client_case:uuid}/documents/{document:uuid}/download', [ClientCaseContoller::class, 'downloadDocument'])->name('clientCase.document.download');
|
||||
Route::middleware("permission:doc-edit")->group( function() {
|
||||
Route::middleware('permission:doc-edit')->group(function () {
|
||||
Route::patch('client-cases/{client_case:uuid}/documents/{document:uuid}', [ClientCaseContoller::class, 'updateDocument'])
|
||||
->withoutScopedBindings()
|
||||
->name('clientCase.document.update');
|
||||
|
|
@ -375,6 +375,7 @@
|
|||
Route::get('settings/field-job', [FieldJobSettingController::class, 'index'])->name('settings.fieldjob.index');
|
||||
|
||||
// field jobs assignment
|
||||
Route::middleware('permission:field-job')->group(function () {
|
||||
Route::get('field-jobs', [FieldJobController::class, 'index'])->name('fieldjobs.index');
|
||||
Route::post('field-jobs/assign', [FieldJobController::class, 'assign'])->name('fieldjobs.assign');
|
||||
Route::post('field-jobs/assign-bulk', [FieldJobController::class, 'assignBulk'])->name('fieldjobs.assign-bulk');
|
||||
|
|
@ -382,6 +383,8 @@
|
|||
Route::post('settings/field-job', [FieldJobSettingController::class, 'store'])->name('settings.fieldjob.store');
|
||||
Route::put('settings/field-job/{setting}', [FieldJobSettingController::class, 'update'])->name('settings.fieldjob.update');
|
||||
// settings / contract-configs
|
||||
});
|
||||
|
||||
Route::get('settings/contract-configs', [ContractConfigController::class, 'index'])->name('settings.contractConfigs.index');
|
||||
Route::post('settings/contract-configs', [ContractConfigController::class, 'store'])->name('settings.contractConfigs.store');
|
||||
Route::put('settings/contract-configs/{config}', [ContractConfigController::class, 'update'])->name('settings.contractConfigs.update');
|
||||
|
|
@ -397,7 +400,7 @@
|
|||
Route::get('segments', [SegmentController::class, 'index'])->name('segments.index');
|
||||
Route::get('segments/{segment}', [SegmentController::class, 'show'])->name('segments.show');
|
||||
|
||||
Route::middleware("permission:manage-imports")->group( function () {
|
||||
Route::middleware('permission:manage-imports')->group(function () {
|
||||
// imports
|
||||
Route::get('imports/create', [ImportController::class, 'create'])->name('imports.create');
|
||||
Route::get('imports', [ImportController::class, 'index'])->name('imports.index');
|
||||
|
|
|
|||
52
tests/Feature/Phone/CaseCompletedTodayTest.php
Normal file
52
tests/Feature/Phone/CaseCompletedTodayTest.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
use App\Models\ClientCase;
|
||||
use App\Models\Contract;
|
||||
use App\Models\FieldJob;
|
||||
use App\Models\FieldJobSetting;
|
||||
use App\Models\User;
|
||||
use Inertia\Testing\AssertableInertia as Assert;
|
||||
|
||||
it('shows contracts completed today for the user when completed mode is on', function () {
|
||||
$user = User::factory()->create();
|
||||
|
||||
// Create a client case and a contract under it
|
||||
$case = ClientCase::factory()->create();
|
||||
$contract = Contract::factory()->create([
|
||||
'client_case_id' => $case->id,
|
||||
]);
|
||||
|
||||
// Create field job setting (required FK)
|
||||
$setting = FieldJobSetting::factory()->create();
|
||||
|
||||
// Create a completed field job for this user, for this contract, completed today
|
||||
FieldJob::query()->create([
|
||||
'field_job_setting_id' => $setting->id,
|
||||
'assigned_user_id' => $user->id,
|
||||
'user_id' => $user->id,
|
||||
'contract_id' => $contract->id,
|
||||
'assigned_at' => now()->subHour(),
|
||||
'completed_at' => now()->subMinutes(5),
|
||||
'cancelled_at' => null,
|
||||
'priority' => false,
|
||||
]);
|
||||
|
||||
// In normal mode (no completed flag), the contract should not be listed (job is completed)
|
||||
$this->actingAs($user)
|
||||
->get(route('phone.case', ['client_case' => $case->uuid]))
|
||||
->assertInertia(fn (Assert $page) => $page
|
||||
->component('Phone/Case/Index')
|
||||
->where('completed_mode', false)
|
||||
->has('contracts', 0)
|
||||
);
|
||||
|
||||
// With completed=1, it should be listed
|
||||
$this->actingAs($user)
|
||||
->get(route('phone.case', ['client_case' => $case->uuid, 'completed' => 1]))
|
||||
->assertInertia(fn (Assert $page) => $page
|
||||
->component('Phone/Case/Index')
|
||||
->where('completed_mode', true)
|
||||
->has('contracts', 1)
|
||||
->where('contracts.0.uuid', $contract->uuid)
|
||||
);
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user