624 lines
28 KiB
PHP
624 lines
28 KiB
PHP
<?php
|
|
|
|
namespace App\Services\GesconImport\Steps;
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Illuminate\Support\Str;
|
|
|
|
trait HandlesUnitaStep
|
|
{
|
|
protected array $tipologiaCache = [];
|
|
protected array $tipologiaMetaCache = [];
|
|
|
|
private function normalizeScalaInternoForImport(string $scala, ?string $interno): array
|
|
{
|
|
$scala = strtoupper(trim($scala));
|
|
$interno = $interno !== null ? trim($interno) : null;
|
|
if ($interno === null || $interno === '') {
|
|
return [$scala, $interno];
|
|
}
|
|
|
|
$m = null;
|
|
if (preg_match('/^([A-Z])\s*[-\/]\s*(.+)$/i', $interno, $m) || preg_match('/^([A-Z])\s+(\d.*)$/i', $interno, $m)) {
|
|
$prefix = strtoupper($m[1]);
|
|
$rest = trim((string)$m[2]);
|
|
if ($rest !== '' && ($scala === '' || strcasecmp($scala, $prefix) === 0)) {
|
|
return [$prefix, $rest];
|
|
}
|
|
}
|
|
|
|
return [$scala, $interno];
|
|
}
|
|
|
|
private function stepUnita(?int $limit): int
|
|
{
|
|
// Fonte: gescon_import.condomin (elenco soggetti/unità)
|
|
if (!Schema::connection('gescon_import')->hasTable('condomin')) {
|
|
return 0;
|
|
}
|
|
$count = 0;
|
|
$updated = 0;
|
|
$hasDetailedSchema = Schema::hasColumn('unita_immobiliari', 'codice_unita');
|
|
$hasTipologiaColumn = Schema::hasColumn('unita_immobiliari', 'tipologia_id');
|
|
$parentStabile = null;
|
|
if (Schema::hasTable('stabili')) {
|
|
if ($this->targetStabileId !== null) {
|
|
$parentStabile = DB::table('stabili')->where('id', $this->targetStabileId)->first();
|
|
} elseif ($this->option('stabile')) {
|
|
$stabileCol = Schema::hasColumn('stabili', 'codice_stabile') ? 'codice_stabile' : 'denominazione';
|
|
$parentStabile = DB::table('stabili')->where($stabileCol, $this->option('stabile'))->first();
|
|
if (!$parentStabile && $stabileCol === 'codice_stabile') {
|
|
$alt = ltrim($this->option('stabile'), '0');
|
|
if ($alt !== '' && $alt !== $this->option('stabile')) {
|
|
$parentStabile = DB::table('stabili')->where($stabileCol, $alt)->first();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$pertinenzeToLink = [];
|
|
$processed = 0;
|
|
$batch = $limit ? min(max(1, $limit), 1000) : 1000;
|
|
$offset = 0;
|
|
while (true) {
|
|
$q = DB::connection('gescon_import')->table('condomin');
|
|
if ($this->option('stabile')) {
|
|
$q->where('cod_stabile', $this->option('stabile'));
|
|
}
|
|
if ($this->option('scala')) {
|
|
$q->where('scala', $this->option('scala'));
|
|
}
|
|
$q->limit($batch)->offset($offset);
|
|
$rows = $q->get();
|
|
if ($rows->isEmpty()) {
|
|
break;
|
|
}
|
|
foreach ($rows as $r) {
|
|
// risolvi stabile_id per riga (multi-stabili)
|
|
$scalaVal = trim((string)($r->scala ?? ''));
|
|
$scalaVal = $scalaVal !== '' ? $scalaVal : 'A';
|
|
$rowStabileId = $this->stabileId;
|
|
$rowStabileCode = $this->targetStabileCode;
|
|
if ($this->targetStabileId !== null) {
|
|
$rowStabileId = $this->targetStabileId;
|
|
if ($this->splitMode === 'stabili-per-scala' && $parentStabile) {
|
|
[$childId, $childCode] = $this->ensureStabilePerScala($parentStabile, $scalaVal);
|
|
if ($childId) {
|
|
$rowStabileId = $childId;
|
|
$rowStabileCode = $childCode ?? $rowStabileCode;
|
|
}
|
|
}
|
|
} else {
|
|
if (Schema::hasTable('stabili')) {
|
|
$stabileCol = Schema::hasColumn('stabili', 'codice_stabile') ? 'codice_stabile' : 'denominazione';
|
|
$stRow = DB::table('stabili')->where($stabileCol, $r->cod_stabile ?? $this->option('stabile'))->first();
|
|
$rowStabileId = $stRow->id ?? $this->stabileId;
|
|
if ($stRow) {
|
|
$rowStabileCode = $stRow->codice_stabile ?? $stRow->denominazione ?? $rowStabileCode;
|
|
}
|
|
if ($this->splitMode === 'stabili-per-scala' && $parentStabile) {
|
|
[$childId, $childCode] = $this->ensureStabilePerScala($parentStabile, $scalaVal);
|
|
if ($childId) {
|
|
$rowStabileId = $childId;
|
|
$rowStabileCode = $childCode ?? $rowStabileCode;
|
|
}
|
|
}
|
|
} else {
|
|
$rowStabileCode = $rowStabileCode ?? ($r->cod_stabile ?? $this->option('stabile'));
|
|
}
|
|
}
|
|
if (!$rowStabileId) {
|
|
continue;
|
|
}
|
|
$interno = isset($r->interno) ? (string)$r->interno : null;
|
|
[$scalaVal, $interno] = $this->normalizeScalaInternoForImport($scalaVal, $interno);
|
|
$sub = $r->sub ?? $interno;
|
|
// Riconosci pertinenze nel campo INT o note: cantina, box/garage, posto auto, soffitta/solaio, locale tecnico
|
|
$internoStr = is_string($interno) ? trim($interno) : (string)$interno;
|
|
$ptype = null;
|
|
$pcode = null; // tipo pertinenza e codice interno normalizzato
|
|
if ($internoStr !== '') {
|
|
if (preg_match('/^CAN\s*(\d+)$/i', preg_replace('/\s+/', ' ', $internoStr), $m)) {
|
|
$ptype = 'cantina';
|
|
$pcode = 'CAN' . $m[1];
|
|
} elseif (preg_match('/^(BOX|GAR|GARAGE)\s*(\d+)?$/i', preg_replace('/\s+/', ' ', $internoStr), $m)) {
|
|
$ptype = 'box';
|
|
$pcode = 'BOX' . ($m[2] ?? '');
|
|
} elseif (preg_match('/^(PA|POSTO\s*AUTO)\s*(\d+)?$/i', preg_replace('/\s+/', ' ', $internoStr), $m)) {
|
|
$ptype = 'posto_auto';
|
|
$pcode = 'PA' . ($m[2] ?? '');
|
|
} elseif (preg_match('/^(SOF|SOFFITTA|SOLAIO)\s*(\d+)?$/i', preg_replace('/\s+/', ' ', $internoStr), $m)) {
|
|
$ptype = 'soffitta';
|
|
$pcode = 'SOF' . ($m[2] ?? '');
|
|
} elseif (preg_match('/^(LT|LOCALE\s*TECNICO)\s*(\d+)?$/i', preg_replace('/\s+/', ' ', $internoStr), $m)) {
|
|
$ptype = 'locale_tecnico';
|
|
$pcode = 'LT' . ($m[2] ?? '');
|
|
}
|
|
}
|
|
// Piano: normalizza (R=0, T=0, 1=1, -1 o S= -1)
|
|
$pianoVal = 0;
|
|
if (isset($r->piano)) {
|
|
$pv = is_string($r->piano) ? strtoupper(trim($r->piano)) : (string)$r->piano;
|
|
if ($pv === 'T' || $pv === 'PT' || $pv === 'R' || $pv === 'PR' || $pv === '') {
|
|
$pianoVal = 0;
|
|
} elseif ($pv === 'S' || $pv === 'PS' || $pv === '-1') {
|
|
$pianoVal = -1;
|
|
} elseif (is_numeric($pv)) {
|
|
$pianoVal = (int)$pv;
|
|
}
|
|
}
|
|
if ($hasDetailedSchema) {
|
|
$normNumeric = function ($v): ?string {
|
|
if ($v === null) {
|
|
return null;
|
|
}
|
|
$s = trim((string) $v);
|
|
if ($s === '') {
|
|
return null;
|
|
}
|
|
$s = str_replace(' ', '', $s);
|
|
if (str_contains($s, ',') && str_contains($s, '.')) {
|
|
$s = str_replace('.', '', $s);
|
|
}
|
|
$s = str_replace(',', '.', $s);
|
|
return is_numeric($s) ? $s : null;
|
|
};
|
|
|
|
$catSez = property_exists($r, 'catasto_sez_urbana') ? (string) ($r->catasto_sez_urbana ?? '') : '';
|
|
$catFoglio = property_exists($r, 'catasto_foglio') ? (string) ($r->catasto_foglio ?? '') : '';
|
|
$catPart = property_exists($r, 'catasto_particella') ? (string) ($r->catasto_particella ?? '') : '';
|
|
$catSub = property_exists($r, 'catasto_sub') ? (string) ($r->catasto_sub ?? '') : '';
|
|
$catCat = property_exists($r, 'catasto_categoria') ? (string) ($r->catasto_categoria ?? '') : '';
|
|
$catClasse = property_exists($r, 'catasto_classe') ? (string) ($r->catasto_classe ?? '') : '';
|
|
$catCons = property_exists($r, 'catasto_consistenza') ? $normNumeric($r->catasto_consistenza ?? null) : null;
|
|
$catSup = property_exists($r, 'catasto_superfice') ? $normNumeric($r->catasto_superfice ?? null) : null;
|
|
$catRend = property_exists($r, 'catasto_rendita') ? $normNumeric($r->catasto_rendita ?? null) : null;
|
|
|
|
// Codice unita coerente: STAB-SCALA-INT (per cantine: STAB-SCALA-CAN<n>)
|
|
$intPart = $ptype && $pcode ? $pcode : (($interno ?? null) ?: '0');
|
|
$codiceBaseStab = $rowStabileCode ?? ($r->cod_stabile ?? $this->option('stabile')) ?: 'S0';
|
|
// Se stabili-per-scala, includi comunque la scala nel codice per leggibilità
|
|
$codice = $codiceBaseStab . '-' . ($scalaVal ?: 'A') . '-' . $intPart;
|
|
// Filtri post-normalizzazione: pertinenze e piano min/max
|
|
if ($this->option('only-pertinenze')) {
|
|
$opt = strtolower((string)$this->option('only-pertinenze'));
|
|
$isPert = (bool)$ptype;
|
|
$ok = $opt === 'any' ? $isPert : ($isPert && $ptype === $opt);
|
|
if (!$ok) {
|
|
continue;
|
|
}
|
|
}
|
|
$pMin = $this->option('piano-min') !== null ? (int)$this->option('piano-min') : null;
|
|
$pMax = $this->option('piano-max') !== null ? (int)$this->option('piano-max') : null;
|
|
if ($pMin !== null && $pianoVal < $pMin) {
|
|
continue;
|
|
}
|
|
if ($pMax !== null && $pianoVal > $pMax) {
|
|
continue;
|
|
}
|
|
$exists = DB::table('unita_immobiliari')->where('codice_unita', $codice)->first();
|
|
if ($exists) {
|
|
// Aggiorna palazzina/scala se richiesto
|
|
$patch = [];
|
|
if ($this->splitMode === 'palazzine') {
|
|
if (Schema::hasColumn('unita_immobiliari', 'palazzina')) {
|
|
if (empty($exists->palazzina) || $exists->palazzina !== $scalaVal) {
|
|
$patch['palazzina'] = $scalaVal;
|
|
}
|
|
}
|
|
if (Schema::hasColumn('unita_immobiliari', 'scala') && (empty($exists->scala) || $exists->scala !== $scalaVal)) {
|
|
$patch['scala'] = $scalaVal;
|
|
}
|
|
}
|
|
if (!empty($patch)) {
|
|
$patch['updated_at'] = now();
|
|
if (!$this->isDryRun) {
|
|
DB::table('unita_immobiliari')->where('id', $exists->id)->update($patch);
|
|
}
|
|
$updated++;
|
|
}
|
|
continue;
|
|
}
|
|
$ownerName = trim(($r->cognome ?? '') . ' ' . ($r->nome ?? '')) ?: null;
|
|
$tipologiaDef = $this->detectTipologiaFromRow($r, $ptype, $internoStr);
|
|
$tipologiaId = $hasTipologiaColumn ? $this->resolveTipologiaIdFor($tipologiaDef) : null;
|
|
$denominazione = $ownerName;
|
|
if (($tipologiaDef['is_condominiale'] ?? false) && !empty($tipologiaDef['nome'])) {
|
|
$denominazione = $tipologiaDef['nome'];
|
|
}
|
|
$tipoUnitaRaw = $tipologiaDef['tipo_unita'] ?? ($ptype ?: 'abitazione');
|
|
$data = [
|
|
'stabile_id' => $rowStabileId,
|
|
'palazzina_id' => null,
|
|
'codice_unita' => $codice,
|
|
'denominazione' => $denominazione,
|
|
'descrizione' => null,
|
|
'palazzina' => $this->splitMode === 'palazzine' ? $scalaVal : null,
|
|
'scala' => $scalaVal,
|
|
'piano' => $pianoVal,
|
|
'interno' => (string)($ptype && $pcode ? $pcode : $interno),
|
|
'subalterno' => (string)$sub,
|
|
'categoria_catastale' => null,
|
|
'classe' => null,
|
|
'consistenza' => null,
|
|
'rendita_catastale' => null,
|
|
'millesimi_generali' => 0,
|
|
'tipo_unita' => $this->normalizeTipoUnita($tipoUnitaRaw),
|
|
'tipologia_id' => $tipologiaId,
|
|
'stato_conservazione' => 'buono',
|
|
'stato_occupazione' => 'occupata_proprietario',
|
|
'attiva' => true,
|
|
'unita_demo' => false,
|
|
'created_at' => now(),
|
|
'updated_at' => now()
|
|
];
|
|
if (!$hasTipologiaColumn) {
|
|
unset($data['tipologia_id']);
|
|
}
|
|
$this->dynamicInsert('unita_immobiliari', $data);
|
|
// Se è pertinenza, memorizza relazione da collegare in un secondo pass
|
|
if ($ptype) {
|
|
$pertinenzeToLink[] = [
|
|
'stabile_id' => $rowStabileId,
|
|
'scala' => $r->scala ?? 'A',
|
|
'interno' => (string)($pcode ?: $interno),
|
|
'tipo' => $tipologiaDef['tipo_unita'] ?? $ptype,
|
|
'owner_signature' => $ownerName,
|
|
];
|
|
}
|
|
} else {
|
|
// schema semplice (anagrafiche base)
|
|
$criteria = ['stabile_id' => $this->stabileId];
|
|
if ($interno !== null) {
|
|
$criteria['interno'] = (string)$interno;
|
|
}
|
|
$exists = DB::table('unita_immobiliari')->where($criteria)->first();
|
|
if ($exists) {
|
|
// Aggiorna palazzina/scala se in split palazzine
|
|
if ($this->splitMode === 'palazzine') {
|
|
$patch = [];
|
|
if (Schema::hasColumn('unita_immobiliari', 'palazzina') && (empty($exists->palazzina) || $exists->palazzina !== $scalaVal)) {
|
|
$patch['palazzina'] = $scalaVal;
|
|
}
|
|
if (Schema::hasColumn('unita_immobiliari', 'scala') && (empty($exists->scala) || $exists->scala !== $scalaVal)) {
|
|
$patch['scala'] = $scalaVal;
|
|
}
|
|
if (!empty($patch)) {
|
|
$patch['updated_at'] = now();
|
|
if (!$this->isDryRun) {
|
|
DB::table('unita_immobiliari')->where('id', $exists->id)->update($patch);
|
|
}
|
|
$updated++;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
$data = [
|
|
'stabile_id' => $rowStabileId,
|
|
'interno' => (string)$interno,
|
|
'scala' => $scalaVal,
|
|
'piano' => $pianoVal,
|
|
'subalterno' => (string)$sub,
|
|
'categoria_catastale' => null,
|
|
'superficie' => null,
|
|
'vani' => null,
|
|
'indirizzo' => $r->indirizzo_corrispondenza ?? null,
|
|
'note' => null,
|
|
'created_at' => now(),
|
|
'updated_at' => now()
|
|
];
|
|
$this->dynamicInsert('unita_immobiliari', $data);
|
|
}
|
|
$count++;
|
|
$processed++;
|
|
if ($limit && $processed >= $limit) {
|
|
break 2;
|
|
}
|
|
}
|
|
$offset += $batch;
|
|
}
|
|
// Collega pertinenze alle unità principali (cumulo) se tabella disponibile
|
|
if (!empty($pertinenzeToLink) && Schema::hasTable('unita_pertinenze')) {
|
|
foreach ($pertinenzeToLink as $p) {
|
|
$mainCandidates = DB::table('unita_immobiliari')
|
|
->where('stabile_id', $p['stabile_id'])
|
|
->where('scala', $p['scala'])
|
|
->orderBy('id')
|
|
->get();
|
|
|
|
$main = $mainCandidates->first(function ($unit) use ($p) {
|
|
if ($this->isUnitPertinenza($unit) || $this->isUnitCondominiale($unit)) {
|
|
return false;
|
|
}
|
|
if (!empty($p['owner_signature'])) {
|
|
$normalized = Str::lower(trim($unit->denominazione ?? ''));
|
|
return $normalized === Str::lower(trim($p['owner_signature']));
|
|
}
|
|
return true;
|
|
});
|
|
|
|
if (!$main) {
|
|
$main = $mainCandidates->first(function ($unit) {
|
|
return !$this->isUnitPertinenza($unit) && !$this->isUnitCondominiale($unit);
|
|
});
|
|
}
|
|
|
|
$cant = DB::table('unita_immobiliari')
|
|
->where('stabile_id', $p['stabile_id'])
|
|
->where('scala', $p['scala'])
|
|
->where('interno', $p['interno'])
|
|
->first();
|
|
|
|
if ($main && $cant) {
|
|
$this->dynamicInsert('unita_pertinenze', [
|
|
'stabile_id' => $p['stabile_id'],
|
|
'unita_principale_id' => $main->id,
|
|
'unita_accessoria_id' => $cant->id,
|
|
'tipo' => $p['tipo'] ?? 'pertinenza',
|
|
'cumulo' => true,
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
if ($updated > 0) {
|
|
$this->line(" → unita aggiornate: {$updated}");
|
|
}
|
|
return $count + $updated;
|
|
}
|
|
|
|
private function detectTipologiaFromRow(object $row, ?string $pertinenzaType, ?string $interno): array
|
|
{
|
|
$defaults = $this->tipologiaDefaults();
|
|
$interno = $interno ?? '';
|
|
$descriptorSources = [
|
|
$interno,
|
|
$row->note_unita ?? null,
|
|
$row->note ?? null,
|
|
$row->destinazione ?? null,
|
|
$row->descrizione ?? null,
|
|
];
|
|
$descriptor = Str::upper(trim(implode(' ', array_filter(array_map(fn($v) => is_string($v) ? $v : '', $descriptorSources)))));
|
|
$owner = Str::upper(trim(($row->cognome ?? '') . ' ' . ($row->nome ?? '')));
|
|
|
|
if ($pertinenzaType) {
|
|
$map = [
|
|
'cantina' => 'CANT',
|
|
'box' => 'BOX',
|
|
'garage' => 'BOX',
|
|
'posto_auto' => 'POSTO_AUTO',
|
|
'soffitta' => 'SOFF',
|
|
'locale_tecnico' => 'LOCALE_TEC',
|
|
];
|
|
$code = $map[$pertinenzaType] ?? null;
|
|
if ($code && isset($defaults[$code])) {
|
|
return array_merge(
|
|
$defaults[$code],
|
|
['tipo_unita' => $pertinenzaType]
|
|
);
|
|
}
|
|
}
|
|
|
|
if ($this->looksLikeCondominio($owner) || $this->looksLikeCondominio($descriptor)) {
|
|
foreach (
|
|
[
|
|
'PORTINERIA' => 'CONDO_PORTINERIA',
|
|
'BICI' => 'CONDO_BICI',
|
|
'CICLO' => 'CONDO_BICI',
|
|
'LAVAND' => 'CONDO_LAVANDERIA',
|
|
'PISCINA' => 'CONDO_PISCINA',
|
|
] as $needle => $code
|
|
) {
|
|
if (Str::contains($descriptor, $needle)) {
|
|
return array_merge(
|
|
$defaults[$code] ?? ['code' => $code, 'nome' => Str::headline(Str::lower($needle)), 'categoria' => 'condominiale', 'is_condominiale' => true],
|
|
['tipo_unita' => 'condominiale']
|
|
);
|
|
}
|
|
}
|
|
|
|
$code = 'CONDO_GENERIC';
|
|
return array_merge(
|
|
$defaults[$code] ?? ['code' => $code, 'nome' => 'Area Condominiale', 'categoria' => 'condominiale', 'is_condominiale' => true],
|
|
['tipo_unita' => 'condominiale']
|
|
);
|
|
}
|
|
|
|
foreach (
|
|
[
|
|
'UFF' => ['UFF', ['UFFICIO', 'STUDIO']],
|
|
'NEGOZIO' => ['NEGOZIO', ['NEGOZIO', 'BOTTEGA', 'COMMERCIALE']],
|
|
] as $code => [$label, $needles]
|
|
) {
|
|
foreach ($needles as $needle) {
|
|
if (Str::contains($descriptor, $needle)) {
|
|
return array_merge(
|
|
$defaults[$code] ?? ['code' => $code, 'nome' => $label, 'categoria' => 'commerciale'],
|
|
['tipo_unita' => Str::lower($label)]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
$code = 'APP';
|
|
return array_merge(
|
|
$defaults[$code] ?? ['code' => $code, 'nome' => 'Appartamento', 'categoria' => 'residenziale'],
|
|
['tipo_unita' => 'abitazione']
|
|
);
|
|
}
|
|
|
|
private function normalizeTipoUnita(?string $value): string
|
|
{
|
|
$allowed = [
|
|
'abitazione',
|
|
'studio_professionale',
|
|
'attivita_commerciale',
|
|
'magazzino_deposito',
|
|
'box_garage',
|
|
'cantina',
|
|
'soffitta',
|
|
'spazio_comune_redditizio',
|
|
'locale_tecnico',
|
|
'altro',
|
|
];
|
|
|
|
$normalized = Str::snake(Str::lower(trim((string)$value)), '_');
|
|
if ($normalized === '' || $normalized === '_') {
|
|
return 'abitazione';
|
|
}
|
|
|
|
$map = [
|
|
'condominiale' => 'spazio_comune_redditizio',
|
|
'spazio_condominiale' => 'spazio_comune_redditizio',
|
|
'area_condominiale' => 'spazio_comune_redditizio',
|
|
'ufficio' => 'studio_professionale',
|
|
'studio' => 'studio_professionale',
|
|
'studio_medico' => 'studio_professionale',
|
|
'negozio' => 'attivita_commerciale',
|
|
'locale_commerciale' => 'attivita_commerciale',
|
|
'attivita' => 'attivita_commerciale',
|
|
'locale_vendita' => 'attivita_commerciale',
|
|
'magazzino' => 'magazzino_deposito',
|
|
'deposito' => 'magazzino_deposito',
|
|
'box' => 'box_garage',
|
|
'garage' => 'box_garage',
|
|
'posto_auto' => 'box_garage',
|
|
'parcheggio' => 'box_garage',
|
|
'solaio' => 'soffitta',
|
|
'locale_condominiale' => 'spazio_comune_redditizio',
|
|
'locale_tecnico' => 'locale_tecnico',
|
|
'centrale_termica' => 'locale_tecnico',
|
|
];
|
|
|
|
$normalized = $map[$normalized] ?? $normalized;
|
|
|
|
if (!in_array($normalized, $allowed, true)) {
|
|
return 'altro';
|
|
}
|
|
|
|
return $normalized;
|
|
}
|
|
|
|
private function resolveTipologiaIdFor(array $definition): ?int
|
|
{
|
|
if (!Schema::hasTable('unita_tipologie')) {
|
|
return null;
|
|
}
|
|
|
|
$code = strtoupper($definition['code'] ?? '');
|
|
if ($code === '') {
|
|
return null;
|
|
}
|
|
|
|
if (array_key_exists($code, $this->tipologiaCache)) {
|
|
return $this->tipologiaCache[$code];
|
|
}
|
|
|
|
$row = DB::table('unita_tipologie')->where('codice', $code)->first();
|
|
if ($row) {
|
|
$this->tipologiaCache[$code] = (int)$row->id;
|
|
$this->tipologiaMetaCache[(int)$row->id] = $row;
|
|
return (int)$row->id;
|
|
}
|
|
|
|
if ($this->isDryRun) {
|
|
$this->tipologiaCache[$code] = null;
|
|
return null;
|
|
}
|
|
|
|
$payload = [
|
|
'codice' => $code,
|
|
'nome' => $definition['nome'] ?? $code,
|
|
'categoria' => $definition['categoria'] ?? null,
|
|
'is_pertinenza' => (bool)($definition['is_pertinenza'] ?? false),
|
|
'is_condominiale' => (bool)($definition['is_condominiale'] ?? false),
|
|
'meta' => $definition['meta'] ?? null,
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
];
|
|
|
|
$id = DB::table('unita_tipologie')->insertGetId($payload);
|
|
$row = (object)array_merge($payload, ['id' => $id]);
|
|
$this->tipologiaCache[$code] = $id;
|
|
$this->tipologiaMetaCache[$id] = $row;
|
|
|
|
return $id;
|
|
}
|
|
|
|
private function loadTipologiaMeta(?int $id): ?object
|
|
{
|
|
if (!$id || $id <= 0) {
|
|
return null;
|
|
}
|
|
|
|
if (isset($this->tipologiaMetaCache[$id])) {
|
|
return $this->tipologiaMetaCache[$id];
|
|
}
|
|
|
|
if (!Schema::hasTable('unita_tipologie')) {
|
|
return null;
|
|
}
|
|
|
|
$row = DB::table('unita_tipologie')->where('id', $id)->first();
|
|
if ($row) {
|
|
$this->tipologiaMetaCache[$id] = $row;
|
|
}
|
|
|
|
return $row;
|
|
}
|
|
|
|
private function isUnitPertinenza(object $unit): bool
|
|
{
|
|
$tipo = $unit->tipo_unita ?? null;
|
|
if (in_array($tipo, ['cantina', 'box', 'garage', 'posto_auto', 'soffitta', 'locale_tecnico'], true)) {
|
|
return true;
|
|
}
|
|
|
|
$meta = $this->loadTipologiaMeta($unit->tipologia_id ?? null);
|
|
return (bool)($meta->is_pertinenza ?? false);
|
|
}
|
|
|
|
private function isUnitCondominiale(object $unit): bool
|
|
{
|
|
$tipo = $unit->tipo_unita ?? null;
|
|
if ($tipo === 'condominiale') {
|
|
return true;
|
|
}
|
|
|
|
$meta = $this->loadTipologiaMeta($unit->tipologia_id ?? null);
|
|
return (bool)($meta->is_condominiale ?? false);
|
|
}
|
|
|
|
private function tipologiaDefaults(): array
|
|
{
|
|
return [
|
|
'APP' => ['code' => 'APP', 'nome' => 'Appartamento', 'categoria' => 'residenziale'],
|
|
'UFF' => ['code' => 'UFF', 'nome' => 'Ufficio', 'categoria' => 'commerciale'],
|
|
'NEGOZIO' => ['code' => 'NEGOZIO', 'nome' => 'Negozio', 'categoria' => 'commerciale'],
|
|
|
|
'CANT' => ['code' => 'CANT', 'nome' => 'Cantina', 'categoria' => 'pertinenza', 'is_pertinenza' => true],
|
|
'BOX' => ['code' => 'BOX', 'nome' => 'Box', 'categoria' => 'pertinenza', 'is_pertinenza' => true],
|
|
'POSTO_AUTO' => ['code' => 'POSTO_AUTO', 'nome' => 'Posto Auto', 'categoria' => 'pertinenza', 'is_pertinenza' => true],
|
|
'SOFF' => ['code' => 'SOFF', 'nome' => 'Soffitta', 'categoria' => 'pertinenza', 'is_pertinenza' => true],
|
|
'LOCALE_TEC' => ['code' => 'LOCALE_TEC', 'nome' => 'Locale Tecnico', 'categoria' => 'pertinenza', 'is_pertinenza' => true],
|
|
|
|
'CONDO_PORTINERIA' => ['code' => 'CONDO_PORTINERIA', 'nome' => 'Portineria Condominiale', 'categoria' => 'condominiale', 'is_condominiale' => true],
|
|
'CONDO_BICI' => ['code' => 'CONDO_BICI', 'nome' => 'Locale Bici', 'categoria' => 'condominiale', 'is_condominiale' => true],
|
|
'CONDO_LAVANDERIA' => ['code' => 'CONDO_LAVANDERIA', 'nome' => 'Lavanderia Condominiale', 'categoria' => 'condominiale', 'is_condominiale' => true],
|
|
'CONDO_PISCINA' => ['code' => 'CONDO_PISCINA', 'nome' => 'Piscina Condominiale', 'categoria' => 'condominiale', 'is_condominiale' => true],
|
|
'CONDO_GENERIC' => ['code' => 'CONDO_GENERIC', 'nome' => 'Area Condominiale', 'categoria' => 'condominiale', 'is_condominiale' => true],
|
|
];
|
|
}
|
|
|
|
private function looksLikeCondominio(string $value): bool
|
|
{
|
|
$value = trim($value);
|
|
if ($value === '') {
|
|
return false;
|
|
}
|
|
|
|
return (bool) preg_match('/\bCOND(?:OMIN|\.)/u', $value);
|
|
}
|
|
}
|