feat(anagrafica): idempotent bonifica of Benedetto duplicate rubrica records & card deduplication (task-b2aa57adea)
This commit is contained in:
parent
ccc0c1ec39
commit
4774ef5751
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class GesconBonificaDuplicatiBenedettoCommand extends Command
|
||||
{
|
||||
protected $signature = 'gescon:bonifica-duplicati-benedetto';
|
||||
|
||||
protected $description = 'Bonifica idempotente delle rubriche duplicate di Daniela Benedetto verso la Persona 323 / Rubrica 697 (CF BNDDNL86M58H224O)';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$this->info('Starting bonifica idempotente Benedetto Daniela...');
|
||||
|
||||
$canonicalPersona = DB::table('persone')->where('codice_fiscale', 'BNDDNL86M58H224O')->first()
|
||||
?? DB::table('persone')->find(323);
|
||||
$canonicalPersonaId = $canonicalPersona?->id ?? 323;
|
||||
|
||||
$canonicalRubrica = DB::table('rubrica_universale')->where('codice_fiscale', 'BNDDNL86M58H224O')->first()
|
||||
?? DB::table('rubrica_universale')->where('codice_univoco', '000000JC')->first()
|
||||
?? DB::table('rubrica_universale')->find(697);
|
||||
$canonicalRubricaId = $canonicalRubrica?->id ?? 697;
|
||||
|
||||
$duplicatePersonaIds = DB::table('persone')
|
||||
->where('cognome', 'BENEDETTO')
|
||||
->where('id', '!=', $canonicalPersonaId)
|
||||
->pluck('id')
|
||||
->all();
|
||||
|
||||
$duplicateRubricaIds = DB::table('rubrica_universale')
|
||||
->where('cognome', 'BENEDETTO')
|
||||
->where('id', '!=', $canonicalRubricaId)
|
||||
->pluck('id')
|
||||
->all();
|
||||
|
||||
// 1. Audit before counts
|
||||
$purBefore = DB::table('persone_unita_relazioni')->whereIn('persona_id', $duplicatePersonaIds)->count();
|
||||
$rrBefore = DB::table('rubrica_ruoli')->whereIn('rubrica_id', $duplicateRubricaIds)->count();
|
||||
|
||||
$this->info(sprintf('BEFORE: Duplicate PUR=%d, Duplicate RR=%d', $purBefore, $rrBefore));
|
||||
|
||||
// 2. Remap relations in persone_unita_relazioni
|
||||
if (! empty($duplicatePersonaIds)) {
|
||||
DB::table('persone_unita_relazioni')
|
||||
->whereIn('persona_id', $duplicatePersonaIds)
|
||||
->update([
|
||||
'persona_id' => $canonicalPersonaId,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
DB::table('persone')
|
||||
->whereIn('id', $duplicatePersonaIds)
|
||||
->update([
|
||||
'attivo' => 0,
|
||||
'note' => '[ARCHIVIATO_DUPLICATO] Riconfigurato verso Persona ' . $canonicalPersonaId . ' CF BNDDNL86M58H224O',
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
// 3. Remap roles in rubrica_ruoli & soft archive rubrica
|
||||
if (! empty($duplicateRubricaIds)) {
|
||||
DB::table('rubrica_ruoli')
|
||||
->whereIn('rubrica_id', $duplicateRubricaIds)
|
||||
->update([
|
||||
'rubrica_id' => $canonicalRubricaId,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
DB::table('rubrica_universale')
|
||||
->whereIn('id', $duplicateRubricaIds)
|
||||
->update([
|
||||
'stato' => 'inattivo',
|
||||
'note' => '[ARCHIVIATO_DUPLICATO] Soft archived verso Rubrica ' . $canonicalRubricaId . ' (CF BNDDNL86M58H224O)',
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
// 4. Ensure canonical persona & rubrica remain active
|
||||
if ($canonicalPersonaId) {
|
||||
DB::table('persone')->where('id', $canonicalPersonaId)->update(['attivo' => 1]);
|
||||
}
|
||||
if ($canonicalRubricaId) {
|
||||
DB::table('rubrica_universale')->where('id', $canonicalRubricaId)->update(['stato' => 'attivo']);
|
||||
}
|
||||
|
||||
// 5. Audit after counts
|
||||
$purAfter = DB::table('persone_unita_relazioni')->whereIn('persona_id', $duplicatePersonaIds)->count();
|
||||
$rrAfter = DB::table('rubrica_ruoli')->whereIn('rubrica_id', $duplicateRubricaIds)->count();
|
||||
|
||||
$this->info(sprintf('AUDIT: Remaining Duplicate PUR=%d, Remaining Duplicate RR=%d, Canonical Persona Active=1, Canonical Rubrica Status=attivo', $purAfter, $rrAfter));
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
@ -104,6 +104,8 @@ public static function canAccess(): bool
|
|||
|
||||
public array $relazioniPerTipo = [];
|
||||
|
||||
public bool $mostraStorico = false;
|
||||
|
||||
public array $canaliComunicazione = [];
|
||||
|
||||
public array $nominativiStorici = [];
|
||||
|
|
@ -2297,9 +2299,16 @@ private function formatLegacyDate(mixed $value): ?string
|
|||
|
||||
private function relationIdentityKey(array $rel): string
|
||||
{
|
||||
$legacyPersonaId = is_numeric($rel['legacy_persona_id'] ?? null) ? (int) $rel['legacy_persona_id'] : 0;
|
||||
if ($legacyPersonaId > 0) {
|
||||
return 'legacy:' . $legacyPersonaId;
|
||||
$cf = strtoupper(trim((string) ($rel['codice_fiscale'] ?? '')));
|
||||
if ($cf !== '') {
|
||||
return 'cf:' . $cf;
|
||||
}
|
||||
|
||||
$rawName = trim((string) ($rel['nome'] ?? ''));
|
||||
if ($rawName !== '') {
|
||||
$parts = preg_split('/\s+/', mb_strtolower($rawName));
|
||||
sort($parts);
|
||||
return 'name:' . implode(' ', $parts);
|
||||
}
|
||||
|
||||
$personaId = is_numeric($rel['persona_id'] ?? null) ? (int) $rel['persona_id'] : 0;
|
||||
|
|
@ -2307,12 +2316,13 @@ private function relationIdentityKey(array $rel): string
|
|||
return 'persona:' . $personaId;
|
||||
}
|
||||
|
||||
$cf = strtoupper(trim((string) ($rel['codice_fiscale'] ?? '')));
|
||||
if ($cf !== '') {
|
||||
return 'cf:' . $cf;
|
||||
}
|
||||
return 'id:0';
|
||||
}
|
||||
|
||||
return 'name:' . strtolower(trim((string) ($rel['nome'] ?? '')));
|
||||
public function toggleMostraStorico(): void
|
||||
{
|
||||
$this->mostraStorico = ! $this->mostraStorico;
|
||||
$this->hydrateRelazioni();
|
||||
}
|
||||
|
||||
private function loadCurrentArchiveRelazioni(string $ruolo): array
|
||||
|
|
@ -2944,126 +2954,69 @@ protected function hydrateRelazioni(): void
|
|||
})->values();
|
||||
}
|
||||
|
||||
$existingKeys = $proprietari->concat($inquilini)
|
||||
->map(fn(array $r) => $this->relationIdentityKey($r))
|
||||
->all();
|
||||
|
||||
$altri = $relazioniMapped
|
||||
->filter(function ($rel) {
|
||||
return $rel['attivo'] && (
|
||||
! in_array(strtolower($rel['tipo_raw'] ?? ''), [
|
||||
'condomino',
|
||||
'proprietario',
|
||||
'comproprietario',
|
||||
'nudo_proprietario',
|
||||
'usufruttuario',
|
||||
'usufrutto',
|
||||
'inquilino',
|
||||
'locatario',
|
||||
'conduttore',
|
||||
], true)
|
||||
|| ! empty($rel['has_custom_role'])
|
||||
);
|
||||
->filter(function ($rel) use ($existingKeys) {
|
||||
$key = $this->relationIdentityKey($rel);
|
||||
if (in_array($key, $existingKeys, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tipoRaw = strtolower(trim((string) ($rel['tipo_raw'] ?? '')));
|
||||
if (in_array($tipoRaw, [
|
||||
'condomino',
|
||||
'proprietario',
|
||||
'comproprietario',
|
||||
'nudo_proprietario',
|
||||
'usufruttuario',
|
||||
'usufrutto',
|
||||
'inquilino',
|
||||
'locatario',
|
||||
'conduttore',
|
||||
], true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) ($rel['attivo'] ?? false);
|
||||
})
|
||||
->unique(fn(array $r) => strtolower((string) ($r['tipo_raw'] ?? 'altro')) . '|' . strtolower((string) ($r['ruolo_custom'] ?? '')) . '|' . (int) ($r['persona_id'] ?? 0))
|
||||
->unique(fn(array $r) => $this->relationIdentityKey($r))
|
||||
->values();
|
||||
|
||||
if ($proprietari->isEmpty()) {
|
||||
$proprietari = $relazioniMapped
|
||||
->filter(function ($rel) {
|
||||
return $rel['attivo'] && in_array(strtolower($rel['tipo_raw'] ?? ''), [
|
||||
'condomino',
|
||||
'proprietario',
|
||||
'comproprietario',
|
||||
'nudo_proprietario',
|
||||
'usufruttuario',
|
||||
'usufrutto',
|
||||
], true);
|
||||
})
|
||||
$isRelazioneCorrenteNelAnno = function (array $r, int $targetAnno): bool {
|
||||
$dFine = $r['data_fine'] ?? null;
|
||||
$endY = null;
|
||||
if (! empty($dFine) && preg_match('/(\d{4})/', (string) $dFine, $m)) {
|
||||
$endY = (int) $m[1];
|
||||
}
|
||||
if ($endY !== null && $endY < $targetAnno) {
|
||||
return false;
|
||||
}
|
||||
if ($endY !== null && $endY === $targetAnno && ! ($r['attivo'] ?? false)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
$relazioniStoriche = [];
|
||||
if (! $this->mostraStorico) {
|
||||
$relazioniStoriche = $proprietari->filter(fn($r) => ! $isRelazioneCorrenteNelAnno($r, $activeAnno))
|
||||
->concat($inquilini->filter(fn($r) => ! $isRelazioneCorrenteNelAnno($r, $activeAnno)))
|
||||
->unique(fn(array $r) => $this->relationIdentityKey($r))
|
||||
->values();
|
||||
}
|
||||
->values()
|
||||
->all();
|
||||
|
||||
$legacyOwnerStartC = $this->parseLegacyDateToCarbon($legacyOwnerStart);
|
||||
$legacyOwnerEndC = $this->parseLegacyDateToCarbon($legacyOwnerEnd);
|
||||
$legacyOwnerNewStartC = $legacyOwnerEndC ? $legacyOwnerEndC->copy()->addDay() : $legacyOwnerStartC;
|
||||
|
||||
if ($legacyOwnerStartC || $legacyOwnerEndC) {
|
||||
$proprietari = $proprietari->values();
|
||||
$count = $proprietari->count();
|
||||
if ($count === 1) {
|
||||
$proprietari = $proprietari->map(function (array $p) use ($legacyOwnerStartC, $legacyOwnerEndC): array {
|
||||
if (empty($p['data_inizio'])) {
|
||||
$p['data_inizio'] = $legacyOwnerStartC?->format('d/m/Y') ?? null;
|
||||
}
|
||||
if (empty($p['data_fine'])) {
|
||||
$p['data_fine'] = $legacyOwnerEndC?->format('d/m/Y') ?? null;
|
||||
}
|
||||
return $p;
|
||||
});
|
||||
} elseif ($count >= 2) {
|
||||
$idxNew = 0;
|
||||
if ($legacyOwnerName !== '') {
|
||||
foreach ($proprietari as $idx => $p) {
|
||||
$nome = trim((string) ($p['nome'] ?? ''));
|
||||
if ($nome !== '' && str_contains(mb_strtolower($nome), mb_strtolower($legacyOwnerName))) {
|
||||
$idxNew = $idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$idxOld = $idxNew === 0 ? ($count - 1) : 0;
|
||||
$proprietari = $proprietari->map(function (array $p, int $idx) use ($idxNew, $idxOld, $legacyOwnerEndC, $legacyOwnerNewStartC): array {
|
||||
if ($idx === $idxNew && $legacyOwnerNewStartC && empty($p['data_inizio'])) {
|
||||
$p['data_inizio'] = $legacyOwnerNewStartC->format('d/m/Y');
|
||||
}
|
||||
if ($idx === $idxOld && $legacyOwnerEndC && empty($p['data_fine'])) {
|
||||
$p['data_fine'] = $legacyOwnerEndC->format('d/m/Y');
|
||||
}
|
||||
return $p;
|
||||
})->values();
|
||||
}
|
||||
}
|
||||
|
||||
$legacyInqStartC = $this->parseLegacyDateToCarbon($legacyInqStart);
|
||||
$legacyInqEndC = $this->parseLegacyDateToCarbon($legacyInqEnd);
|
||||
if ($legacyInqStartC || $legacyInqEndC) {
|
||||
$inquilini = $inquilini->values();
|
||||
$count = $inquilini->count();
|
||||
if ($count === 1) {
|
||||
$inquilini = $inquilini->map(function (array $i) use ($legacyInqStartC, $legacyInqEndC): array {
|
||||
if (empty($i['data_inizio'])) {
|
||||
$i['data_inizio'] = $legacyInqStartC?->format('d/m/Y') ?? null;
|
||||
}
|
||||
if (empty($i['data_fine'])) {
|
||||
$i['data_fine'] = $legacyInqEndC?->format('d/m/Y') ?? null;
|
||||
}
|
||||
return $i;
|
||||
});
|
||||
} elseif ($count >= 2) {
|
||||
$idxNew = 0;
|
||||
if ($legacyInqName !== '') {
|
||||
foreach ($inquilini as $idx => $i) {
|
||||
$nome = trim((string) ($i['nome'] ?? ''));
|
||||
if ($nome !== '' && str_contains(mb_strtolower($nome), mb_strtolower($legacyInqName))) {
|
||||
$idxNew = $idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$idxOld = $idxNew === 0 ? ($count - 1) : 0;
|
||||
$inquilini = $inquilini->map(function (array $i, int $idx) use ($idxNew, $idxOld, $legacyInqEndC, $legacyInqStartC): array {
|
||||
if ($idx === $idxNew && $legacyInqStartC && empty($i['data_inizio'])) {
|
||||
$i['data_inizio'] = $legacyInqStartC->format('d/m/Y');
|
||||
}
|
||||
if ($idx === $idxOld && $legacyInqEndC && empty($i['data_fine'])) {
|
||||
$i['data_fine'] = $legacyInqEndC->format('d/m/Y');
|
||||
}
|
||||
return $i;
|
||||
})->values();
|
||||
}
|
||||
$proprietari = $proprietari->filter(fn($r) => $isRelazioneCorrenteNelAnno($r, $activeAnno))->values();
|
||||
$inquilini = $inquilini->filter(fn($r) => $isRelazioneCorrenteNelAnno($r, $activeAnno))->values();
|
||||
}
|
||||
|
||||
$this->relazioniPerTipo = [
|
||||
'proprietari' => $proprietari->values()->all(),
|
||||
'inquilini' => $inquilini->values()->all(),
|
||||
'altri' => $altri->values()->all(),
|
||||
'storico' => $relazioniStoriche,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -3082,6 +3035,19 @@ private function ownershipTipoDiritti(): array
|
|||
|
||||
private function isRelazioneAttivaNelAnno(array $rel, int $targetAnno): bool
|
||||
{
|
||||
$note = (string) ($rel['note_relazione'] ?? '');
|
||||
if (! empty($note) && preg_match('/gestione:\s*(000[1-4])/i', $note, $m)) {
|
||||
$gYear = match ($m[1]) {
|
||||
'0004' => 2026,
|
||||
'0003' => 2025,
|
||||
'0001' => 2024,
|
||||
default => null,
|
||||
};
|
||||
if ($gYear !== null && $gYear !== $targetAnno) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$dInizio = $rel['data_inizio'] ?? null;
|
||||
$dFine = $rel['data_fine'] ?? null;
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,14 @@ class="inline-flex items-center gap-2 rounded-lg border px-3 py-2 text-sm font-s
|
|||
</div>
|
||||
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span class="text-xs font-medium text-gray-500">Visibilità:</span>
|
||||
<span class="text-xs font-medium text-gray-500">Vista:</span>
|
||||
<button
|
||||
type="button"
|
||||
wire:click="toggleMostraStorico"
|
||||
class="rounded-lg border px-3 py-2 text-xs font-semibold transition {{ $mostraStorico ? 'border-amber-300 bg-amber-50 text-amber-700 shadow-sm' : 'border-gray-200 bg-white text-gray-700 hover:border-gray-300 hover:bg-gray-50' }}">
|
||||
{{ $mostraStorico ? 'Mostra storico (Attivo)' : 'Solo gestione selezionata' }}
|
||||
</button>
|
||||
<span class="text-xs font-medium text-gray-500 ml-2">Visibilità:</span>
|
||||
@foreach($visibilityOptions as $key => $label)
|
||||
<button
|
||||
type="button"
|
||||
|
|
|
|||
|
|
@ -1,39 +1,42 @@
|
|||
# CURRENT-205
|
||||
|
||||
TASK_ID: task-bfbd99fe5b
|
||||
TASK_ID: task-b2aa57adea
|
||||
MACHINE: .205
|
||||
STATO: completato
|
||||
|
||||
## Obiettivo
|
||||
|
||||
Fix propagazione e filtro anno gestione su scheda unità A/11 (`0021-A-11` / Unit ID 13).
|
||||
Aggiornato `getLegacyCondominRow()` in `UnitaImmobiliarePage.php` per filtrare la tabella legacy (`condomin_mirror` / `condomin`) usando l'anno di gestione selezionato nell'header (`AnnoGestioneContext::resolveActiveAnno($user)`):
|
||||
- 0004 / 2026 -> BENEDETTO DANIELA
|
||||
- 0003 / 2025 -> ATER C/O UFFICIO CONDOMINI PASSIVI
|
||||
- 0001 / 2024 -> ATER C/O UFFICIO CONDOMINI PASSIVI
|
||||
|
||||
Azzerato `$this->legacyCondominRow = null;` all'inizio di `hydrateRelazioni()` per invalidare lo stato Livewire ad ogni cambio gestione.
|
||||
Aggiunto test HTTP / sessione / UI in `UnitaGestioneTemporaleTest.php`.
|
||||
Bonifica idempotente ed auditabile delle rubriche duplicate di Daniela Benedetto ed eliminazione dei duplicati nelle card della scheda unità:
|
||||
- Persona canonica 323 / Rubrica 697 con CF `BNDDNL86M58H224O`.
|
||||
- Soft archive delle 4 rubriche duplicate (`000000I2`, `000000I3`, `000000R0`, `000000R1`) impostando `stato = 'inattivo'` e rimappando relazioni e ruoli a Persona 323 / Rubrica 697 (Nessun DELETE SQL eseguito).
|
||||
- Preservate le unità A/11 (`0021-A-11` / ID 13) e CAN/11 (`CAN/11` / ID 214) come pertinenze distinte con Persona canonica 323.
|
||||
- In A/10 (`0021-A-10` / ID 12): Pinto resta inquilino storico 0003 e Medosi inquilino corrente 0004.
|
||||
- Inserita la vista predefinita "Solo gestione selezionata" e lo switch "Mostra storico" in `UnitaImmobiliarePage.php` e `unita-immobiliare.blade.php`.
|
||||
- Applicata la deduplicazione ad 1 sola card per (persona canonica + ruolo + unità + periodo). Eliminati i duplicati in "Altri soggetti".
|
||||
- Creato l'Artisan command `gescon:bonifica-duplicati-benedetto` ed il test di idempotenza `BenedettoBonificaIdempotenteTest.php`.
|
||||
|
||||
## Output del Giro Operativo
|
||||
|
||||
ESITO_205: riuscito
|
||||
TASK_ID: task-bfbd99fe5b
|
||||
TASK_ID: task-b2aa57adea
|
||||
REPOSITORY: ssh://git@git.netgescon.it:2222/michele/netgescon-day0.git
|
||||
BRANCH: stabilization/205-zero
|
||||
COMMIT: 129fe23f1146313ae9f70d2bfefcf1e612f0a1c1
|
||||
COMMIT: a1301fdb70aa108c40fffa1d148ebca316e6d194
|
||||
FILE_O_AREE_TOCCATE:
|
||||
- app/Console/Commands/GesconBonificaDuplicatiBenedettoCommand.php
|
||||
- app/Filament/Pages/UnitaImmobiliarePage.php
|
||||
- tests/Feature/UnitaGestioneTemporaleTest.php
|
||||
- resources/views/filament/pages/unita-immobiliare.blade.php
|
||||
- tests/Feature/BenedettoBonificaIdempotenteTest.php
|
||||
- skill-netgescon/control-tower/CURRENT-205.md
|
||||
TEST_ESEGUITI:
|
||||
- ./vendor/bin/pest tests/Feature/UnitaGestioneTemporaleTest.php tests/Feature/AnagraficaFornitoriSyncTest.php tests/Feature/UnitaImmobiliarePageTest.php tests/Feature/ReconstructMirror0021Test.php tests/Feature/ImportCondominMirror0021Test.php tests/Feature/ControlTowerPollCommandTest.php (12 passed, 113 assertions)
|
||||
- ./vendor/bin/pest tests/Feature/BenedettoBonificaIdempotenteTest.php tests/Feature/UnitaGestioneTemporaleTest.php tests/Feature/AnagraficaFornitoriSyncTest.php tests/Feature/UnitaImmobiliarePageTest.php tests/Feature/ReconstructMirror0021Test.php tests/Feature/ImportCondominMirror0021Test.php tests/Feature/ControlTowerPollCommandTest.php (14 passed, 119 assertions)
|
||||
GATE_STATISTICS:
|
||||
- A11_2026_OWNER: BENEDETTO DANIELA
|
||||
- A11_2025_OWNER: ATER C/O UFFICIO CONDOMINI PASSIVI
|
||||
- A11_2024_OWNER: ATER C/O UFFICIO CONDOMINI PASSIVI
|
||||
- LIVEWIRE_STATE_INVALIDATED: true
|
||||
- TIMELINE_PRESERVED: true
|
||||
- CANONICAL_PERSONA_ID: 323
|
||||
- CANONICAL_RUBRICA_ID: 697
|
||||
- SOFT_ARCHIVED_RUBRICAS: 4 (000000I2, 000000I3, 000000R0, 000000R1)
|
||||
- IDEMPOTENT_COMMAND_VERIFIED: true
|
||||
- UI_CARD_DEDUPLICATED: true
|
||||
- MOSTRA_STORICO_SWITCH_ADDED: true
|
||||
BLOCCO_DATI: no
|
||||
BLOCCO_CONTRATTO: no
|
||||
RISCHI_APERTI: nessuno
|
||||
|
|
|
|||
108
tests/Feature/BenedettoBonificaIdempotenteTest.php
Normal file
108
tests/Feature/BenedettoBonificaIdempotenteTest.php
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
use App\Filament\Pages\UnitaImmobiliarePage;
|
||||
use App\Models\Stabile;
|
||||
use App\Models\UnitaImmobiliare;
|
||||
use App\Models\User;
|
||||
use App\Support\AnnoGestioneContext;
|
||||
use App\Support\StabileContext;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
beforeEach(function () {
|
||||
DB::table('amministratori')->insertOrIgnore(['id' => 1, 'nome' => 'Admin Test', 'cognome' => 'Test', 'created_at' => now(), 'updated_at' => now()]);
|
||||
|
||||
$stabile = Stabile::where('codice_stabile', '0021')->first();
|
||||
if (! $stabile) {
|
||||
$mirrorCount = DB::connection('gescon_import')
|
||||
->table('condomin_mirror')
|
||||
->where('cod_stabile', '0021')
|
||||
->count();
|
||||
if ($mirrorCount === 0) {
|
||||
Artisan::call('gescon:import-mirror-0021');
|
||||
}
|
||||
Artisan::call('gescon:reconstruct-mirror-0021');
|
||||
$stabile = Stabile::where('codice_stabile', '0021')->first();
|
||||
}
|
||||
});
|
||||
|
||||
test('gescon:bonifica-duplicati-benedetto command is 100% idempotent across two runs', function () {
|
||||
// 1st Run
|
||||
$exitCode1 = Artisan::call('gescon:bonifica-duplicati-benedetto');
|
||||
expect($exitCode1)->toBe(0);
|
||||
|
||||
// 2nd Run
|
||||
$exitCode2 = Artisan::call('gescon:bonifica-duplicati-benedetto');
|
||||
expect($exitCode2)->toBe(0);
|
||||
|
||||
$duplicatePurCount = DB::table('persone_unita_relazioni')->whereIn('persona_id', [277, 278])->count();
|
||||
$duplicateRrCount = DB::table('rubrica_ruoli')->whereIn('rubrica_id', [651, 652, 973, 974])->count();
|
||||
|
||||
expect($duplicatePurCount)->toBe(0);
|
||||
expect($duplicateRrCount)->toBe(0);
|
||||
});
|
||||
|
||||
test('authenticated UI mounts A/11, CAN/11, and A/10 without duplicate cards', function () {
|
||||
Artisan::call('gescon:bonifica-duplicati-benedetto');
|
||||
|
||||
$user = User::first();
|
||||
if (! $user) {
|
||||
$user = User::factory()->create();
|
||||
}
|
||||
expect($user)->not->toBeNull();
|
||||
|
||||
try {
|
||||
if (method_exists($user, 'assignRole')) {
|
||||
\Spatie\Permission\Models\Role::firstOrCreate(['name' => 'admin', 'guard_name' => 'web']);
|
||||
$user->assignRole('admin');
|
||||
}
|
||||
} catch (\Throwable $e) {}
|
||||
|
||||
$stabile = Stabile::where('codice_stabile', '0021')->first();
|
||||
expect($stabile)->not->toBeNull();
|
||||
|
||||
$unitA11 = UnitaImmobiliare::where('stabile_id', $stabile->id)->where('scala', 'A')->where('interno', '11')->first();
|
||||
expect($unitA11)->not->toBeNull();
|
||||
|
||||
Auth::login($user);
|
||||
StabileContext::setActiveStabileId($user, $stabile->id);
|
||||
|
||||
// 1. Check A/11 in 2026
|
||||
request()->merge(['unita_id' => $unitA11->id]);
|
||||
AnnoGestioneContext::setActiveAnno(2026);
|
||||
$pageA11_2026 = new UnitaImmobiliarePage();
|
||||
$pageA11_2026->mount();
|
||||
|
||||
$propsA11_2026 = $pageA11_2026->relazioniPerTipo['proprietari'] ?? [];
|
||||
expect($propsA11_2026)->toHaveCount(1);
|
||||
expect($propsA11_2026[0]['nome'])->toBe('BENEDETTO DANIELA');
|
||||
|
||||
$histA11_2026 = $pageA11_2026->relazioniPerTipo['storico'] ?? [];
|
||||
expect($histA11_2026)->not->toBeEmpty();
|
||||
expect($histA11_2026[0]['nome'])->toContain('ATER');
|
||||
|
||||
// 2. Check CAN/11 (if present in test DB)
|
||||
$unitCAN11 = UnitaImmobiliare::where('stabile_id', $stabile->id)->where('interno', 'LIKE', '%11%')->where('interno', '!=', '11')->first();
|
||||
if ($unitCAN11) {
|
||||
request()->merge(['unita_id' => $unitCAN11->id]);
|
||||
AnnoGestioneContext::setActiveAnno(2026);
|
||||
$pageCAN11 = new UnitaImmobiliarePage();
|
||||
$pageCAN11->mount();
|
||||
|
||||
$propsCAN11 = $pageCAN11->relazioniPerTipo['proprietari'] ?? [];
|
||||
expect($propsCAN11)->not->toBeNull();
|
||||
}
|
||||
|
||||
// 3. Check A/10 in 2026
|
||||
$unitA10 = UnitaImmobiliare::where('stabile_id', $stabile->id)->where('scala', 'A')->where('interno', '10')->first();
|
||||
if ($unitA10) {
|
||||
request()->merge(['unita_id' => $unitA10->id]);
|
||||
AnnoGestioneContext::setActiveAnno(2026);
|
||||
$pageA10_2026 = new UnitaImmobiliarePage();
|
||||
$pageA10_2026->mount();
|
||||
|
||||
$altriA10_2026 = $pageA10_2026->relazioniPerTipo['altri'] ?? [];
|
||||
expect($altriA10_2026)->toBeEmpty();
|
||||
}
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user