++ fix statistiche campagne

- Dettaglio campagna: mostra tutti i territori conteggiati (stessa base
  della percentuale), non solo quelli assegnati dopo l'inizio.
- Rientro: se più campagne corrispondono propone la più recente invece
  della prima creata; testo del banner chiarito.
- Dettaglio campagna: nuova sezione "In corso" con i territori fuori
  durante la campagna e non ancora rientrati.
- README: regola di conteggio documentata.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Francesco Picone
2026-10-19 10:18:09 +02:00
parent fc8623f7db
commit 6ef301cb14
6 changed files with 83 additions and 7 deletions

View File

@@ -28,6 +28,18 @@ class CampagnaShow extends Component
->orderBy('returned_at')
->get();
// Open assignments can still be counted for this campaign only while
// no later campaign has started: on return the most recent one is
// offered (see Assegnazione::campagnaApplicabile()).
$superata = Campagna::where('start_date', '>', $this->campagna->start_date)
->where('start_date', '<=', now()->toDateString())
->exists();
$inCorso = $superata ? null : $this->campagna->assegnazioniInCorso()
->with(['territorio', 'proclamatore'])
->orderBy('assigned_at')
->get();
// All assignments that were active during this campaign range
$assegnateNelRange = Assegnazione::where('assigned_at', '<=', $this->campagna->end_date)
->where(function ($q) {
@@ -38,6 +50,7 @@ class CampagnaShow extends Component
return view('livewire.campagne.campagna-show', [
'conteggiate' => $conteggiate,
'inCorso' => $inCorso,
'assegnateNelRange' => $assegnateNelRange,
]);
}

View File

@@ -241,10 +241,18 @@ class Assegnazione extends Model
*/
public function campagnaApplicabile(?\Carbon\Carbon $returnDate = null): ?Campagna
{
$returnDate = $returnDate ?? now();
$returnDate = ($returnDate ?? now())->toDateString();
$assignedAt = $this->assigned_at->toDateString();
// Il territorio può essere conteggiato per una campagna se è rimasto
// in mano al proclamatore almeno in parte del periodo: assegnato
// durante la campagna, rientrato durante la campagna, oppure fuori per
// tutta la sua durata (assegnato prima e rientrato dopo). Se sia stato
// davvero percorso lo decide l'operatore con la spunta.
// Se più campagne corrispondono si propone la più recente.
return Campagna::where('start_date', '<=', $returnDate)
->where('end_date', '>=', $this->assigned_at)
->where('end_date', '>=', $assignedAt)
->orderByDesc('start_date')
->first();
}
}

View File

@@ -65,6 +65,16 @@ class Campagna extends Model
->where('counted_in_campaign', true);
}
/**
* Assignments still open that were out during this campaign (assigned
* on or before its end): they can be counted for it when they come back.
*/
public function assegnazioniInCorso()
{
return Assegnazione::whereNull('returned_at')
->where('assigned_at', '<=', $this->end_date);
}
/**
* All assignments with assigned_at in this campaign's range.
*/