Stabilize supplier ops and strict legacy sync
This commit is contained in:
parent
f1836763ae
commit
09022d5753
584
app/Console/Commands/GesconSyncOrdinariaPreventivoCommand.php
Normal file
584
app/Console/Commands/GesconSyncOrdinariaPreventivoCommand.php
Normal file
|
|
@ -0,0 +1,584 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class GesconSyncOrdinariaPreventivoCommand extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'gescon:sync-ordinaria-preventivo
|
||||||
|
{stabile_code : Codice stabile legacy, es. 0023}
|
||||||
|
{year : Anno gestione, es. 2025}
|
||||||
|
{--stabile-id= : ID stabile NetGescon se gia noto}
|
||||||
|
{--gestione-id= : ID gestione contabile ordinaria se gia noto}';
|
||||||
|
|
||||||
|
protected $description = 'Sincronizza in modo rigoroso preventivo ordinario, tabelle millesimali e dettagli da gescon_import per uno stabile/anno specifici';
|
||||||
|
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
$stableCode = trim((string) $this->argument('stabile_code'));
|
||||||
|
$year = (int) $this->argument('year');
|
||||||
|
|
||||||
|
if ($stableCode === '' || $year < 1900) {
|
||||||
|
$this->error('Parametri non validi.');
|
||||||
|
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stableId = $this->resolveStableId($stableCode);
|
||||||
|
$gestioneId = $this->resolveGestioneId($stableId, $year);
|
||||||
|
$legacyVoci = $this->loadLegacyVoci($stableCode, $year);
|
||||||
|
|
||||||
|
if ($legacyVoci->isEmpty()) {
|
||||||
|
$this->error('Nessuna voce legacy ordinaria trovata per stabile ' . $stableCode . ' anno ' . $year . '.');
|
||||||
|
|
||||||
|
return self::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tableCodes = $legacyVoci
|
||||||
|
->pluck('tabella')
|
||||||
|
->filter(fn ($value): bool => is_string($value) && trim($value) !== '')
|
||||||
|
->map(fn (string $value): string => trim($value))
|
||||||
|
->unique()
|
||||||
|
->values();
|
||||||
|
|
||||||
|
$legacyDetails = $this->loadLegacyDettagli($stableCode, $year, $tableCodes);
|
||||||
|
$legacyHeaders = $this->loadLegacyTableHeaders($stableCode, $tableCodes);
|
||||||
|
|
||||||
|
DB::transaction(function () use ($stableCode, $stableId, $year, $gestioneId, $legacyVoci, $legacyDetails, $tableCodes, $legacyHeaders): void {
|
||||||
|
$this->ensureLegacyUnitCoverage($stableCode, $stableId, $legacyDetails);
|
||||||
|
$tableMap = $this->syncTabelleMillesimali($stableId, $year, $tableCodes, $legacyDetails, $legacyHeaders);
|
||||||
|
$this->syncDettagliMillesimali($stableId, $year, $legacyDetails, $tableMap);
|
||||||
|
$this->syncVociSpesa($stableId, $gestioneId, $year, $legacyVoci, $tableMap);
|
||||||
|
});
|
||||||
|
|
||||||
|
$totalBudget = (float) DB::table('voci_spesa')
|
||||||
|
->where('stabile_id', $stableId)
|
||||||
|
->where('gestione_contabile_id', $gestioneId)
|
||||||
|
->sum('importo_default');
|
||||||
|
|
||||||
|
$this->info('Sync completato per stabile ' . $stableCode . ' anno ' . $year . '.');
|
||||||
|
$this->line('Gestione ordinaria: #' . $gestioneId);
|
||||||
|
$this->line('Voci spesa sincronizzate: ' . DB::table('voci_spesa')->where('stabile_id', $stableId)->where('gestione_contabile_id', $gestioneId)->count());
|
||||||
|
$this->line('Tabelle millesimali sincronizzate: ' . DB::table('tabelle_millesimali')->where('stabile_id', $stableId)->where('anno_gestione', $year)->count());
|
||||||
|
$this->line('Totale preventivo importato: ' . number_format($totalBudget, 2, '.', ''));
|
||||||
|
|
||||||
|
return self::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resolveStableId(string $stableCode): int
|
||||||
|
{
|
||||||
|
$optionStableId = $this->option('stabile-id');
|
||||||
|
if (is_numeric($optionStableId) && (int) $optionStableId > 0) {
|
||||||
|
return (int) $optionStableId;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = DB::table('stabili');
|
||||||
|
$stable = $query
|
||||||
|
->where('codice_stabile', $stableCode)
|
||||||
|
->orWhere('codice_stabile', ltrim($stableCode, '0'))
|
||||||
|
->orderBy('id')
|
||||||
|
->first(['id']);
|
||||||
|
|
||||||
|
if (! $stable) {
|
||||||
|
throw new \RuntimeException('Stabile NetGescon non trovato per codice ' . $stableCode . '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) $stable->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resolveGestioneId(int $stableId, int $year): int
|
||||||
|
{
|
||||||
|
$optionGestioneId = $this->option('gestione-id');
|
||||||
|
if (is_numeric($optionGestioneId) && (int) $optionGestioneId > 0) {
|
||||||
|
return (int) $optionGestioneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gestione = DB::table('gestioni_contabili')
|
||||||
|
->where('stabile_id', $stableId)
|
||||||
|
->where('anno_gestione', $year)
|
||||||
|
->where('tipo_gestione', 'ordinaria')
|
||||||
|
->orderByDesc('gestione_attiva')
|
||||||
|
->orderByDesc('id')
|
||||||
|
->first(['id']);
|
||||||
|
|
||||||
|
if (! $gestione) {
|
||||||
|
throw new \RuntimeException('Gestione ordinaria non trovata per stabile #' . $stableId . ' anno ' . $year . '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) $gestione->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadLegacyVoci(string $stableCode, int $year): Collection
|
||||||
|
{
|
||||||
|
return DB::connection('gescon_import')
|
||||||
|
->table('voc_spe')
|
||||||
|
->where('cod_stabile', $stableCode)
|
||||||
|
->where('legacy_year', $year)
|
||||||
|
->where(function ($query): void {
|
||||||
|
$query->where('v_ors', 'O')->orWhereNull('v_ors');
|
||||||
|
})
|
||||||
|
->orderBy('tabella')
|
||||||
|
->orderBy('cod')
|
||||||
|
->get([
|
||||||
|
'cod',
|
||||||
|
'descriz',
|
||||||
|
'tabella',
|
||||||
|
'preventivo_euro',
|
||||||
|
'consuntivo_euro',
|
||||||
|
'perc_proprietario',
|
||||||
|
'perc_inquilino',
|
||||||
|
'note',
|
||||||
|
'v_ors',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function loadLegacyDettagli(string $stableCode, int $year, Collection $tableCodes): Collection
|
||||||
|
{
|
||||||
|
return DB::connection('gescon_import')
|
||||||
|
->table('dett_tab')
|
||||||
|
->where('cod_stabile', $stableCode)
|
||||||
|
->where('legacy_year', $year)
|
||||||
|
->whereIn('cod_tab', $tableCodes->all())
|
||||||
|
->orderBy('cod_tab')
|
||||||
|
->orderBy('id_cond')
|
||||||
|
->orderBy('cond_inquil')
|
||||||
|
->get([
|
||||||
|
'cod_tab',
|
||||||
|
'id_cond',
|
||||||
|
'cond_inquil',
|
||||||
|
'mm',
|
||||||
|
'prev_euro',
|
||||||
|
'cons_euro',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, object>
|
||||||
|
*/
|
||||||
|
private function loadLegacyTableHeaders(string $stableCode, Collection $tableCodes): array
|
||||||
|
{
|
||||||
|
if ($tableCodes->isEmpty() || ! Schema::connection('gescon_import')->hasTable('tabelle_millesimali')) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$columns = Schema::connection('gescon_import')->getColumnListing('tabelle_millesimali');
|
||||||
|
$codeColumn = in_array('cod_tabella', $columns, true)
|
||||||
|
? 'cod_tabella'
|
||||||
|
: (in_array('cod_tab', $columns, true) ? 'cod_tab' : null);
|
||||||
|
|
||||||
|
if (! $codeColumn) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = DB::connection('gescon_import')->table('tabelle_millesimali');
|
||||||
|
if (in_array('cod_stabile', $columns, true)) {
|
||||||
|
$query->where('cod_stabile', $stableCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows = $query
|
||||||
|
->whereIn($codeColumn, $tableCodes->all())
|
||||||
|
->orderBy($codeColumn)
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$headers = [];
|
||||||
|
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$code = strtoupper(trim((string) ($row->{$codeColumn} ?? '')));
|
||||||
|
if ($code === '' || isset($headers[$code])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers[$code] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function ensureLegacyUnitCoverage(string $stableCode, int $stableId, Collection $legacyDetails): void
|
||||||
|
{
|
||||||
|
$legacyIds = $legacyDetails
|
||||||
|
->pluck('id_cond')
|
||||||
|
->filter(fn ($value): bool => is_string($value) && trim($value) !== '')
|
||||||
|
->map(fn (string $value): string => trim($value))
|
||||||
|
->unique()
|
||||||
|
->values();
|
||||||
|
|
||||||
|
$existingIds = DB::table('unita_immobiliari')
|
||||||
|
->where('stabile_id', $stableId)
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->whereIn('legacy_cond_id', $legacyIds->all())
|
||||||
|
->pluck('legacy_cond_id')
|
||||||
|
->map(fn ($value): string => trim((string) $value))
|
||||||
|
->all();
|
||||||
|
|
||||||
|
$existingSet = array_fill_keys($existingIds, true);
|
||||||
|
|
||||||
|
foreach ($legacyIds as $legacyId) {
|
||||||
|
if (isset($existingSet[$legacyId])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sourceRow = $this->resolveCondominSourceRow($stableCode, $legacyId);
|
||||||
|
$this->createMissingLegacyUnit($stableCode, $stableId, $legacyId, $sourceRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resolveCondominSourceRow(string $stableCode, string $legacyId): object
|
||||||
|
{
|
||||||
|
$idCondRows = DB::connection('gescon_import')
|
||||||
|
->table('condomin')
|
||||||
|
->where('cod_stabile', $stableCode)
|
||||||
|
->where('id_cond', $legacyId)
|
||||||
|
->orderByDesc('legacy_year')
|
||||||
|
->orderByDesc('id')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
if ($idCondRows->isNotEmpty()) {
|
||||||
|
return $idCondRows->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
$codCondRows = DB::connection('gescon_import')
|
||||||
|
->table('condomin')
|
||||||
|
->where('cod_stabile', $stableCode)
|
||||||
|
->where('cod_cond', $legacyId)
|
||||||
|
->orderByDesc('legacy_year')
|
||||||
|
->orderByDesc('id')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
if ($codCondRows->isNotEmpty()) {
|
||||||
|
return $codCondRows->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \RuntimeException('Impossibile risolvere la fonte condomin legacy per id_cond ' . $legacyId . '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createMissingLegacyUnit(string $stableCode, int $stableId, string $legacyId, object $sourceRow): void
|
||||||
|
{
|
||||||
|
$internal = trim((string) ($sourceRow->interno ?? ''));
|
||||||
|
if ($internal === '') {
|
||||||
|
throw new \RuntimeException('Interno mancante per il legacy id ' . $legacyId . '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$scale = trim((string) ($sourceRow->scala ?? ''));
|
||||||
|
$scale = $scale !== '' ? strtoupper($scale) : 'A';
|
||||||
|
$floor = $this->normalizeFloor($sourceRow->piano ?? null);
|
||||||
|
$displayName = trim((string) (($sourceRow->cognome ?? '') . ' ' . ($sourceRow->nome ?? '')));
|
||||||
|
if ($displayName === '') {
|
||||||
|
$displayName = trim((string) ($sourceRow->nom_cond ?? ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
$code = $this->buildUnitCode($stableCode, $scale, $internal, $legacyId);
|
||||||
|
|
||||||
|
if (DB::table('unita_immobiliari')->where('codice_unita', $code)->exists()) {
|
||||||
|
throw new \RuntimeException('Codice unita gia presente durante il backfill rigoroso: ' . $code . '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::table('unita_immobiliari')->insert([
|
||||||
|
'stabile_id' => $stableId,
|
||||||
|
'codice_unita' => $code,
|
||||||
|
'denominazione' => $displayName !== '' ? $displayName : ('Unita legacy ' . $legacyId),
|
||||||
|
'scala' => $scale,
|
||||||
|
'piano' => $floor,
|
||||||
|
'interno' => $internal,
|
||||||
|
'legacy_cond_id' => $legacyId,
|
||||||
|
'tipo_unita' => 'abitazione',
|
||||||
|
'stato_occupazione' => 'occupata_proprietario',
|
||||||
|
'stato_conservazione' => 'buono',
|
||||||
|
'millesimi_generali' => 0,
|
||||||
|
'attiva' => true,
|
||||||
|
'unita_demo' => false,
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, int>
|
||||||
|
*/
|
||||||
|
private function syncTabelleMillesimali(int $stableId, int $year, Collection $tableCodes, Collection $legacyDetails, array $legacyHeaders): array
|
||||||
|
{
|
||||||
|
$detailSummary = $legacyDetails
|
||||||
|
->groupBy('cod_tab')
|
||||||
|
->map(function (Collection $rows): array {
|
||||||
|
return [
|
||||||
|
'total_mm' => (float) $rows->sum(fn ($row): float => is_numeric($row->mm ?? null) ? (float) $row->mm : 0.0),
|
||||||
|
'rows' => $rows->count(),
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
$tableMap = [];
|
||||||
|
$sortOrder = 1;
|
||||||
|
|
||||||
|
foreach ($tableCodes as $tableCode) {
|
||||||
|
$normalizedCode = strtoupper(trim((string) $tableCode));
|
||||||
|
$summary = $detailSummary->get($tableCode, ['total_mm' => 0.0, 'rows' => 0]);
|
||||||
|
$header = $legacyHeaders[$normalizedCode] ?? null;
|
||||||
|
$rawCalcolo = $header->tipo_calcolo ?? $header->calcolo ?? null;
|
||||||
|
$calcolo = $this->normalizeLegacyCalcolo($rawCalcolo);
|
||||||
|
$tipoLegacy = $this->normalizeLegacyTipo($header->tipologia ?? $header->tipo ?? null) ?? 'O';
|
||||||
|
$tipoTabella = $this->resolveTipoTabellaFromLegacy($tipoLegacy, $calcolo, $normalizedCode);
|
||||||
|
$tipoCalcoloDb = in_array($calcolo, ['millesimi', 'parti', 'fisso'], true)
|
||||||
|
? $calcolo
|
||||||
|
: ($normalizedCode === 'ACQUA' ? 'parti' : 'millesimi');
|
||||||
|
$denominazione = trim((string) ($header->denominazione ?? $header->descrizione ?? $tableCode));
|
||||||
|
$ordine = null;
|
||||||
|
|
||||||
|
foreach (['nord', 'ordinamento'] as $orderKey) {
|
||||||
|
if (isset($header->{$orderKey}) && is_numeric($header->{$orderKey})) {
|
||||||
|
$ordine = (int) $header->{$orderKey};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$sortValue = $ordine ?? $sortOrder;
|
||||||
|
|
||||||
|
$payload = [
|
||||||
|
'stabile_id' => $stableId,
|
||||||
|
'anno_gestione' => $year,
|
||||||
|
'nome_tabella' => $tableCode,
|
||||||
|
'denominazione' => $denominazione !== '' ? $denominazione : $tableCode,
|
||||||
|
'codice_tabella' => $tableCode,
|
||||||
|
'legacy_codice' => $tableCode,
|
||||||
|
'ordine_visualizzazione' => $sortValue,
|
||||||
|
'tipo_tabella' => $tipoTabella,
|
||||||
|
'tipo_calcolo' => $tipoCalcoloDb,
|
||||||
|
'attiva' => true,
|
||||||
|
'ordinamento' => $sortValue,
|
||||||
|
'nord' => $sortValue,
|
||||||
|
'totale_millesimi' => $summary['total_mm'],
|
||||||
|
'meta_legacy' => json_encode([
|
||||||
|
'strict_source' => 'gescon_import',
|
||||||
|
'legacy_year' => $year,
|
||||||
|
'cod_tab' => $normalizedCode,
|
||||||
|
'tipo' => $tipoLegacy,
|
||||||
|
'calcolo' => is_string($rawCalcolo) && trim($rawCalcolo) !== '' ? strtoupper(trim($rawCalcolo)) : null,
|
||||||
|
'detail_rows' => $summary['rows'],
|
||||||
|
]),
|
||||||
|
'updated_at' => now(),
|
||||||
|
];
|
||||||
|
|
||||||
|
$existing = DB::table('tabelle_millesimali')
|
||||||
|
->where('stabile_id', $stableId)
|
||||||
|
->where('codice_tabella', $tableCode)
|
||||||
|
->first(['id']);
|
||||||
|
|
||||||
|
if ($existing) {
|
||||||
|
DB::table('tabelle_millesimali')->where('id', (int) $existing->id)->update($payload);
|
||||||
|
$tableMap[$tableCode] = (int) $existing->id;
|
||||||
|
} else {
|
||||||
|
$payload['created_at'] = now();
|
||||||
|
DB::table('tabelle_millesimali')->insert($payload);
|
||||||
|
$tableMap[$tableCode] = (int) DB::table('tabelle_millesimali')
|
||||||
|
->where('stabile_id', $stableId)
|
||||||
|
->where('codice_tabella', $tableCode)
|
||||||
|
->value('id');
|
||||||
|
}
|
||||||
|
|
||||||
|
$sortOrder++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tableMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, int> $tableMap
|
||||||
|
*/
|
||||||
|
private function syncDettagliMillesimali(int $stableId, int $year, Collection $legacyDetails, array $tableMap): void
|
||||||
|
{
|
||||||
|
$tableIds = array_values($tableMap);
|
||||||
|
if ($tableIds === []) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::table('dettaglio_millesimi')
|
||||||
|
->whereIn('tabella_millesimale_id', $tableIds)
|
||||||
|
->delete();
|
||||||
|
|
||||||
|
$groupedRows = $legacyDetails
|
||||||
|
->groupBy(function ($row): string {
|
||||||
|
return implode('|', [
|
||||||
|
trim((string) ($row->cod_tab ?? '')),
|
||||||
|
trim((string) ($row->id_cond ?? '')),
|
||||||
|
strtoupper(trim((string) ($row->cond_inquil ?? ''))),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach ($groupedRows as $groupKey => $rows) {
|
||||||
|
[$tableCode, $legacyId, $role] = explode('|', $groupKey);
|
||||||
|
$tableId = $tableMap[$tableCode] ?? null;
|
||||||
|
if (! $tableId) {
|
||||||
|
throw new \RuntimeException('Tabella millesimale non risolta per codice ' . $tableCode . '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$unitId = DB::table('unita_immobiliari')
|
||||||
|
->where('stabile_id', $stableId)
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->where('legacy_cond_id', $legacyId)
|
||||||
|
->value('id');
|
||||||
|
|
||||||
|
if (! $unitId) {
|
||||||
|
throw new \RuntimeException('Unita NetGescon non risolta per legacy_cond_id ' . $legacyId . '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$millesimi = (float) $rows->sum(fn ($row): float => is_numeric($row->mm ?? null) ? (float) $row->mm : 0.0);
|
||||||
|
$valorePrev = (float) $rows->sum(fn ($row): float => is_numeric($row->prev_euro ?? null) ? (float) $row->prev_euro : 0.0);
|
||||||
|
$valoreCons = (float) $rows->sum(fn ($row): float => is_numeric($row->cons_euro ?? null) ? (float) $row->cons_euro : 0.0);
|
||||||
|
|
||||||
|
DB::table('dettaglio_millesimi')->insert([
|
||||||
|
'tabella_millesimale_id' => $tableId,
|
||||||
|
'unita_immobiliare_id' => (int) $unitId,
|
||||||
|
'millesimi' => $millesimi,
|
||||||
|
'valore_prev' => $valorePrev,
|
||||||
|
'valore_cons' => $valoreCons,
|
||||||
|
'ruolo_legacy' => $role !== '' ? $role : null,
|
||||||
|
'legacy_interno' => $legacyId,
|
||||||
|
'partecipa' => true,
|
||||||
|
'note' => null,
|
||||||
|
'legacy_payload' => json_encode([
|
||||||
|
'strict_source' => 'gescon_import',
|
||||||
|
'legacy_year' => $year,
|
||||||
|
'cod_tab' => $tableCode,
|
||||||
|
'id_cond' => $legacyId,
|
||||||
|
'cond_inquil' => $role !== '' ? $role : null,
|
||||||
|
]),
|
||||||
|
'created_at' => now(),
|
||||||
|
'updated_at' => now(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, int> $tableMap
|
||||||
|
*/
|
||||||
|
private function syncVociSpesa(int $stableId, int $gestioneId, int $year, Collection $legacyVoci, array $tableMap): void
|
||||||
|
{
|
||||||
|
$sortOrder = 1;
|
||||||
|
|
||||||
|
foreach ($legacyVoci as $voce) {
|
||||||
|
$code = trim((string) ($voce->cod ?? ''));
|
||||||
|
if ($code === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tableCode = trim((string) ($voce->tabella ?? ''));
|
||||||
|
$tableId = $tableCode !== '' ? ($tableMap[$tableCode] ?? null) : null;
|
||||||
|
|
||||||
|
if ($tableCode !== '' && ! $tableId) {
|
||||||
|
throw new \RuntimeException('Tabella legacy non risolta per la voce ' . $code . ': ' . $tableCode . '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = [
|
||||||
|
'stabile_id' => $stableId,
|
||||||
|
'gestione_contabile_id' => $gestioneId,
|
||||||
|
'codice' => $code,
|
||||||
|
'legacy_codice' => $code,
|
||||||
|
'descrizione' => trim((string) ($voce->descriz ?? '')),
|
||||||
|
'categoria' => 'ordinaria',
|
||||||
|
'tipo_gestione' => 'ordinaria',
|
||||||
|
'tabella_millesimale_default_id' => $tableId,
|
||||||
|
'importo_default' => is_numeric($voce->preventivo_euro ?? null) ? (float) $voce->preventivo_euro : 0.0,
|
||||||
|
'importo_consuntivo' => is_numeric($voce->consuntivo_euro ?? null) ? (float) $voce->consuntivo_euro : 0.0,
|
||||||
|
'percentuale_condomino' => is_numeric($voce->perc_proprietario ?? null) ? (float) $voce->perc_proprietario : 0.0,
|
||||||
|
'percentuale_inquilino' => is_numeric($voce->perc_inquilino ?? null) ? (float) $voce->perc_inquilino : 0.0,
|
||||||
|
'attiva' => true,
|
||||||
|
'ordinamento' => $sortOrder,
|
||||||
|
'nord' => $sortOrder,
|
||||||
|
'tipo' => 'ordinaria',
|
||||||
|
'legacy_tipo' => trim((string) ($voce->v_ors ?? 'O')) ?: 'O',
|
||||||
|
'note' => trim((string) ($voce->note ?? '')) !== '' ? trim((string) ($voce->note ?? '')) : null,
|
||||||
|
'meta_legacy' => json_encode([
|
||||||
|
'strict_source' => 'gescon_import',
|
||||||
|
'legacy_year' => $year,
|
||||||
|
'cod_tab' => $tableCode !== '' ? $tableCode : null,
|
||||||
|
]),
|
||||||
|
'updated_at' => now(),
|
||||||
|
];
|
||||||
|
|
||||||
|
$existing = DB::table('voci_spesa')
|
||||||
|
->where('stabile_id', $stableId)
|
||||||
|
->where('gestione_contabile_id', $gestioneId)
|
||||||
|
->where('codice', $code)
|
||||||
|
->first(['id']);
|
||||||
|
|
||||||
|
if ($existing) {
|
||||||
|
DB::table('voci_spesa')->where('id', (int) $existing->id)->update($payload);
|
||||||
|
} else {
|
||||||
|
$payload['created_at'] = now();
|
||||||
|
DB::table('voci_spesa')->insert($payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sortOrder++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normalizeFloor(mixed $rawFloor): int
|
||||||
|
{
|
||||||
|
$value = strtoupper(trim((string) $rawFloor));
|
||||||
|
|
||||||
|
return match ($value) {
|
||||||
|
'', 'T', 'PT', 'R', 'PR' => 0,
|
||||||
|
'S', 'PS', '-1' => -1,
|
||||||
|
default => is_numeric($value) ? (int) $value : 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildUnitCode(string $stableCode, string $scale, string $internal, string $legacyId): string
|
||||||
|
{
|
||||||
|
$normalizedStable = trim($stableCode);
|
||||||
|
$normalizedScale = trim($scale) !== '' ? trim($scale) : 'A';
|
||||||
|
$normalizedInternal = strtoupper(trim(preg_replace('/\s+/', '', $internal) ?? $internal));
|
||||||
|
|
||||||
|
return $normalizedStable . '-' . $normalizedScale . '-' . $normalizedInternal . '-C' . $legacyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normalizeLegacyCalcolo(?string $raw): ?string
|
||||||
|
{
|
||||||
|
$value = strtolower(trim((string) ($raw ?? '')));
|
||||||
|
if ($value === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return match ($value) {
|
||||||
|
'm' => 'millesimi',
|
||||||
|
'a', 'c' => 'a_consumo',
|
||||||
|
'x' => 'conguagli',
|
||||||
|
'p' => 'personali',
|
||||||
|
default => $value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normalizeLegacyTipo(?string $raw): ?string
|
||||||
|
{
|
||||||
|
$value = strtoupper(trim((string) ($raw ?? '')));
|
||||||
|
if ($value === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return match ($value) {
|
||||||
|
'O', 'ORD', 'ORDINARIA' => 'O',
|
||||||
|
'R', 'RISC', 'RISCALDAMENTO' => 'R',
|
||||||
|
'S', 'STRA', 'STRAORDINARIA' => 'S',
|
||||||
|
default => $value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resolveTipoTabellaFromLegacy(?string $tipoLegacy, ?string $calcolo, ?string $codice): string
|
||||||
|
{
|
||||||
|
$normalizedCalcolo = strtolower(trim((string) ($calcolo ?? '')));
|
||||||
|
$normalizedCode = strtoupper(trim((string) ($codice ?? '')));
|
||||||
|
|
||||||
|
if ($normalizedCode === 'ACQUA' || in_array($normalizedCalcolo, ['a_consumo', 'acqua', 'consumo', 'c', 'a'], true)) {
|
||||||
|
return 'custom';
|
||||||
|
}
|
||||||
|
|
||||||
|
return match ($tipoLegacy) {
|
||||||
|
'R' => 'riscaldamento',
|
||||||
|
'S' => 'straordinaria',
|
||||||
|
default => 'custom',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -318,7 +318,7 @@ private function resolveLocalFornitoreByLegacyIds(int $legacyId, string $legacyC
|
||||||
}
|
}
|
||||||
|
|
||||||
return $normalizedRagione !== ''
|
return $normalizedRagione !== ''
|
||||||
&& $this->normalizeComparableString((string) ($fornitore->ragione_sociale ?? '')) === $normalizedRagione;
|
&& $this->normalizeComparableString((string) ($fornitore->ragione_sociale ?? '')) === $normalizedRagione;
|
||||||
})->values();
|
})->values();
|
||||||
|
|
||||||
if ($filtered->count() === 1) {
|
if ($filtered->count() === 1) {
|
||||||
|
|
@ -395,11 +395,11 @@ private function extractKeywordTags(string $input): array
|
||||||
}
|
}
|
||||||
|
|
||||||
$keywords = [
|
$keywords = [
|
||||||
'informat' => 'informatica',
|
'informat' => 'informatica',
|
||||||
'assist' => 'assistenza',
|
'assist' => 'assistenza',
|
||||||
'computer' => 'pc',
|
'computer' => 'pc',
|
||||||
' pc ' => 'pc',
|
' pc ' => 'pc',
|
||||||
'apple' => 'apple',
|
'apple' => 'apple',
|
||||||
'idr' => 'idraulico',
|
'idr' => 'idraulico',
|
||||||
'termoidraul' => 'termoidraulico',
|
'termoidraul' => 'termoidraulico',
|
||||||
'elettric' => 'elettricista',
|
'elettric' => 'elettricista',
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Models\Fornitore;
|
use App\Models\Fornitore;
|
||||||
|
|
@ -22,7 +21,7 @@ public function handle(): int
|
||||||
$query = Fornitore::query()->with('amministratore:id,codice_amministratore,codice_univoco');
|
$query = Fornitore::query()->with('amministratore:id,codice_amministratore,codice_univoco');
|
||||||
|
|
||||||
$fornitoreId = $this->argument('fornitore_id');
|
$fornitoreId = $this->argument('fornitore_id');
|
||||||
$adminId = (int) $this->option('admin-id');
|
$adminId = (int) $this->option('admin-id');
|
||||||
|
|
||||||
if ($fornitoreId !== null) {
|
if ($fornitoreId !== null) {
|
||||||
$query->whereKey((int) $fornitoreId);
|
$query->whereKey((int) $fornitoreId);
|
||||||
|
|
@ -35,7 +34,7 @@ public function handle(): int
|
||||||
}
|
}
|
||||||
|
|
||||||
$processed = 0;
|
$processed = 0;
|
||||||
$created = 0;
|
$created = 0;
|
||||||
|
|
||||||
$query->orderBy('amministratore_id')->orderBy('id')->chunkById(100, function ($fornitori) use (&$processed, &$created): void {
|
$query->orderBy('amministratore_id')->orderBy('id')->chunkById(100, function ($fornitori) use (&$processed, &$created): void {
|
||||||
foreach ($fornitori as $fornitore) {
|
foreach ($fornitori as $fornitore) {
|
||||||
|
|
@ -46,7 +45,7 @@ public function handle(): int
|
||||||
$processed++;
|
$processed++;
|
||||||
|
|
||||||
$canonicalBase = ArchivioPaths::fornitoreBase($fornitore);
|
$canonicalBase = ArchivioPaths::fornitoreBase($fornitore);
|
||||||
$legacyBase = ArchivioPaths::fornitoreLegacyBase($fornitore);
|
$legacyBase = ArchivioPaths::fornitoreLegacyBase($fornitore);
|
||||||
|
|
||||||
if (! is_string($canonicalBase) || $canonicalBase === '') {
|
if (! is_string($canonicalBase) || $canonicalBase === '') {
|
||||||
$this->warn('Saltato fornitore #' . (int) $fornitore->id . ': codice archivio non disponibile.');
|
$this->warn('Saltato fornitore #' . (int) $fornitore->id . ': codice archivio non disponibile.');
|
||||||
|
|
@ -61,9 +60,9 @@ public function handle(): int
|
||||||
$created++;
|
$created++;
|
||||||
}
|
}
|
||||||
|
|
||||||
$message = '#'. (int) $fornitore->id
|
$message = '#' . (int) $fornitore->id
|
||||||
. ' ' . trim((string) ($fornitore->ragione_sociale ?: ('Fornitore ' . $fornitore->id)))
|
. ' ' . trim((string) ($fornitore->ragione_sociale ?: ('Fornitore ' . $fornitore->id)))
|
||||||
. ' -> ' . Storage::disk('local')->path($canonicalBase)
|
. ' -> ' . Storage::disk('local')->path($canonicalBase)
|
||||||
. ' [' . ($after ? ($before ? 'gia_esistente' : 'creata') : 'non_creata') . ']';
|
. ' [' . ($after ? ($before ? 'gia_esistente' : 'creata') : 'non_creata') . ']';
|
||||||
|
|
||||||
$this->line($message);
|
$this->line($message);
|
||||||
|
|
@ -78,4 +77,4 @@ public function handle(): int
|
||||||
|
|
||||||
return self::SUCCESS;
|
return self::SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Models\Amministratore;
|
use App\Models\Amministratore;
|
||||||
|
|
@ -64,27 +63,27 @@ public function handle(): int
|
||||||
|
|
||||||
FornitoreCliente::query()->updateOrCreate(
|
FornitoreCliente::query()->updateOrCreate(
|
||||||
[
|
[
|
||||||
'fornitore_id' => (int) $fornitore->id,
|
'fornitore_id' => (int) $fornitore->id,
|
||||||
'legacy_cliente_id' => $customer['legacy_cliente_id'],
|
'legacy_cliente_id' => $customer['legacy_cliente_id'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'amministratore_id' => (int) $admin->id,
|
'amministratore_id' => (int) $admin->id,
|
||||||
'rubrica_id' => $rubrica?->id,
|
'rubrica_id' => $rubrica?->id,
|
||||||
'display_name' => $customer['display_name'],
|
'display_name' => $customer['display_name'],
|
||||||
'phone' => $customer['phone'],
|
'phone' => $customer['phone'],
|
||||||
'phone_alt' => $customer['phone_alt'],
|
'phone_alt' => $customer['phone_alt'],
|
||||||
'email' => $customer['email'],
|
'email' => $customer['email'],
|
||||||
'indirizzo' => $customer['indirizzo'],
|
'indirizzo' => $customer['indirizzo'],
|
||||||
'cap' => $customer['cap'],
|
'cap' => $customer['cap'],
|
||||||
'citta' => $customer['citta'],
|
'citta' => $customer['citta'],
|
||||||
'provincia' => $customer['provincia'],
|
'provincia' => $customer['provincia'],
|
||||||
'partita_iva' => $customer['partita_iva'],
|
'partita_iva' => $customer['partita_iva'],
|
||||||
'codice_fiscale' => $customer['codice_fiscale'],
|
'codice_fiscale' => $customer['codice_fiscale'],
|
||||||
'note' => $customer['note'],
|
'note' => $customer['note'],
|
||||||
'source' => 'tecnorepair_tclienti',
|
'source' => 'tecnorepair_tclienti',
|
||||||
'imported_from_path' => $customer['imported_from_path'],
|
'imported_from_path' => $customer['imported_from_path'],
|
||||||
'imported_at' => now(),
|
'imported_at' => now(),
|
||||||
'metadata' => $customer['metadata'],
|
'metadata' => $customer['metadata'],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -170,17 +169,17 @@ private function collectUniqueCustomers(Collection $rows): Collection
|
||||||
$cliente = is_array($scheda->metadata['cliente'] ?? null) ? $scheda->metadata['cliente'] : [];
|
$cliente = is_array($scheda->metadata['cliente'] ?? null) ? $scheda->metadata['cliente'] : [];
|
||||||
|
|
||||||
$legacyClienteId = $this->toInt($cliente['ID'] ?? $scheda->legacy_cliente_id);
|
$legacyClienteId = $this->toInt($cliente['ID'] ?? $scheda->legacy_cliente_id);
|
||||||
$displayName = $this->cleanString($cliente['NomeCognome'] ?? $scheda->customer_name);
|
$displayName = $this->cleanString($cliente['NomeCognome'] ?? $scheda->customer_name);
|
||||||
$phone = $this->cleanString($cliente['NumeroTelefono'] ?? $scheda->customer_phone);
|
$phone = $this->cleanString($cliente['NumeroTelefono'] ?? $scheda->customer_phone);
|
||||||
$phoneAlt = $this->cleanString($cliente['TelFisso'] ?? $scheda->customer_phone_alt);
|
$phoneAlt = $this->cleanString($cliente['TelFisso'] ?? $scheda->customer_phone_alt);
|
||||||
$email = $this->cleanString($cliente['Email'] ?? $scheda->customer_email);
|
$email = $this->cleanString($cliente['Email'] ?? $scheda->customer_email);
|
||||||
$indirizzo = $this->cleanString($cliente['Indirizzo'] ?? null);
|
$indirizzo = $this->cleanString($cliente['Indirizzo'] ?? null);
|
||||||
$cap = $this->cleanString($cliente['Cap'] ?? null);
|
$cap = $this->cleanString($cliente['Cap'] ?? null);
|
||||||
$citta = $this->cleanString($cliente['Citta'] ?? null);
|
$citta = $this->cleanString($cliente['Citta'] ?? null);
|
||||||
$provincia = $this->cleanString($cliente['Prov'] ?? null);
|
$provincia = $this->cleanString($cliente['Prov'] ?? null);
|
||||||
$partitaIva = $this->cleanString($cliente['PIVA'] ?? null);
|
$partitaIva = $this->cleanString($cliente['PIVA'] ?? null);
|
||||||
$codiceFiscale = $this->cleanString($cliente['CodFis'] ?? null);
|
$codiceFiscale = $this->cleanString($cliente['CodFis'] ?? null);
|
||||||
$note = $this->cleanString($cliente['Annotazioni'] ?? null);
|
$note = $this->cleanString($cliente['Annotazioni'] ?? null);
|
||||||
|
|
||||||
$identity = $legacyClienteId !== null
|
$identity = $legacyClienteId !== null
|
||||||
? 'legacy-' . $legacyClienteId
|
? 'legacy-' . $legacyClienteId
|
||||||
|
|
@ -192,23 +191,23 @@ private function collectUniqueCustomers(Collection $rows): Collection
|
||||||
|
|
||||||
if (! isset($customers[$identity])) {
|
if (! isset($customers[$identity])) {
|
||||||
$customers[$identity] = [
|
$customers[$identity] = [
|
||||||
'legacy_cliente_id' => $legacyClienteId,
|
'legacy_cliente_id' => $legacyClienteId,
|
||||||
'display_name' => $displayName,
|
'display_name' => $displayName,
|
||||||
'phone' => $phone,
|
'phone' => $phone,
|
||||||
'phone_alt' => $phoneAlt,
|
'phone_alt' => $phoneAlt,
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
'indirizzo' => $indirizzo,
|
'indirizzo' => $indirizzo,
|
||||||
'cap' => $cap,
|
'cap' => $cap,
|
||||||
'citta' => $citta,
|
'citta' => $citta,
|
||||||
'provincia' => $provincia,
|
'provincia' => $provincia,
|
||||||
'partita_iva' => $partitaIva,
|
'partita_iva' => $partitaIva,
|
||||||
'codice_fiscale' => $codiceFiscale,
|
'codice_fiscale' => $codiceFiscale,
|
||||||
'note' => $note,
|
'note' => $note,
|
||||||
'imported_from_path'=> $this->cleanString($scheda->imported_from_path),
|
'imported_from_path' => $this->cleanString($scheda->imported_from_path),
|
||||||
'metadata' => [
|
'metadata' => [
|
||||||
'cliente' => $cliente,
|
'cliente' => $cliente,
|
||||||
'ultima_scheda_id' => (int) $scheda->id,
|
'ultima_scheda_id' => (int) $scheda->id,
|
||||||
'ultima_scheda_num' => (string) ($scheda->legacy_numero_scheda ?? ''),
|
'ultima_scheda_num' => (string) ($scheda->legacy_numero_scheda ?? ''),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -233,15 +232,15 @@ private function resolveOrCreateRubrica(Amministratore $admin, array $customer,
|
||||||
{
|
{
|
||||||
$query = RubricaUniversale::query()->where('amministratore_id', (int) $admin->id);
|
$query = RubricaUniversale::query()->where('amministratore_id', (int) $admin->id);
|
||||||
|
|
||||||
$email = $this->cleanString($customer['email'] ?? null);
|
$email = $this->cleanString($customer['email'] ?? null);
|
||||||
$phone = $this->normalizePhone($customer['phone'] ?? null);
|
$phone = $this->normalizePhone($customer['phone'] ?? null);
|
||||||
$phoneAlt = $this->normalizePhone($customer['phone_alt'] ?? null);
|
$phoneAlt = $this->normalizePhone($customer['phone_alt'] ?? null);
|
||||||
$phoneForRubrica = $this->normalizePhoneField($customer['phone'] ?? null);
|
$phoneForRubrica = $this->normalizePhoneField($customer['phone'] ?? null);
|
||||||
$phoneAltForRubrica = $this->normalizePhoneField($customer['phone_alt'] ?? null);
|
$phoneAltForRubrica = $this->normalizePhoneField($customer['phone_alt'] ?? null);
|
||||||
$cf = $this->cleanString($customer['codice_fiscale'] ?? null);
|
$cf = $this->cleanString($customer['codice_fiscale'] ?? null);
|
||||||
$piva = $this->cleanString($customer['partita_iva'] ?? null);
|
$piva = $this->cleanString($customer['partita_iva'] ?? null);
|
||||||
$name = $this->cleanString($customer['display_name'] ?? null);
|
$name = $this->cleanString($customer['display_name'] ?? null);
|
||||||
$provincia = $this->normalizeProvince($customer['provincia'] ?? null);
|
$provincia = $this->normalizeProvince($customer['provincia'] ?? null);
|
||||||
|
|
||||||
$rubrica = null;
|
$rubrica = null;
|
||||||
|
|
||||||
|
|
@ -281,19 +280,19 @@ private function resolveOrCreateRubrica(Amministratore $admin, array $customer,
|
||||||
$dirty = false;
|
$dirty = false;
|
||||||
|
|
||||||
foreach ([
|
foreach ([
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
'telefono_cellulare' => $phoneForRubrica,
|
'telefono_cellulare' => $phoneForRubrica,
|
||||||
'telefono_ufficio' => $phoneAltForRubrica,
|
'telefono_ufficio' => $phoneAltForRubrica,
|
||||||
'indirizzo' => $this->cleanString($customer['indirizzo'] ?? null),
|
'indirizzo' => $this->cleanString($customer['indirizzo'] ?? null),
|
||||||
'cap' => $this->cleanString($customer['cap'] ?? null),
|
'cap' => $this->cleanString($customer['cap'] ?? null),
|
||||||
'citta' => $this->cleanString($customer['citta'] ?? null),
|
'citta' => $this->cleanString($customer['citta'] ?? null),
|
||||||
'provincia' => $provincia,
|
'provincia' => $provincia,
|
||||||
'partita_iva' => $piva,
|
'partita_iva' => $piva,
|
||||||
'codice_fiscale' => $cf,
|
'codice_fiscale' => $cf,
|
||||||
] as $field => $value) {
|
] as $field => $value) {
|
||||||
if ($value !== null && ! filled($rubrica->{$field})) {
|
if ($value !== null && ! filled($rubrica->{$field})) {
|
||||||
$rubrica->{$field} = $value;
|
$rubrica->{$field} = $value;
|
||||||
$dirty = true;
|
$dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -314,26 +313,26 @@ private function resolveOrCreateRubrica(Amministratore $admin, array $customer,
|
||||||
[$nome, $cognome] = $this->splitDisplayName($name);
|
[$nome, $cognome] = $this->splitDisplayName($name);
|
||||||
|
|
||||||
return RubricaUniversale::query()->create([
|
return RubricaUniversale::query()->create([
|
||||||
'amministratore_id' => (int) $admin->id,
|
'amministratore_id' => (int) $admin->id,
|
||||||
'nome' => $nome,
|
'nome' => $nome,
|
||||||
'cognome' => $cognome,
|
'cognome' => $cognome,
|
||||||
'tipo_contatto' => 'persona_fisica',
|
'tipo_contatto' => 'persona_fisica',
|
||||||
'codice_fiscale' => $cf,
|
'codice_fiscale' => $cf,
|
||||||
'partita_iva' => $piva,
|
'partita_iva' => $piva,
|
||||||
'indirizzo' => $this->cleanString($customer['indirizzo'] ?? null),
|
'indirizzo' => $this->cleanString($customer['indirizzo'] ?? null),
|
||||||
'cap' => $this->cleanString($customer['cap'] ?? null),
|
'cap' => $this->cleanString($customer['cap'] ?? null),
|
||||||
'citta' => $this->cleanString($customer['citta'] ?? null),
|
'citta' => $this->cleanString($customer['citta'] ?? null),
|
||||||
'provincia' => $provincia,
|
'provincia' => $provincia,
|
||||||
'telefono_cellulare' => $phoneForRubrica,
|
'telefono_cellulare' => $phoneForRubrica,
|
||||||
'telefono_ufficio' => $phoneAltForRubrica,
|
'telefono_ufficio' => $phoneAltForRubrica,
|
||||||
'email' => $email,
|
'email' => $email,
|
||||||
'note' => $this->buildRubricaNote($customer),
|
'note' => $this->buildRubricaNote($customer),
|
||||||
'categoria' => 'cliente',
|
'categoria' => 'cliente',
|
||||||
'stato' => 'attivo',
|
'stato' => 'attivo',
|
||||||
'data_inserimento' => now(),
|
'data_inserimento' => now(),
|
||||||
'data_ultima_modifica' => now(),
|
'data_ultima_modifica' => now(),
|
||||||
'creato_da' => auth()->id(),
|
'creato_da' => auth()->id(),
|
||||||
'modificato_da' => auth()->id(),
|
'modificato_da' => auth()->id(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -438,4 +437,4 @@ private function toInt(mixed $value): ?int
|
||||||
|
|
||||||
return (int) $value;
|
return (int) $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -680,8 +680,8 @@ public function table(Table $table): Table
|
||||||
->button()
|
->button()
|
||||||
->color('primary')
|
->color('primary')
|
||||||
->url(fn(StabileServizioLettura $record): ?string => $record->fattura_elettronica_id
|
->url(fn(StabileServizioLettura $record): ?string => $record->fattura_elettronica_id
|
||||||
? FatturaElettronicaScheda::getUrl(['record' => (int) $record->fattura_elettronica_id], panel: 'admin-filament')
|
? FatturaElettronicaScheda::getUrl(['record' => (int) $record->fattura_elettronica_id], panel : 'admin-filament')
|
||||||
: null)
|
: null)
|
||||||
->openUrlInNewTab()
|
->openUrlInNewTab()
|
||||||
->visible(fn(StabileServizioLettura $record): bool => (int) ($record->fattura_elettronica_id ?? 0) > 0),
|
->visible(fn(StabileServizioLettura $record): bool => (int) ($record->fattura_elettronica_id ?? 0) > 0),
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,23 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Filament\Pages\Condomini;
|
namespace App\Filament\Pages\Condomini;
|
||||||
|
|
||||||
use App\Models\DettaglioMillesimi;
|
use App\Models\DettaglioMillesimi;
|
||||||
|
use App\Models\RipartizionePreset;
|
||||||
|
use App\Models\RipartizioneSpeseInquilini;
|
||||||
use App\Models\Stabile;
|
use App\Models\Stabile;
|
||||||
use App\Models\TabellaMillesimale;
|
use App\Models\TabellaMillesimale;
|
||||||
use App\Models\UnitaImmobiliare;
|
use App\Models\UnitaImmobiliare;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\VoceSpesa;
|
use App\Models\VoceSpesa;
|
||||||
use App\Models\RipartizioneSpeseInquilini;
|
|
||||||
use App\Models\RipartizionePreset;
|
|
||||||
use App\Support\AnnoGestioneContext;
|
use App\Support\AnnoGestioneContext;
|
||||||
use App\Support\StabileContext;
|
use App\Support\StabileContext;
|
||||||
use BackedEnum;
|
use BackedEnum;
|
||||||
use Filament\Actions\Action;
|
use Filament\Actions\Action;
|
||||||
use Filament\Notifications\Notification;
|
|
||||||
use Filament\Forms\Components\Select;
|
use Filament\Forms\Components\Select;
|
||||||
use Filament\Forms\Components\TextInput;
|
|
||||||
use Filament\Forms\Components\Textarea;
|
use Filament\Forms\Components\Textarea;
|
||||||
|
use Filament\Forms\Components\TextInput;
|
||||||
use Filament\Forms\Components\Toggle;
|
use Filament\Forms\Components\Toggle;
|
||||||
|
use Filament\Notifications\Notification;
|
||||||
use Filament\Pages\Page;
|
use Filament\Pages\Page;
|
||||||
use Filament\Tables\Columns\IconColumn;
|
use Filament\Tables\Columns\IconColumn;
|
||||||
use Filament\Tables\Columns\TextColumn;
|
use Filament\Tables\Columns\TextColumn;
|
||||||
|
|
@ -26,10 +25,10 @@
|
||||||
use Filament\Tables\Contracts\HasTable;
|
use Filament\Tables\Contracts\HasTable;
|
||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Support\Facades\Validator;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
use UnitEnum;
|
use UnitEnum;
|
||||||
|
|
||||||
class TabelleMillesimaliArchivio extends Page implements HasTable
|
class TabelleMillesimaliArchivio extends Page implements HasTable
|
||||||
|
|
@ -86,7 +85,7 @@ public static function canAccess(): bool
|
||||||
{
|
{
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
return $user instanceof User
|
return $user instanceof User
|
||||||
&& $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore']);
|
&& $user->hasAnyRole(['super-admin', 'admin', 'amministratore', 'collaboratore']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mount(): void
|
public function mount(): void
|
||||||
|
|
@ -108,15 +107,15 @@ public function mount(): void
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->stabileId = (int) $stabileId;
|
$this->stabileId = (int) $stabileId;
|
||||||
$this->annoGestione = AnnoGestioneContext::resolveActiveAnno($user);
|
$this->annoGestione = AnnoGestioneContext::resolveActiveAnno($user);
|
||||||
|
|
||||||
$this->codiceStabile = Stabile::query()
|
$this->codiceStabile = Stabile::query()
|
||||||
->whereKey($this->stabileId)
|
->whereKey($this->stabileId)
|
||||||
->value('codice_stabile')
|
->value('codice_stabile')
|
||||||
?: Stabile::query()
|
?: Stabile::query()
|
||||||
->whereKey($this->stabileId)
|
->whereKey($this->stabileId)
|
||||||
->value('codice_interno');
|
->value('codice_interno');
|
||||||
|
|
||||||
$requestedTab = request()->query('tab');
|
$requestedTab = request()->query('tab');
|
||||||
if (in_array($requestedTab, ['archivio', 'prospetto', 'voci'], true)) {
|
if (in_array($requestedTab, ['archivio', 'prospetto', 'voci'], true)) {
|
||||||
|
|
@ -125,7 +124,7 @@ public function mount(): void
|
||||||
|
|
||||||
$this->loadTabelle();
|
$this->loadTabelle();
|
||||||
|
|
||||||
$requested = request()->integer('tabella_id') ?: null;
|
$requested = request()->integer('tabella_id') ?: null;
|
||||||
$this->tabellaId = $this->pickTabellaId($requested);
|
$this->tabellaId = $this->pickTabellaId($requested);
|
||||||
|
|
||||||
$this->loadDettaglioTabella();
|
$this->loadDettaglioTabella();
|
||||||
|
|
@ -183,7 +182,7 @@ protected function getTableQuery(): Builder
|
||||||
|
|
||||||
return TabellaMillesimale::query()
|
return TabellaMillesimale::query()
|
||||||
->where('stabile_id', $activeStabileId)
|
->where('stabile_id', $activeStabileId)
|
||||||
// In UI il conteggio "Unità" deve riflettere quante unità hanno righe millesimi
|
// In UI il conteggio "Unità" deve riflettere quante unità hanno righe millesimi
|
||||||
->withCount([
|
->withCount([
|
||||||
'dettagliMillesimali as unita_partecipanti_count' => function (Builder $q): void {
|
'dettagliMillesimali as unita_partecipanti_count' => function (Builder $q): void {
|
||||||
$q
|
$q
|
||||||
|
|
@ -194,7 +193,7 @@ protected function getTableQuery(): Builder
|
||||||
->select(DB::raw('count(distinct unita_immobiliare_id)'));
|
->select(DB::raw('count(distinct unita_immobiliare_id)'));
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
// Nascondi le tabelle generate automaticamente da GESCON (es. *.ST)
|
// Nascondi le tabelle generate automaticamente da GESCON (es. *.ST)
|
||||||
->where(function (Builder $q) {
|
->where(function (Builder $q) {
|
||||||
$q->whereNull('descrizione')->orWhere('descrizione', 'not like', '%generata automaticamente%');
|
$q->whereNull('descrizione')->orWhere('descrizione', 'not like', '%generata automaticamente%');
|
||||||
})
|
})
|
||||||
|
|
@ -217,8 +216,8 @@ public function table(Table $table): Table
|
||||||
'a_consumo' => 'A CONSUMO',
|
'a_consumo' => 'A CONSUMO',
|
||||||
'conguagli' => 'CONGUAGLI',
|
'conguagli' => 'CONGUAGLI',
|
||||||
'personali' => 'PERSONALI',
|
'personali' => 'PERSONALI',
|
||||||
'parti' => 'PARTI',
|
'parti' => 'PARTI',
|
||||||
'fisso' => 'FISSO',
|
'fisso' => 'FISSO',
|
||||||
];
|
];
|
||||||
|
|
||||||
return $table
|
return $table
|
||||||
|
|
@ -286,32 +285,32 @@ public function table(Table $table): Table
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$gruppo = strtoupper(trim((string) ($data['gruppo'] ?? 'O')));
|
$gruppo = strtoupper(trim((string) ($data['gruppo'] ?? 'O')));
|
||||||
$tipoTabella = match ($gruppo) {
|
$tipoTabella = match ($gruppo) {
|
||||||
'R' => 'riscaldamento',
|
'R' => 'riscaldamento',
|
||||||
'S' => 'straordinaria',
|
'S' => 'straordinaria',
|
||||||
default => 'ordinaria',
|
default => 'ordinaria',
|
||||||
};
|
};
|
||||||
|
|
||||||
$tipoCalcolo = strtolower(trim((string) ($data['tipo_calcolo'] ?? 'millesimi')));
|
$tipoCalcolo = strtolower(trim((string) ($data['tipo_calcolo'] ?? 'millesimi')));
|
||||||
|
|
||||||
$meta = [
|
$meta = [
|
||||||
'tipo' => $gruppo,
|
'tipo' => $gruppo,
|
||||||
'calcolo' => $tipoCalcolo,
|
'calcolo' => $tipoCalcolo,
|
||||||
];
|
];
|
||||||
|
|
||||||
$payload = [
|
$payload = [
|
||||||
'stabile_id' => (int) $stabileId,
|
'stabile_id' => (int) $stabileId,
|
||||||
'codice_tabella' => strtoupper(trim((string) ($data['codice_tabella'] ?? ''))),
|
'codice_tabella' => strtoupper(trim((string) ($data['codice_tabella'] ?? ''))),
|
||||||
'denominazione' => trim((string) ($data['denominazione'] ?? '')),
|
'denominazione' => trim((string) ($data['denominazione'] ?? '')),
|
||||||
'tipo_tabella' => $tipoTabella,
|
'tipo_tabella' => $tipoTabella,
|
||||||
'tipo_calcolo' => $tipoCalcolo,
|
'tipo_calcolo' => $tipoCalcolo,
|
||||||
'totale_millesimi' => is_numeric($data['totale_millesimi'] ?? null) ? (float) $data['totale_millesimi'] : null,
|
'totale_millesimi' => is_numeric($data['totale_millesimi'] ?? null) ? (float) $data['totale_millesimi'] : null,
|
||||||
'ordine_visualizzazione' => is_numeric($data['ordine_visualizzazione'] ?? null) ? (int) $data['ordine_visualizzazione'] : null,
|
'ordine_visualizzazione' => is_numeric($data['ordine_visualizzazione'] ?? null) ? (int) $data['ordine_visualizzazione'] : null,
|
||||||
'ordinamento' => is_numeric($data['ordinamento'] ?? null) ? (int) $data['ordinamento'] : null,
|
'ordinamento' => is_numeric($data['ordinamento'] ?? null) ? (int) $data['ordinamento'] : null,
|
||||||
'attiva' => (bool) ($data['attiva'] ?? true),
|
'attiva' => (bool) ($data['attiva'] ?? true),
|
||||||
'note' => trim((string) ($data['note'] ?? '')) ?: null,
|
'note' => trim((string) ($data['note'] ?? '')) ?: null,
|
||||||
'meta_legacy' => $meta,
|
'meta_legacy' => $meta,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (Schema::hasColumn('tabelle_millesimali', 'creato_da')) {
|
if (Schema::hasColumn('tabelle_millesimali', 'creato_da')) {
|
||||||
|
|
@ -354,10 +353,13 @@ public function table(Table $table): Table
|
||||||
? $record->meta_legacy
|
? $record->meta_legacy
|
||||||
: (is_string($record->meta_legacy) ? json_decode($record->meta_legacy, true) : null);
|
: (is_string($record->meta_legacy) ? json_decode($record->meta_legacy, true) : null);
|
||||||
$v = is_array($meta) ? ($meta['calcolo'] ?? null) : null;
|
$v = is_array($meta) ? ($meta['calcolo'] ?? null) : null;
|
||||||
if (!$v) {
|
if (! $v) {
|
||||||
$v = $record->tipo_calcolo;
|
$v = $record->tipo_calcolo;
|
||||||
}
|
}
|
||||||
if (!$v) return '—';
|
if (! $v) {
|
||||||
|
return '—';
|
||||||
|
}
|
||||||
|
|
||||||
$v = strtolower((string) $v);
|
$v = strtolower((string) $v);
|
||||||
return match ($v) {
|
return match ($v) {
|
||||||
'acqua', 'a', 'consumo', 'c', 'a_consumo' => 'A CONSUMO',
|
'acqua', 'a', 'consumo', 'c', 'a_consumo' => 'A CONSUMO',
|
||||||
|
|
@ -377,7 +379,7 @@ public function table(Table $table): Table
|
||||||
$meta = is_array($record->meta_legacy)
|
$meta = is_array($record->meta_legacy)
|
||||||
? $record->meta_legacy
|
? $record->meta_legacy
|
||||||
: (is_string($record->meta_legacy) ? json_decode($record->meta_legacy, true) : null);
|
: (is_string($record->meta_legacy) ? json_decode($record->meta_legacy, true) : null);
|
||||||
$codice = strtoupper((string) ($record->codice_tabella ?? ''));
|
$codice = strtoupper((string) ($record->codice_tabella ?? ''));
|
||||||
$tipoCalcolo = is_array($meta) ? ($meta['calcolo'] ?? null) : null;
|
$tipoCalcolo = is_array($meta) ? ($meta['calcolo'] ?? null) : null;
|
||||||
$tipoCalcolo = $tipoCalcolo ?: $record->tipo_calcolo;
|
$tipoCalcolo = $tipoCalcolo ?: $record->tipo_calcolo;
|
||||||
$tipoCalcolo = strtolower((string) ($tipoCalcolo ?? ''));
|
$tipoCalcolo = strtolower((string) ($tipoCalcolo ?? ''));
|
||||||
|
|
@ -389,9 +391,9 @@ public function table(Table $table): Table
|
||||||
if ($ors) {
|
if ($ors) {
|
||||||
$u = strtoupper((string) $ors);
|
$u = strtoupper((string) $ors);
|
||||||
return match ($u) {
|
return match ($u) {
|
||||||
'O' => 'O (Ordinaria)',
|
'O' => 'O (Ordinaria)',
|
||||||
'R' => 'R (Riscaldamento)',
|
'R' => 'R (Riscaldamento)',
|
||||||
'S' => 'S (Straordinaria)',
|
'S' => 'S (Straordinaria)',
|
||||||
default => strtoupper((string) $ors),
|
default => strtoupper((string) $ors),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -399,15 +401,21 @@ public function table(Table $table): Table
|
||||||
$tipologia = strtoupper((string) ($record->tipologia ?? ''));
|
$tipologia = strtoupper((string) ($record->tipologia ?? ''));
|
||||||
if (in_array($tipologia, ['O', 'R', 'S'], true)) {
|
if (in_array($tipologia, ['O', 'R', 'S'], true)) {
|
||||||
return match ($tipologia) {
|
return match ($tipologia) {
|
||||||
'R' => 'R (Riscaldamento)',
|
'R' => 'R (Riscaldamento)',
|
||||||
'S' => 'S (Straordinaria)',
|
'S' => 'S (Straordinaria)',
|
||||||
default => 'O (Ordinaria)',
|
default => 'O (Ordinaria)',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
$t = strtolower((string) ($record->tipo_tabella ?? ''));
|
$t = strtolower((string) ($record->tipo_tabella ?? ''));
|
||||||
if ($t === 'riscaldamento') return 'R (Riscaldamento)';
|
if ($t === 'riscaldamento') {
|
||||||
if ($t === '') return '—';
|
return 'R (Riscaldamento)';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($t === '') {
|
||||||
|
return '—';
|
||||||
|
}
|
||||||
|
|
||||||
return 'O (Ordinaria)';
|
return 'O (Ordinaria)';
|
||||||
})
|
})
|
||||||
->sortable()
|
->sortable()
|
||||||
|
|
@ -522,7 +530,7 @@ public function table(Table $table): Table
|
||||||
|
|
||||||
$gruppo = is_array($meta) ? ($meta['tipo'] ?? null) : null;
|
$gruppo = is_array($meta) ? ($meta['tipo'] ?? null) : null;
|
||||||
if (! $gruppo) {
|
if (! $gruppo) {
|
||||||
$t = strtolower((string) ($record->tipo_tabella ?? ''));
|
$t = strtolower((string) ($record->tipo_tabella ?? ''));
|
||||||
$gruppo = $t === 'riscaldamento' ? 'R' : ($t === 'straordinaria' ? 'S' : 'O');
|
$gruppo = $t === 'riscaldamento' ? 'R' : ($t === 'straordinaria' ? 'S' : 'O');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -532,24 +540,24 @@ public function table(Table $table): Table
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'codice_tabella' => (string) ($record->codice_tabella ?? ''),
|
'codice_tabella' => (string) ($record->codice_tabella ?? ''),
|
||||||
'denominazione' => (string) ($record->denominazione ?? ($record->descrizione ?? '')),
|
'denominazione' => (string) ($record->denominazione ?? ($record->descrizione ?? '')),
|
||||||
'gruppo' => strtoupper((string) ($gruppo ?? 'O')),
|
'gruppo' => strtoupper((string) ($gruppo ?? 'O')),
|
||||||
'tipo_calcolo' => strtolower((string) ($calcolo ?? 'millesimi')),
|
'tipo_calcolo' => strtolower((string) ($calcolo ?? 'millesimi')),
|
||||||
'totale_millesimi' => $record->getRawOriginal('totale_millesimi'),
|
'totale_millesimi' => $record->getRawOriginal('totale_millesimi'),
|
||||||
'ordine_visualizzazione' => $record->ordine_visualizzazione,
|
'ordine_visualizzazione' => $record->ordine_visualizzazione,
|
||||||
'ordinamento' => $record->ordinamento,
|
'ordinamento' => $record->ordinamento,
|
||||||
'attiva' => (bool) ($record->attiva ?? true),
|
'attiva' => (bool) ($record->attiva ?? true),
|
||||||
'note' => (string) ($record->note ?? ''),
|
'note' => (string) ($record->note ?? ''),
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
->action(function (TabellaMillesimale $record, array $data): void {
|
->action(function (TabellaMillesimale $record, array $data): void {
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
|
|
||||||
$gruppo = strtoupper(trim((string) ($data['gruppo'] ?? 'O')));
|
$gruppo = strtoupper(trim((string) ($data['gruppo'] ?? 'O')));
|
||||||
$tipoTabella = match ($gruppo) {
|
$tipoTabella = match ($gruppo) {
|
||||||
'R' => 'riscaldamento',
|
'R' => 'riscaldamento',
|
||||||
'S' => 'straordinaria',
|
'S' => 'straordinaria',
|
||||||
default => 'ordinaria',
|
default => 'ordinaria',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -558,21 +566,21 @@ public function table(Table $table): Table
|
||||||
$meta = is_array($record->meta_legacy)
|
$meta = is_array($record->meta_legacy)
|
||||||
? $record->meta_legacy
|
? $record->meta_legacy
|
||||||
: (is_string($record->meta_legacy) ? json_decode($record->meta_legacy, true) : []);
|
: (is_string($record->meta_legacy) ? json_decode($record->meta_legacy, true) : []);
|
||||||
$meta = is_array($meta) ? $meta : [];
|
$meta = is_array($meta) ? $meta : [];
|
||||||
$meta['tipo'] = $gruppo;
|
$meta['tipo'] = $gruppo;
|
||||||
$meta['calcolo'] = $tipoCalcolo;
|
$meta['calcolo'] = $tipoCalcolo;
|
||||||
|
|
||||||
$payload = [
|
$payload = [
|
||||||
'codice_tabella' => strtoupper(trim((string) ($data['codice_tabella'] ?? ''))),
|
'codice_tabella' => strtoupper(trim((string) ($data['codice_tabella'] ?? ''))),
|
||||||
'denominazione' => trim((string) ($data['denominazione'] ?? '')),
|
'denominazione' => trim((string) ($data['denominazione'] ?? '')),
|
||||||
'tipo_tabella' => $tipoTabella,
|
'tipo_tabella' => $tipoTabella,
|
||||||
'tipo_calcolo' => $tipoCalcolo,
|
'tipo_calcolo' => $tipoCalcolo,
|
||||||
'totale_millesimi' => is_numeric($data['totale_millesimi'] ?? null) ? (float) $data['totale_millesimi'] : null,
|
'totale_millesimi' => is_numeric($data['totale_millesimi'] ?? null) ? (float) $data['totale_millesimi'] : null,
|
||||||
'ordine_visualizzazione' => is_numeric($data['ordine_visualizzazione'] ?? null) ? (int) $data['ordine_visualizzazione'] : null,
|
'ordine_visualizzazione' => is_numeric($data['ordine_visualizzazione'] ?? null) ? (int) $data['ordine_visualizzazione'] : null,
|
||||||
'ordinamento' => is_numeric($data['ordinamento'] ?? null) ? (int) $data['ordinamento'] : null,
|
'ordinamento' => is_numeric($data['ordinamento'] ?? null) ? (int) $data['ordinamento'] : null,
|
||||||
'attiva' => (bool) ($data['attiva'] ?? true),
|
'attiva' => (bool) ($data['attiva'] ?? true),
|
||||||
'note' => trim((string) ($data['note'] ?? '')) ?: null,
|
'note' => trim((string) ($data['note'] ?? '')) ?: null,
|
||||||
'meta_legacy' => $meta,
|
'meta_legacy' => $meta,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($user instanceof User && Schema::hasColumn('tabelle_millesimali', 'modificato_da')) {
|
if ($user instanceof User && Schema::hasColumn('tabelle_millesimali', 'modificato_da')) {
|
||||||
|
|
@ -617,13 +625,13 @@ protected function loadTabelle(): void
|
||||||
->get(['id', 'codice_tabella', 'nome_tabella', 'denominazione', 'tipo_tabella', 'tipo_calcolo', 'totale_millesimi', 'ordinamento', 'ordine_visualizzazione', 'nord', 'meta_legacy'])
|
->get(['id', 'codice_tabella', 'nome_tabella', 'denominazione', 'tipo_tabella', 'tipo_calcolo', 'totale_millesimi', 'ordinamento', 'ordine_visualizzazione', 'nord', 'meta_legacy'])
|
||||||
->map(function (TabellaMillesimale $t) {
|
->map(function (TabellaMillesimale $t) {
|
||||||
$codice = $t->codice_tabella ?: ($t->nome_tabella ?: ('TAB ' . $t->id));
|
$codice = $t->codice_tabella ?: ($t->nome_tabella ?: ('TAB ' . $t->id));
|
||||||
$nome = $t->denominazione ?: ($t->nome_tabella_millesimale ?: ($t->nome_tabella ?: 'Tabella'));
|
$nome = $t->denominazione ?: ($t->nome_tabella_millesimale ?: ($t->nome_tabella ?: 'Tabella'));
|
||||||
|
|
||||||
$calcoloRaw = $this->resolveCalcoloRaw($t);
|
$calcoloRaw = $this->resolveCalcoloRaw($t);
|
||||||
$isConsumo = $this->isConsumoCalcolo($calcoloRaw);
|
$isConsumo = $this->isConsumoCalcolo($calcoloRaw);
|
||||||
$calcoloLabel = $this->formatCalcoloLabel($calcoloRaw);
|
$calcoloLabel = $this->formatCalcoloLabel($calcoloRaw);
|
||||||
$tipoLabel = $this->resolveTipoLabel($t, $calcoloRaw);
|
$tipoLabel = $this->resolveTipoLabel($t, $calcoloRaw);
|
||||||
$meta = is_array($t->meta_legacy)
|
$meta = is_array($t->meta_legacy)
|
||||||
? $t->meta_legacy
|
? $t->meta_legacy
|
||||||
: (is_string($t->meta_legacy) ? json_decode($t->meta_legacy, true) : null);
|
: (is_string($t->meta_legacy) ? json_decode($t->meta_legacy, true) : null);
|
||||||
$meta = is_array($meta) ? $meta : [];
|
$meta = is_array($meta) ? $meta : [];
|
||||||
|
|
@ -631,32 +639,32 @@ protected function loadTabelle(): void
|
||||||
$cons = $meta['tot_cons_euro'] ?? $meta['tot_cons'] ?? null;
|
$cons = $meta['tot_cons_euro'] ?? $meta['tot_cons'] ?? null;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'id' => (int) $t->id,
|
'id' => (int) $t->id,
|
||||||
'codice' => $codice,
|
'codice' => $codice,
|
||||||
'nome' => $nome,
|
'nome' => $nome,
|
||||||
'nord' => $this->resolveNordValue($t),
|
'nord' => $this->resolveNordValue($t),
|
||||||
'tipo' => $tipoLabel,
|
'tipo' => $tipoLabel,
|
||||||
'calcolo' => $calcoloLabel,
|
'calcolo' => $calcoloLabel,
|
||||||
'is_consumo' => $isConsumo,
|
'is_consumo' => $isConsumo,
|
||||||
'totale' => is_numeric($t->totale_millesimi) ? (float) $t->totale_millesimi : null,
|
'totale' => is_numeric($t->totale_millesimi) ? (float) $t->totale_millesimi : null,
|
||||||
'ordinamento' => $this->resolveNordValue($t) ?? (int) ($t->ordine_visualizzazione ?? $t->ordinamento ?? 999999),
|
'ordinamento' => $this->resolveNordValue($t) ?? (int) ($t->ordine_visualizzazione ?? $t->ordinamento ?? 999999),
|
||||||
'is_bilanciata' => (bool) ($t->is_bilanciata ?? false),
|
'is_bilanciata' => (bool) ($t->is_bilanciata ?? false),
|
||||||
'preventivo' => is_numeric($prev) ? (float) $prev : null,
|
'preventivo' => is_numeric($prev) ? (float) $prev : null,
|
||||||
'consuntivo' => is_numeric($cons) ? (float) $cons : null,
|
'consuntivo' => is_numeric($cons) ? (float) $cons : null,
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
->values()
|
->values()
|
||||||
->all();
|
->all();
|
||||||
|
|
||||||
usort($this->tabelle, static function (array $left, array $right): int {
|
usort($this->tabelle, static function (array $left, array $right): int {
|
||||||
$leftNord = is_numeric($left['ordinamento'] ?? null) ? (int) $left['ordinamento'] : 999999;
|
$leftNord = is_numeric($left['ordinamento'] ?? null) ? (int) $left['ordinamento'] : 999999;
|
||||||
$rightNord = is_numeric($right['ordinamento'] ?? null) ? (int) $right['ordinamento'] : 999999;
|
$rightNord = is_numeric($right['ordinamento'] ?? null) ? (int) $right['ordinamento'] : 999999;
|
||||||
|
|
||||||
if ($leftNord !== $rightNord) {
|
if ($leftNord !== $rightNord) {
|
||||||
return $leftNord <=> $rightNord;
|
return $leftNord <=> $rightNord;
|
||||||
}
|
}
|
||||||
|
|
||||||
$leftTipo = (string) ($left['tipo'] ?? '');
|
$leftTipo = (string) ($left['tipo'] ?? '');
|
||||||
$rightTipo = (string) ($right['tipo'] ?? '');
|
$rightTipo = (string) ($right['tipo'] ?? '');
|
||||||
if ($leftTipo !== $rightTipo) {
|
if ($leftTipo !== $rightTipo) {
|
||||||
return strnatcasecmp($leftTipo, $rightTipo);
|
return strnatcasecmp($leftTipo, $rightTipo);
|
||||||
|
|
@ -678,7 +686,7 @@ protected function pickTabellaId(?int $candidate): ?int
|
||||||
|
|
||||||
protected function loadDettaglioTabella(): void
|
protected function loadDettaglioTabella(): void
|
||||||
{
|
{
|
||||||
$this->righe = [];
|
$this->righe = [];
|
||||||
$this->tabellaInfo = null;
|
$this->tabellaInfo = null;
|
||||||
|
|
||||||
if (! $this->stabileId || ! $this->tabellaId) {
|
if (! $this->stabileId || ! $this->tabellaId) {
|
||||||
|
|
@ -700,27 +708,27 @@ protected function loadDettaglioTabella(): void
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$rawTotale = $tabella->getRawOriginal('totale_millesimi');
|
$rawTotale = $tabella->getRawOriginal('totale_millesimi');
|
||||||
$totaleCalcolato = (float) ($tabella->calcolaTotaleMillesimi() ?? 0);
|
$totaleCalcolato = (float) ($tabella->calcolaTotaleMillesimi() ?? 0);
|
||||||
$totale = is_numeric($rawTotale) ? (float) $rawTotale : $totaleCalcolato;
|
$totale = is_numeric($rawTotale) ? (float) $rawTotale : $totaleCalcolato;
|
||||||
$codice = $tabella->codice_tabella ?: ($tabella->nome_tabella ?: ('TAB ' . $tabella->id));
|
$codice = $tabella->codice_tabella ?: ($tabella->nome_tabella ?: ('TAB ' . $tabella->id));
|
||||||
$nome = $tabella->denominazione ?: ($tabella->nome_tabella_millesimale ?: ($tabella->nome_tabella ?: 'Tabella'));
|
$nome = $tabella->denominazione ?: ($tabella->nome_tabella_millesimale ?: ($tabella->nome_tabella ?: 'Tabella'));
|
||||||
|
|
||||||
$isBilanciata = is_numeric($rawTotale)
|
$isBilanciata = is_numeric($rawTotale)
|
||||||
? (abs(((float) $rawTotale) - 1000) < 0.01)
|
? (abs(((float) $rawTotale) - 1000) < 0.01)
|
||||||
: (bool) $tabella->isBilanciata();
|
: (bool) $tabella->isBilanciata();
|
||||||
|
|
||||||
$this->tabellaInfo = [
|
$this->tabellaInfo = [
|
||||||
'id' => (int) $tabella->id,
|
'id' => (int) $tabella->id,
|
||||||
'codice' => $codice,
|
'codice' => $codice,
|
||||||
'nome' => $nome,
|
'nome' => $nome,
|
||||||
'tipo' => $this->resolveTipoLabel($tabella, $this->resolveCalcoloRaw($tabella)),
|
'tipo' => $this->resolveTipoLabel($tabella, $this->resolveCalcoloRaw($tabella)),
|
||||||
'calcolo' => $this->formatCalcoloLabel($this->resolveCalcoloRaw($tabella)),
|
'calcolo' => $this->formatCalcoloLabel($this->resolveCalcoloRaw($tabella)),
|
||||||
'is_consumo' => $this->isConsumoCalcolo($this->resolveCalcoloRaw($tabella)),
|
'is_consumo' => $this->isConsumoCalcolo($this->resolveCalcoloRaw($tabella)),
|
||||||
'totale' => $totale,
|
'totale' => $totale,
|
||||||
'is_bilanciata' => $isBilanciata,
|
'is_bilanciata' => $isBilanciata,
|
||||||
'preventivo' => $this->resolveLegacyImporto($tabella, 'tot_prev_euro', 'tot_prev'),
|
'preventivo' => $this->resolveLegacyImporto($tabella, 'tot_prev_euro', 'tot_prev'),
|
||||||
'consuntivo' => $this->resolveLegacyImporto($tabella, 'tot_cons_euro', 'tot_cons'),
|
'consuntivo' => $this->resolveLegacyImporto($tabella, 'tot_cons_euro', 'tot_cons'),
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->righe = $tabella->dettagliMillesimali
|
$this->righe = $tabella->dettagliMillesimali
|
||||||
|
|
@ -737,22 +745,22 @@ protected function loadDettaglioTabella(): void
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
->map(function ($d) use ($totale) {
|
->map(function ($d) use ($totale) {
|
||||||
$u = $d->unitaImmobiliare;
|
$u = $d->unitaImmobiliare;
|
||||||
$millesimi = (float) ($d->millesimi ?? 0);
|
$millesimi = (float) ($d->millesimi ?? 0);
|
||||||
$percentuale = $totale > 0 ? ($millesimi / $totale) * 100 : 0;
|
$percentuale = $totale > 0 ? ($millesimi / $totale) * 100 : 0;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'unita_id' => (int) ($u?->id ?? 0),
|
'unita_id' => (int) ($u?->id ?? 0),
|
||||||
'codice_unita' => $u?->codice_unita ?? ($u?->codice_completo ?? null),
|
'codice_unita' => $u?->codice_unita ?? ($u?->codice_completo ?? null),
|
||||||
'codice_unita_display' => $this->formatCodiceUnita($u?->codice_unita ?? ($u?->codice_completo ?? null)),
|
'codice_unita_display' => $this->formatCodiceUnita($u?->codice_unita ?? ($u?->codice_completo ?? null)),
|
||||||
'denominazione' => $u?->denominazione,
|
'denominazione' => $u?->denominazione,
|
||||||
'palazzina' => $u?->palazzina,
|
'palazzina' => $u?->palazzina,
|
||||||
'scala' => $u?->scala,
|
'scala' => $u?->scala,
|
||||||
'piano' => $u?->piano,
|
'piano' => $u?->piano,
|
||||||
'interno' => $u?->interno,
|
'interno' => $u?->interno,
|
||||||
'millesimi' => $millesimi,
|
'millesimi' => $millesimi,
|
||||||
'percentuale' => round($percentuale, 4),
|
'percentuale' => round($percentuale, 4),
|
||||||
'partecipa' => (bool) ($d->partecipa ?? true),
|
'partecipa' => (bool) ($d->partecipa ?? true),
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
->values()
|
->values()
|
||||||
|
|
@ -772,7 +780,7 @@ protected function loadVociSpesa(): void
|
||||||
}
|
}
|
||||||
|
|
||||||
$hasCond = Schema::hasColumn('voci_spesa', 'percentuale_condomino');
|
$hasCond = Schema::hasColumn('voci_spesa', 'percentuale_condomino');
|
||||||
$hasInq = Schema::hasColumn('voci_spesa', 'percentuale_inquilino');
|
$hasInq = Schema::hasColumn('voci_spesa', 'percentuale_inquilino');
|
||||||
|
|
||||||
$rows = VoceSpesa::query()
|
$rows = VoceSpesa::query()
|
||||||
->where('stabile_id', $this->stabileId)
|
->where('stabile_id', $this->stabileId)
|
||||||
|
|
@ -783,15 +791,15 @@ protected function loadVociSpesa(): void
|
||||||
|
|
||||||
$this->vociSpesa = $rows->map(function (VoceSpesa $v) use ($hasCond, $hasInq): array {
|
$this->vociSpesa = $rows->map(function (VoceSpesa $v) use ($hasCond, $hasInq): array {
|
||||||
return [
|
return [
|
||||||
'id' => (int) $v->id,
|
'id' => (int) $v->id,
|
||||||
'codice' => $v->codice,
|
'codice' => $v->codice,
|
||||||
'descrizione' => $v->descrizione,
|
'descrizione' => $v->descrizione,
|
||||||
'categoria' => $v->categoria,
|
'categoria' => $v->categoria,
|
||||||
'tipo_gestione' => $v->tipo_gestione,
|
'tipo_gestione' => $v->tipo_gestione,
|
||||||
'percentuale_condomino' => $hasCond ? (float) ($v->percentuale_condomino ?? 0) : null,
|
'percentuale_condomino' => $hasCond ? (float) ($v->percentuale_condomino ?? 0) : null,
|
||||||
'percentuale_inquilino' => $hasInq ? (float) ($v->percentuale_inquilino ?? 0) : null,
|
'percentuale_inquilino' => $hasInq ? (float) ($v->percentuale_inquilino ?? 0) : null,
|
||||||
'attiva' => (bool) ($v->attiva ?? true),
|
'attiva' => (bool) ($v->attiva ?? true),
|
||||||
'modifica' => false,
|
'modifica' => false,
|
||||||
];
|
];
|
||||||
})->all();
|
})->all();
|
||||||
|
|
||||||
|
|
@ -830,11 +838,11 @@ public function applyPresetRipartizione(): void
|
||||||
|
|
||||||
foreach ($this->vociSpesa as $i => $voce) {
|
foreach ($this->vociSpesa as $i => $voce) {
|
||||||
$categoria = $this->mapVoceCategoriaToConfedilizia((string) ($voce['categoria'] ?? ''));
|
$categoria = $this->mapVoceCategoriaToConfedilizia((string) ($voce['categoria'] ?? ''));
|
||||||
$default = RipartizioneSpeseInquilini::getDefaultConfedilizia($categoria);
|
$default = RipartizioneSpeseInquilini::getDefaultConfedilizia($categoria);
|
||||||
|
|
||||||
$this->vociSpesa[$i]['percentuale_condomino'] = (float) ($default['proprietario'] ?? 100);
|
$this->vociSpesa[$i]['percentuale_condomino'] = (float) ($default['proprietario'] ?? 100);
|
||||||
$this->vociSpesa[$i]['percentuale_inquilino'] = (float) ($default['inquilino'] ?? 0);
|
$this->vociSpesa[$i]['percentuale_inquilino'] = (float) ($default['inquilino'] ?? 0);
|
||||||
$this->vociSpesa[$i]['modifica'] = true;
|
$this->vociSpesa[$i]['modifica'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->presetDirty = true;
|
$this->presetDirty = true;
|
||||||
|
|
@ -856,7 +864,7 @@ public function applyCustomPreset(): void
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = is_array($preset->dati) ? $preset->dati : [];
|
$data = is_array($preset->dati) ? $preset->dati : [];
|
||||||
$map = [];
|
$map = [];
|
||||||
foreach ($data as $row) {
|
foreach ($data as $row) {
|
||||||
$codice = isset($row['codice']) ? (string) $row['codice'] : '';
|
$codice = isset($row['codice']) ? (string) $row['codice'] : '';
|
||||||
if ($codice !== '') {
|
if ($codice !== '') {
|
||||||
|
|
@ -870,7 +878,7 @@ public function applyCustomPreset(): void
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$row = $map[$codice];
|
$row = $map[$codice];
|
||||||
$cond = isset($row['percentuale_condomino']) && is_numeric($row['percentuale_condomino'])
|
$cond = isset($row['percentuale_condomino']) && is_numeric($row['percentuale_condomino'])
|
||||||
? (float) $row['percentuale_condomino']
|
? (float) $row['percentuale_condomino']
|
||||||
: 100.0;
|
: 100.0;
|
||||||
|
|
@ -880,7 +888,7 @@ public function applyCustomPreset(): void
|
||||||
|
|
||||||
$this->vociSpesa[$i]['percentuale_condomino'] = $cond;
|
$this->vociSpesa[$i]['percentuale_condomino'] = $cond;
|
||||||
$this->vociSpesa[$i]['percentuale_inquilino'] = $inq;
|
$this->vociSpesa[$i]['percentuale_inquilino'] = $inq;
|
||||||
$this->vociSpesa[$i]['modifica'] = true;
|
$this->vociSpesa[$i]['modifica'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->presetDirty = false;
|
$this->presetDirty = false;
|
||||||
|
|
@ -900,7 +908,7 @@ public function savePresetAsNew(): void
|
||||||
|
|
||||||
$data = array_values(array_map(function ($row): array {
|
$data = array_values(array_map(function ($row): array {
|
||||||
return [
|
return [
|
||||||
'codice' => $row['codice'] ?? null,
|
'codice' => $row['codice'] ?? null,
|
||||||
'percentuale_condomino' => is_numeric($row['percentuale_condomino'] ?? null) ? (float) $row['percentuale_condomino'] : null,
|
'percentuale_condomino' => is_numeric($row['percentuale_condomino'] ?? null) ? (float) $row['percentuale_condomino'] : null,
|
||||||
'percentuale_inquilino' => is_numeric($row['percentuale_inquilino'] ?? null) ? (float) $row['percentuale_inquilino'] : null,
|
'percentuale_inquilino' => is_numeric($row['percentuale_inquilino'] ?? null) ? (float) $row['percentuale_inquilino'] : null,
|
||||||
];
|
];
|
||||||
|
|
@ -908,15 +916,15 @@ public function savePresetAsNew(): void
|
||||||
|
|
||||||
$preset = RipartizionePreset::query()->create([
|
$preset = RipartizionePreset::query()->create([
|
||||||
'stabile_id' => $this->stabileId,
|
'stabile_id' => $this->stabileId,
|
||||||
'nome' => $nome,
|
'nome' => $nome,
|
||||||
'dati' => $data,
|
'dati' => $data,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->presetNome = '';
|
$this->presetNome = '';
|
||||||
$this->loadPresetOptions();
|
$this->loadPresetOptions();
|
||||||
$this->presetId = (int) $preset->id;
|
$this->presetId = (int) $preset->id;
|
||||||
$this->presetRipartizione = 'custom';
|
$this->presetRipartizione = 'custom';
|
||||||
$this->presetDirty = false;
|
$this->presetDirty = false;
|
||||||
|
|
||||||
Notification::make()->title('Preset creato')->success()->send();
|
Notification::make()->title('Preset creato')->success()->send();
|
||||||
}
|
}
|
||||||
|
|
@ -938,7 +946,7 @@ public function updatePreset(): void
|
||||||
|
|
||||||
$data = array_values(array_map(function ($row): array {
|
$data = array_values(array_map(function ($row): array {
|
||||||
return [
|
return [
|
||||||
'codice' => $row['codice'] ?? null,
|
'codice' => $row['codice'] ?? null,
|
||||||
'percentuale_condomino' => is_numeric($row['percentuale_condomino'] ?? null) ? (float) $row['percentuale_condomino'] : null,
|
'percentuale_condomino' => is_numeric($row['percentuale_condomino'] ?? null) ? (float) $row['percentuale_condomino'] : null,
|
||||||
'percentuale_inquilino' => is_numeric($row['percentuale_inquilino'] ?? null) ? (float) $row['percentuale_inquilino'] : null,
|
'percentuale_inquilino' => is_numeric($row['percentuale_inquilino'] ?? null) ? (float) $row['percentuale_inquilino'] : null,
|
||||||
];
|
];
|
||||||
|
|
@ -988,23 +996,23 @@ public function updatedVociSpesa($value, string $name): void
|
||||||
private function mapVoceCategoriaToConfedilizia(string $categoriaVoce): string
|
private function mapVoceCategoriaToConfedilizia(string $categoriaVoce): string
|
||||||
{
|
{
|
||||||
return match ($categoriaVoce) {
|
return match ($categoriaVoce) {
|
||||||
'riscaldamento' => 'B',
|
'riscaldamento' => 'B',
|
||||||
'ascensore' => 'C',
|
'ascensore' => 'C',
|
||||||
'illuminazione' => 'D',
|
'illuminazione' => 'D',
|
||||||
'pulizia' => 'E',
|
'pulizia' => 'E',
|
||||||
'acqua' => 'G',
|
'acqua' => 'G',
|
||||||
'energia_elettrica' => 'L',
|
'energia_elettrica' => 'L',
|
||||||
'gas' => 'B',
|
'gas' => 'B',
|
||||||
'giardino_verde' => 'I',
|
'giardino_verde' => 'I',
|
||||||
'sicurezza' => 'N',
|
'sicurezza' => 'N',
|
||||||
'amministrazione' => 'O',
|
'amministrazione' => 'O',
|
||||||
'assicurazioni' => 'A',
|
'assicurazioni' => 'A',
|
||||||
'tasse_tributi' => 'O',
|
'tasse_tributi' => 'O',
|
||||||
'spese_legali' => 'O',
|
'spese_legali' => 'O',
|
||||||
'manutenzione_ordinaria' => 'A',
|
'manutenzione_ordinaria' => 'A',
|
||||||
'manutenzione_straordinaria' => 'A',
|
'manutenzione_straordinaria' => 'A',
|
||||||
'lavori_miglioramento' => 'A',
|
'lavori_miglioramento' => 'A',
|
||||||
default => 'A',
|
default => 'A',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1019,13 +1027,13 @@ public function saveVociSpesa(): void
|
||||||
}
|
}
|
||||||
|
|
||||||
$hasCond = Schema::hasColumn('voci_spesa', 'percentuale_condomino');
|
$hasCond = Schema::hasColumn('voci_spesa', 'percentuale_condomino');
|
||||||
$hasInq = Schema::hasColumn('voci_spesa', 'percentuale_inquilino');
|
$hasInq = Schema::hasColumn('voci_spesa', 'percentuale_inquilino');
|
||||||
|
|
||||||
$validated = Validator::make(
|
$validated = Validator::make(
|
||||||
['voci' => $this->vociSpesa],
|
['voci' => $this->vociSpesa],
|
||||||
[
|
[
|
||||||
'voci' => ['array'],
|
'voci' => ['array'],
|
||||||
'voci.*.id' => ['required', 'integer', 'min:1'],
|
'voci.*.id' => ['required', 'integer', 'min:1'],
|
||||||
'voci.*.percentuale_condomino' => ['nullable', 'numeric', 'min:0', 'max:100'],
|
'voci.*.percentuale_condomino' => ['nullable', 'numeric', 'min:0', 'max:100'],
|
||||||
'voci.*.percentuale_inquilino' => ['nullable', 'numeric', 'min:0', 'max:100'],
|
'voci.*.percentuale_inquilino' => ['nullable', 'numeric', 'min:0', 'max:100'],
|
||||||
]
|
]
|
||||||
|
|
@ -1095,7 +1103,7 @@ private function formatCodiceUnita(?string $codice): ?string
|
||||||
|
|
||||||
if ($prefix !== '') {
|
if ($prefix !== '') {
|
||||||
$pattern = '/^' . preg_quote($prefix, '/') . '[\s\-\/]+/';
|
$pattern = '/^' . preg_quote($prefix, '/') . '[\s\-\/]+/';
|
||||||
$codice = preg_replace($pattern, '', $codice) ?? $codice;
|
$codice = preg_replace($pattern, '', $codice) ?? $codice;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $codice;
|
return $codice;
|
||||||
|
|
@ -1150,12 +1158,12 @@ public function inizializzaRighe(): void
|
||||||
$rows = array_map(function (int $unitaId) use ($userId): array {
|
$rows = array_map(function (int $unitaId) use ($userId): array {
|
||||||
return [
|
return [
|
||||||
'tabella_millesimale_id' => (int) $this->tabellaId,
|
'tabella_millesimale_id' => (int) $this->tabellaId,
|
||||||
'unita_immobiliare_id' => $unitaId,
|
'unita_immobiliare_id' => $unitaId,
|
||||||
'millesimi' => 0,
|
'millesimi' => 0,
|
||||||
'partecipa' => 1,
|
'partecipa' => 1,
|
||||||
'created_by' => $userId,
|
'created_by' => $userId,
|
||||||
'created_at' => now(),
|
'created_at' => now(),
|
||||||
'updated_at' => now(),
|
'updated_at' => now(),
|
||||||
];
|
];
|
||||||
}, $missing);
|
}, $missing);
|
||||||
|
|
||||||
|
|
@ -1179,15 +1187,15 @@ public function saveRighe(): void
|
||||||
$validated = Validator::make(
|
$validated = Validator::make(
|
||||||
['righe' => $this->righe],
|
['righe' => $this->righe],
|
||||||
[
|
[
|
||||||
'righe' => ['array'],
|
'righe' => ['array'],
|
||||||
'righe.*.unita_id' => ['required', 'integer', 'min:1'],
|
'righe.*.unita_id' => ['required', 'integer', 'min:1'],
|
||||||
'righe.*.millesimi' => ['required', 'numeric', 'min:0'],
|
'righe.*.millesimi' => ['required', 'numeric', 'min:0'],
|
||||||
'righe.*.partecipa' => ['nullable', 'boolean'],
|
'righe.*.partecipa' => ['nullable', 'boolean'],
|
||||||
]
|
]
|
||||||
)->validate();
|
)->validate();
|
||||||
|
|
||||||
/** @var array<int, array<string, mixed>> $rows */
|
/** @var array<int, array<string, mixed>> $rows */
|
||||||
$rows = (array) ($validated['righe'] ?? []);
|
$rows = (array) ($validated['righe'] ?? []);
|
||||||
$unitaIds = array_values(array_unique(array_map(fn($r) => (int) ($r['unita_id'] ?? 0), $rows)));
|
$unitaIds = array_values(array_unique(array_map(fn($r) => (int) ($r['unita_id'] ?? 0), $rows)));
|
||||||
$unitaIds = array_values(array_filter($unitaIds, fn(int $v) => $v > 0));
|
$unitaIds = array_values(array_filter($unitaIds, fn(int $v) => $v > 0));
|
||||||
|
|
||||||
|
|
@ -1203,8 +1211,8 @@ public function saveRighe(): void
|
||||||
->all();
|
->all();
|
||||||
|
|
||||||
$allowedSet = array_fill_keys($allowedUnita, true);
|
$allowedSet = array_fill_keys($allowedUnita, true);
|
||||||
$now = now();
|
$now = now();
|
||||||
$userId = Auth::id();
|
$userId = Auth::id();
|
||||||
|
|
||||||
DB::transaction(function () use ($rows, $allowedSet, $now, $userId): void {
|
DB::transaction(function () use ($rows, $allowedSet, $now, $userId): void {
|
||||||
foreach ($rows as $r) {
|
foreach ($rows as $r) {
|
||||||
|
|
@ -1231,12 +1239,12 @@ public function saveRighe(): void
|
||||||
|
|
||||||
DettaglioMillesimi::query()->create([
|
DettaglioMillesimi::query()->create([
|
||||||
'tabella_millesimale_id' => (int) $this->tabellaId,
|
'tabella_millesimale_id' => (int) $this->tabellaId,
|
||||||
'unita_immobiliare_id' => $unitaId,
|
'unita_immobiliare_id' => $unitaId,
|
||||||
'millesimi' => $millesimi,
|
'millesimi' => $millesimi,
|
||||||
'partecipa' => $partecipa,
|
'partecipa' => $partecipa,
|
||||||
'created_by' => $userId,
|
'created_by' => $userId,
|
||||||
'created_at' => $now,
|
'created_at' => $now,
|
||||||
'updated_at' => $now,
|
'updated_at' => $now,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -1275,10 +1283,10 @@ private function resolveCalcoloRaw(TabellaMillesimale $t): ?string
|
||||||
}
|
}
|
||||||
|
|
||||||
return match ($v) {
|
return match ($v) {
|
||||||
'm' => 'millesimi',
|
'm' => 'millesimi',
|
||||||
'a', 'c' => 'a_consumo',
|
'a', 'c' => 'a_consumo',
|
||||||
'x' => 'conguagli',
|
'x' => 'conguagli',
|
||||||
'p' => 'personali',
|
'p' => 'personali',
|
||||||
default => $v,
|
default => $v,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -1316,9 +1324,9 @@ private function resolveTipoLabel(TabellaMillesimale $t, ?string $calcoloRaw): ?
|
||||||
$ors = isset($meta['tipo']) ? strtoupper((string) $meta['tipo']) : null;
|
$ors = isset($meta['tipo']) ? strtoupper((string) $meta['tipo']) : null;
|
||||||
if ($ors) {
|
if ($ors) {
|
||||||
return match ($ors) {
|
return match ($ors) {
|
||||||
'O' => 'O (Ordinaria)',
|
'O' => 'O (Ordinaria)',
|
||||||
'R' => 'R (Riscaldamento)',
|
'R' => 'R (Riscaldamento)',
|
||||||
'S' => 'S (Straordinaria)',
|
'S' => 'S (Straordinaria)',
|
||||||
default => $ors,
|
default => $ors,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -1326,16 +1334,24 @@ private function resolveTipoLabel(TabellaMillesimale $t, ?string $calcoloRaw): ?
|
||||||
$tipologia = strtoupper((string) ($t->tipologia ?? ''));
|
$tipologia = strtoupper((string) ($t->tipologia ?? ''));
|
||||||
if (in_array($tipologia, ['O', 'R', 'S'], true)) {
|
if (in_array($tipologia, ['O', 'R', 'S'], true)) {
|
||||||
return match ($tipologia) {
|
return match ($tipologia) {
|
||||||
'R' => 'R (Riscaldamento)',
|
'R' => 'R (Riscaldamento)',
|
||||||
'S' => 'S (Straordinaria)',
|
'S' => 'S (Straordinaria)',
|
||||||
default => 'O (Ordinaria)',
|
default => 'O (Ordinaria)',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
$tipo = strtolower((string) ($t->tipo_tabella ?? ''));
|
$tipo = strtolower((string) ($t->tipo_tabella ?? ''));
|
||||||
if ($tipo === 'riscaldamento') return 'R (Riscaldamento)';
|
if ($tipo === 'riscaldamento') {
|
||||||
if ($tipo === 'straordinaria') return 'S (Straordinaria)';
|
return 'R (Riscaldamento)';
|
||||||
if ($tipo === 'ordinaria') return 'O (Ordinaria)';
|
}
|
||||||
|
|
||||||
|
if ($tipo === 'straordinaria') {
|
||||||
|
return 'S (Straordinaria)';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($tipo === 'ordinaria') {
|
||||||
|
return 'O (Ordinaria)';
|
||||||
|
}
|
||||||
|
|
||||||
return $tipo !== '' ? strtoupper($tipo) : null;
|
return $tipo !== '' ? strtoupper($tipo) : null;
|
||||||
}
|
}
|
||||||
|
|
@ -1345,7 +1361,7 @@ private function resolveLegacyImporto(TabellaMillesimale $t, string $primary, st
|
||||||
$meta = is_array($t->meta_legacy)
|
$meta = is_array($t->meta_legacy)
|
||||||
? $t->meta_legacy
|
? $t->meta_legacy
|
||||||
: (is_string($t->meta_legacy) ? json_decode($t->meta_legacy, true) : null);
|
: (is_string($t->meta_legacy) ? json_decode($t->meta_legacy, true) : null);
|
||||||
$meta = is_array($meta) ? $meta : [];
|
$meta = is_array($meta) ? $meta : [];
|
||||||
$value = $meta[$primary] ?? $meta[$fallback] ?? null;
|
$value = $meta[$primary] ?? $meta[$fallback] ?? null;
|
||||||
return is_numeric($value) ? (float) $value : null;
|
return is_numeric($value) ? (float) $value : null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@
|
||||||
use App\Models\Stabile;
|
use App\Models\Stabile;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Services\TenantArchivePathService;
|
use App\Services\TenantArchivePathService;
|
||||||
use App\Support\ArchivioPaths;
|
|
||||||
use App\Support\GoogleAccountStore;
|
use App\Support\GoogleAccountStore;
|
||||||
use BackedEnum;
|
use BackedEnum;
|
||||||
use Filament\Notifications\Notification;
|
use Filament\Notifications\Notification;
|
||||||
|
|
@ -575,10 +574,10 @@ private function resolveTecnoRepairMdbPath(?string $rawPath): ?string
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$diskRoot = str_replace('\\', '/', Storage::disk('local')->path(''));
|
$diskRoot = str_replace('\\', '/', Storage::disk('local')->path(''));
|
||||||
$storageBase = str_replace('\\', '/', storage_path('app'));
|
$storageBase = str_replace('\\', '/', storage_path('app'));
|
||||||
$normalizedInput = str_replace('\\', '/', $path);
|
$normalizedInput = str_replace('\\', '/', $path);
|
||||||
$candidatePaths = [];
|
$candidatePaths = [];
|
||||||
|
|
||||||
if (is_file($path)) {
|
if (is_file($path)) {
|
||||||
$candidatePaths[] = $path;
|
$candidatePaths[] = $path;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
|
@ -55,4 +54,4 @@ public function rubrica(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(RubricaUniversale::class, 'rubrica_id');
|
return $this->belongsTo(RubricaUniversale::class, 'rubrica_id');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
use App\Models\Amministratore;
|
use App\Models\Amministratore;
|
||||||
use App\Models\Fornitore;
|
use App\Models\Fornitore;
|
||||||
use App\Models\Stabile;
|
use App\Models\Stabile;
|
||||||
use InvalidArgumentException;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
class TenantArchivePathService
|
class TenantArchivePathService
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Support;
|
namespace App\Support;
|
||||||
|
|
||||||
use App\Models\Amministratore;
|
use App\Models\Amministratore;
|
||||||
|
|
@ -20,7 +19,7 @@ private static function sanitizeFolder(string $value): string
|
||||||
return trim($value, '-');
|
return trim($value, '-');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function adminBase(Amministratore|string $admin): string
|
public static function adminBase(Amministratore | string $admin): string
|
||||||
{
|
{
|
||||||
$code = $admin instanceof Amministratore
|
$code = $admin instanceof Amministratore
|
||||||
? (string) ($admin->codice_univoco ?: $admin->codice_amministratore ?: '')
|
? (string) ($admin->codice_univoco ?: $admin->codice_amministratore ?: '')
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@
|
||||||
],
|
],
|
||||||
|
|
||||||
'google' => [
|
'google' => [
|
||||||
'drive_template_folders' => [
|
'drive_template_folders' => [
|
||||||
'bilanci',
|
'bilanci',
|
||||||
'riscaldamento',
|
'riscaldamento',
|
||||||
'visure_catastali',
|
'visure_catastali',
|
||||||
|
|
@ -171,7 +171,7 @@
|
||||||
'informative',
|
'informative',
|
||||||
'verifiche_periodiche',
|
'verifiche_periodiche',
|
||||||
],
|
],
|
||||||
'drive_template_year_root' => 'archivio_per_anno',
|
'drive_template_year_root' => 'archivio_per_anno',
|
||||||
'drive_template_year_model' => '_anno_modello',
|
'drive_template_year_model' => '_anno_modello',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -53,4 +53,4 @@ public function down(): void
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -45,4 +45,4 @@ public function down(): void
|
||||||
{
|
{
|
||||||
Schema::dropIfExists('fornitore_clienti');
|
Schema::dropIfExists('fornitore_clienti');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration {
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
if (! Schema::hasTable('dettaglio_millesimi') || ! Schema::hasColumn('dettaglio_millesimi', 'ruolo_legacy')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Schema::table('dettaglio_millesimi', function (Blueprint $table): void {
|
||||||
|
$table->unique(
|
||||||
|
['tabella_millesimale_id', 'unita_immobiliare_id', 'ruolo_legacy'],
|
||||||
|
'unique_tabella_unita_ruolo_legacy'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('dettaglio_millesimi', function (Blueprint $table): void {
|
||||||
|
try {
|
||||||
|
DB::statement('ALTER TABLE `dettaglio_millesimi` DROP INDEX `unique_tabella_unita`');
|
||||||
|
} catch (\Throwable) {
|
||||||
|
// Already dropped or not present.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
if (! Schema::hasTable('dettaglio_millesimi')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Schema::table('dettaglio_millesimi', function (Blueprint $table): void {
|
||||||
|
$table->unique(['tabella_millesimale_id', 'unita_immobiliare_id'], 'unique_tabella_unita');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('dettaglio_millesimi', function (Blueprint $table): void {
|
||||||
|
try {
|
||||||
|
DB::statement('ALTER TABLE `dettaglio_millesimi` DROP INDEX `unique_tabella_unita_ruolo_legacy`');
|
||||||
|
} catch (\Throwable) {
|
||||||
|
// Already dropped or not present.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -85,7 +85,7 @@ ## Punti ancora aperti da riprendere
|
||||||
|
|
||||||
## Prompt consigliato per un altro agent
|
## Prompt consigliato per un altro agent
|
||||||
|
|
||||||
"Riparti da `docs/ai/SESSION_HANDOFF.md`. Prima verifica `git status`, poi esegui `php artisan view:clear && php artisan view:cache`. Controlla staging su `tabelle-millesimali`, `ticket-acqua` e `ticket-acqua-generale`. Se il deploy e allineato, passa al raffinamento del QA millesimi/voci per gestioni straordinarie con anno/esercizio, senza fare bonifiche contabili distruttive."
|
"Riparti da `docs/ai/SESSION_HANDOFF.md`. Prima verifica `git status`, poi esegui `php artisan view:clear && php artisan view:cache`. Controlla staging su `tabelle-millesimali`, `ticket-acqua` e `ticket-acqua-generale`. Se il deploy e allineato, passa al raffinamento del QA millesimi/voci per gestioni straordinarie con anno/esercizio, senza fare bonifiche contabili distruttive."
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
51
docs/fornitori/tecnorepair-operativita.md
Normal file
51
docs/fornitori/tecnorepair-operativita.md
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# Operativita fornitore TecnoRepair
|
||||||
|
|
||||||
|
Questa nota riassume i punti introdotti nel flusso fornitore per archivio, rubrica clienti, Google e fatture elettroniche manuali.
|
||||||
|
|
||||||
|
## Archivio fornitore
|
||||||
|
|
||||||
|
- Il root reale del disco locale applicativo e `storage/app/private`.
|
||||||
|
- I percorsi mostrati nelle pagine fornitore devono essere risolti tramite `Storage::disk('local')->path(...)`, non costruiti a mano con `storage/app/...`.
|
||||||
|
- Per riallineare le cartelle fisiche dei fornitori esistenti usare:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php artisan netgescon:provision-fornitori-archives
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rubrica clienti fornitore
|
||||||
|
|
||||||
|
- La rubrica clienti fornitore e materializzata in `fornitore_clienti`.
|
||||||
|
- La sorgente attuale non e una tabella MDB separata a runtime: il dato cliente e ricostruito da `AssistenzaTecnorepairScheda.metadata['cliente']` gia importato dal legacy TecnoRepair.
|
||||||
|
- Il comando operativo e:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php artisan tecnorepair:import-rubrica-clienti {amministratore_id} --fornitore-id={fornitore_id}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Durante l import vengono normalizzati:
|
||||||
|
- province legacy troppo lunghe
|
||||||
|
- campi telefono contaminati da note testuali
|
||||||
|
|
||||||
|
## Google fornitore
|
||||||
|
|
||||||
|
- Gli account Google fornitore usano chiavi dedicate `fornitore-{id}`.
|
||||||
|
- Regola importante: un account fornitore non deve diventare il default Google dell amministratore.
|
||||||
|
- Il blocco legacy `google.oauth` va aggiornato solo dal default amministratore, non dagli account scoped del fornitore.
|
||||||
|
- In caso di collegamento/scollegamento fornitore, la UI amministratore deve continuare a riflettere solo l account default amministratore.
|
||||||
|
|
||||||
|
## FE manuale lato fornitore
|
||||||
|
|
||||||
|
- La pagina `admin-filament/fornitore/contabilita` espone un import manuale FE dal menu azioni in alto.
|
||||||
|
- File ammessi: XML, P7M, ZIP.
|
||||||
|
- Il file viene accettato solo se il cedente della FE coincide con P.IVA/CF del fornitore corrente.
|
||||||
|
- Lo stabile viene risolto in modo automatico dai dati destinatario della FE, ma ristretto agli stabili dell amministratore del fornitore.
|
||||||
|
- L import riusa `FatturaElettronicaImporter`; non crea fornitori nuovi e non introduce acquisizioni automatiche.
|
||||||
|
|
||||||
|
## Scheda intervento
|
||||||
|
|
||||||
|
- La Blade fornitore e stata resa piu compatta con tab operative:
|
||||||
|
- `Segnalazione`
|
||||||
|
- `Operativo`
|
||||||
|
- `Allegati`
|
||||||
|
- `Storico`
|
||||||
|
- L obiettivo e avvicinare la navigazione al flusso desktop TecnoRepair senza riscrivere la logica Livewire esistente.
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
<div class="space-y-4"
|
<div class="space-y-4"
|
||||||
x-data="{
|
x-data="{
|
||||||
|
activeTab: 'scheda',
|
||||||
localFotoPreviews: [],
|
localFotoPreviews: [],
|
||||||
localDocumentoPreviews: [],
|
localDocumentoPreviews: [],
|
||||||
geoBusy: false,
|
geoBusy: false,
|
||||||
|
|
@ -78,9 +79,19 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="rounded-xl border border-slate-200 bg-slate-50 p-3">
|
||||||
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
|
<button type="button" x-on:click="activeTab = 'scheda'" x-bind:class="activeTab === 'scheda' ? 'bg-slate-900 text-white ring-slate-900' : 'bg-white text-slate-700 ring-slate-300'" class="inline-flex items-center rounded-md px-3 py-1.5 text-xs font-semibold ring-1 ring-inset transition">Segnalazione</button>
|
||||||
|
<button type="button" x-on:click="activeTab = 'operativo'" x-bind:class="activeTab === 'operativo' ? 'bg-slate-900 text-white ring-slate-900' : 'bg-white text-slate-700 ring-slate-300'" class="inline-flex items-center rounded-md px-3 py-1.5 text-xs font-semibold ring-1 ring-inset transition">Operativo</button>
|
||||||
|
<button type="button" x-on:click="activeTab = 'allegati'" x-bind:class="activeTab === 'allegati' ? 'bg-slate-900 text-white ring-slate-900' : 'bg-white text-slate-700 ring-slate-300'" class="inline-flex items-center rounded-md px-3 py-1.5 text-xs font-semibold ring-1 ring-inset transition">Allegati</button>
|
||||||
|
<button type="button" x-on:click="activeTab = 'storico'" x-bind:class="activeTab === 'storico' ? 'bg-slate-900 text-white ring-slate-900' : 'bg-white text-slate-700 ring-slate-300'" class="inline-flex items-center rounded-md px-3 py-1.5 text-xs font-semibold ring-1 ring-inset transition">Storico</button>
|
||||||
|
<div class="ml-auto text-[11px] uppercase tracking-wide text-slate-500">Vista compatta TecnoRepair-like</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="grid gap-4 xl:grid-cols-3">
|
<div class="grid gap-4 xl:grid-cols-3">
|
||||||
<div class="space-y-4 xl:col-span-2">
|
<div class="space-y-4 xl:col-span-2">
|
||||||
<div class="rounded-xl border bg-white p-4">
|
<div class="rounded-xl border bg-white p-4" x-show="activeTab === 'scheda'" x-cloak>
|
||||||
<div class="text-sm font-semibold">Scheda segnalazione</div>
|
<div class="text-sm font-semibold">Scheda segnalazione</div>
|
||||||
<div class="mt-3 grid gap-3 md:grid-cols-2">
|
<div class="mt-3 grid gap-3 md:grid-cols-2">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -158,7 +169,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if(count($accessSummaryRows) > 0 || filled($dispatchBoardNote))
|
@if(count($accessSummaryRows) > 0 || filled($dispatchBoardNote))
|
||||||
<div class="rounded-xl border border-amber-200 bg-amber-50/60 p-4">
|
<div class="rounded-xl border border-amber-200 bg-amber-50/60 p-4" x-show="activeTab === 'scheda'" x-cloak>
|
||||||
<div class="text-sm font-semibold text-amber-900">Accesso, chiavi e reperibilità</div>
|
<div class="text-sm font-semibold text-amber-900">Accesso, chiavi e reperibilità</div>
|
||||||
@if(filled($dispatchBoardNote))
|
@if(filled($dispatchBoardNote))
|
||||||
<div class="mt-2 rounded-lg border border-amber-200 bg-white/80 p-3 text-xs text-amber-900">{{ $dispatchBoardNote }}</div>
|
<div class="mt-2 rounded-lg border border-amber-200 bg-white/80 p-3 text-xs text-amber-900">{{ $dispatchBoardNote }}</div>
|
||||||
|
|
@ -211,7 +222,7 @@
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="rounded-xl border bg-white p-4">
|
<div class="rounded-xl border bg-white p-4" x-show="activeTab === 'operativo'" x-cloak>
|
||||||
<div class="flex flex-wrap items-center justify-between gap-2">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<div class="text-sm font-semibold">Operativo e rapportino</div>
|
<div class="text-sm font-semibold">Operativo e rapportino</div>
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
|
|
@ -571,7 +582,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-xl border bg-white p-4">
|
<div class="rounded-xl border bg-white p-4" x-show="activeTab === 'operativo'" x-cloak>
|
||||||
<div class="text-sm font-semibold">Comunicazioni ticket</div>
|
<div class="text-sm font-semibold">Comunicazioni ticket</div>
|
||||||
<div class="mt-3 space-y-2">
|
<div class="mt-3 space-y-2">
|
||||||
@forelse($ticket->messages as $msg)
|
@forelse($ticket->messages as $msg)
|
||||||
|
|
@ -588,7 +599,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<div class="rounded-xl border bg-white p-4">
|
<div class="rounded-xl border bg-white p-4" x-show="activeTab === 'operativo'" x-cloak>
|
||||||
<div class="text-sm font-semibold">Stato operativo</div>
|
<div class="text-sm font-semibold">Stato operativo</div>
|
||||||
<div class="mt-3 space-y-2 text-sm">
|
<div class="mt-3 space-y-2 text-sm">
|
||||||
<div><span class="font-medium">Stato:</span> {{ $this->intervento->stato }}</div>
|
<div><span class="font-medium">Stato:</span> {{ $this->intervento->stato }}</div>
|
||||||
|
|
@ -599,7 +610,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-xl border bg-white p-4">
|
<div class="rounded-xl border bg-white p-4" x-show="activeTab === 'operativo'" x-cloak>
|
||||||
<div class="flex items-center justify-between gap-2">
|
<div class="flex items-center justify-between gap-2">
|
||||||
<div class="text-sm font-semibold">Sessioni e presenza</div>
|
<div class="text-sm font-semibold">Sessioni e presenza</div>
|
||||||
<div class="text-xs text-gray-500">{{ count($sessionRows) }} eventi</div>
|
<div class="text-xs text-gray-500">{{ count($sessionRows) }} eventi</div>
|
||||||
|
|
@ -631,7 +642,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-xl border bg-white p-4">
|
<div class="rounded-xl border bg-white p-4" x-show="activeTab === 'operativo'" x-cloak>
|
||||||
<div class="text-sm font-semibold">Google workspace</div>
|
<div class="text-sm font-semibold">Google workspace</div>
|
||||||
@if($googleWorkspaceStatus)
|
@if($googleWorkspaceStatus)
|
||||||
<div class="mt-3 space-y-2 text-sm">
|
<div class="mt-3 space-y-2 text-sm">
|
||||||
|
|
@ -655,7 +666,7 @@
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-xl border bg-white p-4">
|
<div class="rounded-xl border bg-white p-4" x-show="activeTab === 'allegati'" x-cloak>
|
||||||
<div class="text-sm font-semibold">Allegati ticket</div>
|
<div class="text-sm font-semibold">Allegati ticket</div>
|
||||||
<div class="mt-3 grid gap-3 sm:grid-cols-2">
|
<div class="mt-3 grid gap-3 sm:grid-cols-2">
|
||||||
@forelse($ticket->attachments as $attachment)
|
@forelse($ticket->attachments as $attachment)
|
||||||
|
|
@ -686,7 +697,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="rounded-xl border bg-white p-4">
|
<div class="rounded-xl border bg-white p-4" x-show="activeTab === 'storico'" x-cloak>
|
||||||
<div class="text-sm font-semibold">Storico correlato</div>
|
<div class="text-sm font-semibold">Storico correlato</div>
|
||||||
<div class="mt-3 space-y-2">
|
<div class="mt-3 space-y-2">
|
||||||
@forelse($storicoRows as $row)
|
@forelse($storicoRows as $row)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user