fix(lavorazioni): solve 500 blade error, mount live tecnorepair mdb (1876), refactor lavorazioni with in-page tab scheda and modern design
This commit is contained in:
parent
ce33fe4f08
commit
067be6513a
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -127,3 +127,5 @@ scripts/ops/windows/netgescon-tapi-provider-report.json
|
||||||
storage/app/private/**
|
storage/app/private/**
|
||||||
storage/app/public/**
|
storage/app/public/**
|
||||||
storage/app/*.json
|
storage/app/*.json
|
||||||
|
storage/app/tecnorepair/
|
||||||
|
Google autorizzazioni/
|
||||||
|
|
|
||||||
|
|
@ -593,6 +593,10 @@ protected function buildDomainConsolidatedQuery(int $stabileId): Builder
|
||||||
|
|
||||||
protected function hasLegacyNominativiForStabile(string $codStabile): bool
|
protected function hasLegacyNominativiForStabile(string $codStabile): bool
|
||||||
{
|
{
|
||||||
|
if (! DbSchema::connection('gescon_import')->hasTable('condomin')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return DB::connection('gescon_import')
|
return DB::connection('gescon_import')
|
||||||
->table('condomin')
|
->table('condomin')
|
||||||
->where('cod_stabile', $codStabile)
|
->where('cod_stabile', $codStabile)
|
||||||
|
|
@ -602,6 +606,10 @@ protected function hasLegacyNominativiForStabile(string $codStabile): bool
|
||||||
|
|
||||||
private function getAccumulatedUnits(string $codStabile, string $legacyYear, string $codCond): array
|
private function getAccumulatedUnits(string $codStabile, string $legacyYear, string $codCond): array
|
||||||
{
|
{
|
||||||
|
if (! DbSchema::connection('gescon_import')->hasTable('vw_legacy_condomin_nominativi')) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
$units = DB::connection('gescon_import')
|
$units = DB::connection('gescon_import')
|
||||||
->table('vw_legacy_condomin_nominativi')
|
->table('vw_legacy_condomin_nominativi')
|
||||||
->where('cod_stabile', $codStabile)
|
->where('cod_stabile', $codStabile)
|
||||||
|
|
@ -874,7 +882,7 @@ public function table(Table $table): Table
|
||||||
->label('Anno legacy')
|
->label('Anno legacy')
|
||||||
->visible(fn(): bool => (bool) $useLegacy)
|
->visible(fn(): bool => (bool) $useLegacy)
|
||||||
->options(function () use ($codStabile): array {
|
->options(function () use ($codStabile): array {
|
||||||
if ($codStabile === '') {
|
if ($codStabile === '' || ! DbSchema::connection('gescon_import')->hasTable('condomin')) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return DB::connection('gescon_import')
|
return DB::connection('gescon_import')
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
use App\Models\TicketIntervento;
|
use App\Models\TicketIntervento;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use BackedEnum;
|
use BackedEnum;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Filament\Notifications\Notification;
|
||||||
use Filament\Pages\Page;
|
use Filament\Pages\Page;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
@ -37,13 +39,43 @@ class LavorazioniOperative extends Page
|
||||||
|
|
||||||
public bool $missingAdminContext = false;
|
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 $scope = 'tutte';
|
||||||
|
public string $search = '';
|
||||||
|
public string $filterStato = '';
|
||||||
|
public string $filterOrigine = '';
|
||||||
|
public string $dataDa = '';
|
||||||
|
public string $dataA = '';
|
||||||
|
|
||||||
/** @var array<int, array<string, mixed>> */
|
/** @var array<int, array<string, mixed>> */
|
||||||
public array $rows = [];
|
public array $rows = [];
|
||||||
|
|
||||||
public ?array $detailModal = null;
|
|
||||||
|
|
||||||
/** @var array<string, int> */
|
/** @var array<string, int> */
|
||||||
public array $totals = [
|
public array $totals = [
|
||||||
'tutte' => 0,
|
'tutte' => 0,
|
||||||
|
|
@ -53,6 +85,9 @@ class LavorazioniOperative extends Page
|
||||||
'interne' => 0,
|
'interne' => 0,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Legacy modal compatibility
|
||||||
|
public ?array $detailModal = null;
|
||||||
|
|
||||||
public static function canAccess(): bool
|
public static function canAccess(): bool
|
||||||
{
|
{
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
|
|
@ -61,14 +96,16 @@ public static function canAccess(): bool
|
||||||
&& $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore', 'fornitore']);
|
&& $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore', 'fornitore']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var array<int, string> */
|
|
||||||
public array $fornitoriOptions = [];
|
|
||||||
|
|
||||||
public function mount(): void
|
public function mount(): void
|
||||||
{
|
{
|
||||||
$this->scope = (string) request()->query('scope', 'tutte');
|
$this->scope = (string) request()->query('scope', 'tutte');
|
||||||
[$fornitore] = $this->resolveOperatoreContext(allowAdminWithoutSupplier: true);
|
[$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) {
|
if (! $fornitore instanceof Fornitore) {
|
||||||
$this->missingAdminContext = true;
|
$this->missingAdminContext = true;
|
||||||
return;
|
return;
|
||||||
|
|
@ -84,7 +121,7 @@ public function mount(): void
|
||||||
$q->whereHas('ticketInterventi')
|
$q->whereHas('ticketInterventi')
|
||||||
->orWhere('partita_iva', '10055221005')
|
->orWhere('partita_iva', '10055221005')
|
||||||
->orWhere('partita_iva', '14001151001')
|
->orWhere('partita_iva', '14001151001')
|
||||||
->orWhereIn('id', [236, 392]);
|
->orWhereIn('id', [236, 359, 392]);
|
||||||
})
|
})
|
||||||
->orderBy('ragione_sociale')
|
->orderBy('ragione_sociale')
|
||||||
->get()
|
->get()
|
||||||
|
|
@ -102,7 +139,7 @@ public function updatedFornitoreId(): void
|
||||||
$fornitore = Fornitore::query()->find((int) $this->fornitoreId);
|
$fornitore = Fornitore::query()->find((int) $this->fornitoreId);
|
||||||
if ($fornitore instanceof Fornitore) {
|
if ($fornitore instanceof Fornitore) {
|
||||||
$this->fornitoreLabel = $this->getFornitoreLabel($fornitore);
|
$this->fornitoreLabel = $this->getFornitoreLabel($fornitore);
|
||||||
$this->detailModal = null;
|
$this->closeScheda();
|
||||||
$this->refreshData();
|
$this->refreshData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -115,6 +152,28 @@ public function updatedScope(): void
|
||||||
public function setScope(string $scope): void
|
public function setScope(string $scope): void
|
||||||
{
|
{
|
||||||
$this->scope = $scope;
|
$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();
|
$this->refreshData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,6 +185,14 @@ public function refreshData(): void
|
||||||
}
|
}
|
||||||
|
|
||||||
[$fornitore, $dipendente] = $this->resolveOperatoreContext($this->fornitoreId);
|
[$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);
|
$baseQuery = $this->buildBaseQuery($fornitore, $dipendente);
|
||||||
|
|
||||||
|
|
@ -146,17 +213,20 @@ public function refreshData(): void
|
||||||
}
|
}
|
||||||
|
|
||||||
$ticketRows = $baseQuery
|
$ticketRows = $baseQuery
|
||||||
->limit(120)
|
->limit(150)
|
||||||
->get()
|
->get()
|
||||||
->map(function (TicketIntervento $intervento): array {
|
->map(function (TicketIntervento $intervento): array {
|
||||||
$base = $this->buildInterventoRow($intervento);
|
$base = $this->buildInterventoRow($intervento);
|
||||||
|
$isClosed = $this->isClosedStatus((string) $intervento->stato);
|
||||||
|
|
||||||
return array_merge($base, [
|
return array_merge($base, [
|
||||||
'row_type' => 'ticket',
|
'row_type' => 'ticket',
|
||||||
'row_class' => $this->resolveTicketRowClass((string) $intervento->stato),
|
'row_class' => $this->resolveTicketRowClass((string) $intervento->stato),
|
||||||
'badge_class' => $this->resolveTicketBadgeClass((string) $intervento->stato),
|
'badge_class' => $this->resolveTicketBadgeClass((string) $intervento->stato),
|
||||||
'is_closed' => $this->isClosedStatus((string) $intervento->stato),
|
'row_color' => $isClosed ? 'green' : 'blue',
|
||||||
|
'is_closed' => $isClosed,
|
||||||
'numero' => (string) $intervento->ticket_id,
|
'numero' => (string) $intervento->ticket_id,
|
||||||
|
'numero_scheda'=> (string) $intervento->ticket_id,
|
||||||
'cliente' => $base['contatto'],
|
'cliente' => $base['contatto'],
|
||||||
'difetto' => $base['problema'],
|
'difetto' => $base['problema'],
|
||||||
'brand' => $this->extractDeviceBrand($base['apparato']),
|
'brand' => $this->extractDeviceBrand($base['apparato']),
|
||||||
|
|
@ -167,6 +237,7 @@ public function refreshData(): void
|
||||||
'ticket_id' => (int) $intervento->ticket_id,
|
'ticket_id' => (int) $intervento->ticket_id,
|
||||||
'titolo' => (string) ($intervento->ticket->titolo ?? '-'),
|
'titolo' => (string) ($intervento->ticket->titolo ?? '-'),
|
||||||
'stato' => (string) $intervento->stato,
|
'stato' => (string) $intervento->stato,
|
||||||
|
'status_code' => (string) $intervento->stato,
|
||||||
'stabile' => (string) ($intervento->ticket->stabile->denominazione ?? '-'),
|
'stabile' => (string) ($intervento->ticket->stabile->denominazione ?? '-'),
|
||||||
'operatore' => (string) $intervento->operatore_assegnato_label,
|
'operatore' => (string) $intervento->operatore_assegnato_label,
|
||||||
'tempo_minuti' => (int) ($intervento->tempo_minuti ?? 0),
|
'tempo_minuti' => (int) ($intervento->tempo_minuti ?? 0),
|
||||||
|
|
@ -187,98 +258,319 @@ public function refreshData(): void
|
||||||
$this->totals['aperte'] = count(array_filter($rows, fn(array $row): bool => ! (bool) ($row['is_closed'] ?? false)));
|
$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)));
|
$this->totals['chiuse'] = count(array_filter($rows, fn(array $row): bool => (bool) ($row['is_closed'] ?? false)));
|
||||||
|
|
||||||
|
// Scope filter
|
||||||
if ($this->scope === 'aperte') {
|
if ($this->scope === 'aperte') {
|
||||||
$rows = array_values(array_filter($rows, fn(array $row): bool => ! (bool) ($row['is_closed'] ?? false)));
|
$rows = array_values(array_filter($rows, fn(array $row): bool => ! (bool) ($row['is_closed'] ?? false)));
|
||||||
} elseif ($this->scope === 'chiuse') {
|
} elseif ($this->scope === 'chiuse') {
|
||||||
$rows = array_values(array_filter($rows, fn(array $row): bool => (bool) ($row['is_closed'] ?? false)));
|
$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'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->rows = array_slice($rows, 0, 150);
|
// 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
|
public function openRowDetail(string $rowType, int $rowId): void
|
||||||
{
|
{
|
||||||
if (! $this->fornitoreId) {
|
$this->selectedRowType = $rowType;
|
||||||
return;
|
$this->selectedRowId = $rowId;
|
||||||
}
|
|
||||||
|
|
||||||
if ($rowType === 'tecnorepair') {
|
if ($rowType === 'tecnorepair') {
|
||||||
$scheda = AssistenzaTecnorepairScheda::query()
|
$scheda = AssistenzaTecnorepairScheda::query()->find($rowId);
|
||||||
->where('fornitore_id', (int) $this->fornitoreId)
|
|
||||||
->find($rowId);
|
|
||||||
|
|
||||||
if (! $scheda instanceof AssistenzaTecnorepairScheda) {
|
if (! $scheda instanceof AssistenzaTecnorepairScheda) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$metadata = is_array($scheda->metadata ?? null) ? $scheda->metadata : [];
|
$metadata = is_array($scheda->metadata ?? null) ? $scheda->metadata : [];
|
||||||
$apparecchio = array_filter([
|
$raw = is_array($metadata['raw'] ?? null) ? $metadata['raw'] : [];
|
||||||
'Numero scheda' => (string) ($scheda->legacy_numero_scheda ?: $scheda->legacy_id ?: '-'),
|
$cliente = is_array($metadata['cliente'] ?? null) ? $metadata['cliente'] : [];
|
||||||
'Codice prodotto' => (string) ($scheda->product_code ?: '-'),
|
|
||||||
'Modello' => (string) ($scheda->product_model ?: '-'),
|
|
||||||
'Seriale 1' => (string) ($scheda->serial_number ?: '-'),
|
|
||||||
'Seriale 2' => (string) ($scheda->serial_number_2 ?: '-'),
|
|
||||||
'Numero ordine' => (string) ($scheda->order_number ?: '-'),
|
|
||||||
'RMA' => (string) ($scheda->rma_code ?: '-'),
|
|
||||||
'PIN' => (string) ($scheda->pin_code ?: '-'),
|
|
||||||
'Unlock' => (string) ($scheda->unlock_code ?: '-'),
|
|
||||||
], static fn(string $value): bool => trim($value) !== '');
|
|
||||||
|
|
||||||
$this->detailModal = [
|
// 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',
|
'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,
|
'title' => (string) $scheda->display_title,
|
||||||
'status' => (string) ($scheda->status_label ?: $scheda->status_bucket ?: '-'),
|
'status' => (string) ($scheda->status_label ?: $scheda->status_bucket ?: '-'),
|
||||||
'customer' => (string) ($scheda->customer_name ?: 'Cliente TecnoRepair'),
|
'status_code' => (string) ($scheda->status_code ?: '21'),
|
||||||
'phone' => (string) ($scheda->customer_phone ?: $scheda->customer_phone_alt ?: ''),
|
'customer_name' => (string) ($scheda->customer_name ?: ($cliente['NomeCognome'] ?? 'Cliente TecnoRepair')),
|
||||||
'email' => (string) ($scheda->customer_email ?: ''),
|
'customer_phone' => (string) ($scheda->customer_phone ?: ($cliente['NumeroTelefono'] ?? '')),
|
||||||
'difetto_segnalato' => (string) ($scheda->defect_reported ?: '-'),
|
'customer_phone_alt' => (string) ($scheda->customer_phone_alt ?: ($cliente['TelFisso'] ?? '')),
|
||||||
'note_interne' => trim((string) (($metadata['NoteInterne'] ?? $metadata['note_interne'] ?? $scheda->communications) ?: '')),
|
'customer_email' => (string) ($scheda->customer_email ?: ($cliente['Email'] ?? '')),
|
||||||
'note_stampa' => trim((string) (($metadata['NoteStampa'] ?? $metadata['note_stampa'] ?? $scheda->repair_description) ?: '')),
|
'customer_address' => (string) ($cliente['Indirizzo'] ?? ''),
|
||||||
'communications' => (string) ($scheda->communications ?: ''),
|
'customer_city' => (string) ($cliente['Citta'] ?? ''),
|
||||||
'repair_description' => (string) ($scheda->repair_description ?: ''),
|
'product_type' => (string) ($raw['Cod_TipoApparecchio'] ?? 'Apparecchio Elettronico'),
|
||||||
'operator' => (string) ($scheda->technician_name ?: $scheda->operator_name ?: '-'),
|
'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') ?: '-',
|
'updated_at' => optional($scheda->updated_at)->format('d/m/Y H:i') ?: '-',
|
||||||
'apparecchio_fields' => $apparecchio,
|
|
||||||
'metadata' => $metadata,
|
'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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TICKET AMMINISTRATORE
|
||||||
[$fornitore, $dipendente] = $this->resolveOperatoreContext((int) $this->fornitoreId);
|
[$fornitore, $dipendente] = $this->resolveOperatoreContext((int) $this->fornitoreId);
|
||||||
|
|
||||||
$intervento = $this->buildBaseQuery($fornitore, $dipendente)->find($rowId);
|
$intervento = $this->buildBaseQuery($fornitore, $dipendente)->find($rowId);
|
||||||
if (! $intervento instanceof TicketIntervento) {
|
if (! $intervento instanceof TicketIntervento) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$base = $this->buildInterventoRow($intervento);
|
$base = $this->buildInterventoRow($intervento);
|
||||||
$this->detailModal = [
|
$this->activeScheda = [
|
||||||
'type' => 'ticket',
|
'type' => 'ticket',
|
||||||
|
'id' => (int) $intervento->id,
|
||||||
|
'numero_scheda' => 'TK-' . (int) $intervento->ticket_id,
|
||||||
'title' => 'Ticket #' . (int) $intervento->ticket_id . ' · ' . (string) ($intervento->ticket->titolo ?? '-'),
|
'title' => 'Ticket #' . (int) $intervento->ticket_id . ' · ' . (string) ($intervento->ticket->titolo ?? '-'),
|
||||||
'status' => (string) $intervento->stato,
|
'status' => (string) $intervento->stato,
|
||||||
'customer' => $base['contatto'],
|
'status_code' => (string) $intervento->stato,
|
||||||
'phone' => $base['telefono'],
|
'customer_name' => $base['contatto'],
|
||||||
'email' => '',
|
'customer_phone' => $base['telefono'],
|
||||||
'difetto_segnalato' => $base['problema'],
|
'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_interne' => (string) ($intervento->rapporto_fornitore ?? ''),
|
||||||
'note_stampa' => (string) ($intervento->ticket->descrizione ?? ''),
|
'note_stampa' => (string) ($intervento->ticket->descrizione ?? ''),
|
||||||
'communications' => '',
|
'communications' => '',
|
||||||
'repair_description' => '',
|
|
||||||
'operator' => (string) $intervento->operatore_assegnato_label,
|
|
||||||
'updated_at' => optional($intervento->updated_at)->format('d/m/Y H:i') ?: '-',
|
'updated_at' => optional($intervento->updated_at)->format('d/m/Y H:i') ?: '-',
|
||||||
'url' => TicketInterventoScheda::getUrl(['record' => (int) $intervento->id], panel: 'admin-filament'),
|
'url' => TicketInterventoScheda::getUrl(['record' => (int) $intervento->id], panel: 'admin-filament'),
|
||||||
'apparecchio_fields' => [
|
|
||||||
'Apparato' => $base['apparato'],
|
|
||||||
'Stabile' => (string) ($intervento->ticket->stabile->denominazione ?? '-'),
|
|
||||||
],
|
|
||||||
'metadata' => [],
|
'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
|
public function closeDetailModal(): void
|
||||||
{
|
{
|
||||||
$this->detailModal = null;
|
$this->closeScheda();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTicketsUrl(): string
|
public function getTicketsUrl(): string
|
||||||
|
|
@ -345,10 +637,15 @@ protected function buildBaseQuery(Fornitore $fornitore, ?FornitoreDipendente $di
|
||||||
|
|
||||||
protected function buildTecnorepairQuery(Fornitore $fornitore): Builder
|
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()
|
return AssistenzaTecnorepairScheda::query()
|
||||||
->where('fornitore_id', (int) $fornitore->id)
|
->whereIn('fornitore_id', $fornitoreIds)
|
||||||
->orderByDesc('date_received')
|
->orderByDesc('date_received')
|
||||||
->orderByDesc('updated_at');
|
->orderByDesc('id');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -357,15 +654,30 @@ protected function buildTecnorepairQuery(Fornitore $fornitore): Builder
|
||||||
protected function buildTecnorepairRows(Fornitore $fornitore): array
|
protected function buildTecnorepairRows(Fornitore $fornitore): array
|
||||||
{
|
{
|
||||||
return $this->buildTecnorepairQuery($fornitore)
|
return $this->buildTecnorepairQuery($fornitore)
|
||||||
->limit(120)
|
->limit(200)
|
||||||
->get()
|
->get()
|
||||||
->map(function (AssistenzaTecnorepairScheda $scheda): array {
|
->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 [
|
return [
|
||||||
'row_type' => 'tecnorepair',
|
'row_type' => 'tecnorepair',
|
||||||
'row_class' => (string) $scheda->row_classes,
|
'row_class' => (string) $scheda->row_classes,
|
||||||
'badge_class' => (string) $scheda->status_badge_classes,
|
'badge_class' => (string) $scheda->status_badge_classes,
|
||||||
'is_closed' => (bool) ($scheda->is_closed ?? false),
|
'row_color' => $rowColor,
|
||||||
|
'is_closed' => $isClosed,
|
||||||
'numero' => (string) ($scheda->legacy_numero_scheda ?: $scheda->legacy_id),
|
'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') ?: '-',
|
'ingresso' => optional($scheda->date_received)->format('d/m/Y') ?: '-',
|
||||||
'cliente' => (string) ($scheda->customer_name ?: 'Cliente TecnoRepair'),
|
'cliente' => (string) ($scheda->customer_name ?: 'Cliente TecnoRepair'),
|
||||||
'contatto' => (string) ($scheda->customer_name ?: 'Cliente TecnoRepair'),
|
'contatto' => (string) ($scheda->customer_name ?: 'Cliente TecnoRepair'),
|
||||||
|
|
@ -381,6 +693,7 @@ protected function buildTecnorepairRows(Fornitore $fornitore): array
|
||||||
'ticket_id' => null,
|
'ticket_id' => null,
|
||||||
'titolo' => (string) $scheda->display_title,
|
'titolo' => (string) $scheda->display_title,
|
||||||
'stato' => (string) ($scheda->status_label ?: $scheda->status_bucket ?: '-'),
|
'stato' => (string) ($scheda->status_label ?: $scheda->status_bucket ?: '-'),
|
||||||
|
'status_code' => (string) ($scheda->status_code ?: ''),
|
||||||
'stabile' => 'Archivio TecnoRepair',
|
'stabile' => 'Archivio TecnoRepair',
|
||||||
'operatore' => (string) ($scheda->technician_name ?: $scheda->operator_name ?: '-'),
|
'operatore' => (string) ($scheda->technician_name ?: $scheda->operator_name ?: '-'),
|
||||||
'tempo_minuti' => 0,
|
'tempo_minuti' => 0,
|
||||||
|
|
@ -438,4 +751,22 @@ protected function extractDeviceBrand(string $label): string
|
||||||
|
|
||||||
return $first !== '' ? strtoupper($first) : '-';
|
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 . ')',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -835,7 +835,7 @@ public function getOperazioniProperty()
|
||||||
|
|
||||||
$vociMap = [];
|
$vociMap = [];
|
||||||
$vociTabellaMap = [];
|
$vociTabellaMap = [];
|
||||||
if (! empty($codSpe)) {
|
if (! empty($codSpe) && Schema::connection('gescon_import')->hasTable('voc_spe')) {
|
||||||
$vociRows = DB::connection('gescon_import')
|
$vociRows = DB::connection('gescon_import')
|
||||||
->table('voc_spe')
|
->table('voc_spe')
|
||||||
->whereIn('cod', $codSpe)
|
->whereIn('cod', $codSpe)
|
||||||
|
|
@ -866,7 +866,7 @@ public function getOperazioniProperty()
|
||||||
}
|
}
|
||||||
|
|
||||||
$tabelleMap = [];
|
$tabelleMap = [];
|
||||||
if (! empty($codTab)) {
|
if (! empty($codTab) && Schema::connection('gescon_import')->hasTable('tabelle_millesimali')) {
|
||||||
$tabelleMap = DB::connection('gescon_import')
|
$tabelleMap = DB::connection('gescon_import')
|
||||||
->table('tabelle_millesimali')
|
->table('tabelle_millesimali')
|
||||||
->whereIn('cod_tabella', $codTab)
|
->whereIn('cod_tabella', $codTab)
|
||||||
|
|
@ -1528,7 +1528,7 @@ public function getConsuntivoProperty(): array
|
||||||
$codes = $allRows->pluck('cod_spe')->filter()->unique()->values()->all();
|
$codes = $allRows->pluck('cod_spe')->filter()->unique()->values()->all();
|
||||||
$vociMap = [];
|
$vociMap = [];
|
||||||
$tabellaByCod = [];
|
$tabellaByCod = [];
|
||||||
if (! empty($codes)) {
|
if (! empty($codes) && Schema::connection('gescon_import')->hasTable('voc_spe')) {
|
||||||
$vocRows = DB::connection('gescon_import')
|
$vocRows = DB::connection('gescon_import')
|
||||||
->table('voc_spe')
|
->table('voc_spe')
|
||||||
->whereIn('cod', $codes)
|
->whereIn('cod', $codes)
|
||||||
|
|
@ -1543,7 +1543,7 @@ public function getConsuntivoProperty(): array
|
||||||
|
|
||||||
$tabellaMap = [];
|
$tabellaMap = [];
|
||||||
$tabellaInfo = [];
|
$tabellaInfo = [];
|
||||||
if (! empty($tabCodes)) {
|
if (! empty($tabCodes) && Schema::connection('gescon_import')->hasTable('tabelle_millesimali')) {
|
||||||
$tabellaMap = DB::connection('gescon_import')
|
$tabellaMap = DB::connection('gescon_import')
|
||||||
->table('tabelle_millesimali')
|
->table('tabelle_millesimali')
|
||||||
->whereIn('cod_tabella', $tabCodes)
|
->whereIn('cod_tabella', $tabCodes)
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,8 @@ public function resolveMdbPath(?string $candidatePath = null, ?Fornitore $fornit
|
||||||
|
|
||||||
// Candidates for fallback
|
// Candidates for fallback
|
||||||
$fallbackCandidates = [
|
$fallbackCandidates = [
|
||||||
|
'/mnt/cservergo/LunaSoftware_TecnoRepair/Archivi/TecnoRepairDB.mdb',
|
||||||
|
storage_path('app/tecnorepair/TecnoRepairDB.mdb'),
|
||||||
self::DEFAULT_LOCAL_PATH,
|
self::DEFAULT_LOCAL_PATH,
|
||||||
'/home/michele/MIki/netgescon-day0-backup/Miki-Bug-workspace/screenshot/Assistenza gestionale/Archivi/TecnoRepairDB.mdb',
|
'/home/michele/MIki/netgescon-day0-backup/Miki-Bug-workspace/screenshot/Assistenza gestionale/Archivi/TecnoRepairDB.mdb',
|
||||||
'/mnt/gescon-archives/TecnoRepairDB.mdb',
|
'/mnt/gescon-archives/TecnoRepairDB.mdb',
|
||||||
|
|
|
||||||
|
|
@ -786,10 +786,8 @@ class="inline-flex items-center gap-1 rounded-lg border border-amber-300 bg-ambe
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="divide-y divide-slate-100 bg-white">
|
<tbody class="divide-y divide-slate-100 bg-white">
|
||||||
@forelse($canoniRighe as $r)
|
@forelse($canoniRighe as $r)
|
||||||
@php
|
@php($d = (float)($r['totale_dovuto'] ?? 0))
|
||||||
$d = (float)($r['totale_dovuto'] ?? 0);
|
@php($p = (float)($r['totale_pagato'] ?? 0))
|
||||||
$p = (float)($r['totale_pagato'] ?? 0);
|
|
||||||
@endphp
|
|
||||||
<tr class="hover:bg-slate-50/70 transition">
|
<tr class="hover:bg-slate-50/70 transition">
|
||||||
<td class="px-3 py-2 font-medium text-slate-800">{{ $r['mese_descrizione'] ?? ($r['mese'] ?? '') }} {{ $r['anno'] ?? '' }}</td>
|
<td class="px-3 py-2 font-medium text-slate-800">{{ $r['mese_descrizione'] ?? ($r['mese'] ?? '') }} {{ $r['anno'] ?? '' }}</td>
|
||||||
<td class="px-3 py-2 text-slate-600">
|
<td class="px-3 py-2 text-slate-600">
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,78 +1,65 @@
|
||||||
# CURRENT-205
|
# CURRENT-205
|
||||||
|
|
||||||
TASK_ID: task-email-service-password-reset
|
TASK_ID: task-lavorazioni-tecnorepair-tab-sync
|
||||||
MACHINE: .205
|
MACHINE: .205
|
||||||
STATO: completato
|
STATO: completato
|
||||||
|
|
||||||
## Obiettivo Completato
|
## Obiettivo Completato
|
||||||
|
|
||||||
1. **Attivazione e Diagnostica Servizio Posta SMTP (Google Workspace / Gmail)**:
|
1. **Risoluzione Errore HTTP 500 Blade Lexer (`ParseError: unexpected token '=' / 'endforeach'`)**:
|
||||||
- Configurato e bonificato `.env` con credenziali dedicate Google Workspace:
|
- Diagnosi: in `resources/views/filament/pages/affitti/gestione-affitti.blade.php`, un blocco `@php ... @endphp` multiriga dentro un `@forelse` entrava in conflitto con la regex interna di Blade `/(?<!@)@php(.*?)@endphp/s`. La regex inglobava 19.000 caratteri da una precedente direttiva `@php(...)`, lasciando orfano `@empty` e mandando il contatore `forElseCounter` a `-1`, scatenando `$__empty_-1 = true;` in compilazioni successive.
|
||||||
- `MAIL_MAILER=smtp`
|
- Soluzione: convertite le righe a direttive inline `@php($d = ...)` e `@php($p = ...)`.
|
||||||
- `MAIL_HOST=smtp.gmail.com`
|
- Verifica: `php artisan view:clear && php artisan view:cache` -> **Blade templates cached successfully con zero errori**.
|
||||||
- `MAIL_PORT=587`
|
|
||||||
- `MAIL_ENCRYPTION=tls`
|
|
||||||
- `MAIL_USERNAME=netgescon@gmail.com`
|
|
||||||
- `MAIL_FROM_ADDRESS=michele@netgescon.it` (NetGescon)
|
|
||||||
- Risolto il blocco delle email in coda: impostato `QUEUE_CONNECTION=sync` ed eliminata la dipendenza da daemon `queue:work` non presenti a sistema.
|
|
||||||
- Svuotata la tabella `jobs` evadendo le notifiche pendenti.
|
|
||||||
|
|
||||||
2. **Notifica di Reimpostazione Password Personalizzata in Italiano (`NetGesconResetPasswordNotification`)**:
|
2. **Diagnosi e Risoluzione Discrepanza Schede TecnoRepair (1831 vs 1876)**:
|
||||||
- Creata la notifica `App\Notifications\NetGesconResetPasswordNotification`:
|
- Diagnosi: il file locale di staging `screenshot/Assistenza gestionale/Archivi/TecnoRepairDB.mdb` era uno snapshot datato 1 aprile 2026 fermo all'ID 1834.
|
||||||
- Invio sincrono immediato (senza code asincrone).
|
- Connessione al server di rete: montata la share live Windows `//192.168.0.36/CServerGO` in `/mnt/cservergo` con credenziali dedicate e persistita in `/etc/fstab`.
|
||||||
- Testo in italiano, grafica formattata, pulsante "Reimposta Password", token univoco e link per copia-incolla con scadenza 60 minuti.
|
- Il database live contiene le schede aggiornate ad oggi (fino a ID legacy 1879, inclusa la #1876).
|
||||||
- Mittente ufficiale `michele@netgescon.it` (NetGescon).
|
- Aggiornato `TecnoRepairArchiveService.php` per dare precedenza al percorso live `/mnt/cservergo/LunaSoftware_TecnoRepair/Archivi/TecnoRepairDB.mdb`.
|
||||||
- Registrato il binding in `AppServiceProvider` su `\Filament\Auth\Notifications\ResetPassword`.
|
- Eseguito import: `php artisan tecnorepair:import-legacy 13` -> **1874 schede importate (max legacy_id 1879, inclusa scheda 1876)**.
|
||||||
- Agganciato il metodo `sendPasswordResetNotification()` su `App\Models\User`.
|
|
||||||
|
|
||||||
3. **Autonomia Cambio Password Utente**:
|
3. **Chiarimento Architettura di Sincronizzazione (Sviluppo .205, Gitea e Produzione Cloud)**:
|
||||||
- **Da non autenticato**: abilitato il flusso completo su `/admin-filament/password-reset/request` (link "Hai dimenticato la password?" nella maschera di login).
|
- Sviluppo `.205`: Codice locale sul branch `stabilization/205-zero`, database locale MariaDB `netgescon` e montaggi CIFS diretti verso gli archivi MDB (`/mnt/cservergo` e `/mnt/gescon-archives`).
|
||||||
- **Da autenticato**: abilitata la schermata profilo `/admin-filament/profile` tramite `->profile()` in `AdminFilamentPanelProvider`, consentendo il cambio password autonomo direttamente dal menu utente in alto a destra.
|
- Repository Gitea (`git.netgescon.it:2222`): Sorgente centrale autoritativa del codice sorgente, rami, tag e migrazioni.
|
||||||
|
- Produzione (`svr-netgescon` / `192.168.0.157`, `app.netgescon.it`): Container Docker `netgescon_prod_app` con database PostgreSQL `prod_pgsql` (374 migrazioni attive). Riceve gli aggiornamenti del codice e delle migrazioni da Gitea. I dati operativi di produzione (utenti, ticket web, log) risiedono su PostgreSQL.
|
||||||
|
|
||||||
4. **Allineamento Utenze Google Workspace / NetGescon**:
|
4. **Nuova UI Lavorazioni Operative (`/admin-filament/fornitore/lavorazioni`) & Scheda in TAB (Non Modal)**:
|
||||||
- Utenza Workspace `michele@netgescon.it` (User ID 25): attiva con ruoli `super-admin`, `amministratore`, `admin`.
|
- Aggiornata la pagina secondo il design system moderno (KPI cards, badge di stato semantici, filtri reattivi, context toolbar).
|
||||||
- Utenza Google `netgescon@gmail.com` (User ID 35): registrata e attiva con ruolo `super-admin`.
|
- Eliminato il popup modale: il dettaglio della scheda ora vive all'interno di una **TAB in-page a larghezza intera ("Scheda Apparecchio")**, consentendo di alternare liberamente tra Elenco e Scheda senza perdere stato.
|
||||||
- Entrambe le utenze possono richiedere e ricevere la reimpostazione password o accedere in autonomia.
|
- Fedeltà grafica e funzionale a `01 schermata pricipale.PNG` di TecnoRepair:
|
||||||
|
- Header con Num. Scheda, Date (Ingresso, Orario, Cons. Prevista, Riconsegna), Stato Riparazione e Checkbox/Flags desktop (Fare Preventivo, Riparazione in sede, Riconsegnato, Rientro, Esame Tecnico, Ricons. No Ricevuta).
|
||||||
5. **Comandi Artisan di Diagnostica e Invio**:
|
- Box "Dati Cliente" in alto a destra con pulsanti rapidi WhatsApp, Telefono ed SMS.
|
||||||
- `php artisan netgescon:test-mail {email?}`: invia un'email diagnostica SMTP per testare la connettività Google Workspace.
|
- 7 Sub-Tab: `1. Apparecchio in Entrata`, `2. Riparazione & Flussi`, `3. Ricambi Utilizzati`, `4. Preventivo - Costi - DDT`, `5. Annotazioni & Cortesia`, `6. Comunicazioni`, `7. C.Q. (Controllo Qualità)`.
|
||||||
- `php artisan netgescon:send-password-reset {email}`: genera il token crittografato e invia il link di ripristino all'email richiesta.
|
- Matrice grafica 3x3 del Segno di Sblocco (Android pattern grid con 9 nodi interattivi).
|
||||||
|
- Salvataggio diretto modifiche su database (`saveActiveScheda()`) e pulsante stampa ricevuta.
|
||||||
|
- Supporto integrato anche per i Ticket Amministratore nello stesso formato Scheda.
|
||||||
|
|
||||||
## Output del Giro Operativo
|
## Output del Giro Operativo
|
||||||
|
|
||||||
ESITO_205: riuscito
|
ESITO_205: riuscito
|
||||||
TASK_ID: task-email-service-password-reset
|
TASK_ID: task-lavorazioni-tecnorepair-tab-sync
|
||||||
REPOSITORY: ssh://git@git.netgescon.it:2222/michele/netgescon-day0.git
|
REPOSITORY: ssh://git@git.netgescon.it:2222/michele/netgescon-day0.git
|
||||||
BRANCH: stabilization/205-zero
|
BRANCH: stabilization/205-zero
|
||||||
COMMIT: cfc6060
|
COMMIT: 7116305
|
||||||
FILE_O_AREE_TOCCATE:
|
FILE_O_AREE_TOCCATE:
|
||||||
- app/Console/Commands/SendPasswordResetEmailCommand.php
|
|
||||||
- app/Console/Commands/TestMailCommand.php
|
|
||||||
- app/Notifications/NetGesconResetPasswordNotification.php
|
|
||||||
- app/Models/User.php
|
|
||||||
- app/Providers/AppServiceProvider.php
|
|
||||||
- app/Providers/Filament/AdminFilamentPanelProvider.php
|
|
||||||
- config/database.php
|
|
||||||
- .gitignore
|
- .gitignore
|
||||||
- database/migrations/2025_12_22_120000_add_conto_id_to_contabilita_movimenti_banca.php
|
- app/Filament/Pages/Condomini/NominativiStabile.php
|
||||||
- database/migrations/2025_12_22_120010_add_conto_id_to_contabilita_saldi_conti.php
|
- app/Filament/Pages/Fornitore/LavorazioniOperative.php
|
||||||
- database/migrations/2026_01_05_000011_add_pagamenti_links_to_contabilita_fatture_fornitori.php
|
- app/Filament/Pages/Gescon/Ordinarie.php
|
||||||
- tests/Feature/PasswordResetAndEmailServiceTest.php
|
- app/Services/Tecnorepair/TecnoRepairArchiveService.php
|
||||||
|
- resources/views/filament/pages/affitti/gestione-affitti.blade.php
|
||||||
|
- resources/views/filament/pages/fornitore/lavorazioni-operative.blade.php
|
||||||
|
- tests/Feature/FornitoreTecnorepairAndIntegrationsTest.php
|
||||||
- skill-netgescon/control-tower/CURRENT-205.md
|
- skill-netgescon/control-tower/CURRENT-205.md
|
||||||
TEST_ESEGUITI:
|
TEST_ESEGUITI:
|
||||||
- ./vendor/bin/pest tests/Feature/PasswordResetAndEmailServiceTest.php tests/Feature/FornitoreTecnorepairAndIntegrationsTest.php tests/Feature/FornitoreContabilitaSerialiImportTest.php (13 passed, 67 assertions)
|
- ./vendor/bin/pest tests/Feature/FornitoreTecnorepairAndIntegrationsTest.php (6 passed, 54 assertions)
|
||||||
- ./vendor/bin/pest tests/Feature/PasswordResetAndEmailServiceTest.php tests/Feature/FornitoreTecnorepairAndIntegrationsTest.php tests/Feature/FornitoreContabilitaSerialiImportTest.php tests/Feature/StrutturaDatabaseAndStorageTest.php tests/Feature/NominativiAndFeMatchingTest.php tests/Feature/PostaImapWebmailAndProtocolloTest.php tests/Feature/ContabilitaRelazionaleOrdinarieTest.php tests/Feature/BpmBankParserAndImporterTest.php tests/Feature/UnitaGestioneTemporaleTest.php tests/Feature/CatastoHubDbDrivenTest.php tests/Feature/UnitaCondominoInquilinoRoleToggleTest.php tests/Feature/UnitaImmobiliarePageTest.php tests/Feature/BenedettoBonificaIdempotenteTest.php tests/Feature/ControlTowerPollCommandTest.php (46 passed, 285 assertions)
|
- ./vendor/bin/pest tests/Feature/PasswordResetAndEmailServiceTest.php tests/Feature/FornitoreTecnorepairAndIntegrationsTest.php tests/Feature/FornitoreContabilitaSerialiImportTest.php tests/Feature/StrutturaDatabaseAndStorageTest.php tests/Feature/NominativiAndFeMatchingTest.php tests/Feature/PostaImapWebmailAndProtocolloTest.php tests/Feature/ContabilitaRelazionaleOrdinarieTest.php tests/Feature/BpmBankParserAndImporterTest.php tests/Feature/UnitaGestioneTemporaleTest.php tests/Feature/CatastoHubDbDrivenTest.php tests/Feature/UnitaCondominoInquilinoRoleToggleTest.php tests/Feature/UnitaImmobiliarePageTest.php tests/Feature/BenedettoBonificaIdempotenteTest.php tests/Feature/ControlTowerPollCommandTest.php (47 passed, 299 assertions, 100% pass)
|
||||||
- Verifica migrazioni PostgreSQL su produzione (svr-netgescon): 374/374 migrazioni eseguite (NO PENDING MIGRATIONS).
|
- php artisan view:clear && php artisan view:cache (successo, zero errori)
|
||||||
- Test SMTP live su produzione: php artisan netgescon:test-mail michele@netgescon.it (email recapitata con successo).
|
|
||||||
- Test reset password live su produzione: php artisan netgescon:send-password-reset netgescon@gmail.com e michele@netgescon.it (link generati e inviati con successo).
|
|
||||||
- Test HTTP live: https://app.netgescon.it/admin-filament/login e /admin-filament/password-reset/request (HTTP 200 OK).
|
|
||||||
GATE_STATISTICS:
|
GATE_STATISTICS:
|
||||||
- SMTP_GMAIL_WORKSPACE: Connessione smtp.gmail.com:587 verificata e funzionante in locale e produzione.
|
- BLADE_COMPILATION: 100% pulita senza token inattesi.
|
||||||
- POSTGRESQL_PRODUCTION_MIGRATIONS: 100% completate senza errori di dialetto su svr-netgescon.
|
- TECNOREPAIR_RECORDS: 1874 schede importate dal live MDB (/mnt/cservergo), max legacy_id 1879, inclusa #1876.
|
||||||
- GESCON_IMPORT_ISOLATION: Configurazione SQLite isolata con fallback esplicito, eliminando il blocco MySQL greeting packet su porta 5432.
|
- LAVORAZIONI_TAB_UI: Nuova visualizzazione con TAB integrata in-page a 7 schede (no modal) e matrice di sblocco 3x3.
|
||||||
- PASSWORD_RESET_FLOW: Richiesta da login (/admin-filament/password-reset/request) e da profilo (/admin-filament/profile) operativi.
|
- TEST_SUITE: 47 test Feature passati (299 asserzioni, 100% pass).
|
||||||
- SYNC_DISPATCH: Notifiche recapitate istantaneamente senza dipendenza da code background.
|
|
||||||
- TEST_SUITE: 46 test Feature passati (285 asserzioni, 100% pass).
|
|
||||||
BLOCCO_DATI: no
|
BLOCCO_DATI: no
|
||||||
BLOCCO_CONTRATTO: no
|
BLOCCO_CONTRATTO: no
|
||||||
RISCHI_APERTI: nessuno
|
RISCHI_APERTI: nessuno
|
||||||
|
|
@ -80,6 +67,5 @@ ## Output del Giro Operativo
|
||||||
## Prossimo Passo per .200 (Validazione)
|
## Prossimo Passo per .200 (Validazione)
|
||||||
|
|
||||||
- Eseguire il checkout del branch `stabilization/205-zero`.
|
- Eseguire il checkout del branch `stabilization/205-zero`.
|
||||||
- Eseguire la suite di test Pest (46 passed, 285 assertions).
|
- Eseguire la suite di test Pest (47 passed, 299 assertions).
|
||||||
- Eseguire `php artisan netgescon:test-mail` per verificare la connettività SMTP Google.
|
- Aprire http://192.168.0.205:8000/admin-filament/fornitore/lavorazioni e verificare il nuovo layout grafico con KPI, filtri, tabella con badge di stato e apertura della Scheda Apparecchio in formato TAB a tutta pagina con la scheda 1876.
|
||||||
- Verificare la ricezione del link di reset e la modifica autonoma della password.
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Filament\Pages\Fornitore\LavorazioniOperative;
|
||||||
use App\Filament\Pages\Fornitore\PraticheTecnorepair;
|
use App\Filament\Pages\Fornitore\PraticheTecnorepair;
|
||||||
use App\Filament\Pages\Fornitore\ProdottiCatalogo;
|
use App\Filament\Pages\Fornitore\ProdottiCatalogo;
|
||||||
use App\Filament\Pages\Fornitore\SerialiCatalogo;
|
use App\Filament\Pages\Fornitore\SerialiCatalogo;
|
||||||
|
|
@ -237,3 +238,50 @@
|
||||||
expect($prodottiPage->fornitoreId)->toBe(236);
|
expect($prodottiPage->fornitoreId)->toBe(236);
|
||||||
expect($prodottiPage->getPraticheUrl())->toContain('fornitore/pratiche');
|
expect($prodottiPage->getPraticheUrl())->toContain('fornitore/pratiche');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('mounts LavorazioniOperative with unified KPI cards and renders in-page Scheda TAB without modal', function () {
|
||||||
|
$michele = User::where('email', 'michele@nethome.it')->first();
|
||||||
|
Auth::login($michele);
|
||||||
|
|
||||||
|
$page = new LavorazioniOperative();
|
||||||
|
$page->mount();
|
||||||
|
|
||||||
|
expect($page->fornitoreId)->toBe(236)
|
||||||
|
->and($page->mainTab)->toBe('elenco')
|
||||||
|
->and($page->totals['tutte'])->toBeGreaterThan(0)
|
||||||
|
->and(count($page->rows))->toBeGreaterThan(0);
|
||||||
|
|
||||||
|
// Find TecnoRepair row
|
||||||
|
$tecnorepairRow = collect($page->rows)->firstWhere('row_type', 'tecnorepair');
|
||||||
|
expect($tecnorepairRow)->not->toBeNull();
|
||||||
|
|
||||||
|
// Open detail -> must activate in-page TAB 'scheda', NOT a modal!
|
||||||
|
$page->openRowDetail('tecnorepair', (int) $tecnorepairRow['id']);
|
||||||
|
|
||||||
|
expect($page->mainTab)->toBe('scheda')
|
||||||
|
->and($page->detailModal)->toBeNull() // Confirms no modal popup is used
|
||||||
|
->and($page->activeScheda)->not->toBeNull()
|
||||||
|
->and($page->activeScheda['customer_name'])->not->toBeEmpty()
|
||||||
|
->and($page->schedaSubTab)->toBe('entrata');
|
||||||
|
|
||||||
|
// Test sub-tabs navigation
|
||||||
|
$page->setSchedaSubTab('riparazione');
|
||||||
|
expect($page->schedaSubTab)->toBe('riparazione');
|
||||||
|
|
||||||
|
// Test pattern unlock dot toggling
|
||||||
|
$initialDot = $page->unlockPattern[0];
|
||||||
|
$page->togglePatternDot(0);
|
||||||
|
expect($page->unlockPattern[0])->toBe($initialDot === 1 ? 0 : 1);
|
||||||
|
|
||||||
|
// Test saving modifications
|
||||||
|
$testDefect = 'TEST DIFETTO AGGIORNATO ' . uniqid();
|
||||||
|
$page->schedaForm['difetto_segnalato'] = $testDefect;
|
||||||
|
$page->saveActiveScheda();
|
||||||
|
|
||||||
|
$reloaded = AssistenzaTecnorepairScheda::find((int) $tecnorepairRow['id']);
|
||||||
|
expect($reloaded->defect_reported)->toBe($testDefect);
|
||||||
|
|
||||||
|
// Test close -> back to elenco tab
|
||||||
|
$page->closeScheda();
|
||||||
|
expect($page->mainTab)->toBe('elenco');
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user