188 lines
7.1 KiB
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',
|
|
};
|
|
}
|
|
}
|