mivita/app/Console/Commands/RepairMissingInvoices.php
2026-04-10 17:15:27 +02:00

129 lines
4.3 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Models\ShoppingOrder;
use App\Repositories\InvoiceRepository;
use App\Services\BusinessPlan\SalesPointsVolume;
use App\Services\Incentive\IncentiveTracker;
use Illuminate\Console\Command;
class RepairMissingInvoices extends Command
{
protected $signature = 'repair:missing-invoices
{--fix : Tatsaechlich reparieren (ohne Flag nur Vorschau)}
{--no-mail : Keine Rechnungs-Mails versenden}
{--since=2026-02-20 : Ab welchem Datum suchen}';
protected $description = 'Repariert fehlende Rechnungen und SalesVolumes fuer bezahlte Bestellungen (Bug: addSalesPointsVolumeUser)';
public function handle(): int
{
$since = $this->option('since') ?? '2026-03-16';
$fix = $this->option('fix') ?? false;
$orders = ShoppingOrder::query()
->where('mode', 'live')
->where('paid', 0)
->where('txaction', 'paid')
->where('created_at', '>=', $since)
->whereNull('deleted_at')
->whereDoesntHave('user_invoice')
->whereDoesntHave('user_sales_volume')
// ->whereDoesntHave('shopping_payments', fn($q) => $q->where('clearingtype', 'vor'))
->orderBy('created_at')
->get();
$this->info("Betroffene Bestellungen seit {$since}: {$orders->count()}");
if ($orders->isEmpty()) {
$this->info('Keine betroffenen Bestellungen gefunden.');
return self::SUCCESS;
}
// Zusammenfassung
$total = $orders->sum('total');
$byPaymentFor = $orders->groupBy('payment_for')->map->count();
$this->table(
['payment_for', 'Anzahl'],
$byPaymentFor->map(fn ($count, $type) => [$type, $count])->values()
);
$this->info("Gesamtwert: {$total} EUR");
if (! $fix) {
$this->warn('Trockenlauf! Nutze --fix um die Reparatur durchzufuehren.');
$this->newLine();
// Erste 10 anzeigen
$this->table(
['ID', 'payment_for', 'total', 'txaction', 'created_at'],
$orders->take(100)->map(fn ($o) => [
$o->id,
$o->payment_for,
$o->total,
$o->txaction,
$o->created_at->format('Y-m-d H:i'),
])
);
if ($orders->count() > 100) {
$this->info('... und '.($orders->count() - 100).' weitere');
}
return self::SUCCESS;
}
$send_mail = ! $this->option('no-mail');
if ($send_mail) {
$this->info('Rechnungs-Mails werden versendet. Nutze --no-mail um dies zu unterdruecken.');
} else {
$this->warn('Rechnungs-Mails werden NICHT versendet.');
}
if (! $this->confirm("Wirklich {$orders->count()} Bestellungen reparieren?")) {
return self::SUCCESS;
}
$success = 0;
$errors = 0;
$bar = $this->output->createProgressBar($orders->count());
$bar->start();
foreach ($orders as $order) {
try {
// 1. SalesVolume erstellen
$user_sales_volume = SalesPointsVolume::User($order);
// 2. Rechnung erstellen (mit Mail-Versand)
$invoice_repo = new InvoiceRepository($order);
$user_invoice = $invoice_repo->create([
'invoice_send_mail' => $send_mail,
]);
// 3. SalesVolume mit Rechnung verknuepfen
$user_sales_volume->user_invoice_id = $user_invoice->id;
$user_sales_volume->save();
// 4. Incentive tracking (falls relevant)
IncentiveTracker::trackSalesVolume($user_sales_volume);
$success++;
$this->info("Order #{$order->id}: Reparatur erfolgreich");
} catch (\Throwable $e) {
$errors++;
$this->newLine();
$this->error("Order #{$order->id}: {$e->getMessage()}");
}
$bar->advance();
}
$bar->finish();
$this->newLine(2);
$this->info("Fertig: {$success} repariert, {$errors} Fehler.");
return $errors > 0 ? self::FAILURE : self::SUCCESS;
}
}