netgescon-day0/app/Filament/Pages/Fornitore/LavorazioniOperative.php

773 lines
37 KiB
PHP
Executable File

<?php
namespace App\Filament\Pages\Fornitore;
use App\Filament\Pages\Fornitore\Concerns\ResolvesOperatoreContext;
use App\Models\AssistenzaTecnorepairScheda;
use App\Models\Fornitore;
use App\Models\FornitoreDipendente;
use App\Models\TicketIntervento;
use App\Models\User;
use BackedEnum;
use Carbon\Carbon;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Auth;
use UnitEnum;
class LavorazioniOperative extends Page
{
use ResolvesOperatoreContext;
protected static ?string $navigationLabel = 'Lavorazioni';
protected static ?string $title = 'Lavorazioni operative';
protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-queue-list';
protected static UnitEnum|string|null $navigationGroup = 'Fornitore';
protected static ?int $navigationSort = 1;
protected static ?string $slug = 'fornitore/lavorazioni';
protected string $view = 'filament.pages.fornitore.lavorazioni-operative';
public ?int $fornitoreId = null;
public ?string $fornitoreLabel = null;
public bool $missingAdminContext = false;
/** @var array<int, string> */
public array $fornitoriOptions = [];
// Main view navigation: 'elenco' or 'scheda'
public string $mainTab = 'elenco';
// Sub-tab inside the Scheda detail view (reproducing TecnoRepair desktop tabs)
public string $schedaSubTab = 'entrata';
public ?int $selectedRowId = null;
public ?string $selectedRowType = null; // 'tecnorepair' or 'ticket'
/** @var array<string, mixed>|null */
public ?array $activeScheda = null;
/** @var array<string, mixed> Editable form fields for active scheda */
public array $schedaForm = [];
/** @var array<int, int> 3x3 pattern unlock grid nodes */
public array $unlockPattern = [0, 0, 0, 0, 0, 0, 0, 0, 0];
// Quick workflow inputs
public string $workflowNote = '';
public string $workflowRmaCode = '';
// Filter properties
public string $scope = 'tutte';
public string $search = '';
public string $filterStato = '';
public string $filterOrigine = '';
public string $dataDa = '';
public string $dataA = '';
/** @var array<int, array<string, mixed>> */
public array $rows = [];
/** @var array<string, int> */
public array $totals = [
'tutte' => 0,
'aperte' => 0,
'chiuse' => 0,
'ticket_amministratore' => 0,
'interne' => 0,
];
// Legacy modal compatibility
public ?array $detailModal = null;
public static function canAccess(): bool
{
$user = Auth::user();
return $user instanceof User
&& $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore', 'fornitore']);
}
public function mount(): void
{
$this->scope = (string) request()->query('scope', 'tutte');
[$fornitore] = $this->resolveOperatoreContext(allowAdminWithoutSupplier: true);
if (! $fornitore instanceof Fornitore) {
$fornitore = Fornitore::query()->where('partita_iva', '10055221005')->first()
?? Fornitore::query()->orderBy('id')->first();
}
if (! $fornitore instanceof Fornitore) {
$this->missingAdminContext = true;
return;
}
$this->fornitoreId = (int) $fornitore->id;
$this->fornitoreLabel = $this->getFornitoreLabel($fornitore);
$user = Auth::user();
if ($this->isInternalOperator($user)) {
$this->fornitoriOptions = Fornitore::query()
->where(function ($q) {
$q->whereHas('ticketInterventi')
->orWhere('partita_iva', '10055221005')
->orWhere('partita_iva', '14001151001')
->orWhereIn('id', [236, 359, 392]);
})
->orderBy('ragione_sociale')
->get()
->mapWithKeys(fn(Fornitore $f): array => [
(int) $f->id => trim((string) ($f->ragione_sociale ?: ('Fornitore #' . $f->id))) . ($f->partita_iva ? ' (' . $f->partita_iva . ')' : ''),
])
->all();
}
$this->refreshData();
}
public function updatedFornitoreId(): void
{
$fornitore = Fornitore::query()->find((int) $this->fornitoreId);
if ($fornitore instanceof Fornitore) {
$this->fornitoreLabel = $this->getFornitoreLabel($fornitore);
$this->closeScheda();
$this->refreshData();
}
}
public function updatedScope(): void
{
$this->refreshData();
}
public function setScope(string $scope): void
{
$this->scope = $scope;
$this->mainTab = 'elenco';
$this->refreshData();
}
public function setMainTab(string $tab): void
{
$this->mainTab = in_array($tab, ['elenco', 'scheda'], true) ? $tab : 'elenco';
}
public function setSchedaSubTab(string $subTab): void
{
$this->schedaSubTab = $subTab;
}
public function resetFiltri(): void
{
$this->search = '';
$this->filterStato = '';
$this->filterOrigine = '';
$this->dataDa = '';
$this->dataA = '';
$this->scope = 'tutte';
$this->refreshData();
}
public function refreshData(): void
{
if (! $this->fornitoreId) {
$this->rows = [];
return;
}
[$fornitore, $dipendente] = $this->resolveOperatoreContext($this->fornitoreId);
if (! $fornitore instanceof Fornitore) {
$fornitore = Fornitore::query()->find($this->fornitoreId);
}
if (! $fornitore instanceof Fornitore) {
$this->rows = [];
return;
}
$baseQuery = $this->buildBaseQuery($fornitore, $dipendente);
$ticketCount = (clone $baseQuery)->count();
$tecnorepairCount = $this->buildTecnorepairQuery($fornitore)->count();
$this->totals = [
'tutte' => $ticketCount + $tecnorepairCount,
'aperte' => 0,
'chiuse' => 0,
'ticket_amministratore' => $ticketCount,
'interne' => 0,
];
if ($this->scope === 'interne') {
$this->rows = [];
return;
}
$ticketRows = $baseQuery
->limit(150)
->get()
->map(function (TicketIntervento $intervento): array {
$base = $this->buildInterventoRow($intervento);
$isClosed = $this->isClosedStatus((string) $intervento->stato);
return array_merge($base, [
'row_type' => 'ticket',
'row_class' => $this->resolveTicketRowClass((string) $intervento->stato),
'badge_class' => $this->resolveTicketBadgeClass((string) $intervento->stato),
'row_color' => $isClosed ? 'green' : 'blue',
'is_closed' => $isClosed,
'numero' => (string) $intervento->ticket_id,
'numero_scheda'=> (string) $intervento->ticket_id,
'cliente' => $base['contatto'],
'difetto' => $base['problema'],
'brand' => $this->extractDeviceBrand($base['apparato']),
'modello' => $base['apparato'],
'seriale' => '-',
'cod_prodotto' => '-',
'id' => (int) $intervento->id,
'ticket_id' => (int) $intervento->ticket_id,
'titolo' => (string) ($intervento->ticket->titolo ?? '-'),
'stato' => (string) $intervento->stato,
'status_code' => (string) $intervento->stato,
'stabile' => (string) ($intervento->ticket->stabile->denominazione ?? '-'),
'operatore' => (string) $intervento->operatore_assegnato_label,
'tempo_minuti' => (int) ($intervento->tempo_minuti ?? 0),
'updated_at' => optional($intervento->updated_at)->format('d/m/Y H:i') ?: '-',
'sort_at' => optional($intervento->created_at)->format('Y-m-d H:i:s') ?: '1970-01-01 00:00:00',
'origine' => 'Ticket amministratore',
'url' => TicketInterventoScheda::getUrl(['record' => (int) $intervento->id], panel: 'admin-filament'),
]);
})
->all();
$rows = array_merge($ticketRows, $this->buildTecnorepairRows($fornitore));
usort($rows, function (array $left, array $right): int {
return strcmp((string) ($right['sort_at'] ?? ''), (string) ($left['sort_at'] ?? ''));
});
$this->totals['aperte'] = count(array_filter($rows, fn(array $row): bool => ! (bool) ($row['is_closed'] ?? false)));
$this->totals['chiuse'] = count(array_filter($rows, fn(array $row): bool => (bool) ($row['is_closed'] ?? false)));
// Scope filter
if ($this->scope === 'aperte') {
$rows = array_values(array_filter($rows, fn(array $row): bool => ! (bool) ($row['is_closed'] ?? false)));
} elseif ($this->scope === 'chiuse') {
$rows = array_values(array_filter($rows, fn(array $row): bool => (bool) ($row['is_closed'] ?? false)));
} elseif ($this->scope === 'ticket_amministratore') {
$rows = array_values(array_filter($rows, fn(array $row): bool => ($row['row_type'] ?? '') === 'ticket'));
}
// Additional filters
if (trim($this->search) !== '') {
$term = strtolower(trim($this->search));
$rows = array_values(array_filter($rows, function (array $row) use ($term): bool {
return str_contains(strtolower((string) ($row['numero'] ?? '')), $term)
|| str_contains(strtolower((string) ($row['cliente'] ?? '')), $term)
|| str_contains(strtolower((string) ($row['telefono'] ?? '')), $term)
|| str_contains(strtolower((string) ($row['modello'] ?? '')), $term)
|| str_contains(strtolower((string) ($row['seriale'] ?? '')), $term)
|| str_contains(strtolower((string) ($row['difetto'] ?? '')), $term)
|| str_contains(strtolower((string) ($row['brand'] ?? '')), $term)
|| str_contains(strtolower((string) ($row['cod_prodotto'] ?? '')), $term);
}));
}
if (trim($this->filterStato) !== '' && $this->filterStato !== '0') {
$rows = array_values(array_filter($rows, fn(array $r): bool => (string) ($r['status_code'] ?? '') === (string) $this->filterStato || str_contains(strtolower((string) ($r['stato'] ?? '')), strtolower($this->filterStato))));
}
if (trim($this->filterOrigine) !== '') {
$rows = array_values(array_filter($rows, fn(array $r): bool => ($r['row_type'] ?? '') === $this->filterOrigine));
}
$this->rows = array_slice($rows, 0, 160);
}
public function openRowDetail(string $rowType, int $rowId): void
{
$this->selectedRowType = $rowType;
$this->selectedRowId = $rowId;
if ($rowType === 'tecnorepair') {
$scheda = AssistenzaTecnorepairScheda::query()->find($rowId);
if (! $scheda instanceof AssistenzaTecnorepairScheda) {
return;
}
$metadata = is_array($scheda->metadata ?? null) ? $scheda->metadata : [];
$raw = is_array($metadata['raw'] ?? null) ? $metadata['raw'] : [];
$cliente = is_array($metadata['cliente'] ?? null) ? $metadata['cliente'] : [];
// Segno di sblocco (pattern grid 3x3)
$segnoStr = trim((string) ($raw['SegnoDiSblocco'] ?? ''));
$segnoParts = preg_split('/\s+/', $segnoStr);
$pattern = [0, 0, 0, 0, 0, 0, 0, 0, 0];
if (is_array($segnoParts) && count($segnoParts) >= 9) {
for ($i = 0; $i < 9; $i++) {
$pattern[$i] = (int) ($segnoParts[$i] ?? 0);
}
}
$this->unlockPattern = $pattern;
$this->activeScheda = [
'type' => 'tecnorepair',
'id' => (int) $scheda->id,
'legacy_id' => (int) ($scheda->legacy_id ?? 0),
'numero_scheda' => (string) ($scheda->legacy_numero_scheda ?: $scheda->legacy_id ?: '-'),
'title' => (string) $scheda->display_title,
'status' => (string) ($scheda->status_label ?: $scheda->status_bucket ?: '-'),
'status_code' => (string) ($scheda->status_code ?: '21'),
'customer_name' => (string) ($scheda->customer_name ?: ($cliente['NomeCognome'] ?? 'Cliente TecnoRepair')),
'customer_phone' => (string) ($scheda->customer_phone ?: ($cliente['NumeroTelefono'] ?? '')),
'customer_phone_alt' => (string) ($scheda->customer_phone_alt ?: ($cliente['TelFisso'] ?? '')),
'customer_email' => (string) ($scheda->customer_email ?: ($cliente['Email'] ?? '')),
'customer_address' => (string) ($cliente['Indirizzo'] ?? ''),
'customer_city' => (string) ($cliente['Citta'] ?? ''),
'product_type' => (string) ($raw['Cod_TipoApparecchio'] ?? 'Apparecchio Elettronico'),
'brand' => (string) ($this->extractDeviceBrand((string) ($scheda->product_model ?: ''))),
'product_model' => (string) ($scheda->product_model ?: ($raw['Modello'] ?? '-')),
'product_code' => (string) ($scheda->product_code ?: ($raw['CodiceProdotto'] ?? '-')),
'serial_number' => (string) ($scheda->serial_number ?: ($raw['SerialNumber'] ?? '-')),
'serial_number_2' => (string) ($scheda->serial_number_2 ?: ($raw['SerialNumber2'] ?? '-')),
'serial_number_3' => (string) ($raw['SerialNumber3'] ?? '-'),
'tag' => (string) ($raw['Tag'] ?? '-'),
'accessories' => (string) ($raw['AccessoriConsegnati'] ?? 'NESSUNO'),
'location' => (string) ($raw['Locazione'] ?? ($raw['Cod_Ubicazione'] ?? 'Laboratorio')),
'technician' => (string) ($scheda->technician_name ?: ($raw['NomeTecnicoRiparatore'] ?? 'Tecnico')),
'operator' => (string) ($scheda->operator_name ?: ($raw['NomeOperatore'] ?? 'Operatore')),
'defect_reported' => (string) ($scheda->defect_reported ?: ($raw['DifettoSegnalato'] ?? '-')),
'customer_requests' => (string) ($raw['RiparazioneRichiesta'] ?? '-'),
'general_state' => (string) ($raw['StatoGenerale'] ?? '-'),
'pin_code' => (string) ($scheda->pin_code ?: ($raw['CodicePIN'] ?? '-')),
'unlock_code' => (string) ($scheda->unlock_code ?: ($raw['CodiceSblocco'] ?? '-')),
'repair_description' => (string) ($scheda->repair_description ?: ($raw['DescrizioneRiparazione'] ?? '')),
'note_interne' => (string) ($raw['NoteInterne'] ?? ''),
'note_stampa' => (string) ($raw['NoteStampa'] ?? ''),
'communications' => (string) ($scheda->communications ?: ($raw['Comunicazioni'] ?? '')),
'date_received' => optional($scheda->date_received)->format('d/m/Y') ?: '-',
'time_received' => (string) ($raw['OrarioIngresso'] ?? '10:00'),
'date_delivery_prev' => ! empty($raw['DataPrevRip']) ? Carbon::parse($raw['DataPrevRip'])->format('d/m/Y') : '-',
'date_repaired' => ! empty($raw['DataRiparazione']) ? Carbon::parse($raw['DataRiparazione'])->format('d/m/Y') : '-',
'date_returned' => ! empty($raw['DataRiconsegna']) ? Carbon::parse($raw['DataRiconsegna'])->format('d/m/Y') : '-',
'is_fare_preventivo' => (bool) ($raw['isFarePreventivo'] ?? false),
'is_riparazione_sede' => (bool) ($raw['isRiparazioneInSede'] ?? false),
'is_riconsegnato' => (bool) ($raw['isRiconsegnato'] ?? false),
'is_rientro' => (bool) ($raw['Rientro'] ?? false),
'is_esame_tecnico' => (bool) ($raw['isEsameTecnico'] ?? false),
'consegnato_no_doc' => (bool) ($raw['ConsegnatoSenzaDoc'] ?? false),
'costo_preventivo' => (string) ($raw['CostoPreventivo'] ?? '0.00'),
'costo_subito' => (string) ($raw['CostoSubito'] ?? '0.00'),
'costo_addebitato' => (string) ($raw['CostoAddebitato'] ?? '0.00'),
'acconto' => (string) ($raw['AccontoRiparazione'] ?? '0.00'),
'rif_ddt_entrata' => (string) ($raw['RifDDTEntrata'] ?? '-'),
'rif_ddt_uscita' => (string) ($raw['RifDDTUscita'] ?? '-'),
'sost_marca_modello' => (string) ($raw['Sost_MarcaModello'] ?? '-'),
'sost_seriale' => (string) ($raw['Sost_SerialNumber'] ?? '-'),
'sost_stato' => (string) ($raw['Sost_StatoGenerale'] ?? '-'),
'updated_at' => optional($scheda->updated_at)->format('d/m/Y H:i') ?: '-',
'metadata' => $metadata,
];
$this->schedaForm = [
'status_code' => (string) ($scheda->status_code ?: '21'),
'status_label' => (string) ($scheda->status_label ?: 'IN RIPARAZIONE'),
'is_fare_preventivo' => (bool) ($raw['isFarePreventivo'] ?? false),
'is_riparazione_sede'=> (bool) ($raw['isRiparazioneInSede'] ?? false),
'is_riconsegnato' => (bool) ($raw['isRiconsegnato'] ?? false),
'is_rientro' => (bool) ($raw['Rientro'] ?? false),
'is_esame_tecnico' => (bool) ($raw['isEsameTecnico'] ?? false),
'consegnato_no_doc' => (bool) ($raw['ConsegnatoSenzaDoc'] ?? false),
'cliente_nome' => (string) ($scheda->customer_name ?: ($cliente['NomeCognome'] ?? '')),
'cliente_telefono' => (string) ($scheda->customer_phone ?: ($cliente['NumeroTelefono'] ?? '')),
'cliente_tel_fisso' => (string) ($scheda->customer_phone_alt ?: ($cliente['TelFisso'] ?? '')),
'cliente_email' => (string) ($scheda->customer_email ?: ($cliente['Email'] ?? '')),
'cliente_indirizzo' => (string) ($cliente['Indirizzo'] ?? ''),
'cliente_citta' => (string) ($cliente['Citta'] ?? ''),
'difetto_segnalato' => (string) ($scheda->defect_reported ?: ($raw['DifettoSegnalato'] ?? '')),
'richieste_cliente' => (string) ($raw['RiparazioneRichiesta'] ?? ''),
'stato_generale' => (string) ($raw['StatoGenerale'] ?? ''),
'pin_code' => (string) ($scheda->pin_code ?: ($raw['CodicePIN'] ?? '')),
'unlock_code' => (string) ($scheda->unlock_code ?: ($raw['CodiceSblocco'] ?? '')),
'repair_description' => (string) ($scheda->repair_description ?: ($raw['DescrizioneRiparazione'] ?? '')),
'note_interne' => (string) ($raw['NoteInterne'] ?? ''),
'note_stampa' => (string) ($raw['NoteStampa'] ?? ''),
'communications' => (string) ($scheda->communications ?: ($raw['Comunicazioni'] ?? '')),
'tecnico' => (string) ($scheda->technician_name ?: ($raw['NomeTecnicoRiparatore'] ?? '')),
'costo_preventivo' => (string) ($raw['CostoPreventivo'] ?? '0.00'),
'costo_subito' => (string) ($raw['CostoSubito'] ?? '0.00'),
'costo_addebitato' => (string) ($raw['CostoAddebitato'] ?? '0.00'),
'acconto' => (string) ($raw['AccontoRiparazione'] ?? '0.00'),
];
$this->schedaSubTab = 'entrata';
$this->mainTab = 'scheda';
$this->detailModal = null;
return;
}
// TICKET AMMINISTRATORE
[$fornitore, $dipendente] = $this->resolveOperatoreContext((int) $this->fornitoreId);
$intervento = $this->buildBaseQuery($fornitore, $dipendente)->find($rowId);
if (! $intervento instanceof TicketIntervento) {
return;
}
$base = $this->buildInterventoRow($intervento);
$this->activeScheda = [
'type' => 'ticket',
'id' => (int) $intervento->id,
'numero_scheda' => 'TK-' . (int) $intervento->ticket_id,
'title' => 'Ticket #' . (int) $intervento->ticket_id . ' · ' . (string) ($intervento->ticket->titolo ?? '-'),
'status' => (string) $intervento->stato,
'status_code' => (string) $intervento->stato,
'customer_name' => $base['contatto'],
'customer_phone' => $base['telefono'],
'customer_email' => '',
'customer_address' => (string) ($intervento->ticket->stabile->indirizzo ?? ''),
'customer_city' => (string) ($intervento->ticket->stabile->citta ?? ''),
'brand' => $this->extractDeviceBrand($base['apparato']),
'product_model' => $base['apparato'],
'product_code' => '-',
'serial_number' => '-',
'stabile' => (string) ($intervento->ticket->stabile->denominazione ?? '-'),
'unita' => (string) ($intervento->ticket->unitaImmobiliare->denominazione ?? '-'),
'operator' => (string) $intervento->operatore_assegnato_label,
'defect_reported' => $base['problema'],
'repair_description' => (string) ($intervento->rapporto_fornitore ?? ''),
'note_interne' => (string) ($intervento->rapporto_fornitore ?? ''),
'note_stampa' => (string) ($intervento->ticket->descrizione ?? ''),
'communications' => '',
'updated_at' => optional($intervento->updated_at)->format('d/m/Y H:i') ?: '-',
'url' => TicketInterventoScheda::getUrl(['record' => (int) $intervento->id], panel: 'admin-filament'),
'metadata' => [],
];
$this->schedaForm = [
'status_code' => (string) $intervento->stato,
'repair_description' => (string) ($intervento->rapporto_fornitore ?? ''),
'note_interne' => (string) ($intervento->rapporto_fornitore ?? ''),
];
$this->schedaSubTab = 'entrata';
$this->mainTab = 'scheda';
$this->detailModal = null;
}
public function togglePatternDot(int $index): void
{
if (isset($this->unlockPattern[$index])) {
$this->unlockPattern[$index] = $this->unlockPattern[$index] === 1 ? 0 : 1;
}
}
public function saveActiveScheda(): void
{
if (! $this->selectedRowId) {
return;
}
if ($this->selectedRowType === 'tecnorepair') {
$scheda = AssistenzaTecnorepairScheda::query()->find($this->selectedRowId);
if (! $scheda instanceof AssistenzaTecnorepairScheda) {
return;
}
$scheda->defect_reported = $this->schedaForm['difetto_segnalato'] ?? $scheda->defect_reported;
$scheda->repair_description = $this->schedaForm['repair_description'] ?? $scheda->repair_description;
$scheda->communications = $this->schedaForm['communications'] ?? $scheda->communications;
$scheda->pin_code = $this->schedaForm['pin_code'] ?? $scheda->pin_code;
$scheda->unlock_code = $this->schedaForm['unlock_code'] ?? $scheda->unlock_code;
$scheda->technician_name = $this->schedaForm['tecnico'] ?? $scheda->technician_name;
$scheda->status_code = (string) ($this->schedaForm['status_code'] ?? $scheda->status_code);
$scheda->status_label = $this->resolveStatusLabel((string) $scheda->status_code);
$scheda->status_bucket = AssistenzaTecnorepairScheda::normalizeStatusBucket($scheda->status_label);
$metadata = is_array($scheda->metadata ?? null) ? $scheda->metadata : [];
$raw = is_array($metadata['raw'] ?? null) ? $metadata['raw'] : [];
$cliente = is_array($metadata['cliente'] ?? null) ? $metadata['cliente'] : [];
$raw['isFarePreventivo'] = ! empty($this->schedaForm['is_fare_preventivo']) ? '1' : '0';
$raw['isRiparazioneInSede'] = ! empty($this->schedaForm['is_riparazione_sede']) ? '1' : '0';
$raw['isRiconsegnato'] = ! empty($this->schedaForm['is_riconsegnato']) ? '1' : '0';
$raw['Rientro'] = ! empty($this->schedaForm['is_rientro']) ? '1' : '0';
$raw['isEsameTecnico'] = ! empty($this->schedaForm['is_esame_tecnico']) ? '1' : '0';
$raw['ConsegnatoSenzaDoc'] = ! empty($this->schedaForm['consegnato_no_doc']) ? '1' : '0';
$raw['StatoGenerale'] = (string) ($this->schedaForm['stato_generale'] ?? '');
$raw['RiparazioneRichiesta'] = (string) ($this->schedaForm['richieste_cliente'] ?? '');
$raw['NoteInterne'] = (string) ($this->schedaForm['note_interne'] ?? '');
$raw['NoteStampa'] = (string) ($this->schedaForm['note_stampa'] ?? '');
$raw['SegnoDiSblocco'] = implode(' ', $this->unlockPattern);
$cliente['NomeCognome'] = (string) ($this->schedaForm['cliente_nome'] ?? ($cliente['NomeCognome'] ?? ''));
$cliente['NumeroTelefono'] = (string) ($this->schedaForm['cliente_telefono'] ?? ($cliente['NumeroTelefono'] ?? ''));
$cliente['TelFisso'] = (string) ($this->schedaForm['cliente_tel_fisso'] ?? ($cliente['TelFisso'] ?? ''));
$cliente['Email'] = (string) ($this->schedaForm['cliente_email'] ?? ($cliente['Email'] ?? ''));
$cliente['Indirizzo'] = (string) ($this->schedaForm['cliente_indirizzo'] ?? ($cliente['Indirizzo'] ?? ''));
$cliente['Citta'] = (string) ($this->schedaForm['cliente_citta'] ?? ($cliente['Citta'] ?? ''));
$metadata['raw'] = $raw;
$metadata['cliente'] = $cliente;
$scheda->metadata = $metadata;
$scheda->save();
Notification::make()
->title('Scheda #' . ($scheda->legacy_numero_scheda ?: $scheda->legacy_id) . ' salvata con successo')
->success()
->send();
$this->openRowDetail('tecnorepair', (int) $scheda->id);
$this->refreshData();
return;
}
if ($this->selectedRowType === 'ticket') {
$intervento = TicketIntervento::query()->find($this->selectedRowId);
if ($intervento instanceof TicketIntervento) {
$intervento->rapporto_fornitore = (string) ($this->schedaForm['repair_description'] ?? $intervento->rapporto_fornitore);
if (! empty($this->schedaForm['status_code'])) {
$intervento->stato = $this->schedaForm['status_code'];
}
$intervento->save();
Notification::make()
->title('Ticket intervento salvato con successo')
->success()
->send();
$this->openRowDetail('ticket', (int) $intervento->id);
$this->refreshData();
}
}
}
public function cambiaStatoRapido(string $code): void
{
$this->schedaForm['status_code'] = $code;
if ($code === '4') { // Riparato
$this->schedaForm['is_riconsegnato'] = false;
} elseif ($code === '23') { // Rottamazione
$this->schedaForm['is_riconsegnato'] = false;
}
$this->saveActiveScheda();
}
public function closeScheda(): void
{
$this->mainTab = 'elenco';
$this->detailModal = null;
}
public function closeDetailModal(): void
{
$this->closeScheda();
}
public function getTicketsUrl(): string
{
if ($this->fornitoreId) {
return TicketOperativi::getUrl(['fornitore' => $this->fornitoreId], panel: 'admin-filament');
}
return TicketOperativi::getUrl(panel: 'admin-filament');
}
public function getCollaboratoriUrl(): string
{
if ($this->fornitoreId) {
return Collaboratori::getUrl(['fornitore' => $this->fornitoreId], panel: 'admin-filament');
}
return Collaboratori::getUrl(panel: 'admin-filament');
}
public function getRubricaUrl(): string
{
if ($this->fornitoreId) {
return RubricaClienti::getUrl(['fornitore' => $this->fornitoreId], panel: 'admin-filament');
}
return RubricaClienti::getUrl(panel: 'admin-filament');
}
public function getProdottiUrl(): string
{
if ($this->fornitoreId) {
return ProdottiCatalogo::getUrl(['fornitore' => $this->fornitoreId], panel: 'admin-filament');
}
return ProdottiCatalogo::getUrl(panel: 'admin-filament');
}
public function getImpostazioniUrl(): string
{
if ($this->fornitoreId) {
return ImpostazioniArchivio::getUrl(['fornitore' => $this->fornitoreId], panel: 'admin-filament');
}
return ImpostazioniArchivio::getUrl(panel: 'admin-filament');
}
protected function buildBaseQuery(Fornitore $fornitore, ?FornitoreDipendente $dipendente): Builder
{
$query = TicketIntervento::query()
->with(['ticket.stabile', 'ticket.unitaImmobiliare', 'ticket.soggettoRichiedente', 'eseguitoDaDipendente'])
->where('fornitore_id', (int) $fornitore->id)
->orderByDesc('created_at');
if ($dipendente instanceof FornitoreDipendente) {
$query->where(function (Builder $builder) use ($dipendente): void {
$builder->whereNull('eseguito_da_dipendente_id')
->orWhere('eseguito_da_dipendente_id', (int) $dipendente->id);
});
}
return $query;
}
protected function buildTecnorepairQuery(Fornitore $fornitore): Builder
{
$fornitoreIds = [(int) $fornitore->id];
if (in_array((int) $fornitore->id, [236, 359], true) || str_contains(strtoupper($fornitore->ragione_sociale), 'NETHOME')) {
$fornitoreIds = [236, 359];
}
return AssistenzaTecnorepairScheda::query()
->whereIn('fornitore_id', $fornitoreIds)
->orderByDesc('date_received')
->orderByDesc('id');
}
/**
* @return array<int, array<string, mixed>>
*/
protected function buildTecnorepairRows(Fornitore $fornitore): array
{
return $this->buildTecnorepairQuery($fornitore)
->limit(200)
->get()
->map(function (AssistenzaTecnorepairScheda $scheda): array {
$raw = data_get($scheda->metadata, 'raw', []);
$isRiconsegnato = (bool) ($raw['isRiconsegnato'] ?? false);
$isRiparato = ((string) $scheda->status_code === '4') || (bool) ($raw['isRiparato'] ?? false);
$isClosed = (bool) ($scheda->is_closed ?? false) || $isRiconsegnato || $isRiparato || in_array((string) $scheda->status_code, ['4', '10', '23', '31', '37'], true);
$rowColor = match ((string) $scheda->status_code) {
'4' => 'green',
'10', '23' => 'red',
'2', '21' => 'blue',
'5', '6', '33' => 'amber',
default => $isClosed ? 'green' : 'blue',
};
return [
'row_type' => 'tecnorepair',
'row_class' => (string) $scheda->row_classes,
'badge_class' => (string) $scheda->status_badge_classes,
'row_color' => $rowColor,
'is_closed' => $isClosed,
'numero' => (string) ($scheda->legacy_numero_scheda ?: $scheda->legacy_id),
'numero_scheda'=> (string) ($scheda->legacy_numero_scheda ?: $scheda->legacy_id),
'ingresso' => optional($scheda->date_received)->format('d/m/Y') ?: '-',
'cliente' => (string) ($scheda->customer_name ?: 'Cliente TecnoRepair'),
'contatto' => (string) ($scheda->customer_name ?: 'Cliente TecnoRepair'),
'telefono' => (string) ($scheda->customer_phone ?: $scheda->customer_phone_alt ?: ''),
'difetto' => (string) ($scheda->defect_reported ?: '-'),
'problema' => (string) ($scheda->defect_reported ?: '-'),
'brand' => $this->extractDeviceBrand((string) ($scheda->product_model ?: '')),
'apparato' => (string) ($scheda->product_model ?: '-'),
'modello' => (string) ($scheda->product_model ?: '-'),
'seriale' => (string) $scheda->serial_label,
'cod_prodotto' => (string) ($scheda->product_code ?: '-'),
'id' => (int) $scheda->id,
'ticket_id' => null,
'titolo' => (string) $scheda->display_title,
'stato' => (string) ($scheda->status_label ?: $scheda->status_bucket ?: '-'),
'status_code' => (string) ($scheda->status_code ?: ''),
'stabile' => 'Archivio TecnoRepair',
'operatore' => (string) ($scheda->technician_name ?: $scheda->operator_name ?: '-'),
'tempo_minuti' => 0,
'updated_at' => optional($scheda->updated_at)->format('d/m/Y H:i') ?: '-',
'sort_at' => optional($scheda->date_received ?? $scheda->updated_at)->format('Y-m-d H:i:s') ?: '1970-01-01 00:00:00',
'origine' => 'TecnoRepair MDB',
'url' => null,
];
})
->all();
}
protected function resolveTicketRowClass(string $status): string
{
$status = strtolower(trim($status));
return match (true) {
in_array($status, ['chiuso', 'fatturato'], true) => 'bg-emerald-50/70 hover:bg-emerald-50',
in_array($status, ['fatturabile', 'verifica'], true) => 'bg-amber-50/70 hover:bg-amber-50',
default => 'bg-sky-50/60 hover:bg-sky-50',
};
}
protected function resolveTicketBadgeClass(string $status): string
{
$status = strtolower(trim($status));
return match (true) {
in_array($status, ['chiuso', 'fatturato'], true) => 'border-emerald-200 bg-emerald-50 text-emerald-800',
in_array($status, ['fatturabile', 'verifica'], true) => 'border-amber-200 bg-amber-50 text-amber-800',
default => 'border-sky-200 bg-sky-50 text-sky-800',
};
}
protected function isClosedStatus(string $status): bool
{
$status = strtolower(trim($status));
return str_contains($status, 'chius')
|| str_contains($status, 'fatturat')
|| str_contains($status, 'riconsegn')
|| str_contains($status, 'riparato')
|| str_contains($status, 'acquisto');
}
protected function extractDeviceBrand(string $label): string
{
$label = trim($label);
if ($label === '' || $label === '-') {
return '-';
}
$parts = preg_split('/\s+/', $label) ?: [];
$first = trim((string) ($parts[0] ?? ''));
return $first !== '' ? strtoupper($first) : '-';
}
protected function resolveStatusLabel(string $code): string
{
return match ($code) {
'0' => 'TUTTI',
'4' => 'RIPARATO',
'21' => 'INGRESSO ACCETTAZIONE',
'2' => 'DISPOSITIVO IN RIPARAZIONE',
'5' => 'ATTESA RICAMBIO',
'6' => 'INVIATO NUOVO PREVENTIVO',
'10' => 'DISPOSITIVO IRRIPARABILE',
'23' => 'PC DA UTILIZZARE COME RICAMBI',
'33' => 'MANDATO IN GARANZIA AL PRODUTTORE',
'31' => 'ACQUISTO RICONDIZIONATO',
'37' => 'SMALTITO PER ABBANDONO',
default => 'IN LAVORAZIONE (' . $code . ')',
};
}
}