191 lines
6.7 KiB
PHP
191 lines
6.7 KiB
PHP
<?php
|
|
namespace App\Http\Controllers\Fornitore;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Fornitore;
|
|
use App\Models\FornitoreDipendente;
|
|
use App\Models\TicketIntervento;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
class TicketOperativoController extends Controller
|
|
{
|
|
public function index(Request $request)
|
|
{
|
|
[$fornitore] = $this->resolveOperatoreContext();
|
|
|
|
$stato = (string) $request->query('stato', 'aperti');
|
|
$query = TicketIntervento::query()
|
|
->with(['ticket.stabile'])
|
|
->where('fornitore_id', $fornitore->id)
|
|
->orderByDesc('created_at');
|
|
|
|
if ($stato === 'chiusi') {
|
|
$query->whereIn('stato', ['chiuso', 'fatturato']);
|
|
} elseif ($stato === 'fatturabili') {
|
|
$query->whereIn('stato', ['fatturabile', 'fatturato']);
|
|
} else {
|
|
$query->whereNotIn('stato', ['chiuso']);
|
|
}
|
|
|
|
$interventi = $query->paginate(15)->withQueryString();
|
|
|
|
$fatturabili = TicketIntervento::query()
|
|
->where('fornitore_id', $fornitore->id)
|
|
->whereIn('stato', ['fatturabile', 'fatturato'])
|
|
->orderByDesc('updated_at')
|
|
->limit(100)
|
|
->get();
|
|
|
|
return view('fornitore.tickets.index', [
|
|
'fornitore' => $fornitore,
|
|
'interventi' => $interventi,
|
|
'stato' => $stato,
|
|
'fatturabili' => $fatturabili,
|
|
]);
|
|
}
|
|
|
|
public function show(TicketIntervento $intervento)
|
|
{
|
|
[$fornitore] = $this->resolveOperatoreContext();
|
|
$this->authorizeIntervento($intervento, $fornitore);
|
|
|
|
$intervento->load(['ticket.stabile', 'ticket.messages.user', 'eseguitoDaDipendente']);
|
|
|
|
return view('fornitore.tickets.show', [
|
|
'fornitore' => $fornitore,
|
|
'intervento' => $intervento,
|
|
]);
|
|
}
|
|
|
|
public function start(TicketIntervento $intervento)
|
|
{
|
|
[$fornitore, $dipendente] = $this->resolveOperatoreContext();
|
|
$this->authorizeIntervento($intervento, $fornitore);
|
|
|
|
$intervento->update([
|
|
'stato' => 'in_corso',
|
|
'preso_in_carico_da_user_id' => Auth::id(),
|
|
'eseguito_da_dipendente_id' => $dipendente?->id,
|
|
'iniziato_at' => $intervento->iniziato_at ?? now(),
|
|
]);
|
|
|
|
$intervento->ticket->update(['stato' => 'In Lavorazione']);
|
|
|
|
return redirect()->route('fornitore.tickets.show', $intervento)
|
|
->with('success', 'Intervento preso in carico.');
|
|
}
|
|
|
|
public function complete(Request $request, TicketIntervento $intervento)
|
|
{
|
|
[$fornitore, $dipendente] = $this->resolveOperatoreContext();
|
|
$this->authorizeIntervento($intervento, $fornitore);
|
|
|
|
$validated = $request->validate([
|
|
'rapporto_fornitore' => 'required|string|max:5000',
|
|
'tempo_minuti' => 'nullable|integer|min:1|max:1440',
|
|
'articoli_utilizzati' => 'nullable|array',
|
|
'articoli_utilizzati.*' => 'nullable|string|max:120',
|
|
'foto_lavoro' => 'nullable|image|max:5120',
|
|
'qr_token' => 'nullable|string|max:40',
|
|
]);
|
|
|
|
$payload = [
|
|
'rapporto_fornitore' => $validated['rapporto_fornitore'],
|
|
'tempo_minuti' => $validated['tempo_minuti'] ?? null,
|
|
'terminato_at' => now(),
|
|
'stato' => 'in_verifica',
|
|
'eseguito_da_dipendente_id' => $dipendente?->id ?? $intervento->eseguito_da_dipendente_id,
|
|
];
|
|
|
|
$articoli = collect($validated['articoli_utilizzati'] ?? [])
|
|
->map(fn($item) => trim((string) $item))
|
|
->filter()
|
|
->values()
|
|
->all();
|
|
|
|
if ($articoli !== []) {
|
|
$payload['articoli_utilizzati'] = $articoli;
|
|
}
|
|
|
|
if ($request->hasFile('foto_lavoro')) {
|
|
$payload['foto_path'] = $request->file('foto_lavoro')
|
|
->store('ticket-interventi/foto/' . $intervento->id, 'public');
|
|
}
|
|
|
|
$tokenInserito = trim((string) ($validated['qr_token'] ?? ''));
|
|
if ($tokenInserito !== '' && strcasecmp($tokenInserito, (string) $intervento->qr_token) === 0) {
|
|
$payload['qr_scansionato_at'] = now();
|
|
}
|
|
|
|
$intervento->update($payload);
|
|
|
|
$intervento->ticket->messages()->create([
|
|
'user_id' => Auth::id(),
|
|
'messaggio' => 'Rapporto intervento caricato dal fornitore.',
|
|
'canale' => 'interno',
|
|
'direzione' => 'inbound',
|
|
'inviato_il' => now(),
|
|
]);
|
|
|
|
return redirect()->route('fornitore.tickets.show', $intervento)
|
|
->with('success', 'Intervento inviato in verifica amministratore.');
|
|
}
|
|
|
|
/**
|
|
* @return array{0:Fornitore,1:?FornitoreDipendente}
|
|
*/
|
|
private function resolveOperatoreContext(): array
|
|
{
|
|
$user = Auth::user();
|
|
|
|
if ($user && $user->hasAnyRole(['super-admin', 'admin', 'amministratore'])) {
|
|
$fornitoreId = (int) request()->query('fornitore', 0);
|
|
|
|
if ($fornitoreId <= 0) {
|
|
$interventoRoute = request()->route('intervento');
|
|
if ($interventoRoute instanceof TicketIntervento) {
|
|
$fornitoreId = (int) ($interventoRoute->fornitore_id ?? 0);
|
|
}
|
|
}
|
|
|
|
if ($fornitoreId > 0) {
|
|
$fornitoreAdmin = Fornitore::query()->find($fornitoreId);
|
|
abort_unless($fornitoreAdmin, 404);
|
|
return [$fornitoreAdmin, null];
|
|
}
|
|
}
|
|
|
|
$dipendente = null;
|
|
$fornitore = Fornitore::query()
|
|
->where('email', (string) $user->email)
|
|
->first();
|
|
|
|
if (! $fornitore && $user) {
|
|
$dipendente = FornitoreDipendente::query()
|
|
->where('attivo', true)
|
|
->where(function ($q) use ($user): void {
|
|
$q->where('user_id', (int) $user->id)
|
|
->orWhereRaw('LOWER(email) = ?', [mb_strtolower((string) $user->email)]);
|
|
})
|
|
->orderByDesc('id')
|
|
->first();
|
|
|
|
if ($dipendente) {
|
|
$fornitore = Fornitore::query()->find((int) $dipendente->fornitore_id);
|
|
$dipendente->ultimo_accesso_at = now();
|
|
$dipendente->save();
|
|
}
|
|
}
|
|
|
|
abort_unless($fornitore, 403, 'Profilo fornitore non collegato.');
|
|
|
|
return [$fornitore, $dipendente];
|
|
}
|
|
|
|
private function authorizeIntervento(TicketIntervento $intervento, Fornitore $fornitore): void
|
|
{
|
|
abort_unless((int) $intervento->fornitore_id === (int) $fornitore->id, 403);
|
|
}
|
|
}
|