*/ public array $fornitoriOptions = []; // Filter properties public string $searchMatricola = ''; public string $searchNumScheda = ''; public string $searchCliente = ''; public bool $searchClienteParziale = true; public string $searchNumOrdine = ''; public string $filterStato = '0'; public bool $escludiRiconsegnati = true; public bool $soloRiconsegnati = false; public ?int $nonLavorateDaGiorni = null; public string $dataIngressoDal = ''; public string $dataIngressoAl = ''; // Active Scheda modal state public ?int $selectedSchedaId = null; public string $schedaTab = 'entrata'; /** @var array|null */ public ?array $activeScheda = null; // Workflow inputs for active scheda public string $workflowNote = ''; public string $workflowMotivoRottamazione = ''; public bool $workflowComeRicambi = false; public string $workflowRmaCode = ''; public ?int $workflowFornitoreResoId = null; /** @var array> */ public array $rows = []; /** @var array */ public array $totals = [ 'totale' => 0, 'aperte' => 0, 'riparate' => 0, 'rottamate' => 0, 'rma_garanzia' => 0, ]; public static function canAccess(): bool { $user = Auth::user(); return $user instanceof User && $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore', 'fornitore']); } public function mount(): void { [$fornitore] = $this->resolveOperatoreContext(allowAdminWithoutSupplier: true); 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('productSerials') ->orWhere('partita_iva', '10055221005') ->orWhere('partita_iva', '14001151001') ->orWhereIn('id', [236, 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(); } // Optional date range $this->dataIngressoDal = trim((string) request()->query('dal', '')); $this->dataIngressoAl = trim((string) request()->query('al', '')); // Optional query params if (request()->has('scheda')) { $this->searchNumScheda = trim((string) request()->query('scheda')); } if (request()->has('q')) { $this->searchMatricola = trim((string) request()->query('q')); } $this->refreshData(); if (request()->has('open')) { $openId = (int) request()->query('open'); if ($openId > 0) { $this->openScheda($openId); } } } public function updatedFornitoreId(): void { $fornitore = Fornitore::query()->find((int) $this->fornitoreId); if ($fornitore instanceof Fornitore) { $this->fornitoreLabel = $this->getFornitoreLabel($fornitore); $this->selectedSchedaId = null; $this->activeScheda = null; $this->refreshData(); } } public function updatedSearchMatricola(): void { $this->refreshData(); } public function updatedSearchNumScheda(): void { $this->refreshData(); } public function updatedSearchCliente(): void { $this->refreshData(); } public function updatedFilterStato(): void { $this->refreshData(); } public function updatedEscludiRiconsegnati(): void { $this->refreshData(); } public function updatedSoloRiconsegnati(): void { $this->refreshData(); } public function resetFiltri(): void { $this->searchMatricola = ''; $this->searchNumScheda = ''; $this->searchCliente = ''; $this->searchNumOrdine = ''; $this->filterStato = '0'; $this->escludiRiconsegnati = true; $this->soloRiconsegnati = false; $this->nonLavorateDaGiorni = null; $this->dataIngressoDal = now()->subYears(2)->startOfYear()->format('Y-m-d'); $this->dataIngressoAl = now()->addYear()->endOfYear()->format('Y-m-d'); $this->refreshData(); } public function refreshData(): void { if (! $this->fornitoreId) { $this->rows = []; return; } $query = AssistenzaTecnorepairScheda::query() ->where(function (Builder $builder) { $builder->where('fornitore_id', (int) $this->fornitoreId); // Also include merged suppliers (e.g. NCOMSRL if Nethome) if ((int) $this->fornitoreId === 236) { $builder->orWhere('fornitore_id', 392); } }); // Search filters if (trim($this->searchMatricola) !== '') { $val = trim($this->searchMatricola); $query->where(function (Builder $b) use ($val) { $b->where('serial_number', 'like', "%{$val}%") ->orWhere('serial_number_2', 'like', "%{$val}%") ->orWhere('product_code', 'like', "%{$val}%"); }); } if (trim($this->searchNumScheda) !== '') { $val = trim($this->searchNumScheda); $query->where(function (Builder $b) use ($val) { $b->where('legacy_numero_scheda', 'like', "%{$val}%") ->orWhere('legacy_id', $val); }); } if (trim($this->searchCliente) !== '') { $val = trim($this->searchCliente); $query->where('customer_name', 'like', "%{$val}%"); } if (trim($this->searchNumOrdine) !== '') { $val = trim($this->searchNumOrdine); $query->where('order_number', 'like', "%{$val}%"); } if ($this->filterStato !== '0' && trim($this->filterStato) !== '') { $st = trim($this->filterStato); $query->where(function (Builder $b) use ($st) { $b->where('status_code', $st) ->orWhere('status_label', 'like', "%{$st}%"); }); } if ($this->escludiRiconsegnati) { $query->where(function (Builder $b) { $b->whereNull('metadata->raw->isRiconsegnato') ->orWhere('metadata->raw->isRiconsegnato', 0) ->orWhere('metadata->raw->isRiconsegnato', '0') ->orWhere('metadata->raw->isRiconsegnato', false); }); } elseif ($this->soloRiconsegnati) { $query->where(function (Builder $b) { $b->where('metadata->raw->isRiconsegnato', 1) ->orWhere('metadata->raw->isRiconsegnato', '1') ->orWhere('metadata->raw->isRiconsegnato', true); }); } if ($this->dataIngressoDal !== '') { $query->where('date_received', '>=', Carbon::parse($this->dataIngressoDal)->startOfDay()); } if ($this->dataIngressoAl !== '') { $query->where('date_received', '<=', Carbon::parse($this->dataIngressoAl)->endOfDay()); } // Count totals across dataset $baseTotalQuery = AssistenzaTecnorepairScheda::query() ->where(function (Builder $builder) { $builder->where('fornitore_id', (int) $this->fornitoreId); if ((int) $this->fornitoreId === 236) { $builder->orWhere('fornitore_id', 392); } }); $this->totals = [ 'totale' => (clone $baseTotalQuery)->count(), 'riparate' => (clone $baseTotalQuery)->where('status_code', '4')->count(), 'rottamate' => (clone $baseTotalQuery)->whereIn('status_code', ['10', '23', '37'])->count(), 'rma_garanzia' => (clone $baseTotalQuery)->where('status_code', '33')->count(), 'aperte' => (clone $baseTotalQuery)->whereNotIn('status_code', ['4', '10', '23', '37'])->count(), ]; $records = $query->orderByDesc('legacy_id')->limit(120)->get(); $this->rows = $records->map(function (AssistenzaTecnorepairScheda $s): array { $raw = (array) data_get($s->metadata, 'raw', []); $isRiconsegnato = (bool) ($raw['isRiconsegnato'] ?? false); $statusCode = (string) ($s->status_code ?: ''); $statusLabel = strtoupper((string) ($s->status_label ?: 'IN LAVORAZIONE')); // Row style logic matching TecnoRepair screenshots: // Green: RIPARATO (4) / ACQUISTO RICONDIZIONATO (31) // Red: DISPOSITIVO IRRIPARABILE (10) / PZ-RICAM (23) / SMALTITO (37) // Blue: INGRESSO ACCETTAZIONE (21) // Amber: ATTESA RICAMBIO (5) / LABORATORIO ESTERNO (27) $rowColor = 'white'; if (in_array($statusCode, ['4', '31'], true) || str_contains($statusLabel, 'RIPARATO') || str_contains($statusLabel, 'ACQUISTO RICONDIZIONATO')) { $rowColor = 'green'; } elseif (in_array($statusCode, ['10', '23', '37'], true) || str_contains($statusLabel, 'IRRIPARABILE') || str_contains($statusLabel, 'RICAMBI') || str_contains($statusLabel, 'SMALTITO')) { $rowColor = 'red'; } elseif ($statusCode === '21' || str_contains($statusLabel, 'INGRESSO') || str_contains($statusLabel, 'ACCETTAZIONE')) { $rowColor = 'blue'; } elseif (in_array($statusCode, ['5', '27', '30'], true) || str_contains($statusLabel, 'ATTESA') || str_contains($statusLabel, 'URGENTE')) { $rowColor = 'amber'; } return [ 'id' => (int) $s->id, 'legacy_id' => (int) ($s->legacy_id ?: $s->id), 'numero_scheda' => (string) ($s->legacy_numero_scheda ?: $s->legacy_id ?: $s->id), 'ingresso' => optional($s->date_received)->format('d/m/Y') ?: '-', 'cliente' => (string) ($s->customer_name ?: '-'), 'telefono' => (string) ($s->customer_phone ?: $s->customer_phone_alt ?: '-'), 'difetto' => (string) ($s->defect_reported ?: '-'), 'marca' => (string) ($raw['Cod_Marca'] ?? $this->extractBrand($s->product_model)), 'modello' => (string) ($s->product_model ?: '-'), 'seriale' => (string) ($s->serial_number ?: '-'), 'cod_prodotto' => (string) ($s->product_code ?: '-'), 'riconsegnato' => $isRiconsegnato, 'data_ricons' => ! empty($raw['DataRiconsegna']) ? Carbon::parse($raw['DataRiconsegna'])->format('d/m/Y') : '-', 'num_ordine' => (string) ($s->order_number ?: '0'), 'stato_rip' => $statusLabel, 'status_code' => $statusCode, 'operatore' => (string) ($s->operator_name ?: $s->technician_name ?: 'MICHELE BARONE'), 'row_color' => $rowColor, ]; })->all(); } public function openScheda(int $schedaId): void { $scheda = AssistenzaTecnorepairScheda::query() ->with(['allegati']) ->find($schedaId); if (! $scheda instanceof AssistenzaTecnorepairScheda) { return; } $raw = (array) data_get($scheda->metadata, 'raw', []); $cliente = (array) data_get($scheda->metadata, 'cliente', []); $ricambi = (array) data_get($scheda->metadata, 'ricambi_scheda', []); $this->selectedSchedaId = (int) $scheda->id; $this->schedaTab = 'entrata'; $this->workflowNote = ''; $this->workflowRmaCode = (string) ($scheda->rma_code ?: ('RMA-' . date('Ymd') . '-' . ($scheda->legacy_numero_scheda ?: $scheda->id))); $this->activeScheda = [ 'id' => (int) $scheda->id, 'numero_scheda' => (string) ($scheda->legacy_numero_scheda ?: $scheda->legacy_id ?: $scheda->id), 'data_ingresso' => optional($scheda->date_received)->format('d/m/Y H:i') ?: '-', 'data_riparazione' => ! empty($raw['DataRiparazione']) ? Carbon::parse($raw['DataRiparazione'])->format('d/m/Y H:i') : '-', 'data_riconsegna' => ! empty($raw['DataRiconsegna']) ? Carbon::parse($raw['DataRiconsegna'])->format('d/m/Y') : '-', 'stato_rip' => (string) ($scheda->status_label ?: 'INGRESSO ACCETTAZIONE'), 'status_code' => (string) ($scheda->status_code ?: '21'), 'rma_code' => (string) ($scheda->rma_code ?: ''), 'num_ordine' => (string) ($scheda->order_number ?: '0'), // Cliente 'cliente_nome' => (string) ($scheda->customer_name ?: '-'), 'cliente_email' => (string) ($scheda->customer_email ?: '-'), 'cliente_telefono' => (string) ($scheda->customer_phone ?: '-'), 'cliente_fisso' => (string) ($scheda->customer_phone_alt ?: '-'), 'cliente_indirizzo' => (string) ($cliente['Indirizzo'] ?? '-'), 'cliente_citta' => (string) ($cliente['Citta'] ?? '-'), // Apparecchio 'tipo_apparecchio' => (string) ($raw['Cod_TipoApparecchio'] ?? 'AIO / PC / Dispositivo'), 'marca' => (string) ($raw['Cod_Marca'] ?? $this->extractBrand($scheda->product_model)), 'modello' => (string) ($scheda->product_model ?: '-'), 'codice_prodotto' => (string) ($scheda->product_code ?: '-'), 'seriale' => (string) ($scheda->serial_number ?: '-'), 'seriale_2' => (string) ($scheda->serial_number_2 ?: '-'), 'accessori' => (string) ($raw['AccessoriConsegnati'] ?? 'NESSUNO'), 'difetto' => (string) ($scheda->defect_reported ?: '-'), 'richieste_cliente' => (string) ($raw['RiparazioneRichiesta'] ?? '-'), 'stato_generale' => (string) ($raw['StatoGenerale'] ?? '-'), 'codice_pin' => (string) ($scheda->pin_code ?: '-'), 'codice_sblocco' => (string) ($scheda->unlock_code ?: '-'), 'tecnico' => (string) ($scheda->technician_name ?: $scheda->operator_name ?: 'MICHELE BARONE'), // Riparazione 'descrizione_lavorazione'=> (string) ($scheda->repair_description ?: '-'), 'comunicazioni' => (string) ($scheda->communications ?: '-'), // Economico 'costo_subito' => (float) str_replace(',', '.', (string) ($raw['CostoSubito'] ?? 0)), 'costo_addebitato' => (float) str_replace(',', '.', (string) ($raw['CostoAddebitato'] ?? 0)), 'acconto' => (float) str_replace(',', '.', (string) ($raw['AccontoRiparazione'] ?? 0)), 'preventivo' => (float) str_replace(',', '.', (string) ($raw['CostoPreventivo'] ?? 0)), // Ricambi 'ricambi' => $ricambi, 'allegati' => $scheda->allegati->map(fn(AssistenzaTecnorepairAllegato $a) => [ 'nome' => $a->file_name, 'path' => $a->file_path, ])->all(), ]; } public function closeScheda(): void { $this->selectedSchedaId = null; $this->activeScheda = null; } public function setSchedaTab(string $tab): void { $this->schedaTab = $tab; } // Automated Workflow Actions public function eseguiChiusuraRiparato(): void { if (! $this->selectedSchedaId) { return; } $scheda = AssistenzaTecnorepairScheda::query()->find($this->selectedSchedaId); if (! $scheda instanceof AssistenzaTecnorepairScheda) { return; } $service = app(TecnoRepairArchiveService::class); $service->chiudiComeRiparato($scheda, $this->workflowNote ?: 'Intervento concluso e collaudato con successo.'); Notification::make()->title('Pratica segnata come RIPARATO con successo')->success()->send(); $this->openScheda($this->selectedSchedaId); $this->refreshData(); } public function eseguiChiusuraRottamazione(): void { if (! $this->selectedSchedaId) { return; } $scheda = AssistenzaTecnorepairScheda::query()->find($this->selectedSchedaId); if (! $scheda instanceof AssistenzaTecnorepairScheda) { return; } $service = app(TecnoRepairArchiveService::class); $service->chiudiComeRottamato( $scheda, $this->workflowMotivoRottamazione ?: 'Apparato non riparabile convenientemente', $this->workflowComeRicambi ); $label = $this->workflowComeRicambi ? 'destinato a recupero ricambi' : 'contrassegnato per rottamazione'; Notification::make()->title("Apparato {$label}")->warning()->send(); $this->openScheda($this->selectedSchedaId); $this->refreshData(); } public function eseguiResoFornitoreRma(): void { if (! $this->selectedSchedaId) { return; } $scheda = AssistenzaTecnorepairScheda::query()->find($this->selectedSchedaId); if (! $scheda instanceof AssistenzaTecnorepairScheda) { return; } $service = app(TecnoRepairArchiveService::class); $service->rendiAFornitoreRma( $scheda, $this->workflowRmaCode, $this->workflowFornitoreResoId ?: 392, $this->workflowNote ?: 'Reso in garanzia al produttore / fornitore' ); Notification::make()->title("Pratica inviata in RMA/Garanzia (RMA: {$scheda->rma_code})")->info()->send(); $this->openScheda($this->selectedSchedaId); $this->refreshData(); } public function sincronizzaMdb(): void { try { $service = app(TecnoRepairArchiveService::class); $stats = $service->importArchive(13, (int) $this->fornitoreId); $msg = sprintf( 'Archivio MDB TecnoRepair sincronizzato: %d schede (%d create, %d agg.), %d ricambi, %d seriali.', $stats['schede_lette'], $stats['schede_create'], $stats['schede_aggiornate'], $stats['ricambi_catalogati'], $stats['seriali_allineati'] ); Notification::make()->title($msg)->success()->send(); $this->refreshData(); } catch (\Throwable $e) { Notification::make()->title('Errore sincronizzazione TecnoRepair: ' . $e->getMessage())->danger()->send(); } } public function sincronizzaContabilita(): void { try { $service = app(ContabilitaMysqlSerialImportService::class); $stats = $service->importForSupplier('NCOMSRL'); $msg = sprintf( 'Contabilità MySQL sincronizzata: %d fatture lette, %d seriali aggiornati.', $stats['invoices_count'], $stats['serials_created'] + $stats['serials_updated'] ); Notification::make()->title($msg)->success()->send(); $this->refreshData(); } catch (\Throwable $e) { Notification::make()->title('Errore sincronizzazione Contabilità: ' . $e->getMessage())->danger()->send(); } } private function extractBrand(?string $model): string { $model = trim((string) $model); if ($model === '') { return '-'; } $firstWord = strtoupper(explode(' ', $model)[0] ?? ''); if (in_array($firstWord, ['HP', 'LENOVO', 'DELL', 'ASUS', 'ACER', 'APPLE', 'TOSHIBA', 'MSI', 'SAMSUNG', 'HANSUNG'], true)) { return $firstWord; } return $firstWord ?: '-'; } }