mivita/app/Console/Commands/RecognitionsFreeze.php
Kevin Adametz 7bc551ca1f Anerkennungen: firmenweite Monats-Ranglisten im Salescenter
- Neue Seite Anerkennungen (/user/recognitions, Menue unter News Archiv) fuer
  alle Berater mit aktivem Konto: oben die Anerkennungen des Vormonats in den
  fuenf Kategorien der Monatsmail, Filter zurueck bis Januar 2026; darunter
  Live-Ranglisten (Top 10 je Kategorie) des laufenden Monats, 15 Min. Cache.
- Kategorien: Top-Recruiter (ab 2 Neupartnern), neue Kunden-Abos,
  Kundenabo-Punkte, Kunden-Abos gesamt, Gesamtpunkte (1.000-Punkte-Shop,
  mit Platz 4). Regeln wie TopResultsService/VIP-Statistik, nur firmenweit.
- Firmenkonto (6) und Grosskundin (3) nie aufgefuehrt:
  config mivita.recognition_excluded_user_ids.
- Abgeschlossene Monate sind bis zum 3. des Folgemonats vorlaeufig und werden
  dann eingefroren: neue Tabelle recognition_snapshots, Command
  recognitions:freeze (taeglich 06:15, idempotent, holt offene Monate nach).
- September-Anerkennungen firmenweit geprueft und korrigiert.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 13:13:22 +00:00

72 lines
2.3 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Services\Team\RecognitionService;
use Illuminate\Console\Command;
class RecognitionsFreeze extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'recognitions:freeze
{--month= : Nur diesen Monat einfrieren (mit --year)}
{--year= : Nur dieses Jahr einfrieren (mit --month)}
{--force : Bereits eingefrorene Monate neu berechnen}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Friert die Anerkennungen abgeschlossener Monate ein (ab dem 3. des Folgemonats)';
/**
* Ohne Optionen werden alle noch offenen Monate seit dem ersten
* Anerkennungsmonat nachgezogen — der tägliche Lauf holt damit auch einen
* verpassten Stichtag nach. Ein neu gebauter Snapshot rechnet mit dem Stand
* des Ausführungstags; `--force` deshalb nur bewusst einsetzen.
*/
public function handle(RecognitionService $recognitions): int
{
$months = $this->monthsToFreeze();
$force = (bool) $this->option('force');
$stored = 0;
$skipped = 0;
foreach ($months as ['month' => $month, 'year' => $year]) {
if (! RecognitionService::isFreezable($month, $year)) {
$this->line(sprintf('%02d/%d: noch nicht festschreibbar (ab %s)', $month, $year, RecognitionService::freezeDate($month, $year)->format('d.m.Y')));
$skipped++;
continue;
}
if ($recognitions->freeze($month, $year, $force)) {
$this->info(sprintf('%02d/%d: eingefroren', $month, $year));
$stored++;
} else {
$skipped++;
}
}
$this->info("Fertig. Eingefroren: {$stored}, uebersprungen: {$skipped}");
return self::SUCCESS;
}
/**
* @return array<int, array{month: int, year: int}>
*/
private function monthsToFreeze(): array
{
if ($this->option('month') && $this->option('year')) {
return [['month' => max(1, min(12, (int) $this->option('month'))), 'year' => (int) $this->option('year')]];
}
return RecognitionService::closedMonths();
}
}