633 lines
24 KiB
PHP
633 lines
24 KiB
PHP
<?php
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\RubricaUniversale;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
class GesconQaRubricaLegamiCommand extends Command
|
|
{
|
|
protected $signature = 'gescon:qa-rubrica-legami
|
|
{--rubrica-id=* : Uno o piu ID rubrica da analizzare}
|
|
{--limit=50 : Numero massimo di record se non passi rubrica-id}
|
|
{--apply-safe : Applica solo fix non ambigui su riferimenti e rubrica_ruoli}';
|
|
|
|
protected $description = 'Analizza e, se richiesto, applica fix sicuri sui legami rubrica -> stabile -> unita -> rubrica_ruoli.';
|
|
|
|
public function handle(): int
|
|
{
|
|
foreach (['rubrica_universale', 'stabili', 'unita_immobiliari'] as $table) {
|
|
if (! Schema::hasTable($table)) {
|
|
$this->error('Tabella richiesta mancante: ' . $table);
|
|
return self::FAILURE;
|
|
}
|
|
}
|
|
|
|
$rubricaIds = array_values(array_filter(array_map(
|
|
fn($value): int => is_numeric($value) ? (int) $value : 0,
|
|
(array) $this->option('rubrica-id')
|
|
)));
|
|
|
|
$query = RubricaUniversale::query()
|
|
->where('categoria', 'condomino')
|
|
->orderByDesc('id');
|
|
|
|
if ($rubricaIds !== []) {
|
|
$query->whereIn('id', $rubricaIds);
|
|
} else {
|
|
$query->where(function ($inner): void {
|
|
$inner->whereNull('riferimento_stabile')
|
|
->orWhereNull('riferimento_unita');
|
|
});
|
|
}
|
|
|
|
$rows = $query->limit(max(1, min(500, (int) $this->option('limit'))))->get();
|
|
if ($rows->isEmpty()) {
|
|
$this->info('Nessun record rubrica da analizzare.');
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$applySafe = (bool) $this->option('apply-safe');
|
|
$updatedReferences = 0;
|
|
$createdRuoli = 0;
|
|
$ambiguous = 0;
|
|
$manualReview = 0;
|
|
|
|
foreach ($rows as $rubrica) {
|
|
$analysis = $this->analyzeRubrica($rubrica);
|
|
|
|
$this->line('');
|
|
$this->info('Rubrica #' . (int) $rubrica->id . ' - ' . $this->displayRubricaName($rubrica));
|
|
$this->line('Legacy: cod_stabile=' . ($analysis['legacy']['cod_stabile'] ?: '-') . ' | cod_cond=' . ($analysis['legacy']['cod_cond'] ?: '-') . ' | ruolo=' . ($analysis['legacy']['ruolo'] ?: '-'));
|
|
$this->line('Stabile candidato: ' . ($analysis['stabile_label'] ?: '-'));
|
|
$this->line('Ruoli esistenti: ' . count($analysis['existing_ruoli']));
|
|
$this->line('Persona match: ' . ($analysis['persona_summary'] !== '' ? $analysis['persona_summary'] : '-'));
|
|
|
|
if ($analysis['candidate_units'] === []) {
|
|
$this->warn('Nessuna unita candidata trovata.');
|
|
} else {
|
|
foreach ($analysis['candidate_units'] as $candidate) {
|
|
$this->line('- unita #' . $candidate['unit_id']
|
|
. ' [' . $candidate['source'] . '] '
|
|
. $candidate['unit_label']
|
|
. ' | ruolo=' . ($candidate['role_standard'] ?: '-')
|
|
. ' | fix-ruolo=' . ($candidate['safe_role_creation'] ? 'si' : 'no'));
|
|
}
|
|
}
|
|
|
|
if ($analysis['unique_unit'] === null && $analysis['candidate_units'] !== []) {
|
|
$ambiguous++;
|
|
$this->warn('Caso ambiguo: piu unita candidate o ruolo non sicuro.');
|
|
} elseif ($analysis['requires_manual_review']) {
|
|
$manualReview++;
|
|
$this->warn('Caso da revisione manuale: unita unica trovata, ma il ruolo strutturato non e abbastanza sicuro da creare rubrica_ruoli.');
|
|
}
|
|
|
|
if (! $applySafe) {
|
|
continue;
|
|
}
|
|
|
|
$applied = $this->applySafeFixes($rubrica, $analysis);
|
|
$updatedReferences += $applied['references_updated'];
|
|
$createdRuoli += $applied['ruoli_created'];
|
|
}
|
|
|
|
$this->line('');
|
|
$this->info('QA legami completato.');
|
|
$this->line('Record analizzati: ' . $rows->count());
|
|
$this->line('Casi ambigui: ' . $ambiguous);
|
|
$this->line('Casi da revisione manuale: ' . $manualReview);
|
|
if ($applySafe) {
|
|
$this->line('Riferimenti aggiornati: ' . $updatedReferences);
|
|
$this->line('Rubrica ruoli creati: ' . $createdRuoli);
|
|
}
|
|
|
|
return ($ambiguous > 0 || $manualReview > 0) ? self::INVALID : self::SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @return array<string,mixed>
|
|
*/
|
|
private function analyzeRubrica(RubricaUniversale $rubrica): array
|
|
{
|
|
$legacy = $this->parseLegacyMeta((string) ($rubrica->note ?? ''));
|
|
$stabile = $this->resolveStabile($legacy['cod_stabile']);
|
|
$existingRuoli = Schema::hasTable('rubrica_ruoli')
|
|
? DB::table('rubrica_ruoli')->where('rubrica_id', (int) $rubrica->id)->get()->all()
|
|
: [];
|
|
|
|
$personaMatches = $this->findPersonaMatches($rubrica, $stabile['id']);
|
|
$candidateUnits = $this->mergeCandidates(
|
|
$this->collectLegacyUnitCandidates($stabile['id'], $legacy),
|
|
$this->collectPersonaRelationCandidates($personaMatches, $stabile['id']),
|
|
$this->collectImportUnitCandidates($rubrica, $stabile['id'], $legacy)
|
|
);
|
|
|
|
$uniqueUnit = count($candidateUnits) === 1 ? $candidateUnits[0] : null;
|
|
if ($uniqueUnit !== null && ($uniqueUnit['role_standard'] ?? null) === null) {
|
|
$uniqueUnit['role_standard'] = $this->mapRoleStandard($legacy['ruolo']);
|
|
}
|
|
if ($uniqueUnit !== null && ($uniqueUnit['role_standard'] ?? null) === null) {
|
|
$uniqueUnit = null;
|
|
}
|
|
|
|
$requiresManualReview = $uniqueUnit !== null
|
|
&& ! empty($stabile['id'])
|
|
&& ! $uniqueUnit['safe_role_creation']
|
|
&& count($existingRuoli) === 0;
|
|
|
|
return [
|
|
'legacy' => $legacy,
|
|
'stabile' => $stabile,
|
|
'stabile_label' => $this->buildStabileReference($stabile),
|
|
'existing_ruoli' => $existingRuoli,
|
|
'candidate_units' => $candidateUnits,
|
|
'unique_unit' => $uniqueUnit,
|
|
'persona_summary' => $this->summarizePersonas($personaMatches),
|
|
'requires_manual_review' => $requiresManualReview,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array{references_updated:int,ruoli_created:int}
|
|
*/
|
|
private function applySafeFixes(RubricaUniversale $rubrica, array $analysis): array
|
|
{
|
|
$referencesUpdated = 0;
|
|
$ruoliCreated = 0;
|
|
$stabile = $analysis['stabile'];
|
|
$uniqueUnit = $analysis['unique_unit'];
|
|
|
|
$dirty = false;
|
|
if (($rubrica->riferimento_stabile === null || trim((string) $rubrica->riferimento_stabile) === '') && ! empty($stabile['id'])) {
|
|
$rubrica->riferimento_stabile = $this->buildStabileReference($stabile);
|
|
$dirty = true;
|
|
}
|
|
|
|
if (($rubrica->riferimento_unita === null || trim((string) $rubrica->riferimento_unita) === '') && $uniqueUnit !== null) {
|
|
$rubrica->riferimento_unita = $uniqueUnit['unit_reference'];
|
|
$dirty = true;
|
|
}
|
|
|
|
if ($dirty) {
|
|
$rubrica->data_ultima_modifica = now();
|
|
$rubrica->save();
|
|
$referencesUpdated++;
|
|
}
|
|
|
|
if (
|
|
$uniqueUnit !== null
|
|
&& ! empty($stabile['id'])
|
|
&& $uniqueUnit['safe_role_creation']
|
|
&& ($uniqueUnit['role_standard'] ?? null) !== null
|
|
&& Schema::hasTable('rubrica_ruoli')
|
|
&& count($analysis['existing_ruoli']) === 0
|
|
) {
|
|
DB::table('rubrica_ruoli')->updateOrInsert(
|
|
[
|
|
'rubrica_id' => (int) $rubrica->id,
|
|
'stabile_id' => (int) $stabile['id'],
|
|
'unita_immobiliare_id' => (int) $uniqueUnit['unit_id'],
|
|
'ruolo_standard' => $uniqueUnit['role_standard'],
|
|
],
|
|
[
|
|
'is_attivo' => true,
|
|
'is_preferito' => true,
|
|
'meta' => json_encode([
|
|
'source' => $uniqueUnit['source'],
|
|
'created_by' => 'gescon:qa-rubrica-legami',
|
|
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
|
|
'updated_at' => now(),
|
|
'created_at' => now(),
|
|
]
|
|
);
|
|
|
|
$ruoliCreated++;
|
|
}
|
|
|
|
return [
|
|
'references_updated' => $referencesUpdated,
|
|
'ruoli_created' => $ruoliCreated,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array{cod_stabile:?string,cod_cond:?string,ruolo:?string}
|
|
*/
|
|
private function parseLegacyMeta(string $note): array
|
|
{
|
|
$payload = [
|
|
'cod_stabile' => null,
|
|
'cod_cond' => null,
|
|
'ruolo' => null,
|
|
];
|
|
|
|
foreach (['cod_stabile', 'cod_cond', 'ruolo'] as $key) {
|
|
if (preg_match('/' . preg_quote($key, '/') . '=([^|\n\r]+)/i', $note, $matches) === 1) {
|
|
$payload[$key] = trim((string) ($matches[1] ?? '')) ?: null;
|
|
}
|
|
}
|
|
|
|
return $payload;
|
|
}
|
|
|
|
/**
|
|
* @return array{id:int|null,codice_stabile:?string,cod_stabile:?string,denominazione:?string}
|
|
*/
|
|
private function resolveStabile(?string $legacyCode): array
|
|
{
|
|
$blank = ['id' => null, 'codice_stabile' => null, 'cod_stabile' => null, 'denominazione' => null];
|
|
$code = trim((string) $legacyCode);
|
|
if ($code === '') {
|
|
return $blank;
|
|
}
|
|
|
|
$trimmed = ltrim($code, '0');
|
|
$row = DB::table('stabili')
|
|
->select(['id', 'codice_stabile', 'cod_stabile', 'denominazione'])
|
|
->where(function ($query) use ($code, $trimmed): void {
|
|
$query->where('codice_stabile', $code)
|
|
->orWhere('cod_stabile', $code);
|
|
|
|
if ($trimmed !== '' && $trimmed !== $code) {
|
|
$query->orWhere('codice_stabile', $trimmed)
|
|
->orWhere('cod_stabile', $trimmed);
|
|
}
|
|
})
|
|
->orderBy('id')
|
|
->first();
|
|
|
|
if (! $row) {
|
|
return $blank;
|
|
}
|
|
|
|
return [
|
|
'id' => (int) $row->id,
|
|
'codice_stabile' => $row->codice_stabile ? (string) $row->codice_stabile : null,
|
|
'cod_stabile' => $row->cod_stabile ? (string) $row->cod_stabile : null,
|
|
'denominazione' => $row->denominazione ? (string) $row->denominazione : null,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array<int,array<string,mixed>>
|
|
*/
|
|
private function collectLegacyUnitCandidates(?int $stabileId, array $legacy): array
|
|
{
|
|
if (! Schema::hasTable('unita_immobiliare_nominativi') || ! $stabileId || empty($legacy['cod_cond'])) {
|
|
return [];
|
|
}
|
|
|
|
$rows = DB::table('unita_immobiliare_nominativi as uin')
|
|
->join('unita_immobiliari as ui', 'ui.id', '=', 'uin.unita_immobiliare_id')
|
|
->where('uin.stabile_id', $stabileId)
|
|
->where('uin.legacy_cond_id', trim((string) $legacy['cod_cond']))
|
|
->select([
|
|
'ui.id as unit_id',
|
|
'ui.codice_unita',
|
|
'ui.denominazione',
|
|
'ui.scala',
|
|
'ui.interno',
|
|
'uin.ruolo',
|
|
])
|
|
->orderBy('ui.id')
|
|
->get();
|
|
|
|
$grouped = [];
|
|
foreach ($rows as $row) {
|
|
$unitId = (int) $row->unit_id;
|
|
$grouped[$unitId] ??= [
|
|
'unit_id' => $unitId,
|
|
'unit_label' => $this->buildUnitLabel($row),
|
|
'unit_reference' => $this->buildUnitReference($row),
|
|
'source' => 'legacy_local',
|
|
'role_tokens' => [],
|
|
'safe_role_creation' => true,
|
|
];
|
|
|
|
$roleToken = $this->mapLegacyRoleToken((string) ($row->ruolo ?? ''));
|
|
if ($roleToken !== null) {
|
|
$grouped[$unitId]['role_tokens'][$roleToken] = true;
|
|
}
|
|
}
|
|
|
|
return array_values(array_map(function (array $candidate) use ($legacy): array {
|
|
$roleStandard = $this->mapRoleStandard($legacy['ruolo']);
|
|
if ($roleStandard === null) {
|
|
$tokens = array_keys($candidate['role_tokens']);
|
|
$roleStandard = count($tokens) === 1 ? $tokens[0] : null;
|
|
}
|
|
|
|
unset($candidate['role_tokens']);
|
|
$candidate['role_standard'] = $roleStandard;
|
|
|
|
return $candidate;
|
|
}, $grouped));
|
|
}
|
|
|
|
/**
|
|
* @param array<int,array<string,mixed>> $personaMatches
|
|
* @return array<int,array<string,mixed>>
|
|
*/
|
|
private function collectPersonaRelationCandidates(array $personaMatches, ?int $stabileId): array
|
|
{
|
|
if (! Schema::hasTable('persone_unita_relazioni') || $personaMatches === []) {
|
|
return [];
|
|
}
|
|
|
|
$personaIds = array_values(array_unique(array_map(fn(array $row): int => (int) $row['id'], $personaMatches)));
|
|
$rows = DB::table('persone_unita_relazioni as pur')
|
|
->join('unita_immobiliari as ui', 'ui.id', '=', 'pur.unita_id')
|
|
->whereIn('pur.persona_id', $personaIds)
|
|
->when($stabileId, fn($query) => $query->where('ui.stabile_id', $stabileId))
|
|
->select([
|
|
'pur.persona_id',
|
|
'pur.tipo_relazione',
|
|
'ui.id as unit_id',
|
|
'ui.codice_unita',
|
|
'ui.denominazione',
|
|
'ui.scala',
|
|
'ui.interno',
|
|
])
|
|
->orderBy('ui.id')
|
|
->get();
|
|
|
|
$grouped = [];
|
|
foreach ($rows as $row) {
|
|
$unitId = (int) $row->unit_id;
|
|
$grouped[$unitId] ??= [
|
|
'unit_id' => $unitId,
|
|
'unit_label' => $this->buildUnitLabel($row),
|
|
'unit_reference' => $this->buildUnitReference($row),
|
|
'source' => 'persona_relazione',
|
|
'role_tokens' => [],
|
|
'safe_role_creation' => true,
|
|
];
|
|
|
|
$roleStandard = $this->mapRoleStandard((string) ($row->tipo_relazione ?? ''));
|
|
if ($roleStandard !== null) {
|
|
$grouped[$unitId]['role_tokens'][$roleStandard] = true;
|
|
}
|
|
}
|
|
|
|
return array_values(array_map(function (array $candidate): array {
|
|
$tokens = array_keys($candidate['role_tokens']);
|
|
unset($candidate['role_tokens']);
|
|
$candidate['role_standard'] = count($tokens) === 1 ? $tokens[0] : null;
|
|
|
|
return $candidate;
|
|
}, $grouped));
|
|
}
|
|
|
|
/**
|
|
* @return array<int,array<string,mixed>>
|
|
*/
|
|
private function collectImportUnitCandidates(RubricaUniversale $rubrica, ?int $stabileId, array $legacy): array
|
|
{
|
|
if (! $stabileId || empty($legacy['cod_stabile']) || empty($legacy['cod_cond']) || ! $this->hasGesconImportCondomin()) {
|
|
return [];
|
|
}
|
|
|
|
$rows = DB::connection('gescon_import')
|
|
->table('condomin')
|
|
->where('cod_stabile', trim((string) $legacy['cod_stabile']))
|
|
->where('cod_cond', trim((string) $legacy['cod_cond']))
|
|
->select(['nom_cond', 'scala', 'interno', 'proprietario', 'inquilino'])
|
|
->get();
|
|
|
|
$candidates = [];
|
|
foreach ($rows as $row) {
|
|
$unit = $this->resolveUnitFromImportRow($stabileId, [
|
|
'nom_cond' => (string) ($row->nom_cond ?? ''),
|
|
'scala' => (string) ($row->scala ?? ''),
|
|
'interno' => (string) ($row->interno ?? ''),
|
|
]);
|
|
|
|
if ($unit === null) {
|
|
continue;
|
|
}
|
|
|
|
$roleFromNote = $this->mapRoleStandard($legacy['ruolo']);
|
|
$candidates[] = [
|
|
'unit_id' => (int) $unit->unit_id,
|
|
'unit_label' => $this->buildUnitLabel($unit),
|
|
'unit_reference' => $this->buildUnitReference($unit),
|
|
'source' => 'gescon_import',
|
|
'role_standard' => $roleFromNote,
|
|
'safe_role_creation' => false,
|
|
];
|
|
}
|
|
|
|
return $candidates;
|
|
}
|
|
|
|
/**
|
|
* @return array<int,array<string,mixed>>
|
|
*/
|
|
private function findPersonaMatches(RubricaUniversale $rubrica, ?int $stabileId): array
|
|
{
|
|
if (! Schema::hasTable('persone')) {
|
|
return [];
|
|
}
|
|
|
|
$query = DB::table('persone')->select(['id', 'nome', 'cognome', 'ragione_sociale', 'codice_fiscale', 'email_principale', 'telefono_principale']);
|
|
|
|
$cf = trim((string) ($rubrica->codice_fiscale ?? ''));
|
|
if ($cf !== '') {
|
|
$rows = (clone $query)->where('codice_fiscale', $cf)->get();
|
|
if ($rows->isNotEmpty()) {
|
|
return $rows->map(fn($row) => (array) $row)->all();
|
|
}
|
|
}
|
|
|
|
$email = mb_strtolower(trim((string) ($rubrica->email ?? '')));
|
|
if ($email !== '') {
|
|
$rows = (clone $query)->whereRaw('LOWER(email_principale) = ?', [$email])->get();
|
|
if ($rows->isNotEmpty()) {
|
|
return $rows->map(fn($row) => (array) $row)->all();
|
|
}
|
|
}
|
|
|
|
$phone = $this->normalizeDigits((string) ($rubrica->telefono_cellulare ?: $rubrica->telefono_ufficio ?: ''));
|
|
if ($phone !== '') {
|
|
$rows = (clone $query)
|
|
->whereRaw("REPLACE(REPLACE(REPLACE(COALESCE(telefono_principale, ''), ' ', ''), '+', ''), '-', '') = ?", [$phone])
|
|
->get();
|
|
if ($rows->isNotEmpty()) {
|
|
return $rows->map(fn($row) => (array) $row)->all();
|
|
}
|
|
}
|
|
|
|
$ragioneSociale = $this->normalizeText((string) ($rubrica->ragione_sociale ?: $rubrica->nome_completo));
|
|
if ($ragioneSociale !== '') {
|
|
return (clone $query)
|
|
->whereRaw("UPPER(REGEXP_REPLACE(COALESCE(ragione_sociale, ''), '[^A-Z0-9]', '')) = ?", [$ragioneSociale])
|
|
->get()
|
|
->map(fn($row) => (array) $row)
|
|
->all();
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* @param array<int,array<string,mixed>> ...$candidateSets
|
|
* @return array<int,array<string,mixed>>
|
|
*/
|
|
private function mergeCandidates(array ...$candidateSets): array
|
|
{
|
|
$merged = [];
|
|
foreach ($candidateSets as $candidateSet) {
|
|
foreach ($candidateSet as $candidate) {
|
|
$unitId = (int) ($candidate['unit_id'] ?? 0);
|
|
if ($unitId <= 0) {
|
|
continue;
|
|
}
|
|
|
|
if (! isset($merged[$unitId])) {
|
|
$merged[$unitId] = $candidate;
|
|
continue;
|
|
}
|
|
|
|
$merged[$unitId]['source'] .= '+' . $candidate['source'];
|
|
$merged[$unitId]['safe_role_creation'] = (bool) $merged[$unitId]['safe_role_creation'] || (bool) $candidate['safe_role_creation'];
|
|
if (($merged[$unitId]['role_standard'] ?? null) === null && ($candidate['role_standard'] ?? null) !== null) {
|
|
$merged[$unitId]['role_standard'] = $candidate['role_standard'];
|
|
}
|
|
}
|
|
}
|
|
|
|
ksort($merged);
|
|
|
|
return array_values($merged);
|
|
}
|
|
|
|
private function resolveUnitFromImportRow(int $stabileId, array $row): ?object
|
|
{
|
|
$query = DB::table('unita_immobiliari')
|
|
->where('stabile_id', $stabileId)
|
|
->select(['id as unit_id', 'codice_unita', 'denominazione', 'scala', 'interno']);
|
|
|
|
$scala = trim((string) ($row['scala'] ?? ''));
|
|
$interno = trim((string) ($row['interno'] ?? ''));
|
|
|
|
if ($scala !== '' || $interno !== '') {
|
|
$strict = (clone $query)
|
|
->when($scala !== '', fn($inner) => $inner->where('scala', $scala))
|
|
->when($interno !== '', fn($inner) => $inner->where('interno', $interno))
|
|
->get();
|
|
if ($strict->count() === 1) {
|
|
return $strict->first();
|
|
}
|
|
}
|
|
|
|
$normalizedName = $this->normalizeText((string) ($row['nom_cond'] ?? ''));
|
|
if ($normalizedName === '') {
|
|
return null;
|
|
}
|
|
|
|
$matches = (clone $query)->get()->filter(function ($unit) use ($normalizedName): bool {
|
|
$haystack = $this->normalizeText((string) ($unit->denominazione ?? ''));
|
|
|
|
return $haystack !== '' && ($haystack === $normalizedName || str_contains($haystack, $normalizedName) || str_contains($normalizedName, $haystack));
|
|
})->values();
|
|
|
|
return $matches->count() === 1 ? $matches->first() : null;
|
|
}
|
|
|
|
private function hasGesconImportCondomin(): bool
|
|
{
|
|
try {
|
|
return Schema::connection('gescon_import')->hasTable('condomin');
|
|
} catch (\Throwable) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private function buildStabileReference(array $stabile): ?string
|
|
{
|
|
if (empty($stabile['id'])) {
|
|
return null;
|
|
}
|
|
|
|
$parts = array_values(array_filter([
|
|
trim((string) ($stabile['cod_stabile'] ?? '')),
|
|
trim((string) ($stabile['codice_stabile'] ?? '')),
|
|
trim((string) ($stabile['denominazione'] ?? '')),
|
|
]));
|
|
|
|
return $parts !== [] ? implode(' - ', $parts) : ('Stabile #' . (int) $stabile['id']);
|
|
}
|
|
|
|
private function buildUnitReference(object | array $row): string
|
|
{
|
|
$code = trim((string) data_get((array) $row, 'codice_unita', data_get($row, 'codice_unita', '')));
|
|
$label = trim((string) data_get((array) $row, 'denominazione', data_get($row, 'denominazione', '')));
|
|
|
|
return trim($code . ($label !== '' ? ' - ' . $label : ''));
|
|
}
|
|
|
|
private function buildUnitLabel(object | array $row): string
|
|
{
|
|
$code = trim((string) data_get((array) $row, 'codice_unita', data_get($row, 'codice_unita', '')));
|
|
$scala = trim((string) data_get((array) $row, 'scala', data_get($row, 'scala', '')));
|
|
$interno = trim((string) data_get((array) $row, 'interno', data_get($row, 'interno', '')));
|
|
$denominazione = trim((string) data_get((array) $row, 'denominazione', data_get($row, 'denominazione', '')));
|
|
|
|
$bits = array_values(array_filter([$code, $scala, $interno, $denominazione]));
|
|
|
|
return implode(' / ', $bits);
|
|
}
|
|
|
|
private function mapRoleStandard(?string $value): ?string
|
|
{
|
|
$normalized = strtolower(trim((string) $value));
|
|
|
|
return match ($normalized) {
|
|
'c', 'condomino', 'proprietario', 'comproprietario', 'nudo_proprietario', 'usufruttuario', 'titolare' => 'condomino',
|
|
'i', 'inquilino', 'conduttore', 'locatario' => 'inquilino',
|
|
default => null,
|
|
};
|
|
}
|
|
|
|
private function mapLegacyRoleToken(string $value): ?string
|
|
{
|
|
return $this->mapRoleStandard($value);
|
|
}
|
|
|
|
private function displayRubricaName(RubricaUniversale $rubrica): string
|
|
{
|
|
return trim((string) ($rubrica->nome_completo ?: $rubrica->ragione_sociale ?: ('Rubrica #' . $rubrica->id)));
|
|
}
|
|
|
|
/**
|
|
* @param array<int,array<string,mixed>> $personaMatches
|
|
*/
|
|
private function summarizePersonas(array $personaMatches): string
|
|
{
|
|
if ($personaMatches === []) {
|
|
return '';
|
|
}
|
|
|
|
return implode(', ', array_map(function (array $row): string {
|
|
$label = trim((string) (($row['ragione_sociale'] ?? '') ?: trim((string) (($row['cognome'] ?? '') . ' ' . ($row['nome'] ?? '')))));
|
|
|
|
return '#' . (int) $row['id'] . ' ' . ($label !== '' ? $label : 'persona');
|
|
}, $personaMatches));
|
|
}
|
|
|
|
private function normalizeDigits(string $value): string
|
|
{
|
|
return preg_replace('/\D+/', '', $value) ?: '';
|
|
}
|
|
|
|
private function normalizeText(string $value): string
|
|
{
|
|
$upper = mb_strtoupper(trim($value));
|
|
$normalized = preg_replace('/[^A-Z0-9]+/u', '', $upper);
|
|
|
|
return is_string($normalized) ? $normalized : '';
|
|
}
|
|
}
|