- 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>
141 lines
5.8 KiB
PHP
141 lines
5.8 KiB
PHP
<?php
|
|
|
|
namespace App\Console;
|
|
|
|
use App\Console\Commands\BusinessStore;
|
|
use App\Console\Commands\BusinessStoreOptimized;
|
|
use App\Console\Commands\CheckPaymentsAccount;
|
|
use App\Console\Commands\CheckPaymentUptime;
|
|
use App\Console\Commands\DhlUpdateTracking;
|
|
use App\Console\Commands\UserCleanUp;
|
|
use App\Console\Commands\UserMakeAboOrder;
|
|
use App\Support\OperationalAlert;
|
|
use Illuminate\Console\Scheduling\Schedule;
|
|
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
|
use Illuminate\Support\Str;
|
|
|
|
class Kernel extends ConsoleKernel
|
|
{
|
|
/**
|
|
* The Artisan commands provided by your application.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $commands = [
|
|
BusinessStore::class,
|
|
BusinessStoreOptimized::class,
|
|
CheckPaymentUptime::class,
|
|
CheckPaymentsAccount::class,
|
|
UserMakeAboOrder::class,
|
|
UserCleanUp::class,
|
|
DhlUpdateTracking::class,
|
|
];
|
|
|
|
/**
|
|
* Define the application's command schedule.
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function schedule(Schedule $schedule)
|
|
{
|
|
// Herzschlag fuer /health und den Systemstatus: bleibt er aus, laeuft der Cron nicht
|
|
$schedule->command('monitoring:heartbeat')->everyMinute()->withoutOverlapping(2);
|
|
|
|
// Uptime-Check: PAYONE-Erreichbarkeit alle 5 Minuten prüfen
|
|
$schedule->command('payment:check-uptime')
|
|
->everyFiveMinutes()
|
|
->withoutOverlapping(10)
|
|
->runInBackground();
|
|
|
|
// Job 1: Überprüft täglich um 02:00 Uhr die Zahlungskonten.
|
|
$schedule->command('payments:check-accounts')->dailyAt('02:00');
|
|
// Jobs 2, 3, 4: Die Befehle aus deinem alten Shell-Skript.
|
|
// Werden nacheinander täglich zu unterschiedlichen Zeiten ausgeführt,
|
|
// um die Serverlast zu verteilen.
|
|
$schedule->command('business:store-optimized 0 0')->dailyAt('03:00');
|
|
|
|
$schedule->command('user:cleanup')->dailyAt('03:30');
|
|
$schedule->command('user:make_abo_order')->dailyAt('04:00');
|
|
|
|
// Laufende Abos mit verstrichenem Termin melden — ohne Nachbuchung (Befund Abo 39).
|
|
$schedule->command('abo:check-overdue')->dailyAt('05:30');
|
|
|
|
// Stripe: liegengebliebene Webhook-Events nachverarbeiten (Cron-Race /
|
|
// verzögerter Stripe-Retry; Stripe CLI auf dem Test-Server retryt gar nicht).
|
|
$schedule->command('stripe:process-pending-events')
|
|
->everyTenMinutes()
|
|
->withoutOverlapping(30)
|
|
->runInBackground();
|
|
|
|
// Stripe: offene Zahlungen aktiv gegen die API abgleichen. Fängt den Fall
|
|
// ab, dass ein Webhook NIE zugestellt wurde (Endpoint down, falsches
|
|
// Konto am Listener, Stripe gibt Retries nach ~3 Tagen auf) — dann läge
|
|
// das Geld bei Stripe, während die Bestellung auf "offen" steht.
|
|
// Läuft über denselben, idempotenten Paid-Pfad wie ein echter Webhook.
|
|
$schedule->command('stripe:sync-payment-status --pending --days=3')
|
|
->hourly()
|
|
->withoutOverlapping(60)
|
|
->runInBackground();
|
|
|
|
// Abo-Einmalprodukte: Reminder-Mail vor der Ausführung (Einmalprodukte-Fenster)
|
|
$schedule->command('abo:send-execution-reminder')->dailyAt('06:00');
|
|
|
|
// Abo-Chart-Snapshots: vergangene Monate einfrieren (nach allen Abo-Jobs)
|
|
$schedule->command('abo:store-chart-snapshots')->dailyAt('04:30');
|
|
|
|
// Backoffice-Statistik-Snapshots: abgeschlossene Monate fuer VIP-Statistiken einfrieren
|
|
$schedule->command('backoffice:store-statistics-snapshots')->dailyAt('04:45');
|
|
|
|
// VP-Punkte des Sponsors: fehlende Registrierungs-Buchungen des laufenden
|
|
// Monats nachziehen (Callback-Aussetzer), vor business:store-optimized um 03:00
|
|
$schedule->command('sales:repair-sponsor-vp')->dailyAt('02:30');
|
|
|
|
// Laufstand-Drift (Ticket C2): letzte Zeile in user_sales_volumes gegen die
|
|
// Zeilensumme pruefen und abweichende User neu rechnen — vor dem
|
|
// Provisionslauf um 03:00, damit er nie mit einem verschobenen Laufstand rechnet
|
|
$schedule->command('sales:repair-running-totals')->dailyAt('02:45');
|
|
|
|
// Incentive: Punkteberechnung täglich nach business:store-optimized
|
|
$schedule->command('incentive:calculate')->dailyAt('05:00');
|
|
|
|
// Anerkennungen: abgeschlossene Monate ab dem 3. des Folgemonats einfrieren
|
|
// (idempotent; nach Provisionslauf, Repairs und Incentive)
|
|
$schedule->command('recognitions:freeze')->dailyAt('06:15');
|
|
|
|
// Cleanup old log files weekly (keeps logs for 30 days)
|
|
$schedule->command('logs:cleanup --days=30')->weekly()->sundays()->at('05:00');
|
|
|
|
// Horizon: Kennzahlen fuer das Dashboard, fehlgeschlagene Jobs nach 30 Tagen loeschen
|
|
$schedule->command('horizon:snapshot')->everyFiveMinutes();
|
|
$schedule->command('queue:prune-failed --hours=720')->dailyAt('05:15');
|
|
|
|
// DHL Tracking Update: Stündlich mit status-basierten Intervallen und Batch-API
|
|
$schedule->command('dhl:update-tracking --days=30 --send-emails')
|
|
->hourly()
|
|
->withoutOverlapping(60)
|
|
->runInBackground();
|
|
|
|
// Betriebs-Alert (Log, Mail, optional ntfy), wenn eine geplante Aufgabe fehlschlaegt
|
|
foreach ($schedule->events() as $event) {
|
|
$event->onFailure(function () use ($event): void {
|
|
$task = $event->description ?: trim(Str::after((string) $event->command, "'artisan'"));
|
|
|
|
OperationalAlert::send('Geplante Aufgabe fehlgeschlagen: '.$task, [
|
|
'exit_code' => $event->exitCode,
|
|
]);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register the commands for the application.
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function commands()
|
|
{
|
|
$this->load(__DIR__.'/Commands');
|
|
|
|
require base_path('routes/console.php');
|
|
}
|
|
}
|