mivita/app/Console/Commands/ReportDecimalPointsDiff.php
Kevin a21bebc932 Punkte: Dezimalpunkte in Einmalprodukten, Homeparty und Shop-API nicht mehr abschneiden
Produkte mit 7,5 Punkten wurden an drei Stellen zu ganzen Zahlen:
user_abo_one_time_items (PHP-Cast int, 7,5 -> 7), homeparty_user_order_items
(MySQL rundete auf 8) und shopping_collect_orders (Summe der Shop-API).
Die Migration zieht die drei Spalten auf DECIMAL(10,2) nach (Nachtrag zu
2026_01_22), Cast und Abo-Snapshot rechnen mit float.

points:report-decimal-diff wertet die Differenzen je Berater und Monat aus
(nur lesend), points:repair-decimal korrigiert den laufenden Monat und
zieht die Monatssummen nach.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 15:42:27 +00:00

119 lines
4.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Console\Commands;
use App\Services\DecimalPointsDiffReportService;
use Illuminate\Console\Command;
/**
* Read-only Auswertung der Punkte-Differenzen aus dem Dezimal-Punkte-Fehler,
* je Berater und Provisionsmonat. Grundlage fuer Gutschrift-Entscheidungen.
*
* Schreibt nichts. Hintergrund siehe {@see DecimalPointsDiffReportService}.
*/
class ReportDecimalPointsDiff extends Command
{
protected $signature = 'points:report-decimal-diff
{--from= : Startmonat YYYY-MM (Standard: alles)}
{--to= : Endmonat YYYY-MM (Standard: alles)}
{--csv= : Pfad fuer CSV-Export je Berater/Monat}
{--details : Einzelzeilen je Berater ausgeben}';
protected $description = 'Punkte-Differenzen aus dem Dezimal-Punkte-Fehler je Berater und Monat auswerten (read-only)';
public function handle(DecimalPointsDiffReportService $service): int
{
$from = $this->option('from') ?: null;
$to = $this->option('to') ?: null;
$this->info('Punkte-Differenzen'.($from || $to ? " ({$from} bis {$to})" : ' (gesamter Zeitraum)'));
$this->line('Vorzeichen: + = Berater bekam ZU WENIG (Gutschrift), − = ZU VIEL');
$this->newLine();
$report = $service->report($from, $to);
if ($report['rows'] === []) {
$this->info('Keine Differenzen gefunden.');
return self::SUCCESS;
}
if ($this->option('details')) {
$this->info('Je Berater und Monat:');
$this->table(
['Monat', 'Berater', 'Abo-Addon', 'Sammelbest.', 'Homeparty', 'Summe'],
array_map(fn (array $row) => [
sprintf('%02d/%d', $row['month'], $row['year']),
mb_strimwidth($row['consultant'], 0, 38, '…'),
$this->fmt($row['addon']),
$this->fmt($row['collect']),
$this->fmt($row['homeparty']),
$this->fmt($row['delta']),
], $report['rows'])
);
$this->newLine();
}
$this->info('Je Monat:');
$this->table(
['Monat', 'Berater', 'Abo-Addon', 'Sammelbest.', 'Homeparty', 'Summe'],
array_map(fn (array $row) => [
sprintf('%02d/%d', $row['month'], $row['year']),
$row['users'],
$this->fmt($row['addon']),
$this->fmt($row['collect']),
$this->fmt($row['homeparty']),
$this->fmt($row['delta']),
], $report['by_month'])
);
$totals = $report['totals'];
$this->newLine();
$this->info('Gesamt:');
$this->line(' Abo-Einmalartikel (zu wenig): '.$this->fmt($totals['addon']));
$this->line(' Sammelbestellungen (zu viel): '.$this->fmt($totals['collect']));
$this->line(' Homeparty (zu viel, Obergrenze): '.$this->fmt($totals['homeparty']));
$this->line(' ── Netto: '.$this->fmt($totals['delta']));
$this->newLine();
$this->line(' Gutschriften an Berater: '.$this->fmt($report['credits_owed']));
$this->line(' Zu viel gebucht: '.$this->fmt($report['overbooked']));
$this->line(' Betroffene Berater: '.$totals['users']);
if ($csv = $this->option('csv')) {
$this->writeCsv($csv, $report['rows']);
$this->newLine();
$this->info("CSV geschrieben: {$csv}");
}
return self::SUCCESS;
}
private function fmt(float $value): string
{
return ($value > 0 ? '+' : '').number_format($value, 2, ',', '.');
}
/**
* @param list<array<string, mixed>> $rows
*/
private function writeCsv(string $path, array $rows): void
{
$handle = fopen($path, 'w');
fputcsv($handle, ['Jahr', 'Monat', 'UserId', 'Berater', 'AboAddon', 'Sammelbestellung', 'Homeparty', 'Summe'], ';');
foreach ($rows as $row) {
fputcsv($handle, [
$row['year'],
sprintf('%02d', $row['month']),
$row['user_id'],
$row['consultant'],
number_format((float) $row['addon'], 2, ',', ''),
number_format((float) $row['collect'], 2, ',', ''),
number_format((float) $row['homeparty'], 2, ',', ''),
number_format((float) $row['delta'], 2, ',', ''),
], ';');
}
fclose($handle);
}
}