Die orange Ampel bei abgeschlossenen Bestellungen ist KEIN ERP-Fehler: der
Endpoint /api/wp/status liefert für versendete Bestellungen bereits sent/close
(Live-DB: 111× shipped=2, 1× shipped=3). Ursache liegt shopseitig (Cron/Auth) —
wird per SSH geprüft. Unabhängig davon die latenten Mapping-Lücken geschlossen:
ERP (ShoppingOrder::$apiShippedTypes):
- Status 5 (Wartestellung) fehlte und lieferte den Default 'free' (im Shop gar
kein Licht). Jetzt 5 => 'process' (Shop-Ampel orange = in Bearbeitung).
Connector (partnercenter-api, Teil von v1.6.0 — noch nicht ausgerollt):
- admin/post-list.php: Ampel-Switch deckt jetzt 'pick_up' (Abholung ⇒ grün) und
'cancel' (storniert ⇒ neue rote Kugel) ab; vorher fielen beide auf ⚠️.
- woocommerce/order-status.php: 'pick_up' und 'cancel' gelten jetzt als
Endzustände und fallen aus der stündlichen Nachfrage-Liste
(_partnercenter_api_unclear_order_ids) — vorher wurden 12 stornierte
Bestellungen dauerhaft weiter gepollt.
Test: AP-38-Mapping prüft alle shipped-Werte (kein stiller 'free'-Fallback mehr).
Suite 338 grün.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
161 lines
4.9 KiB
PHP
161 lines
4.9 KiB
PHP
<?php
|
|
|
|
use App\Models\Country;
|
|
use App\Models\Shipping;
|
|
use App\Models\ShippingCountry;
|
|
use App\Models\ShoppingOrder;
|
|
use App\Models\ShoppingUser;
|
|
use App\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
uses(TestCase::class, RefreshDatabase::class);
|
|
|
|
function salesMakeAdmin(int $adminLevel = 7): User
|
|
{
|
|
$user = User::query()->create([
|
|
'email' => uniqid('sales_', true).'@test.example',
|
|
'password' => bcrypt('password'),
|
|
]);
|
|
$user->forceFill([
|
|
'admin' => $adminLevel,
|
|
'confirmed' => true,
|
|
'active' => true,
|
|
'wizard' => 100,
|
|
'blocked' => false,
|
|
])->save();
|
|
|
|
return $user->fresh();
|
|
}
|
|
|
|
function salesMakeOrder(array $overrides = []): ShoppingOrder
|
|
{
|
|
$country = Country::query()->forceCreate([
|
|
'code' => 'DE',
|
|
'en' => 'Germany',
|
|
'de' => 'Deutschland',
|
|
'es' => 'Alemania',
|
|
'fr' => 'Allemagne',
|
|
'it' => 'Germania',
|
|
'ru' => 'Germanija',
|
|
]);
|
|
$shipping = Shipping::query()->forceCreate(['name' => 'Standard']);
|
|
$shippingCountry = ShippingCountry::query()->forceCreate([
|
|
'shipping_id' => $shipping->id,
|
|
'country_id' => $country->id,
|
|
]);
|
|
$shoppingUser = ShoppingUser::query()->forceCreate([
|
|
'billing_country_id' => $country->id,
|
|
'shipping_country_id' => $country->id,
|
|
'billing_firstname' => 'Test',
|
|
'billing_lastname' => 'Kunde',
|
|
]);
|
|
|
|
return ShoppingOrder::query()->forceCreate(array_merge([
|
|
'shopping_user_id' => $shoppingUser->id,
|
|
'auth_user_id' => salesMakeAdmin(0)->id,
|
|
'country_id' => $shippingCountry->id,
|
|
'shipped' => 0,
|
|
], $overrides));
|
|
}
|
|
|
|
test('versand-status versendet setzt shipped_at', function () {
|
|
$admin = salesMakeAdmin();
|
|
$order = salesMakeOrder();
|
|
|
|
$response = $this->actingAs($admin)->post(route('admin_sales_store'), [
|
|
'id' => $order->id,
|
|
'action' => 'store_shipped',
|
|
'shipped' => 2,
|
|
]);
|
|
|
|
$response->assertRedirect();
|
|
$order->refresh();
|
|
expect($order->shipped)->toBe(2)
|
|
->and($order->shipped_at)->not->toBeNull();
|
|
});
|
|
|
|
test('zuruecksetzen auf offen entfernt shipped_at', function () {
|
|
$admin = salesMakeAdmin();
|
|
$order = salesMakeOrder(['shipped' => 2, 'shipped_at' => now()]);
|
|
|
|
$this->actingAs($admin)->post(route('admin_sales_store'), [
|
|
'id' => $order->id,
|
|
'action' => 'store_shipped',
|
|
'shipped' => 0,
|
|
])->assertRedirect();
|
|
|
|
$order->refresh();
|
|
expect($order->shipped)->toBe(0)
|
|
->and($order->shipped_at)->toBeNull();
|
|
});
|
|
|
|
test('ungueltiger versand-status wird abgelehnt', function () {
|
|
$admin = salesMakeAdmin();
|
|
$order = salesMakeOrder();
|
|
|
|
$response = $this->actingAs($admin)->from(route('admin_sales'))->post(route('admin_sales_store'), [
|
|
'id' => $order->id,
|
|
'action' => 'store_shipped',
|
|
'shipped' => 99,
|
|
]);
|
|
|
|
$response->assertSessionHasErrors('shipped');
|
|
expect($order->fresh()->shipped)->toBe(0);
|
|
});
|
|
|
|
test('unbekannte action wird abgelehnt', function () {
|
|
$admin = salesMakeAdmin();
|
|
$order = salesMakeOrder();
|
|
|
|
$this->actingAs($admin)->post(route('admin_sales_store'), [
|
|
'id' => $order->id,
|
|
'action' => 'delete_everything',
|
|
])->assertSessionHasErrors('action');
|
|
});
|
|
|
|
test('nicht-admin wird umgeleitet und aendert nichts', function () {
|
|
$user = salesMakeAdmin(1);
|
|
$order = salesMakeOrder();
|
|
|
|
$this->actingAs($user)->post(route('admin_sales_store'), [
|
|
'id' => $order->id,
|
|
'action' => 'store_shipped',
|
|
'shipped' => 2,
|
|
])->assertRedirect('/home');
|
|
|
|
expect($order->fresh()->shipped)->toBe(0);
|
|
});
|
|
|
|
test('fehlende id ergibt 404', function () {
|
|
$admin = salesMakeAdmin();
|
|
|
|
$this->actingAs($admin)->post(route('admin_sales_store'), [
|
|
'action' => 'store_shipped',
|
|
'shipped' => 2,
|
|
])->assertNotFound();
|
|
});
|
|
|
|
test('AP-38: API-Status-Mapping deckt alle shipped-Werte ab (Wartestellung nicht mehr free)', function () {
|
|
// Der Shop pollt getAPIShippedType(); versendete Bestellungen müssen grün-fähig
|
|
// sein (sent/close), Wartestellung darf NICHT 'free' (im Shop kein Licht) liefern.
|
|
$expected = [
|
|
0 => 'open', // orange
|
|
1 => 'process', // orange
|
|
2 => 'sent', // grün
|
|
3 => 'close', // grün
|
|
4 => 'pick_up', // grün (Abholung)
|
|
5 => 'process', // AP-38: Wartestellung ⇒ orange statt 'free'
|
|
10 => 'cancel', // rot
|
|
];
|
|
|
|
foreach ($expected as $shipped => $apiStatus) {
|
|
$order = salesMakeOrder(['shipped' => $shipped]);
|
|
expect($order->getAPIShippedType())->toBe($apiStatus);
|
|
}
|
|
|
|
// Jeder gepflegte Versandstatus hat auch ein API-Mapping (kein stiller 'free'-Fallback).
|
|
foreach (array_keys(ShoppingOrder::$shippedTypes) as $shipped) {
|
|
expect(ShoppingOrder::$apiShippedTypes)->toHaveKey($shipped);
|
|
}
|
|
});
|