659 lines
24 KiB
PHP
659 lines
24 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\Persona;
|
|
use App\Models\RubricaUniversale;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Illuminate\Support\Str;
|
|
|
|
class GesconMaterializePersoneRelazioniCommand extends Command
|
|
{
|
|
protected $signature = 'gescon:materialize-persone-relazioni
|
|
{--stabile= : Codice stabile dominio/legacy da filtrare}
|
|
{--limit=10000 : Max righe nominativi da processare}
|
|
{--apply : Esegue realmente le scritture. Senza flag e dry-run}';
|
|
|
|
protected $description = 'Materializza persone e persone_unita_relazioni a partire da unita_immobiliare_nominativi.';
|
|
|
|
public function handle(): int
|
|
{
|
|
$apply = (bool) $this->option('apply');
|
|
$stabile = trim((string) ($this->option('stabile') ?? ''));
|
|
$limit = max(1, min(50000, (int) ($this->option('limit') ?? 10000)));
|
|
|
|
foreach (['unita_immobiliare_nominativi', 'unita_immobiliari', 'stabili', 'persone', 'persone_unita_relazioni'] as $table) {
|
|
if (! Schema::hasTable($table)) {
|
|
$this->error("Tabella {$table} non disponibile.");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
$query = DB::table('unita_immobiliare_nominativi as uin')
|
|
->join('unita_immobiliari as ui', 'ui.id', '=', 'uin.unita_immobiliare_id')
|
|
->join('stabili as s', 's.id', '=', 'ui.stabile_id')
|
|
->select([
|
|
'uin.id',
|
|
'uin.unita_immobiliare_id',
|
|
'uin.legacy_cond_id',
|
|
'uin.ruolo',
|
|
'uin.nominativo',
|
|
'uin.data_inizio',
|
|
'uin.data_fine',
|
|
'uin.percentuale',
|
|
'uin.fonte',
|
|
'uin.legacy_payload',
|
|
'ui.stabile_id',
|
|
'ui.codice_unita',
|
|
'ui.scala',
|
|
'ui.interno',
|
|
'ui.piano',
|
|
's.codice_stabile',
|
|
's.amministratore_id',
|
|
])
|
|
->orderBy('s.codice_stabile')
|
|
->orderBy('ui.id')
|
|
->orderBy('uin.id');
|
|
|
|
if ($stabile !== '') {
|
|
$trimmed = ltrim($stabile, '0');
|
|
$query->where(function ($builder) use ($stabile, $trimmed): void {
|
|
$builder->where('s.codice_stabile', $stabile);
|
|
if ($trimmed !== '' && $trimmed !== $stabile) {
|
|
$builder->orWhere('s.codice_stabile', $trimmed);
|
|
}
|
|
});
|
|
}
|
|
|
|
$rows = $query->limit($limit)->get();
|
|
if ($rows->isEmpty()) {
|
|
$this->info('Nessun nominativo unita da materializzare.');
|
|
return 0;
|
|
}
|
|
|
|
$stats = [
|
|
'processed' => 0,
|
|
'skipped' => 0,
|
|
'persona_created' => 0,
|
|
'persona_updated' => 0,
|
|
'rel_created' => 0,
|
|
'rel_updated' => 0,
|
|
];
|
|
|
|
foreach ($rows as $row) {
|
|
$stats['processed']++;
|
|
|
|
$nominativo = trim((string) ($row->nominativo ?? ''));
|
|
if ($nominativo === '') {
|
|
$stats['skipped']++;
|
|
continue;
|
|
}
|
|
|
|
$tipoRelazione = $this->resolveTipoRelazione($row);
|
|
$ruoloRate = $this->deriveRuoloRate($tipoRelazione);
|
|
$rubrica = $this->findMatchingRubrica($row, $tipoRelazione);
|
|
$payload = $this->buildPersonaPayload($row, $rubrica);
|
|
|
|
if (! $this->hasPersonaIdentity($payload)) {
|
|
$stats['skipped']++;
|
|
continue;
|
|
}
|
|
|
|
$persona = $this->resolvePersonaMatch($payload);
|
|
if ($apply) {
|
|
if ($persona) {
|
|
$updated = $this->fillPersonaMissingFields($persona, $payload);
|
|
if ($updated) {
|
|
$stats['persona_updated']++;
|
|
}
|
|
} else {
|
|
$persona = $this->createPersonaFromPayload($payload);
|
|
if (! $persona) {
|
|
$stats['skipped']++;
|
|
continue;
|
|
}
|
|
$stats['persona_created']++;
|
|
}
|
|
|
|
$relationPayload = [
|
|
'quota_relazione' => $this->normalizePercentValue($row->percentuale ?? null),
|
|
'data_inizio' => $this->normalizeDateToYmd($row->data_inizio ?? null) ?: '1900-01-01',
|
|
'data_fine' => $this->normalizeDateToYmd($row->data_fine ?? null),
|
|
'attivo' => $this->isRelationActive($row->data_fine ?? null),
|
|
'riceve_comunicazioni' => true,
|
|
'riceve_convocazioni' => $ruoloRate === 'C',
|
|
'vota_assemblea' => $ruoloRate === 'C',
|
|
'note_relazione' => $this->buildRelationNote($row, $tipoRelazione),
|
|
];
|
|
|
|
if (Schema::hasColumn('persone_unita_relazioni', 'ruolo_rate')) {
|
|
$relationPayload['ruolo_rate'] = $ruoloRate;
|
|
}
|
|
|
|
$existingRelationId = $this->findExistingRelationId(
|
|
(int) $persona->id,
|
|
(int) $row->unita_immobiliare_id,
|
|
$tipoRelazione,
|
|
$relationPayload['data_inizio'],
|
|
$relationPayload['data_fine'],
|
|
);
|
|
|
|
if ($existingRelationId) {
|
|
DB::table('persone_unita_relazioni')
|
|
->where('id', $existingRelationId)
|
|
->update($relationPayload + ['updated_at' => now()]);
|
|
$stats['rel_updated']++;
|
|
} else {
|
|
DB::table('persone_unita_relazioni')->insert([
|
|
'persona_id' => (int) $persona->id,
|
|
'unita_id' => (int) $row->unita_immobiliare_id,
|
|
'tipo_relazione' => $tipoRelazione,
|
|
'quota_relazione' => $relationPayload['quota_relazione'],
|
|
'data_inizio' => $relationPayload['data_inizio'],
|
|
'data_fine' => $relationPayload['data_fine'],
|
|
'attivo' => $relationPayload['attivo'],
|
|
'riceve_comunicazioni' => $relationPayload['riceve_comunicazioni'],
|
|
'riceve_convocazioni' => $relationPayload['riceve_convocazioni'],
|
|
'vota_assemblea' => $relationPayload['vota_assemblea'],
|
|
'note_relazione' => $relationPayload['note_relazione'],
|
|
'ruolo_rate' => $relationPayload['ruolo_rate'] ?? null,
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
$stats['rel_created']++;
|
|
}
|
|
}
|
|
}
|
|
|
|
$mode = $apply ? 'Materializzazione eseguita' : 'Dry-run materializzazione';
|
|
$this->info($mode
|
|
. " - processati: {$stats['processed']}"
|
|
. ", persone create: {$stats['persona_created']}"
|
|
. ", persone aggiornate: {$stats['persona_updated']}"
|
|
. ", relazioni create: {$stats['rel_created']}"
|
|
. ", relazioni aggiornate: {$stats['rel_updated']}"
|
|
. ", saltati: {$stats['skipped']}");
|
|
|
|
return 0;
|
|
}
|
|
|
|
private function findMatchingRubrica(object $row, string $tipoRelazione): ?RubricaUniversale
|
|
{
|
|
if (! Schema::hasTable('rubrica_universale')) {
|
|
return null;
|
|
}
|
|
|
|
$role = $this->deriveRuoloRate($tipoRelazione) === 'I' ? 'inquilino' : 'condomino';
|
|
$codCond = trim((string) ($row->legacy_cond_id ?? ''));
|
|
$codStabile = trim((string) ($row->codice_stabile ?? ''));
|
|
$adminId = (int) ($row->amministratore_id ?? 0);
|
|
|
|
if ($codCond !== '' && $codStabile !== '') {
|
|
$stabileVariants = array_values(array_unique(array_filter([$codStabile, ltrim($codStabile, '0')])));
|
|
|
|
foreach ($stabileVariants as $stabileVariant) {
|
|
$rubrica = RubricaUniversale::query()
|
|
->when($adminId > 0, fn($query) => $query->where('amministratore_id', $adminId))
|
|
->where('categoria', 'condomino')
|
|
->whereNotNull('note')
|
|
->where('note', 'like', '%cod_stabile=' . $stabileVariant . '%')
|
|
->where('note', 'like', '%cod_cond=' . $codCond . '%')
|
|
->where('note', 'like', '%ruolo=' . $role . '%')
|
|
->orderBy('id')
|
|
->first();
|
|
if ($rubrica) {
|
|
return $rubrica;
|
|
}
|
|
}
|
|
}
|
|
|
|
$identityKey = $this->normalizeIdentityKey($row->nominativo ?? null);
|
|
if (! $identityKey) {
|
|
return null;
|
|
}
|
|
|
|
return RubricaUniversale::query()
|
|
->when($adminId > 0, fn($query) => $query->where('amministratore_id', $adminId))
|
|
->where(function ($query) use ($identityKey): void {
|
|
$query->whereRaw("UPPER(REGEXP_REPLACE(COALESCE(ragione_sociale, ''), '[^A-Z0-9]', '')) = ?", [$identityKey])
|
|
->orWhereRaw("UPPER(REGEXP_REPLACE(CONCAT(COALESCE(cognome, ''), COALESCE(nome, '')), '[^A-Z0-9]', '')) = ?", [$identityKey]);
|
|
})
|
|
->orderBy('id')
|
|
->first();
|
|
}
|
|
|
|
private function buildPersonaPayload(object $row, ?RubricaUniversale $rubrica): array
|
|
{
|
|
if ($rubrica) {
|
|
$ragione = $this->sanitizeString($rubrica->ragione_sociale, 255);
|
|
$nome = $this->sanitizeString($rubrica->nome, 100);
|
|
$cognome = $this->sanitizeString($rubrica->cognome, 100);
|
|
} else {
|
|
[$cognome, $nome, $ragione] = $this->splitNomeCognomeOrRagione((string) ($row->nominativo ?? ''));
|
|
}
|
|
|
|
if ($ragione && ! $cognome) {
|
|
$cognome = $ragione;
|
|
}
|
|
if (! $nome) {
|
|
$nome = $ragione ? 'Impresa' : ($cognome ?: 'N/D');
|
|
}
|
|
if (! $cognome) {
|
|
$cognome = $nome ?: 'N/D';
|
|
}
|
|
|
|
$rawFiscal = $rubrica?->codice_fiscale ?: $rubrica?->partita_iva;
|
|
$fiscal = $this->normalizeFiscalIds(is_string($rawFiscal) ? $rawFiscal : null);
|
|
|
|
return [
|
|
'tipologia' => $ragione ? 'giuridica' : 'fisica',
|
|
'nome' => $nome,
|
|
'cognome' => $cognome,
|
|
'ragione_sociale' => $ragione,
|
|
'codice_fiscale' => $fiscal['cf'],
|
|
'partita_iva' => $fiscal['piva'],
|
|
'email_principale' => $this->sanitizeEmail($rubrica?->email),
|
|
'email_pec' => $this->sanitizeEmail($rubrica?->pec),
|
|
'telefono_principale' => $this->normalizePhone($rubrica?->telefono_cellulare ?: $rubrica?->telefono_ufficio),
|
|
'telefono_secondario' => $this->normalizePhone($rubrica?->telefono_ufficio),
|
|
'residenza_via' => $this->sanitizeString($rubrica?->indirizzo, 255),
|
|
'note' => $this->buildPersonaNote($row, $rubrica),
|
|
'attivo' => true,
|
|
'name_key' => $this->normalizeNameKey($nome, $cognome),
|
|
];
|
|
}
|
|
|
|
private function resolvePersonaMatch(array $payload): ?object
|
|
{
|
|
$cf = $payload['codice_fiscale'] ?? null;
|
|
if ($cf) {
|
|
$found = DB::table('persone')->where('codice_fiscale', $cf)->orderBy('id')->first();
|
|
if ($found) {
|
|
return $found;
|
|
}
|
|
}
|
|
|
|
$piva = $payload['partita_iva'] ?? null;
|
|
if ($piva) {
|
|
$found = DB::table('persone')
|
|
->where(function ($query) use ($piva): void {
|
|
$query->where('partita_iva', $piva)
|
|
->orWhere('partita_iva_societa', $piva);
|
|
})
|
|
->orderBy('id')
|
|
->first();
|
|
if ($found) {
|
|
return $found;
|
|
}
|
|
}
|
|
|
|
$telefono = $payload['telefono_principale'] ?? null;
|
|
if ($telefono) {
|
|
$found = DB::table('persone')->where('telefono_principale', $telefono)->orderBy('id')->first();
|
|
if ($found) {
|
|
return $found;
|
|
}
|
|
}
|
|
|
|
$email = $payload['email_principale'] ?? null;
|
|
if ($email) {
|
|
$found = DB::table('persone')->where('email_principale', $email)->orderBy('id')->first();
|
|
if ($found) {
|
|
return $found;
|
|
}
|
|
}
|
|
|
|
$nameKey = $payload['name_key'] ?? null;
|
|
if ($nameKey) {
|
|
return DB::table('persone')
|
|
->whereRaw("UPPER(CONCAT(TRIM(cognome), ' ', TRIM(nome))) = ?", [$nameKey])
|
|
->orderBy('id')
|
|
->first();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private function createPersonaFromPayload(array $payload): ?Persona
|
|
{
|
|
$data = [
|
|
'tipologia' => $payload['tipologia'] ?? 'fisica',
|
|
'cognome' => $payload['cognome'],
|
|
'nome' => $payload['nome'],
|
|
'ragione_sociale' => $payload['ragione_sociale'],
|
|
'codice_fiscale' => $payload['codice_fiscale'],
|
|
'partita_iva' => $payload['partita_iva'],
|
|
'residenza_via' => $payload['residenza_via'],
|
|
'telefono_principale' => $payload['telefono_principale'],
|
|
'telefono_secondario' => $payload['telefono_secondario'],
|
|
'email_principale' => $payload['email_principale'],
|
|
'email_pec' => $payload['email_pec'],
|
|
'note' => $payload['note'],
|
|
'attivo' => $payload['attivo'] ?? true,
|
|
];
|
|
|
|
if ($data['telefono_principale'] && DB::table('persone')->where('telefono_principale', $data['telefono_principale'])->exists()) {
|
|
$data['telefono_principale'] = null;
|
|
}
|
|
|
|
try {
|
|
return Persona::query()->create($data);
|
|
} catch (\Throwable $e) {
|
|
$this->warn('Creazione persona fallita per nominativo ' . ($payload['ragione_sociale'] ?: trim($payload['cognome'] . ' ' . $payload['nome'])) . ': ' . $e->getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private function fillPersonaMissingFields(object $persona, array $payload): bool
|
|
{
|
|
$updates = [];
|
|
foreach ([
|
|
'tipologia',
|
|
'cognome',
|
|
'nome',
|
|
'ragione_sociale',
|
|
'codice_fiscale',
|
|
'partita_iva',
|
|
'residenza_via',
|
|
'telefono_principale',
|
|
'telefono_secondario',
|
|
'email_principale',
|
|
'email_pec',
|
|
] as $field) {
|
|
$value = $payload[$field] ?? null;
|
|
if (! $value) {
|
|
continue;
|
|
}
|
|
|
|
$current = $persona->{$field} ?? null;
|
|
if (empty($current)) {
|
|
if ($field === 'telefono_principale' && DB::table('persone')->where('telefono_principale', $value)->where('id', '!=', $persona->id)->exists()) {
|
|
continue;
|
|
}
|
|
$updates[$field] = $value;
|
|
}
|
|
}
|
|
|
|
if (! empty($updates)) {
|
|
$updates['updated_at'] = now();
|
|
DB::table('persone')->where('id', $persona->id)->update($updates);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private function findExistingRelationId(int $personaId, int $unitaId, string $tipoRelazione, string $dataInizio, ?string $dataFine): ?int
|
|
{
|
|
$query = DB::table('persone_unita_relazioni')
|
|
->where('persona_id', $personaId)
|
|
->where('unita_id', $unitaId)
|
|
->where('tipo_relazione', $tipoRelazione)
|
|
->where('data_inizio', $dataInizio);
|
|
|
|
if ($dataFine === null) {
|
|
$query->whereNull('data_fine');
|
|
} else {
|
|
$query->where('data_fine', $dataFine);
|
|
}
|
|
|
|
$id = $query->orderBy('id')->value('id');
|
|
|
|
return $id ? (int) $id : null;
|
|
}
|
|
|
|
private function resolveTipoRelazione(object $row): string
|
|
{
|
|
$ruolo = strtoupper(trim((string) ($row->ruolo ?? 'C')));
|
|
if ($ruolo === 'I') {
|
|
return 'inquilino';
|
|
}
|
|
|
|
$payload = $this->decodeLegacyPayload($row->legacy_payload ?? null);
|
|
$diritto = $this->normalizeRoleCustom((string) ($payload['diritto_reale'] ?? $payload['diritto_label'] ?? ''));
|
|
|
|
if ($diritto !== null && in_array($diritto, ['comproprietario', 'nudo_proprietario', 'usufruttuario', 'titolare'], true)) {
|
|
return $diritto;
|
|
}
|
|
|
|
$percentuale = $this->normalizePercentValue($row->percentuale ?? null);
|
|
if (($row->fonte ?? null) === 'legacy_comproprietari' && $percentuale !== null && $percentuale < 100) {
|
|
return 'comproprietario';
|
|
}
|
|
|
|
return 'proprietario';
|
|
}
|
|
|
|
private function deriveRuoloRate(string $tipoRelazione): string
|
|
{
|
|
return in_array($tipoRelazione, ['inquilino', 'locatario', 'conduttore'], true) ? 'I' : 'C';
|
|
}
|
|
|
|
private function buildRelationNote(object $row, string $tipoRelazione): string
|
|
{
|
|
$parts = [
|
|
'source=unita_immobiliare_nominativi',
|
|
'uin_id=' . (int) ($row->id ?? 0),
|
|
'fonte=' . trim((string) ($row->fonte ?? 'manuale')),
|
|
'cod_stabile=' . trim((string) ($row->codice_stabile ?? '')),
|
|
'cod_cond=' . trim((string) ($row->legacy_cond_id ?? '')),
|
|
'tipo=' . $tipoRelazione,
|
|
];
|
|
|
|
return implode(' | ', array_filter($parts));
|
|
}
|
|
|
|
private function buildPersonaNote(object $row, ?RubricaUniversale $rubrica): string
|
|
{
|
|
$parts = [
|
|
'Materializzato da unita_immobiliare_nominativi',
|
|
'uin_id=' . (int) ($row->id ?? 0),
|
|
'fonte=' . trim((string) ($row->fonte ?? 'manuale')),
|
|
'cod_stabile=' . trim((string) ($row->codice_stabile ?? '')),
|
|
'cod_cond=' . trim((string) ($row->legacy_cond_id ?? '')),
|
|
];
|
|
|
|
if ($rubrica) {
|
|
$parts[] = 'rubrica_id=' . (int) $rubrica->id;
|
|
}
|
|
|
|
return implode(' | ', array_filter($parts));
|
|
}
|
|
|
|
private function hasPersonaIdentity(array $payload): bool
|
|
{
|
|
foreach (['ragione_sociale', 'nome', 'cognome', 'codice_fiscale', 'partita_iva', 'email_principale', 'telefono_principale'] as $field) {
|
|
if (! empty($payload[$field])) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private function sanitizeString(?string $value, int $maxLength = 255): ?string
|
|
{
|
|
if ($value === null) {
|
|
return null;
|
|
}
|
|
|
|
$value = trim($value);
|
|
|
|
return $value === '' ? null : mb_substr($value, 0, $maxLength);
|
|
}
|
|
|
|
private function sanitizeEmail(?string $value): ?string
|
|
{
|
|
if ($value === null) {
|
|
return null;
|
|
}
|
|
|
|
$value = strtolower(trim($value));
|
|
$value = preg_replace('/\s+/', '', $value);
|
|
|
|
return $value === '' ? null : $value;
|
|
}
|
|
|
|
private function normalizePhone(?string $value): ?string
|
|
{
|
|
if ($value === null) {
|
|
return null;
|
|
}
|
|
|
|
$normalized = preg_replace('/[^\d+]/', '', (string) $value);
|
|
|
|
return $normalized === '' ? null : $normalized;
|
|
}
|
|
|
|
private function normalizeFiscalIds(?string $raw): array
|
|
{
|
|
$raw = strtoupper(trim((string) ($raw ?? '')));
|
|
$raw = preg_replace('/[^A-Z0-9]/', '', $raw);
|
|
if ($raw === '') {
|
|
return ['cf' => null, 'piva' => null];
|
|
}
|
|
|
|
if (preg_match('/^\d+$/', $raw)) {
|
|
$raw = strlen($raw) < 11 ? str_pad($raw, 11, '0', STR_PAD_LEFT) : $raw;
|
|
if (strlen($raw) === 11) {
|
|
return ['cf' => $raw, 'piva' => $raw];
|
|
}
|
|
}
|
|
|
|
return ['cf' => $raw, 'piva' => null];
|
|
}
|
|
|
|
private function normalizeIdentityKey(mixed $value): ?string
|
|
{
|
|
if ($value === null) {
|
|
return null;
|
|
}
|
|
|
|
$value = Str::upper(trim((string) $value));
|
|
$value = preg_replace('/[^A-Z0-9]+/u', '', $value);
|
|
|
|
return $value !== '' ? $value : null;
|
|
}
|
|
|
|
private function normalizeNameKey(?string $nome, ?string $cognome): ?string
|
|
{
|
|
$full = trim(strtoupper(trim((string) ($cognome ?? '')) . ' ' . trim((string) ($nome ?? ''))));
|
|
$full = preg_replace('/\s+/', ' ', $full);
|
|
$full = preg_replace('/[^A-Z0-9 ]/', '', $full);
|
|
|
|
return $full !== '' ? $full : null;
|
|
}
|
|
|
|
private function splitNomeCognomeOrRagione(?string $raw): array
|
|
{
|
|
$value = trim((string) ($raw ?? ''));
|
|
if ($value === '') {
|
|
return [null, null, null];
|
|
}
|
|
|
|
if (preg_match('/\b(SRL|SPA|S\.R\.L\.|S\.P\.A\.|SAS|SNC|ASSOCIAZIONE|CONDOMINIO)\b/i', $value)) {
|
|
return [null, null, mb_substr($value, 0, 255)];
|
|
}
|
|
|
|
$parts = array_values(array_filter(preg_split('/\s+/', $value) ?: []));
|
|
if (count($parts) >= 2) {
|
|
$nome = array_pop($parts);
|
|
$cognome = implode(' ', $parts);
|
|
|
|
return [mb_substr($cognome, 0, 100), mb_substr($nome, 0, 100), null];
|
|
}
|
|
|
|
return [null, null, mb_substr($value, 0, 255)];
|
|
}
|
|
|
|
private function normalizeDateToYmd(mixed $value): ?string
|
|
{
|
|
if ($value === null) {
|
|
return null;
|
|
}
|
|
|
|
$value = trim((string) $value);
|
|
if ($value === '') {
|
|
return null;
|
|
}
|
|
|
|
if (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $value)) {
|
|
return $value;
|
|
}
|
|
|
|
$date = \DateTime::createFromFormat('Y-m-d H:i:s', $value)
|
|
?: \DateTime::createFromFormat('d/m/Y', $value)
|
|
?: \DateTime::createFromFormat('d/m/y', $value)
|
|
?: \DateTime::createFromFormat('m/d/Y', $value)
|
|
?: \DateTime::createFromFormat('m/d/y', $value)
|
|
?: \DateTime::createFromFormat('d/m/Y H:i:s', $value)
|
|
?: \DateTime::createFromFormat('m/d/Y H:i:s', $value);
|
|
|
|
if ($date instanceof \DateTimeInterface) {
|
|
return $date->format('Y-m-d');
|
|
}
|
|
|
|
$timestamp = @strtotime($value);
|
|
|
|
return $timestamp ? date('Y-m-d', $timestamp) : null;
|
|
}
|
|
|
|
private function normalizePercentValue(mixed $value): ?float
|
|
{
|
|
if ($value === null) {
|
|
return null;
|
|
}
|
|
|
|
if (is_string($value)) {
|
|
$value = str_replace(['%', ' '], '', trim($value));
|
|
$value = str_replace(',', '.', $value);
|
|
}
|
|
|
|
return is_numeric($value) ? (float) $value : null;
|
|
}
|
|
|
|
private function isRelationActive(mixed $dataFine): bool
|
|
{
|
|
$normalized = $this->normalizeDateToYmd($dataFine);
|
|
|
|
return $normalized === null || $normalized >= now()->toDateString();
|
|
}
|
|
|
|
private function normalizeRoleCustom(string $value): ?string
|
|
{
|
|
$value = strtolower(trim($value));
|
|
if ($value === '') {
|
|
return null;
|
|
}
|
|
|
|
$value = str_replace(['à', 'è', 'é', 'ì', 'ò', 'ù'], ['a', 'e', 'e', 'i', 'o', 'u'], $value);
|
|
$value = preg_replace('/[^a-z0-9_\s-]+/', '', $value) ?? $value;
|
|
$value = str_replace([' ', '-'], '_', $value);
|
|
$value = preg_replace('/_+/', '_', $value) ?? $value;
|
|
$value = trim($value, '_');
|
|
|
|
return match ($value) {
|
|
'comproprietario', 'co_proprietario' => 'comproprietario',
|
|
'nudo_proprietario', 'nuda_proprieta' => 'nudo_proprietario',
|
|
'usufruttuario', 'usufrutto' => 'usufruttuario',
|
|
'titolare' => 'titolare',
|
|
default => null,
|
|
};
|
|
}
|
|
|
|
private function decodeLegacyPayload(mixed $payload): array
|
|
{
|
|
if (is_array($payload)) {
|
|
return $payload;
|
|
}
|
|
|
|
if (is_string($payload) && trim($payload) !== '') {
|
|
$decoded = json_decode($payload, true);
|
|
return is_array($decoded) ? $decoded : [];
|
|
}
|
|
|
|
return [];
|
|
}
|
|
} |