773 lines
37 KiB
PHP
Executable File
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 . ')',
|
|
};
|
|
}
|
|
}
|