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>
103 lines
3.6 KiB
PHP
103 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
|
|
/**
|
|
* AP-13: Protokolleintrag einer Bestell-Übertragung über die Partnercenter-API (wp/order).
|
|
*
|
|
* payload['lines'] enthält je Position: article (WP-SKU), qty, price (Cent),
|
|
* product_id/product_name (Zuordnung im Partnercenter, null = nicht zugeordnet),
|
|
* messages (API-Rohmeldungen) und failed (Position wurde nicht übernommen).
|
|
*/
|
|
class ApiOrderLog extends Model
|
|
{
|
|
protected $fillable = [
|
|
'shopping_order_id',
|
|
'shopping_user_id',
|
|
'wp_order_number',
|
|
'endpoint',
|
|
'payload',
|
|
'has_errors',
|
|
'error_summary',
|
|
];
|
|
|
|
protected $casts = [
|
|
'payload' => 'array',
|
|
'has_errors' => 'bool',
|
|
];
|
|
|
|
public function shoppingOrder(): BelongsTo
|
|
{
|
|
return $this->belongsTo(ShoppingOrder::class, 'shopping_order_id');
|
|
}
|
|
|
|
public function shoppingUser(): BelongsTo
|
|
{
|
|
return $this->belongsTo(ShoppingUser::class, 'shopping_user_id');
|
|
}
|
|
|
|
/**
|
|
* Fehlgeschlagene Übertragung ohne verwertbare Positionen (Kunde unbekannt,
|
|
* Bestellung existiert bereits, Speicherfehler).
|
|
*
|
|
* @param mixed $rawOrder eingehender wp_order-Payload (String oder Array)
|
|
*/
|
|
public static function recordFailure(mixed $wpOrderNumber, ?ShoppingUser $shoppingUser, mixed $rawOrder, string $summary): self
|
|
{
|
|
return self::query()->create([
|
|
'shopping_user_id' => $shoppingUser?->id,
|
|
'wp_order_number' => is_numeric($wpOrderNumber) ? (int) $wpOrderNumber : null,
|
|
'endpoint' => 'order',
|
|
'payload' => ['raw' => is_string($rawOrder) ? $rawOrder : json_decode(json_encode($rawOrder), true)],
|
|
'has_errors' => true,
|
|
'error_summary' => $summary,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Erfolgreich verarbeitete Übertragung: Positionen inkl. Zuordnungsergebnis protokollieren.
|
|
* Positionen ohne Produktzuordnung (SKU unbekannt / Parameter fehlen) markieren den Eintrag.
|
|
*
|
|
* @param array<int, object> $lines Zeilen aus prepareOrder() (article/qty/price/message)
|
|
*/
|
|
public static function recordTransfer(mixed $wpOrderNumber, ShoppingUser $shoppingUser, ?ShoppingOrder $shoppingOrder, array $lines): self
|
|
{
|
|
$payloadLines = [];
|
|
$failedCount = 0;
|
|
|
|
foreach ($lines as $line) {
|
|
$line = (object) $line;
|
|
$article = $line->article ?? null;
|
|
$product = $article !== null ? Product::whereWpNumber($article)->first() : null;
|
|
$failed = $product === null;
|
|
if ($failed) {
|
|
$failedCount++;
|
|
}
|
|
|
|
$payloadLines[] = [
|
|
'article' => $article,
|
|
'qty' => $line->qty ?? null,
|
|
'price' => $line->price ?? null,
|
|
'product_id' => $product?->id,
|
|
'product_name' => $product?->name,
|
|
'messages' => array_values((array) ($line->message ?? [])),
|
|
'failed' => $failed,
|
|
];
|
|
}
|
|
|
|
return self::query()->create([
|
|
'shopping_order_id' => $shoppingOrder?->id,
|
|
'shopping_user_id' => $shoppingUser->id,
|
|
'wp_order_number' => is_numeric($wpOrderNumber) ? (int) $wpOrderNumber : null,
|
|
'endpoint' => 'order',
|
|
'payload' => ['lines' => $payloadLines],
|
|
'has_errors' => $failedCount > 0,
|
|
'error_summary' => $failedCount > 0
|
|
? __(':failed von :total Positionen ohne Produktzuordnung', ['failed' => $failedCount, 'total' => count($payloadLines)])
|
|
: null,
|
|
]);
|
|
}
|
|
}
|