Warenwirtschaft: API ordnet Variations-SKUs dem Basisprodukt zu

Shop-Variationen (z. B. „10042-1") sind dasselbe Produkt mit derselben
WP-Nummer. Bei der Bestellannahme zählt für die Zuordnung nur der Teil
vor dem ersten „-"; die Original-SKU bleibt im API-Protokoll erhalten.
Leere Basis (z. B. „-1") wird nicht zugeordnet statt auf 0 zu matchen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-21 09:25:10 +00:00
parent c171aa269a
commit 0e27478b44
2 changed files with 51 additions and 1 deletions

View file

@ -710,7 +710,14 @@ class ShoppingUserController extends Controller
$error[] = 'article parameter is missing';
} else {
$product = Product::whereWpNumber($order->article)->first();
// Variations-SKUs aus dem Shop (z. B. „10042-1") sind dasselbe Produkt:
// für die Zuordnung zählt nur der Teil vor dem ersten „-". Das Original
// bleibt in $order->article, damit das API-Protokoll die echte SKU zeigt.
$baseArticle = trim(explode('-', trim((string) $order->article), 2)[0]);
$product = $baseArticle !== ''
? Product::whereWpNumber($baseArticle)->first()
: null;
if (! $product) {
$error[] = 'article not found';
} else {

View file

@ -150,6 +150,49 @@ test('bekannte sku ohne menge wird als fehler markiert (position fehlt in der be
->and(ShoppingOrderItem::query()->where('product_id', $product->id)->count())->toBe(0);
});
test('variations-sku wird dem basisprodukt zugeordnet', function () {
// Shop-Variationen (z. B. „10042-1") sind dasselbe Produkt: für die
// Zuordnung zählt nur der Teil vor dem ersten „-".
Mail::fake();
Passport::actingAs(apilogMakeUser());
$product = apilogMakeProduct('Apilog Variante', 10042);
apilogMakeShoppingUser(4716);
$this->postJson('https://api.'.config('app.api_domain').'/wp/order', [
'wp_order_number' => 4716,
'wp_order' => [
['article' => '10042-1', 'qty' => 1, 'price' => 1990],
],
])->assertOk();
$log = ApiOrderLog::query()->sole();
expect($log->has_errors)->toBeFalse()
->and($log->payload['lines'][0]['article'])->toBe('10042-1') // Original-SKU bleibt im Protokoll
->and($log->payload['lines'][0]['product_id'])->toBe($product->id)
->and($log->payload['lines'][0]['failed'])->toBeFalse();
expect(ShoppingOrderItem::query()->where('shopping_order_id', $log->shopping_order_id)->where('product_id', $product->id)->count())->toBe(1);
});
test('sku ohne basis vor dem minus wird nicht zugeordnet', function () {
Mail::fake();
Passport::actingAs(apilogMakeUser());
apilogMakeProduct('Apilog NullNummer', 10043);
apilogMakeShoppingUser(4717);
$this->postJson('https://api.'.config('app.api_domain').'/wp/order', [
'wp_order_number' => 4717,
'wp_order' => [
['article' => '-1', 'qty' => 1, 'price' => 1990],
],
])->assertOk();
$log = ApiOrderLog::query()->sole();
expect($log->has_errors)->toBeTrue()
->and($log->payload['lines'][0]['failed'])->toBeTrue()
->and($log->payload['lines'][0]['messages'])->toContain('article not found');
});
test('fehlerfreie uebertragung wird als ok protokolliert', function () {
Mail::fake();
Passport::actingAs(apilogMakeUser());