334 lines
12 KiB
PHP
334 lines
12 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Livewire\Registro;
|
|
use App\Models\AnnoTeocratico;
|
|
use App\Models\Assegnazione;
|
|
use App\Models\Proclamatore;
|
|
use App\Models\Territorio;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Collection;
|
|
use ReflectionMethod;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* Modulo S-13-I: il ciclo da quattro gruppi "Assegnato a" e la colonna
|
|
* "Restituito l'ultima volta il".
|
|
*
|
|
* E' la regola meno intuitiva del Registro — la quinta assegnazione non si
|
|
* aggiunge alle quattro precedenti, le sostituisce — e finisce su un modulo che
|
|
* viene firmato e archiviato: se sbaglia, sbaglia su carta.
|
|
*
|
|
* righeS13() e' privata di proposito (non e' un'azione Livewire); qui la si
|
|
* chiama in riflessione perche' e' il calcolo, non il PDF, quello da proteggere.
|
|
*/
|
|
class RegistroS13Test extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private User $utente;
|
|
private Proclamatore $proclamatore;
|
|
private AnnoTeocratico $anno;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$this->utente = User::create([
|
|
'name' => 'Amministratore',
|
|
'email' => 'admin@example.test',
|
|
'password' => 'password',
|
|
]);
|
|
|
|
$this->proclamatore = Proclamatore::create([
|
|
'nome' => 'Mario',
|
|
'cognome' => 'Rossi',
|
|
'attivo' => true,
|
|
]);
|
|
|
|
$this->anno = AnnoTeocratico::create([
|
|
'label' => '2025-2026',
|
|
'start_date' => '2025-09-01',
|
|
'end_date' => '2026-08-31',
|
|
]);
|
|
}
|
|
|
|
// ─── Il primo ciclo ─────────────────────────────────────────
|
|
|
|
public function test_una_sola_assegnazione_riempie_la_prima_colonna_e_lascia_le_altre_in_bianco(): void
|
|
{
|
|
$territorio = $this->territorio('1');
|
|
$this->assegna($territorio, '2025-09-10', '2025-10-15');
|
|
|
|
$riga = $this->righe()->sole();
|
|
|
|
$this->assertSame('1', $riga['numero']);
|
|
$this->assertSame('', $riga['riporto']);
|
|
$this->assertCount(4, $riga['assegnazioni']);
|
|
$this->assertSame(
|
|
['nome' => 'Rossi Mario', 'assegnato_il' => '10/09/2025', 'restituito_il' => '15/10/2025'],
|
|
$riga['assegnazioni'][0]
|
|
);
|
|
|
|
// Le colonne libere restano stampate: sul modulo cartaceo si compilano
|
|
// a mano.
|
|
foreach ([1, 2, 3] as $indice) {
|
|
$this->assertSame(
|
|
['nome' => '', 'assegnato_il' => '', 'restituito_il' => ''],
|
|
$riga['assegnazioni'][$indice]
|
|
);
|
|
}
|
|
}
|
|
|
|
public function test_un_assegnazione_ancora_aperta_ha_la_data_di_rientro_vuota(): void
|
|
{
|
|
$territorio = $this->territorio('1');
|
|
$this->assegna($territorio, '2025-09-10');
|
|
|
|
$riga = $this->righe()->sole();
|
|
|
|
$this->assertSame('10/09/2025', $riga['assegnazioni'][0]['assegnato_il']);
|
|
$this->assertSame('', $riga['assegnazioni'][0]['restituito_il']);
|
|
}
|
|
|
|
public function test_tre_assegnazioni_occupano_le_prime_tre_colonne(): void
|
|
{
|
|
$territorio = $this->territorio('1');
|
|
$this->assegna($territorio, '2025-09-01', '2025-09-20');
|
|
$this->assegna($territorio, '2025-10-01', '2025-10-20');
|
|
$this->assegna($territorio, '2025-11-01', '2025-11-20');
|
|
|
|
$riga = $this->righe()->sole();
|
|
|
|
$this->assertSame(
|
|
['01/09/2025', '01/10/2025', '01/11/2025', ''],
|
|
array_column($riga['assegnazioni'], 'assegnato_il')
|
|
);
|
|
$this->assertSame('', $riga['riporto']);
|
|
}
|
|
|
|
public function test_quattro_assegnazioni_riempiono_la_riga_senza_riporto(): void
|
|
{
|
|
$territorio = $this->territorio('1');
|
|
$this->assegna($territorio, '2025-09-01', '2025-09-20');
|
|
$this->assegna($territorio, '2025-10-01', '2025-10-20');
|
|
$this->assegna($territorio, '2025-11-01', '2025-11-20');
|
|
$this->assegna($territorio, '2025-12-01', '2025-12-20');
|
|
|
|
$riga = $this->righe()->sole();
|
|
|
|
$this->assertSame(
|
|
['01/09/2025', '01/10/2025', '01/11/2025', '01/12/2025'],
|
|
array_column($riga['assegnazioni'], 'assegnato_il')
|
|
);
|
|
|
|
// Finche' il primo ciclo non e' esaurito non c'e' niente da riportare.
|
|
$this->assertSame('', $riga['riporto']);
|
|
}
|
|
|
|
// ─── Il ciclo che ricomincia ────────────────────────────────
|
|
|
|
/**
|
|
* Il caso che da' il nome alla regola: riempito il quarto gruppo si
|
|
* ricomincia da capo, come sul modulo cartaceo si aprirebbe una riga nuova.
|
|
* Le prime quattro assegnazioni escono dal modulo e restano solo nel
|
|
* riporto.
|
|
*/
|
|
public function test_la_quinta_assegnazione_apre_un_ciclo_nuovo_e_lascia_il_riporto(): void
|
|
{
|
|
$territorio = $this->territorio('1');
|
|
$this->assegna($territorio, '2025-09-01', '2025-09-20');
|
|
$this->assegna($territorio, '2025-10-01', '2025-10-20');
|
|
$this->assegna($territorio, '2025-11-01', '2025-11-20');
|
|
$this->assegna($territorio, '2025-12-01', '2025-12-24');
|
|
$this->assegna($territorio, '2026-01-05', '2026-01-25');
|
|
|
|
$riga = $this->righe()->sole();
|
|
|
|
$this->assertSame(
|
|
['05/01/2026', '', '', ''],
|
|
array_column($riga['assegnazioni'], 'assegnato_il')
|
|
);
|
|
|
|
// La colonna riporta la data di rientro della quarta, cioe' quella che
|
|
// chiudeva il giro precedente — senza il nome di chi lo aveva.
|
|
$this->assertSame('24/12/2025', $riga['riporto']);
|
|
}
|
|
|
|
public function test_otto_assegnazioni_mostrano_il_secondo_ciclo_per_intero(): void
|
|
{
|
|
$territorio = $this->territorio('1');
|
|
$date = [
|
|
['2025-09-01', '2025-09-20'],
|
|
['2025-10-01', '2025-10-20'],
|
|
['2025-11-01', '2025-11-20'],
|
|
['2025-12-01', '2025-12-24'],
|
|
['2026-01-05', '2026-01-25'],
|
|
['2026-02-05', '2026-02-25'],
|
|
['2026-03-05', '2026-03-25'],
|
|
['2026-04-05', '2026-04-25'],
|
|
];
|
|
foreach ($date as [$da, $a]) {
|
|
$this->assegna($territorio, $da, $a);
|
|
}
|
|
|
|
$riga = $this->righe()->sole();
|
|
|
|
$this->assertSame(
|
|
['05/01/2026', '05/02/2026', '05/03/2026', '05/04/2026'],
|
|
array_column($riga['assegnazioni'], 'assegnato_il')
|
|
);
|
|
$this->assertSame('24/12/2025', $riga['riporto']);
|
|
}
|
|
|
|
public function test_alla_nona_assegnazione_il_riporto_e_quello_dell_ottava(): void
|
|
{
|
|
$territorio = $this->territorio('1');
|
|
$date = [
|
|
['2025-09-01', '2025-09-20'],
|
|
['2025-10-01', '2025-10-20'],
|
|
['2025-11-01', '2025-11-20'],
|
|
['2025-12-01', '2025-12-24'],
|
|
['2026-01-05', '2026-01-25'],
|
|
['2026-02-05', '2026-02-25'],
|
|
['2026-03-05', '2026-03-25'],
|
|
['2026-04-05', '2026-04-28'],
|
|
['2026-05-05', null],
|
|
];
|
|
foreach ($date as [$da, $a]) {
|
|
$this->assegna($territorio, $da, $a);
|
|
}
|
|
|
|
$riga = $this->righe()->sole();
|
|
|
|
$this->assertSame(
|
|
['05/05/2026', '', '', ''],
|
|
array_column($riga['assegnazioni'], 'assegnato_il')
|
|
);
|
|
$this->assertSame('28/04/2026', $riga['riporto']);
|
|
}
|
|
|
|
/**
|
|
* Il riporto legge la data di rientro dell'ultima assegnazione del giro
|
|
* precedente: se quella e' ancora aperta la colonna resta vuota invece di
|
|
* inventarsi una data.
|
|
*/
|
|
public function test_il_riporto_resta_vuoto_se_l_ultima_del_giro_precedente_non_e_rientrata(): void
|
|
{
|
|
$territorio = $this->territorio('1');
|
|
$this->assegna($territorio, '2025-09-01', '2025-09-20');
|
|
$this->assegna($territorio, '2025-10-01', '2025-10-20');
|
|
$this->assegna($territorio, '2025-11-01', '2025-11-20');
|
|
$this->assegna($territorio, '2025-12-01', null);
|
|
$this->assegna($territorio, '2026-01-05', '2026-01-25');
|
|
|
|
$riga = $this->righe()->sole();
|
|
|
|
$this->assertSame('05/01/2026', $riga['assegnazioni'][0]['assegnato_il']);
|
|
$this->assertSame('', $riga['riporto']);
|
|
}
|
|
|
|
// ─── Cosa entra nel modulo ──────────────────────────────────
|
|
|
|
public function test_i_territori_disattivati_restano_fuori_dal_modulo(): void
|
|
{
|
|
$attivo = $this->territorio('1');
|
|
$disattivato = $this->territorio('2', attivo: false);
|
|
|
|
$this->assegna($attivo, '2025-09-01');
|
|
$this->assegna($disattivato, '2025-09-01');
|
|
|
|
$this->assertSame(['1'], $this->righe()->pluck('numero')->all());
|
|
}
|
|
|
|
public function test_i_territori_nel_cestino_restano_fuori_dal_modulo(): void
|
|
{
|
|
$vivo = $this->territorio('1');
|
|
$cestinato = $this->territorio('2');
|
|
|
|
$this->assegna($vivo, '2025-09-01');
|
|
$this->assegna($cestinato, '2025-09-01');
|
|
$cestinato->delete();
|
|
|
|
$this->assertSame(['1'], $this->righe()->pluck('numero')->all());
|
|
}
|
|
|
|
public function test_le_assegnazioni_di_un_altro_anno_di_servizio_non_compaiono(): void
|
|
{
|
|
$altroAnno = AnnoTeocratico::create([
|
|
'label' => '2024-2025',
|
|
'start_date' => '2024-09-01',
|
|
'end_date' => '2025-08-31',
|
|
]);
|
|
|
|
$territorio = $this->territorio('1');
|
|
$this->assegna($territorio, '2025-09-01', '2025-09-20');
|
|
$this->assegna($territorio, '2025-01-10', '2025-02-10', $altroAnno);
|
|
|
|
$riga = $this->righe()->sole();
|
|
|
|
$this->assertSame(
|
|
['01/09/2025', '', '', ''],
|
|
array_column($riga['assegnazioni'], 'assegnato_il')
|
|
);
|
|
}
|
|
|
|
public function test_un_territorio_senza_assegnazioni_nell_anno_non_produce_una_riga(): void
|
|
{
|
|
$this->territorio('1');
|
|
|
|
$this->assertTrue($this->righe()->isEmpty());
|
|
}
|
|
|
|
/**
|
|
* I numeri di territorio sono stringhe ("1", "1 A", "10"): l'ordinamento e'
|
|
* naturale, non alfabetico, altrimenti il 10 finirebbe fra l'1 e il 2.
|
|
*/
|
|
public function test_le_righe_sono_in_ordine_naturale_di_numero(): void
|
|
{
|
|
foreach (['10', '2', '1 A', '1'] as $numero) {
|
|
$this->assegna($this->territorio($numero), '2025-09-01');
|
|
}
|
|
|
|
$this->assertSame(['1', '1 A', '2', '10'], $this->righe()->pluck('numero')->all());
|
|
}
|
|
|
|
// ─── helper ─────────────────────────────────────────────────
|
|
|
|
private function territorio(string $numero, bool $attivo = true): Territorio
|
|
{
|
|
return Territorio::create([
|
|
'numero' => $numero,
|
|
'attivo' => $attivo,
|
|
]);
|
|
}
|
|
|
|
private function assegna(
|
|
Territorio $territorio,
|
|
string $assegnatoIl,
|
|
?string $rientratoIl = null,
|
|
?AnnoTeocratico $anno = null
|
|
): Assegnazione {
|
|
return Assegnazione::create([
|
|
'territorio_id' => $territorio->id,
|
|
'proclamatore_id' => $this->proclamatore->id,
|
|
'anno_teocratico_id' => ($anno ?? $this->anno)->id,
|
|
'assigned_at' => $assegnatoIl,
|
|
'returned_at' => $rientratoIl,
|
|
'created_by' => $this->utente->id,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @return Collection<int, array>
|
|
*/
|
|
private function righe(?AnnoTeocratico $anno = null): Collection
|
|
{
|
|
$metodo = new ReflectionMethod(Registro::class, 'righeS13');
|
|
|
|
return $metodo->invoke(new Registro(), $anno ?? $this->anno);
|
|
}
|
|
}
|