netgescon-day0/app/Console/Commands/GesconSyncRubricaRuoli.php

188 lines
7.1 KiB
PHP

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use App\Models\Persona;
use App\Models\PersonaUnitaRelazione;
use App\Models\RubricaRuolo;
use App\Models\RubricaUniversale;
class GesconSyncRubricaRuoli extends Command
{
protected $signature = 'gescon:sync-rubrica-ruoli
{--stabile= : Filtra per stabile_id (dominio)}
{--limit=5000 : Max relazioni da processare}
{--create-missing : Se manca un contatto in rubrica_universale, lo crea da Persona (richiede --apply)}
{--apply : Esegue realmente l\'upsert. Senza flag è solo report}';
protected $description = 'Sincronizza ruoli/relazioni da persone_unita_relazioni verso rubrica_ruoli (con match CF/email/telefono).';
public function handle(): int
{
if (!Schema::hasTable('rubrica_universale') || !Schema::hasTable('rubrica_ruoli')) {
$this->error('Tabelle rubrica_universale/rubrica_ruoli non disponibili.');
return 1;
}
$apply = (bool)$this->option('apply');
$createMissing = (bool) $this->option('create-missing');
$stabileFilter = $this->option('stabile');
$limit = (int)$this->option('limit');
if ($limit < 100) $limit = 100;
if ($limit > 20000) $limit = 20000;
$query = PersonaUnitaRelazione::with(['persona', 'unitaImmobiliare.stabile'])
->orderBy('id');
if ($stabileFilter) {
$query->whereHas('unitaImmobiliare', function ($q) use ($stabileFilter) {
$q->where('stabile_id', $stabileFilter);
});
}
$total = (clone $query)->count();
if ($total === 0) {
$this->info('Nessuna relazione da sincronizzare.');
return 0;
}
$processed = $inserted = $updated = $skipped = 0;
$query->limit($limit)->chunkById(200, function ($chunk) use (&$processed, &$inserted, &$updated, &$skipped, $apply, $createMissing) {
foreach ($chunk as $relazione) {
$processed++;
$persona = $relazione->persona;
$unita = $relazione->unitaImmobiliare;
$stabile = $unita?->stabile;
if (!$persona || !$unita || !$stabile) {
$skipped++;
continue;
}
$rubrica = $this->trovaRubricaPerPersona($persona, $stabile->amministratore_id ?? null, $apply && $createMissing);
if (!$rubrica) {
$skipped++;
continue;
}
$ruoloStandard = $this->mapRuolo($relazione->tipo_relazione);
$match = [
'rubrica_id' => $rubrica->id,
'stabile_id' => $stabile->id,
'unita_immobiliare_id' => $unita->id,
'ruolo_standard' => $ruoloStandard,
];
$payload = [
'is_attivo' => $relazione->isAttiva(),
'is_preferito' => $relazione->isAttiva(),
'meta' => [
'percentuale_possesso' => $relazione->quota_relazione,
'tipo_relazione_orig' => $relazione->tipo_relazione,
'persona_id_orig' => $persona->id,
],
];
if (!$apply) {
RubricaRuolo::where($match)->exists() ? $updated++ : $inserted++;
continue;
}
$record = RubricaRuolo::updateOrCreate($match, $payload);
$record->wasRecentlyCreated ? $inserted++ : $updated++;
}
});
$this->info(($apply ? 'Sync eseguito' : 'Dry-run') . " - processati: {$processed}, inseriti: {$inserted}, aggiornati: {$updated}, saltati: {$skipped}");
return 0;
}
protected function trovaRubricaPerPersona(Persona $persona, $amministratoreId = null, bool $createIfMissing = false): ?RubricaUniversale
{
if (!$this->personaHasRubricaIdentity($persona)) {
return null;
}
$cf = $persona->codice_fiscale;
if ($cf) {
$found = RubricaUniversale::where('codice_fiscale', $cf)->first();
if ($found) return $found;
}
$email = $persona->email_principale;
if ($email) {
$found = RubricaUniversale::where('email', $email)->first();
if ($found) return $found;
}
$phone = $persona->telefono_principale;
if ($phone) {
$found = RubricaUniversale::where(function ($q) use ($phone) {
$q->where('telefono_ufficio', $phone)->orWhere('telefono_cellulare', $phone);
})->first();
if ($found) return $found;
}
if (!$createIfMissing) {
return null;
}
$tipo = $persona->tipologia === 'giuridica' ? 'persona_giuridica' : 'persona_fisica';
$now = now();
return RubricaUniversale::query()->create([
'amministratore_id' => $amministratoreId ? (int) $amministratoreId : null,
'nome' => $tipo === 'persona_fisica' ? ($persona->nome ?? null) : null,
'cognome' => $tipo === 'persona_fisica' ? ($persona->cognome ?? null) : null,
'ragione_sociale' => $tipo === 'persona_giuridica' ? ($persona->ragione_sociale ?? $persona->nome_completo) : null,
'tipo_contatto' => $tipo,
'categoria' => 'condomino',
'stato' => 'attivo',
'codice_fiscale' => $cf ?: null,
'partita_iva' => $persona->partita_iva ?: null,
'email' => $persona->email_principale ?? null,
'pec' => $persona->email_pec ?? null,
'telefono_ufficio' => $persona->telefono_principale ?? null,
'telefono_cellulare' => $persona->telefono_secondario ?? null,
'note' => $persona->note ?? null,
'data_inserimento' => $now,
'data_ultima_modifica' => $now,
]);
}
private function personaHasRubricaIdentity(Persona $persona): bool
{
$vals = [
trim((string) ($persona->nome ?? '')),
trim((string) ($persona->cognome ?? '')),
trim((string) ($persona->ragione_sociale ?? '')),
trim((string) ($persona->nome_completo ?? '')),
trim((string) ($persona->codice_fiscale ?? '')),
trim((string) ($persona->partita_iva ?? '')),
trim((string) ($persona->email_principale ?? '')),
trim((string) ($persona->email_pec ?? '')),
trim((string) ($persona->telefono_principale ?? '')),
trim((string) ($persona->telefono_secondario ?? '')),
];
foreach ($vals as $v) {
if ($v !== '') {
return true;
}
}
return false;
}
protected function mapRuolo(?string $tipo): string
{
$tipo = strtolower((string)$tipo);
return match ($tipo) {
'inquilino' => 'inquilino',
'proprietario', 'comproprietario', 'nudo_proprietario', 'usufruttuario', 'titolare' => 'condomino',
default => 'condomino',
};
}
}