tests
This commit is contained in:
@@ -1,161 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Modules\Helpdesk\Http\Controllers;
|
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
|
||||||
use Illuminate\Http\RedirectResponse;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Gate;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
use Illuminate\Validation\Rule;
|
|
||||||
use Modules\Helpdesk\Models\Status;
|
|
||||||
use Modules\Helpdesk\Models\Ticket;
|
|
||||||
use Modules\Helpdesk\Services\SlaService;
|
|
||||||
use Modules\Helpdesk\Services\WorkflowNotificationService;
|
|
||||||
|
|
||||||
final class TicketControlsController extends Controller
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Persist the assigned agent from the ticket detail controls.
|
|
||||||
*/
|
|
||||||
public function updateAgent(Request $request, Ticket $ticket, WorkflowNotificationService $workflow): RedirectResponse
|
|
||||||
{
|
|
||||||
Gate::authorize('update', $ticket);
|
|
||||||
|
|
||||||
$validated = $request->validate([
|
|
||||||
'agent_id' => [
|
|
||||||
'nullable',
|
|
||||||
'integer',
|
|
||||||
Rule::exists('users', 'id')->where(function ($query) use ($ticket): void {
|
|
||||||
if ($ticket->company_id !== null && Schema::hasColumn('users', 'company_id')) {
|
|
||||||
$query->where(function ($query) use ($ticket): void {
|
|
||||||
$query->where('company_id', $ticket->company_id)
|
|
||||||
->orWhereNull('company_id');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$agentId = $this->nullableInt($validated['agent_id'] ?? null);
|
|
||||||
|
|
||||||
$this->updateTicket($ticket, [
|
|
||||||
'agent_id' => $agentId,
|
|
||||||
'last_activity_at' => now(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$fresh = $ticket->fresh(['agent', 'owner', 'status', 'priority', 'category', 'project', 'team', 'product']) ?? $ticket;
|
|
||||||
$workflow->dispatch($fresh, 'ticket.updated', Auth::user());
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->route('helpdesk.tickets.show', $fresh)
|
|
||||||
->with('ticket-action-updated', $agentId === null
|
|
||||||
? 'Ticket is now unassigned.'
|
|
||||||
: 'Ticket assigned to '.($fresh->agent?->name ?? 'selected agent').'.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the selected ticket status from the ticket detail controls.
|
|
||||||
*/
|
|
||||||
public function updateStatus(Request $request, Ticket $ticket, WorkflowNotificationService $workflow, SlaService $sla): RedirectResponse
|
|
||||||
{
|
|
||||||
Gate::authorize('update', $ticket);
|
|
||||||
|
|
||||||
$validated = $request->validate([
|
|
||||||
'status_id' => ['required', 'integer', Rule::exists('helpdesk_statuses', 'id')],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$status = Status::query()->findOrFail((int) $validated['status_id']);
|
|
||||||
|
|
||||||
$this->updateTicket($ticket, [
|
|
||||||
'status_id' => $status->id,
|
|
||||||
'completed_at' => $status->is_closed ? now() : null,
|
|
||||||
'last_activity_at' => now(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->ensureBoardContainsStatus($ticket, (int) $status->id);
|
|
||||||
|
|
||||||
$fresh = $ticket->fresh(['agent', 'owner', 'status', 'priority', 'category', 'project', 'team', 'product']) ?? $ticket;
|
|
||||||
|
|
||||||
if ($status->is_closed) {
|
|
||||||
$sla->recordClosure($fresh);
|
|
||||||
}
|
|
||||||
|
|
||||||
$workflow->dispatch($fresh, $status->is_closed ? 'ticket.closed' : 'ticket.updated', Auth::user());
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->route('helpdesk.tickets.show', $fresh)
|
|
||||||
->with('ticket-action-updated', 'Status updated to '.($fresh->status?->name ?? 'selected status').'.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persist the selected ticket priority from the ticket detail controls.
|
|
||||||
*/
|
|
||||||
public function updatePriority(Request $request, Ticket $ticket, WorkflowNotificationService $workflow): RedirectResponse
|
|
||||||
{
|
|
||||||
Gate::authorize('update', $ticket);
|
|
||||||
|
|
||||||
$validated = $request->validate([
|
|
||||||
'priority_id' => ['required', 'integer', Rule::exists('helpdesk_priorities', 'id')],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->updateTicket($ticket, [
|
|
||||||
'priority_id' => (int) $validated['priority_id'],
|
|
||||||
'last_activity_at' => now(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$fresh = $ticket->fresh(['agent', 'owner', 'status', 'priority', 'category', 'project', 'team', 'product']) ?? $ticket;
|
|
||||||
$workflow->dispatch($fresh, 'ticket.updated', Auth::user());
|
|
||||||
|
|
||||||
return redirect()
|
|
||||||
->route('helpdesk.tickets.show', $fresh)
|
|
||||||
->with('ticket-action-updated', 'Priority updated to '.($fresh->priority?->name ?? 'selected priority').'.');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply a direct guarded ticket update without relying on Livewire hydration.
|
|
||||||
*
|
|
||||||
* @param array<string, mixed> $updates
|
|
||||||
*/
|
|
||||||
private function updateTicket(Ticket $ticket, array $updates): void
|
|
||||||
{
|
|
||||||
if (Schema::hasColumn('helpdesk_tickets', 'updated_at')) {
|
|
||||||
$updates['updated_at'] = now();
|
|
||||||
}
|
|
||||||
|
|
||||||
DB::table('helpdesk_tickets')
|
|
||||||
->where('id', $ticket->id)
|
|
||||||
->update($updates);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Keep the active Kanban board usable when a ticket is moved to a status not yet assigned to the board.
|
|
||||||
*/
|
|
||||||
private function ensureBoardContainsStatus(Ticket $ticket, int $statusId): void
|
|
||||||
{
|
|
||||||
if ($ticket->board_id === null || ! Schema::hasTable('helpdesk_kanban_board_statuses')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DB::table('helpdesk_kanban_board_statuses')->updateOrInsert(
|
|
||||||
['board_id' => $ticket->board_id, 'status_id' => $statusId],
|
|
||||||
['updated_at' => now(), 'created_at' => now()],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert form select values to nullable integers.
|
|
||||||
*/
|
|
||||||
private function nullableInt(mixed $value): ?int
|
|
||||||
{
|
|
||||||
if ($value === null || $value === '' || $value === '0' || $value === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int) $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -162,6 +162,15 @@
|
|||||||
],
|
],
|
||||||
"pre-package-uninstall": [
|
"pre-package-uninstall": [
|
||||||
"Illuminate\\Foundation\\ComposerScripts::prePackageUninstall"
|
"Illuminate\\Foundation\\ComposerScripts::prePackageUninstall"
|
||||||
|
],
|
||||||
|
"test:modules": [
|
||||||
|
"@php artisan test Modules"
|
||||||
|
],
|
||||||
|
"dusk:modules": [
|
||||||
|
"@php artisan dusk --testsuite=Modules"
|
||||||
|
],
|
||||||
|
"test:helpdesk": [
|
||||||
|
"@php artisan test Modules/Helpdesk"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
|
|||||||
Reference in New Issue
Block a user