Refine water services and bank movement views
This commit is contained in:
parent
6ac70ce38e
commit
e9cf216fa4
|
|
@ -4,6 +4,7 @@ # Changelog
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
- Surfaced ACQUA invoices in the servizi-utenze area even when the supplier is only flagged via FE water features, compacted the supplier scheda actions into a single toolbar without page-level horizontal overflow, standardized the bank movements grid to the requested visible columns with a richer raw-data modal, and made affitti canoni start from the effective management takeover date.
|
||||
- Reworked the banking operations hub so the topbar stays full-width, the sidebar stays fixed below it, the movements tab remains focused on imported/manual bank movements, and archive or gestione structure moved into a dedicated tab. The same slice also added first-pass QIF cleanup metadata for CBILL, SIA, commissions and provider hints, plus stronger bank-to-supplier matching and ACQ assignment for water invoices extracted from FE/PDF data.
|
||||
- Fixed document archive visibility queries to work safely even when single-user ACL columns are not yet present in older databases, and added the missing `documenti.allowed_user_ids` schema field for per-document access control.
|
||||
- Restored a cleaner two-column layout in Post-it Gestione boards and hid visual noise from calls that terminate on internal response group `601` while keeping the underlying records in the system.
|
||||
|
|
|
|||
|
|
@ -621,6 +621,7 @@ private function loadAffitti(): void
|
|||
'nome_inquilino' => $a->nome_inquilino,
|
||||
'proprietario_nome' => $a->proprietario_nome,
|
||||
'inizio_contratto' => $a->inizio_contratto,
|
||||
'presa_in_carico_operativa_dal' => $a->presa_in_carico_operativa_dal,
|
||||
'prossima_registrazione' => $a->prossima_registrazione,
|
||||
'tipo_riga' => $a->tipo_riga,
|
||||
'stabile_id' => $a->stabile_id,
|
||||
|
|
@ -657,12 +658,44 @@ private function buildAffittoWarnings(AffittoImmobile $affitto): array
|
|||
}
|
||||
}
|
||||
|
||||
$managementStart = $this->resolveCanoniManagementStart($affitto);
|
||||
|
||||
$scadutiNonPagati = AffittoCanoneDovuto::query()
|
||||
->where('affitto_id', $affitto->id)
|
||||
->when($managementStart, function ($query) use ($managementStart) {
|
||||
$query->where(function ($inner) use ($managementStart) {
|
||||
$inner->whereDate('data_scadenza', '>=', $managementStart->toDateString())
|
||||
->orWhere(function ($fallback) use ($managementStart) {
|
||||
$fallback->whereNull('data_scadenza')
|
||||
->where(function ($monthQuery) use ($managementStart) {
|
||||
$monthQuery->where('anno', '>', (int) $managementStart->year)
|
||||
->orWhere(function ($sameYear) use ($managementStart) {
|
||||
$sameYear->where('anno', (int) $managementStart->year)
|
||||
->where('mese', '>=', (int) $managementStart->month);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
->whereDate('data_scadenza', '<', $today->toDateString())
|
||||
->sum('totale')
|
||||
- AffittoCanonePagato::query()
|
||||
->where('affitto_id', $affitto->id)
|
||||
->when($managementStart, function ($query) use ($managementStart) {
|
||||
$query->where(function ($inner) use ($managementStart) {
|
||||
$inner->whereDate('data_pagamento', '>=', $managementStart->toDateString())
|
||||
->orWhere(function ($fallback) use ($managementStart) {
|
||||
$fallback->whereNull('data_pagamento')
|
||||
->where(function ($monthQuery) use ($managementStart) {
|
||||
$monthQuery->where('anno', '>', (int) $managementStart->year)
|
||||
->orWhere(function ($sameYear) use ($managementStart) {
|
||||
$sameYear->where('anno', (int) $managementStart->year)
|
||||
->where('mese', '>=', (int) $managementStart->month);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
->whereDate('data_pagamento', '<=', $today->toDateString())
|
||||
->sum('totale');
|
||||
|
||||
|
|
@ -786,6 +819,7 @@ private function loadSelected(): void
|
|||
'numero_registrazione_ade' => null,
|
||||
'data_registrazione_ade' => null,
|
||||
'inizio_contratto' => null,
|
||||
'presa_in_carico_operativa_dal' => null,
|
||||
'ultimo_rinnovo' => null,
|
||||
'prossima_scadenza' => null,
|
||||
'prossima_registrazione' => null,
|
||||
|
|
@ -852,8 +886,9 @@ private function loadSelected(): void
|
|||
$this->ensureRicevute($record, $dovuti);
|
||||
$pagati = AffittoCanonePagato::where('affitto_id', $record->id)->orderByDesc('anno')->orderByDesc('mese')->get();
|
||||
|
||||
if (! empty($record->inizio_contratto)) {
|
||||
$start = Carbon::parse($record->inizio_contratto)->startOfMonth();
|
||||
$managementStart = $this->resolveCanoniManagementStart($record);
|
||||
if ($managementStart) {
|
||||
$start = $managementStart->copy()->startOfMonth();
|
||||
$dovuti = $dovuti->filter(function (AffittoCanoneDovuto $row) use ($start) {
|
||||
$month = Carbon::create((int) $row->anno, (int) $row->mese, 1);
|
||||
return $month->gte($start);
|
||||
|
|
@ -1219,11 +1254,12 @@ private function emitCanoniAutomaticiForRecord(AffittoImmobile $record): int
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (empty($record->inizio_contratto)) {
|
||||
$managementStart = $this->resolveCanoniManagementStart($record);
|
||||
if (! $managementStart) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$start = Carbon::parse($record->inizio_contratto)->startOfMonth();
|
||||
$start = $managementStart->copy()->startOfMonth();
|
||||
$todayMonth = Carbon::today()->startOfMonth();
|
||||
$end = $todayMonth;
|
||||
|
||||
|
|
@ -1406,6 +1442,31 @@ private function emitCanoniAutomaticiForRecord(AffittoImmobile $record): int
|
|||
return $created;
|
||||
}
|
||||
|
||||
private function resolveCanoniManagementStart(AffittoImmobile $record): ?Carbon
|
||||
{
|
||||
$dates = [];
|
||||
|
||||
if (! empty($record->inizio_contratto)) {
|
||||
$dates[] = Carbon::parse($record->inizio_contratto)->startOfMonth();
|
||||
}
|
||||
|
||||
if (! empty($record->presa_in_carico_operativa_dal)) {
|
||||
$dates[] = Carbon::parse($record->presa_in_carico_operativa_dal)->startOfMonth();
|
||||
}
|
||||
|
||||
if ($record->stabile && $record->stabile->latestAmministratoreTransfer?->created_at) {
|
||||
$dates[] = $record->stabile->latestAmministratoreTransfer->created_at->copy()->startOfMonth();
|
||||
}
|
||||
|
||||
if ($dates === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
usort($dates, fn(Carbon $left, Carbon $right): int => $left->getTimestamp() <=> $right->getTimestamp());
|
||||
|
||||
return $dates[count($dates) - 1];
|
||||
}
|
||||
|
||||
private function resolveIstatQuotaFromClause(AffittoContrattoClausola $clausola): float
|
||||
{
|
||||
$content = trim((string) ($clausola->titolo ?? '') . ' ' . (string) ($clausola->testo ?? ''));
|
||||
|
|
|
|||
|
|
@ -1429,6 +1429,32 @@ public function getAcquaFatturePerGestioneProperty(): array
|
|||
->values()
|
||||
->all();
|
||||
|
||||
if (Schema::hasTable('fornitori') && Schema::hasColumn('fornitori', 'fe_features')) {
|
||||
$waterEnabledSupplierIds = Fornitore::query()
|
||||
->where(function (Builder $query) use ($stabileId): Builder {
|
||||
return $query->whereExists(function ($subQuery) use ($stabileId) {
|
||||
$subQuery->selectRaw('1')
|
||||
->from('fatture_elettroniche as fe')
|
||||
->whereColumn('fe.fornitore_id', 'fornitori.id')
|
||||
->where('fe.stabile_id', $stabileId);
|
||||
})->orWhereExists(function ($subQuery) use ($stabileId) {
|
||||
$subQuery->selectRaw('1')
|
||||
->from('contabilita_fatture_fornitori as cff')
|
||||
->whereColumn('cff.fornitore_id', 'fornitori.id')
|
||||
->where('cff.stabile_id', $stabileId);
|
||||
});
|
||||
})
|
||||
->whereRaw("JSON_EXTRACT(fe_features, '$.acqua.enabled') = true")
|
||||
->pluck('id')
|
||||
->map(fn($v) => (int) $v)
|
||||
->filter(fn($v) => $v > 0)
|
||||
->unique()
|
||||
->values()
|
||||
->all();
|
||||
|
||||
$fornitoreIds = array_values(array_unique(array_merge($fornitoreIds, $waterEnabledSupplierIds)));
|
||||
}
|
||||
|
||||
if ($fornitoreIds !== []) {
|
||||
$contabili = DB::table('contabilita_fatture_fornitori as f')
|
||||
->leftJoin('gestioni_contabili as g', 'g.id', '=', 'f.gestione_id')
|
||||
|
|
|
|||
|
|
@ -1305,149 +1305,6 @@ public function table(Table $table): Table
|
|||
}),
|
||||
])
|
||||
->columns([
|
||||
TextColumn::make('codice_descrizione')
|
||||
->label('Codice')
|
||||
->state(function (MovimentoBanca $record): string {
|
||||
$descr = (string) ($record->descrizione ?? '');
|
||||
$raw = strtoupper($descr);
|
||||
if (str_contains($raw, 'ACCREDITO_BEU_CON_CONTABILE')) {
|
||||
return 'ACCBEUCONCON';
|
||||
}
|
||||
if (str_contains($raw, 'COMBONMYB')) {
|
||||
return 'COMBONMYB';
|
||||
}
|
||||
$raw = preg_replace('/[^A-Z0-9]+/', ' ', $raw) ?? $raw;
|
||||
$parts = array_filter(explode(' ', $raw), fn($v) => $v !== '');
|
||||
if (! empty($parts)) {
|
||||
$code = '';
|
||||
foreach ($parts as $p) {
|
||||
$chunk = substr($p, 0, 3);
|
||||
$code .= $chunk;
|
||||
if (strlen($code) >= 12) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$code = substr($code, 0, 12);
|
||||
if ($code !== '') {
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
$raw = preg_replace('/[^A-Z0-9]+/', '_', $raw) ?? $raw;
|
||||
$raw = trim($raw, '_');
|
||||
$raw = preg_replace('/_+/', '_', $raw) ?? $raw;
|
||||
return mb_substr($raw, 0, 32);
|
||||
})
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('disp')
|
||||
->label('Disp')
|
||||
->state(function (MovimentoBanca $record): string {
|
||||
$match = is_array($record->match_data ?? null) ? $record->match_data : [];
|
||||
$disp = $match['cod_disp'] ?? null;
|
||||
return is_string($disp) ? trim($disp) : '';
|
||||
})
|
||||
->toggleable(),
|
||||
TextColumn::make('cash')
|
||||
->label('Cash')
|
||||
->state(function (MovimentoBanca $record): string {
|
||||
$match = is_array($record->match_data ?? null) ? $record->match_data : [];
|
||||
$cash = $match['cash'] ?? null;
|
||||
return is_string($cash) ? trim($cash) : '';
|
||||
})
|
||||
->toggleable(),
|
||||
TextColumn::make('mittente')
|
||||
->label('Mittente')
|
||||
->state(function (MovimentoBanca $record): string {
|
||||
$match = is_array($record->match_data ?? null) ? $record->match_data : [];
|
||||
$mitt = $match['mittente'] ?? null;
|
||||
return is_string($mitt) ? trim($mitt) : '';
|
||||
})
|
||||
->wrap()
|
||||
->toggleable(),
|
||||
BadgeColumn::make('commissioni')
|
||||
->label('Comm.')
|
||||
->getStateUsing(function (MovimentoBanca $record): string {
|
||||
$raw = strtoupper((string) ($record->descrizione ?? ''));
|
||||
return str_contains($raw, 'COMBONMYB') ? 'si' : 'no';
|
||||
})
|
||||
->colors([
|
||||
'success' => 'si',
|
||||
'gray' => 'no',
|
||||
])
|
||||
->formatStateUsing(fn(string $state): string => $state === 'si' ? 'SI' : '—')
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
TextColumn::make('disp')
|
||||
->label('Disp')
|
||||
->state(function (MovimentoBanca $record): string {
|
||||
$match = is_array($record->match_data ?? null) ? $record->match_data : [];
|
||||
$disp = $match['cod_disp'] ?? null;
|
||||
return is_string($disp) ? trim($disp) : '';
|
||||
})
|
||||
->toggleable(),
|
||||
BadgeColumn::make('da_confermare')
|
||||
->label('Conferma')
|
||||
->getStateUsing(fn(MovimentoBanca $record): string => ! empty($record->da_confermare) ? 'da_confermare' : 'ok')
|
||||
->colors([
|
||||
'warning' => 'da_confermare',
|
||||
'success' => 'ok',
|
||||
])
|
||||
->formatStateUsing(fn(string $state): string => $state === 'da_confermare' ? 'DA CONF.' : 'OK')
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
|
||||
BadgeColumn::make('stato_quadratura')
|
||||
->label('Stato')
|
||||
->getStateUsing(fn(MovimentoBanca $record): string => $this->resolveStatoQuadratura($record))
|
||||
->colors([
|
||||
'gray' => 'non_collegato',
|
||||
'warning' => 'collegato_non_quadrato',
|
||||
'success' => 'quadrato',
|
||||
])
|
||||
->formatStateUsing(function (string $state): string {
|
||||
return match ($state) {
|
||||
'quadrato' => 'OK',
|
||||
'collegato_non_quadrato' => 'ATT',
|
||||
default => 'NO',
|
||||
};
|
||||
})
|
||||
->sortable(false),
|
||||
|
||||
TextColumn::make('voci_collegate')
|
||||
->label('Voce spesa')
|
||||
->state(function (MovimentoBanca $record): string {
|
||||
if (! $record->registrazione_id || ! Schema::hasColumn('contabilita_movimenti', 'voce_spesa_id')) {
|
||||
return '—';
|
||||
}
|
||||
|
||||
static $cache = [];
|
||||
$regId = (int) $record->registrazione_id;
|
||||
if (array_key_exists($regId, $cache)) {
|
||||
return $cache[$regId];
|
||||
}
|
||||
|
||||
$rows = DB::table('contabilita_movimenti as m')
|
||||
->leftJoin('voci_spesa as v', 'v.id', '=', 'm.voce_spesa_id')
|
||||
->where('m.registrazione_id', $regId)
|
||||
->whereNotNull('m.voce_spesa_id')
|
||||
->select('v.codice', 'v.descrizione')
|
||||
->distinct()
|
||||
->limit(5)
|
||||
->get();
|
||||
|
||||
if ($rows->isEmpty()) {
|
||||
return $cache[$regId] = '—';
|
||||
}
|
||||
|
||||
$labels = [];
|
||||
foreach ($rows as $row) {
|
||||
$code = trim((string) ($row->codice ?? ''));
|
||||
$desc = trim((string) ($row->descrizione ?? ''));
|
||||
$labels[] = $code !== '' ? ($code . ($desc !== '' ? ' · ' . $desc : '')) : ($desc !== '' ? $desc : 'Voce');
|
||||
}
|
||||
|
||||
return $cache[$regId] = implode(' | ', array_values(array_unique($labels)));
|
||||
})
|
||||
->wrap()
|
||||
->toggleable(),
|
||||
|
||||
TextColumn::make('data')
|
||||
->label('Data')
|
||||
->date('d/m/Y')
|
||||
|
|
@ -1455,8 +1312,10 @@ public function table(Table $table): Table
|
|||
|
||||
TextColumn::make('valuta')
|
||||
->label('Valuta')
|
||||
->date('d/m/Y')
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
->date('d/m/Y'),
|
||||
|
||||
TextColumn::make('causale')
|
||||
->label('Caus'),
|
||||
|
||||
TextColumn::make('descrizione')
|
||||
->label('Descrizione')
|
||||
|
|
@ -1466,7 +1325,8 @@ public function table(Table $table): Table
|
|||
|
||||
TextColumn::make('gestioneContabile.denominazione')
|
||||
->label('Gestione')
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
->toggleable(isToggledHiddenByDefault: true)
|
||||
->toggledHiddenByDefault(),
|
||||
|
||||
TextColumn::make('entrate')
|
||||
->label('Entrate')
|
||||
|
|
@ -1492,17 +1352,14 @@ public function table(Table $table): Table
|
|||
->toggleable(isToggledHiddenByDefault: true)
|
||||
->formatStateUsing(fn($state) => '€ ' . number_format((float) $state, 2, ',', '.')),
|
||||
|
||||
TextColumn::make('causale')
|
||||
->label('Caus.')
|
||||
->toggleable(),
|
||||
|
||||
TextColumn::make('iban')
|
||||
->label('IBAN')
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
->toggleable(isToggledHiddenByDefault: true)
|
||||
->toggledHiddenByDefault(),
|
||||
])
|
||||
->actions([
|
||||
Action::make('dettaglio_movimento')
|
||||
->label('Dettaglio')
|
||||
->label('Apri dati')
|
||||
->icon('heroicon-o-eye')
|
||||
->modalWidth('7xl')
|
||||
->action(function (MovimentoBanca $record): void {
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class AffittoImmobile extends Model
|
|||
'numero_registrazione_ade',
|
||||
'data_registrazione_ade',
|
||||
'inizio_contratto',
|
||||
'presa_in_carico_operativa_dal',
|
||||
'ultimo_rinnovo',
|
||||
'prossima_scadenza',
|
||||
'prossima_registrazione',
|
||||
|
|
@ -77,6 +78,7 @@ class AffittoImmobile extends Model
|
|||
'data_registrazione_ade' => 'date',
|
||||
'obsoleto' => 'boolean',
|
||||
'obsoleto_dal' => 'date',
|
||||
'presa_in_carico_operativa_dal' => 'date',
|
||||
'giorno_emissione_canone' => 'integer',
|
||||
'mese_adempimenti_annuali' => 'integer',
|
||||
'giorno_adempimenti_annuali' => 'integer',
|
||||
|
|
|
|||
|
|
@ -23,10 +23,18 @@
|
|||
<div class="text-gray-500">Data</div>
|
||||
<div class="font-semibold">{{ optional($record->data)->format('d/m/Y') ?: '—' }}</div>
|
||||
</div>
|
||||
<div class="rounded-lg border bg-white p-3 text-xs">
|
||||
<div class="text-gray-500">Valuta</div>
|
||||
<div class="font-semibold">{{ optional($record->valuta)->format('d/m/Y') ?: '—' }}</div>
|
||||
</div>
|
||||
<div class="rounded-lg border bg-white p-3 text-xs">
|
||||
<div class="text-gray-500">Importo</div>
|
||||
<div class="font-semibold">€ {{ number_format((float) $record->importo, 2, ',', '.') }}</div>
|
||||
</div>
|
||||
<div class="rounded-lg border bg-white p-3 text-xs">
|
||||
<div class="text-gray-500">Causale</div>
|
||||
<div class="font-semibold">{{ $record->causale ?? '—' }}</div>
|
||||
</div>
|
||||
<div class="rounded-lg border bg-white p-3 text-xs">
|
||||
<div class="text-gray-500">Descrizione</div>
|
||||
<div class="font-semibold">{{ $record->descrizione ?? '—' }}</div>
|
||||
|
|
@ -35,6 +43,20 @@
|
|||
<div class="text-gray-500">Descrizione estesa</div>
|
||||
<div class="font-semibold">{{ $record->descrizione_estesa_pulita ?? $record->descrizione_estesa ?? '—' }}</div>
|
||||
</div>
|
||||
<div class="rounded-lg border bg-white p-3 text-xs">
|
||||
<div class="text-gray-500">Saldo progressivo</div>
|
||||
<div class="font-semibold">
|
||||
@if(isset($record->saldo_progressivo) && is_numeric($record->saldo_progressivo))
|
||||
€ {{ number_format((float) $record->saldo_progressivo, 2, ',', '.') }}
|
||||
@else
|
||||
—
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="rounded-lg border bg-white p-3 text-xs">
|
||||
<div class="text-gray-500">File sorgente</div>
|
||||
<div class="font-semibold">{{ $record->source_file ?? '—' }}</div>
|
||||
</div>
|
||||
<div class="rounded-lg border bg-white p-3 text-xs">
|
||||
<div class="text-gray-500">Disp</div>
|
||||
<div class="font-semibold">{{ is_array($record->match_data ?? null) ? ($record->match_data['cod_disp'] ?? '—') : '—' }}</div>
|
||||
|
|
@ -47,6 +69,10 @@
|
|||
<div class="text-gray-500">Mittente</div>
|
||||
<div class="font-semibold">{{ is_array($record->match_data ?? null) ? ($record->match_data['mittente'] ?? '—') : '—' }}</div>
|
||||
</div>
|
||||
<div class="rounded-lg border bg-white p-3 text-xs md:col-span-2">
|
||||
<div class="text-gray-500">Riga raw importata</div>
|
||||
<div class="font-semibold break-words">{{ $record->raw_line ?? '—' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@php
|
||||
|
|
@ -63,10 +89,5 @@
|
|||
</div>
|
||||
@endif
|
||||
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<x-filament::button size="sm" color="primary" disabled>Conferma</x-filament::button>
|
||||
<x-filament::button size="sm" color="gray" disabled>Genera prima nota</x-filament::button>
|
||||
<x-filament::button size="sm" color="gray" disabled>Paga fornitore</x-filament::button>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
|
|
|||
|
|
@ -7,9 +7,21 @@
|
|||
'catalogo' => 'Catalogo e prodotti',
|
||||
'contabilita' => 'Contabilita',
|
||||
];
|
||||
$catalogoActions = [
|
||||
['action' => 'nuovo_prodotto', 'label' => 'Nuovo prodotto', 'color' => 'gray'],
|
||||
['action' => 'estrai_prodotti_fe', 'label' => 'Estrai da FE', 'color' => 'primary'],
|
||||
['action' => 'importa_listino_csv', 'label' => 'Importa listino CSV', 'color' => 'success'],
|
||||
['action' => 'scarica_asset_catalogo', 'label' => 'Internalizza asset', 'color' => 'warning'],
|
||||
['action' => 'genera_referral_amazon', 'label' => 'Prepara link Amazon', 'color' => 'gray'],
|
||||
];
|
||||
$assistenzaActions = [
|
||||
['action' => 'impostazioni_fe', 'label' => 'Impostazioni FE', 'color' => 'gray'],
|
||||
['action' => 'acqua_config', 'label' => 'Configura acqua', 'color' => 'gray'],
|
||||
['action' => 'acqua_scan', 'label' => 'Scansiona FE acqua', 'color' => 'primary'],
|
||||
];
|
||||
@endphp
|
||||
|
||||
<div class="space-y-6" x-data="{ tab: @js($this->sectionTab) }">
|
||||
<div class="space-y-6 overflow-x-hidden" x-data="{ tab: @js($this->sectionTab) }">
|
||||
<div class="rounded-xl border bg-white p-4">
|
||||
<div class="flex flex-wrap items-start justify-between gap-4">
|
||||
<div>
|
||||
|
|
@ -41,6 +53,37 @@ class="inline-flex items-center rounded-full px-4 py-2 text-sm font-medium"
|
|||
Qui restano visibili modulo fornitore e catalogo operativo. Il magazzino e la gestione completa del prodotto possono essere spostati in menu dedicati mantenendo qui il quadro sintetico e i collegamenti rapidi.
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-slate-200 bg-white p-4" x-show="tab === 'catalogo' || tab === 'assistenza'" x-cloak>
|
||||
<div class="flex flex-wrap items-start justify-between gap-3">
|
||||
<div>
|
||||
<div class="text-sm font-semibold text-slate-900" x-show="tab === 'catalogo'">Azioni catalogo</div>
|
||||
<div class="text-sm font-semibold text-slate-900" x-show="tab === 'assistenza'">Azioni automazioni</div>
|
||||
<div class="mt-1 text-xs text-slate-500" x-show="tab === 'catalogo'">Un solo punto per le azioni operative del catalogo, senza duplicarle in più riquadri.</div>
|
||||
<div class="mt-1 text-xs text-slate-500" x-show="tab === 'assistenza'">FE e acqua raccolte in una toolbar compatta, così la colonna destra non spinge più il layout.</div>
|
||||
</div>
|
||||
<div class="flex max-w-full flex-wrap justify-end gap-2">
|
||||
@foreach($catalogoActions as $action)
|
||||
<x-filament::button
|
||||
x-show="tab === 'catalogo'"
|
||||
size="sm"
|
||||
:color="$action['color']"
|
||||
type="button"
|
||||
wire:click="mountAction('{{ $action['action'] }}')"
|
||||
>{{ $action['label'] }}</x-filament::button>
|
||||
@endforeach
|
||||
@foreach($assistenzaActions as $action)
|
||||
<x-filament::button
|
||||
x-show="tab === 'assistenza'"
|
||||
size="sm"
|
||||
:color="$action['color']"
|
||||
type="button"
|
||||
wire:click="mountAction('{{ $action['action'] }}')"
|
||||
>{{ $action['label'] }}</x-filament::button>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-900" x-show="tab === 'assistenza'" x-cloak>
|
||||
Questa tab concentra TecnoRepair, seriali e automazioni collegate al fornitore. I ticket operativi e il protocollo comunicazioni possono poi evolvere come viste dedicate, senza ricadere in una scheda unica confusa.
|
||||
</div>
|
||||
|
|
@ -49,8 +92,8 @@ class="inline-flex items-center rounded-full px-4 py-2 text-sm font-medium"
|
|||
Qui si prepara il perimetro economico del fornitore: pagamenti, fatture, anteprime contabili e ritenute. Preventivi, ordini e fatturazione completa possono innestarsi in questa area senza mischiarsi con catalogo o assistenza.
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-6 lg:grid-cols-3">
|
||||
<div class="space-y-6 lg:col-span-2">
|
||||
<div class="grid min-w-0 grid-cols-1 gap-6 lg:grid-cols-3">
|
||||
<div class="min-w-0 space-y-6 lg:col-span-2">
|
||||
<div class="rounded-lg border p-4" x-show="tab === 'profilo'" x-cloak>
|
||||
<div class="text-lg font-semibold">Fornitore</div>
|
||||
<div class="mt-2 grid grid-cols-1 gap-2 md:grid-cols-2">
|
||||
|
|
@ -261,13 +304,6 @@ class="inline-flex items-center rounded-full px-4 py-2 text-sm font-medium"
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex flex-wrap gap-2">
|
||||
<x-filament::button size="sm" color="gray" type="button" wire:click="mountAction('nuovo_prodotto')">Nuovo prodotto</x-filament::button>
|
||||
<x-filament::button size="sm" color="primary" type="button" wire:click="mountAction('estrai_prodotti_fe')">Estrai da FE</x-filament::button>
|
||||
<x-filament::button size="sm" color="success" type="button" wire:click="mountAction('importa_listino_csv')">Importa listino CSV</x-filament::button>
|
||||
<x-filament::button size="sm" color="warning" type="button" wire:click="mountAction('scarica_asset_catalogo')">Internalizza asset</x-filament::button>
|
||||
<x-filament::button size="sm" color="gray" type="button" wire:click="mountAction('genera_referral_amazon')">Prepara link Amazon</x-filament::button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4" x-show="tab === 'catalogo'" x-cloak>
|
||||
|
|
@ -276,13 +312,7 @@ class="inline-flex items-center rounded-full px-4 py-2 text-sm font-medium"
|
|||
<div class="text-lg font-semibold">Catalogo operativo interno</div>
|
||||
<div class="mt-1 text-xs text-gray-500">Anagrafica prodotti/servizi del fornitore. I riferimenti esterni importati restano interni al gestionale e la pubblicazione usa il codice interno del catalogo.</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<x-filament::button size="sm" color="gray" type="button" wire:click="mountAction('nuovo_prodotto')">Nuovo prodotto</x-filament::button>
|
||||
<x-filament::button size="sm" color="primary" type="button" wire:click="mountAction('estrai_prodotti_fe')">Estrai da FE</x-filament::button>
|
||||
<x-filament::button size="sm" color="success" type="button" wire:click="mountAction('importa_listino_csv')">Importa CSV</x-filament::button>
|
||||
<x-filament::button size="sm" color="warning" type="button" wire:click="mountAction('scarica_asset_catalogo')">Asset interni</x-filament::button>
|
||||
<x-filament::button size="sm" color="gray" type="button" wire:click="mountAction('genera_referral_amazon')">Amazon</x-filament::button>
|
||||
</div>
|
||||
<div class="rounded-md bg-slate-100 px-3 py-2 text-xs text-slate-600">Le azioni operative sono state raccolte sopra.</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 grid grid-cols-2 gap-3 md:grid-cols-4">
|
||||
|
|
@ -457,7 +487,7 @@ class="w-full rounded-lg border-gray-300 text-sm"
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-6">
|
||||
<div class="min-w-0 space-y-6">
|
||||
@php
|
||||
$features = is_array($box['fornitore_features'] ?? null) ? $box['fornitore_features'] : [];
|
||||
$acqua = is_array($features['acqua'] ?? null) ? $features['acqua'] : [];
|
||||
|
|
@ -537,17 +567,7 @@ class="w-full rounded-lg border-gray-300 text-sm"
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex flex-col gap-2">
|
||||
<x-filament::button type="button" color="gray" wire:click="mountAction('impostazioni_fe')">
|
||||
Impostazioni FE
|
||||
</x-filament::button>
|
||||
<x-filament::button type="button" color="gray" wire:click="mountAction('acqua_config')">
|
||||
Configura acqua
|
||||
</x-filament::button>
|
||||
<x-filament::button type="button" color="primary" wire:click="mountAction('acqua_scan')">
|
||||
Scansiona FE acqua
|
||||
</x-filament::button>
|
||||
</div>
|
||||
<div class="mt-4 rounded-md bg-slate-100 px-3 py-2 text-xs text-slate-600">Le azioni FE/acqua sono state raccolte nella toolbar in alto.</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-4" x-show="tab === 'contabilita'" x-cloak>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user