Warenwirtschaft: AP-13 API-Bestellungen — Protokoll mit SKU-Fehlermarkierung

Neuer Navigationspunkt „API-Bestellungen": jede wp/order-Übertragung wird
protokolliert (api_order_logs) — auch abgelehnte (Kunde unbekannt, Bestellung
existiert bereits, Speicherfehler). Positionen ohne Produktzuordnung
(unbekannte WP-Nummer) markieren den Eintrag rot; das Modal zeigt den Inhalt
der Übertragung je Position (SKU, Produkt, Menge, Preis, Meldung übersetzt).
Dazu SKU-Konsistenzprüfung auf der Seite: doppelte WP-Nummern aktiver Produkte
(Warnung) und aktive Produkte ohne WP-Nummer (aufklappbar). Behebt die stille
Lücke, dass „article not found" nur in der API-Antwort unterging und die
Position kommentarlos in Bestellung und Bestandsabzug fehlte (Plan §4).
ShoppingUserController per Pint formatiert.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-16 08:04:16 +00:00
parent 211aeed384
commit 71d5591e7b
8 changed files with 859 additions and 170 deletions

View file

@ -0,0 +1,65 @@
<?php
namespace App\Http\Controllers\Admin\Inventory;
use App\Http\Controllers\Controller;
use App\Models\ApiOrderLog;
use App\Models\Product;
use Illuminate\Http\Request;
/**
* AP-13: Übersicht der über die Partnercenter-API eingegangenen Bestell-Übertragungen.
* Einträge mit fehlgeschlagener Produktzuordnung (unbekannte SKU) sind markiert;
* das Modal zeigt den Inhalt der Übertragung je Position.
*/
class ApiOrderLogController extends Controller
{
private const INDEX_LIMIT = 500;
public function index(Request $request)
{
$limit = $request->query('all') ? null : self::INDEX_LIMIT;
$logs = ApiOrderLog::query()
->with(['shoppingOrder', 'shoppingUser'])
->orderByDesc('id')
->when($limit !== null, fn ($query) => $query->limit($limit))
->get();
$errorCount = ApiOrderLog::query()->where('has_errors', true)->count();
// SKU-Konsistenz (Plan §4): doppelte WP-Nummern brechen die Zuordnung,
// aktive Produkte ohne WP-Nummer können nie per API zugeordnet werden.
$duplicateNumbers = Product::query()
->where('active', true)
->whereNotNull('wp_number')
->where('wp_number', '!=', 0)
->selectRaw('wp_number, COUNT(*) as sku_count')
->groupBy('wp_number')
->havingRaw('COUNT(*) > 1')
->pluck('wp_number');
$duplicateSkuProducts = $duplicateNumbers->isEmpty()
? collect()
: Product::query()
->where('active', true)
->whereIn('wp_number', $duplicateNumbers)
->orderBy('wp_number')
->orderBy('name')
->get(['id', 'name', 'wp_number']);
$missingSkuProducts = Product::query()
->where('active', true)
->where(fn ($query) => $query->whereNull('wp_number')->orWhere('wp_number', 0))
->orderBy('name')
->get(['id', 'name']);
return view('admin.inventory.api-orders.index', [
'logs' => $logs,
'listLimit' => $limit,
'errorCount' => $errorCount,
'duplicateSkuProducts' => $duplicateSkuProducts,
'missingSkuProducts' => $missingSkuProducts,
]);
}
}