++ add creation S-13_I
This commit is contained in:
@@ -11,11 +11,18 @@ use App\Models\Proclamatore;
|
||||
use App\Models\Territorio;
|
||||
use App\Models\Zona;
|
||||
use App\Models\Tipologia;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
|
||||
class Registro extends Component
|
||||
{
|
||||
use WithPagination;
|
||||
|
||||
/** Blocchi-territorio per foglio, come nel modulo cartaceo S-13. */
|
||||
private const S13_RIGHE_PER_PAGINA = 21;
|
||||
|
||||
/** Gruppi "Assegnato a" disponibili su ogni riga del modulo S-13. */
|
||||
private const S13_ASSEGNAZIONI_PER_RIGA = 4;
|
||||
|
||||
public string $search = '';
|
||||
public string $filtroAnno = '';
|
||||
public string $filtroZona = '';
|
||||
@@ -167,6 +174,156 @@ class Registro extends Component
|
||||
$this->showDeleteConfirm = false;
|
||||
}
|
||||
|
||||
// ─── Modulo S-13 ────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Modulo ufficiale S-13-I ("Registrazione delle assegnazioni del
|
||||
* territorio") compilato con le assegnazioni dell'anno di servizio
|
||||
* selezionato nei filtri.
|
||||
*
|
||||
* Solo amministratore, come il resto del CRUD di questa pagina: il modulo
|
||||
* espone in un unico file l'anagrafica completa di chi ha avuto quale
|
||||
* territorio, dati personali che il ruolo assegnatario non deve poter
|
||||
* esportare in blocco.
|
||||
*/
|
||||
public function downloadS13()
|
||||
{
|
||||
abort_if(!auth()->user()->can('settings.manage'), 403);
|
||||
|
||||
// Il modulo è per definizione relativo a un singolo anno di servizio:
|
||||
// con "Tutti gli anni" selezionato si ripiega sull'anno corrente.
|
||||
$anno = $this->filtroAnno
|
||||
? AnnoTeocratico::find($this->filtroAnno)
|
||||
: null;
|
||||
$anno ??= AnnoTeocratico::corrente();
|
||||
|
||||
$pdf = Pdf::loadView('pdf.registro-s13', [
|
||||
'annoLabel' => $anno->label,
|
||||
'pagine' => $this->impaginaS13($this->righeS13($anno)),
|
||||
])->setPaper('a4', 'portrait');
|
||||
|
||||
return response()->streamDownload(
|
||||
fn () => print($pdf->output()),
|
||||
'S-13-registro-assegnazioni-' . $anno->label . '.pdf'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Impagina le righe in fogli da 21 blocchi, completando l'ultimo con
|
||||
* blocchi vuoti: il foglio stampato resta identico al modulo cartaceo e le
|
||||
* righe libere restano disponibili per la compilazione a mano.
|
||||
*
|
||||
* Senza righe da stampare si restituisce comunque un foglio vuoto, così il
|
||||
* modulo scaricato è un S-13 in bianco anziché un PDF senza pagine.
|
||||
*
|
||||
* @param \Illuminate\Support\Collection<int, array> $righe
|
||||
* @return \Illuminate\Support\Collection<int, \Illuminate\Support\Collection<int, array>>
|
||||
*/
|
||||
private function impaginaS13(\Illuminate\Support\Collection $righe): \Illuminate\Support\Collection
|
||||
{
|
||||
$vuota = [
|
||||
'numero' => '',
|
||||
'rientro_precedente' => '',
|
||||
'assegnazioni' => $this->completaCelleS13([]),
|
||||
];
|
||||
|
||||
$pagine = $righe->isEmpty()
|
||||
? collect([collect()])
|
||||
: $righe->chunk(self::S13_RIGHE_PER_PAGINA)->map->values()->values();
|
||||
|
||||
return $pagine->map(fn ($pagina) => collect(
|
||||
array_pad($pagina->all(), self::S13_RIGHE_PER_PAGINA, $vuota)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Righe del modulo: un blocco per ogni territorio attivo con almeno
|
||||
* un'assegnazione (chiusa o in corso) nell'anno indicato, in ordine di
|
||||
* numero crescente.
|
||||
*
|
||||
* @return \Illuminate\Support\Collection<int, array>
|
||||
*/
|
||||
private function righeS13(AnnoTeocratico $anno): \Illuminate\Support\Collection
|
||||
{
|
||||
// territorio() è definita withTrashed(), quindi la condizione sui
|
||||
// cestinati va scritta a mano: senza, i territori eliminati
|
||||
// rientrerebbero nel modulo.
|
||||
$assegnazioni = Assegnazione::with(['proclamatore', 'territorio'])
|
||||
->where('anno_teocratico_id', $anno->id)
|
||||
->whereHas('territorio', fn ($q) => $q
|
||||
->where('attivo', true)
|
||||
->whereNull('territori.deleted_at'))
|
||||
->orderBy('assigned_at')
|
||||
->orderBy('id')
|
||||
->get()
|
||||
->groupBy('territorio_id');
|
||||
|
||||
$rientriPrecedenti = $this->ultimiRientriPrimaDi(
|
||||
$assegnazioni->keys()->all(),
|
||||
$anno
|
||||
);
|
||||
|
||||
return $assegnazioni
|
||||
->map(function ($gruppo, $territorioId) use ($rientriPrecedenti) {
|
||||
// Se un territorio è girato più di quattro volte nell'anno il
|
||||
// modulo non ha spazio per tutte: si stampano le ultime
|
||||
// quattro, mantenendo l'ordine cronologico da sinistra.
|
||||
$ultime = $gruppo->slice(-self::S13_ASSEGNAZIONI_PER_RIGA)->values();
|
||||
|
||||
$celle = $ultime->map(fn (Assegnazione $a) => [
|
||||
'nome' => $a->proclamatore?->nome_completo ?? '',
|
||||
'assegnato_il' => $a->assigned_at?->format('d/m/Y') ?? '',
|
||||
'restituito_il' => $a->returned_at?->format('d/m/Y') ?? '',
|
||||
])->all();
|
||||
|
||||
$rientro = $rientriPrecedenti->get($territorioId);
|
||||
|
||||
return [
|
||||
'numero' => $gruppo->first()->territorio?->numero ?? '',
|
||||
'rientro_precedente' => $rientro ? \Carbon\Carbon::parse($rientro)->format('d/m/Y') : '',
|
||||
'assegnazioni' => $this->completaCelleS13($celle),
|
||||
];
|
||||
})
|
||||
->sort(fn (array $a, array $b) => strnatcasecmp((string) $a['numero'], (string) $b['numero']))
|
||||
->values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ultima data di rientro di ogni territorio *precedente* all'inizio
|
||||
* dell'anno di servizio: è il dato che la colonna "Restituito l'ultima
|
||||
* volta il" del modulo chiede di riportare quando si apre un foglio nuovo.
|
||||
*
|
||||
* @param array<int, int> $territorioIds
|
||||
* @return \Illuminate\Support\Collection<int, string>
|
||||
*/
|
||||
private function ultimiRientriPrimaDi(array $territorioIds, AnnoTeocratico $anno): \Illuminate\Support\Collection
|
||||
{
|
||||
if ($territorioIds === []) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
return Assegnazione::whereIn('territorio_id', $territorioIds)
|
||||
->whereNotNull('returned_at')
|
||||
->whereDate('returned_at', '<', $anno->start_date)
|
||||
->groupBy('territorio_id')
|
||||
->selectRaw('territorio_id, MAX(returned_at) as ultimo_rientro')
|
||||
->pluck('ultimo_rientro', 'territorio_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Porta le celle a quattro riempiendo con voci vuote: le colonne
|
||||
* inutilizzate restano stampate e a disposizione della compilazione a mano.
|
||||
*
|
||||
* @param array<int, array> $celle
|
||||
* @return array<int, array>
|
||||
*/
|
||||
private function completaCelleS13(array $celle): array
|
||||
{
|
||||
$vuota = ['nome' => '', 'assegnato_il' => '', 'restituito_il' => ''];
|
||||
|
||||
return array_pad($celle, self::S13_ASSEGNAZIONI_PER_RIGA, $vuota);
|
||||
}
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
if ($this->filtroAnno === '') {
|
||||
|
||||
Reference in New Issue
Block a user