Warenwirtschaft: AP-32-Brückenlösung — DHL-Label aus WooCommerce übernehmen
Bestell-Übertragung (wp/order) akzeptiert wp_label_url + wp_tracking_number: Label-PDF wird als lokale Kopie im privaten Storage gespeichert (Shop-URL ist öffentlich erratbar; Kopie überlebt Löschung im Shop), Sendungsnummer landet in shopping_orders.tracking. Neuer Endpoint wp/label zum Nachreichen (Connector-Hook pr_save_dhl_label_tracking), wp/status liefert die Sendungsnummer an den Shop zurück. Abwicklungs-Board + Bestell-Details zeigen Label-Download (copyreader-Dokumentroute type=label, Fallback Shop-Link) und Sendungsnummer. Download-Fehler blockieren die Übertragung nie. Doku: Connector-Update-Anleitung (dev/product management), Hinweise, Testleitfaden §11, Plan-Protokoll. pint.json schließt dev/ (Fremdcode) aus. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
a1f94ea427
commit
0eed974576
13 changed files with 611 additions and 25 deletions
269
tests/Feature/WpLabelTransferTest.php
Normal file
269
tests/Feature/WpLabelTransferTest.php
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Country;
|
||||
use App\Models\Product;
|
||||
use App\Models\Shipping;
|
||||
use App\Models\ShippingCountry;
|
||||
use App\Models\ShoppingOrder;
|
||||
use App\Models\ShoppingUser;
|
||||
use App\Models\UserAccount;
|
||||
use App\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Laravel\Passport\Passport;
|
||||
use Tests\TestCase;
|
||||
|
||||
uses(TestCase::class, RefreshDatabase::class);
|
||||
|
||||
function wplabelCountry(): Country
|
||||
{
|
||||
return Country::query()->where('code', 'DE')->first() ?? Country::query()->forceCreate([
|
||||
'code' => 'DE',
|
||||
'en' => 'Germany',
|
||||
'de' => 'Deutschland',
|
||||
'es' => 'Alemania',
|
||||
'fr' => 'Allemagne',
|
||||
'it' => 'Germania',
|
||||
'ru' => 'Germanija',
|
||||
]);
|
||||
}
|
||||
|
||||
function wplabelMakeUser(int $adminLevel = 7): User
|
||||
{
|
||||
$user = User::query()->create([
|
||||
'email' => uniqid('wplabel_', true).'@test.example',
|
||||
'password' => bcrypt('password'),
|
||||
]);
|
||||
$account = UserAccount::query()->create([
|
||||
'm_first_name' => 'Label',
|
||||
'm_last_name' => 'Partner',
|
||||
'country_id' => wplabelCountry()->id,
|
||||
]);
|
||||
$user->forceFill([
|
||||
'admin' => $adminLevel,
|
||||
'confirmed' => true,
|
||||
'active' => true,
|
||||
'wizard' => 100,
|
||||
'blocked' => false,
|
||||
'account_id' => $account->id,
|
||||
])->save();
|
||||
|
||||
return $user->fresh();
|
||||
}
|
||||
|
||||
function wplabelMakeShoppingUser(int $wpOrderNumber): ShoppingUser
|
||||
{
|
||||
$country = wplabelCountry();
|
||||
$shipping = Shipping::query()->forceCreate(['name' => 'Standard']);
|
||||
ShippingCountry::query()->forceCreate([
|
||||
'shipping_id' => $shipping->id,
|
||||
'country_id' => $country->id,
|
||||
]);
|
||||
|
||||
return ShoppingUser::query()->forceCreate([
|
||||
'billing_country_id' => $country->id,
|
||||
'shipping_country_id' => $country->id,
|
||||
'billing_firstname' => 'Label',
|
||||
'billing_lastname' => 'Kunde',
|
||||
'wp_order_number' => $wpOrderNumber,
|
||||
'member_id' => wplabelMakeUser(0)->id,
|
||||
'auth_user_id' => wplabelMakeUser(0)->id,
|
||||
]);
|
||||
}
|
||||
|
||||
function wplabelMakeProduct(int $wpNumber): Product
|
||||
{
|
||||
return Product::query()->create([
|
||||
'name' => 'Label Creme '.$wpNumber,
|
||||
'title' => 'Label Creme '.$wpNumber,
|
||||
'active' => true,
|
||||
'is_set' => false,
|
||||
'wp_number' => $wpNumber,
|
||||
'price' => '19,90',
|
||||
'tax' => '19',
|
||||
'weight' => 100,
|
||||
]);
|
||||
}
|
||||
|
||||
function wplabelTransfer(int $wpOrderNumber, array $extra = [])
|
||||
{
|
||||
return test()->postJson('https://api.'.config('app.api_domain').'/wp/order', array_merge([
|
||||
'wp_order_number' => $wpOrderNumber,
|
||||
'wp_order' => [['article' => 100, 'qty' => 1, 'price' => 1990]],
|
||||
], $extra));
|
||||
}
|
||||
|
||||
test('uebertragung mit label-url speichert pdf-kopie und sendungsnummer', function () {
|
||||
Mail::fake();
|
||||
Storage::fake('local');
|
||||
Http::fake(['*' => Http::response('%PDF-1.4 label-inhalt', 200)]);
|
||||
Passport::actingAs(wplabelMakeUser());
|
||||
wplabelMakeProduct(100);
|
||||
wplabelMakeShoppingUser(5711);
|
||||
|
||||
$response = wplabelTransfer(5711, [
|
||||
'wp_label_url' => 'https://shop.example/wp-content/uploads/woocommerce_dhl_label/dhl-label-5711.pdf',
|
||||
'wp_tracking_number' => '00340434161094000001',
|
||||
]);
|
||||
|
||||
$response->assertOk()
|
||||
->assertJsonPath('success', true)
|
||||
->assertJsonPath('data.wp_label_stored', true)
|
||||
->assertJsonPath('data.wp_tracking_number', '00340434161094000001');
|
||||
|
||||
$order = ShoppingOrder::query()->sole();
|
||||
expect($order->tracking)->toBe('00340434161094000001')
|
||||
->and($order->wp_label_url)->toContain('dhl-label-5711.pdf')
|
||||
->and($order->wp_label_path)->toBe('wp-labels/label-'.$order->id.'.pdf');
|
||||
Storage::disk('local')->assertExists($order->wp_label_path);
|
||||
});
|
||||
|
||||
test('fehlgeschlagener label-download blockiert die uebertragung nicht', function () {
|
||||
Mail::fake();
|
||||
Storage::fake('local');
|
||||
Http::fake(['*' => Http::response('Serverfehler', 500)]);
|
||||
Passport::actingAs(wplabelMakeUser());
|
||||
wplabelMakeProduct(100);
|
||||
wplabelMakeShoppingUser(5712);
|
||||
|
||||
wplabelTransfer(5712, [
|
||||
'wp_label_url' => 'https://shop.example/label.pdf',
|
||||
'wp_tracking_number' => '00340434161094000002',
|
||||
])->assertOk()->assertJsonPath('data.wp_label_stored', false);
|
||||
|
||||
$order = ShoppingOrder::query()->sole();
|
||||
expect($order->wp_label_path)->toBeNull()
|
||||
->and($order->wp_label_url)->toBe('https://shop.example/label.pdf')
|
||||
->and($order->tracking)->toBe('00340434161094000002');
|
||||
});
|
||||
|
||||
test('antwort ohne pdf-inhalt wird nicht als label gespeichert', function () {
|
||||
Mail::fake();
|
||||
Storage::fake('local');
|
||||
Http::fake(['*' => Http::response('<html>Login</html>', 200)]);
|
||||
Passport::actingAs(wplabelMakeUser());
|
||||
wplabelMakeProduct(100);
|
||||
wplabelMakeShoppingUser(5713);
|
||||
|
||||
wplabelTransfer(5713, ['wp_label_url' => 'https://shop.example/label.pdf'])
|
||||
->assertOk()->assertJsonPath('data.wp_label_stored', false);
|
||||
|
||||
expect(ShoppingOrder::query()->sole()->wp_label_path)->toBeNull();
|
||||
});
|
||||
|
||||
test('mehrere sendungsnummern werden zusammengefasst', function () {
|
||||
Mail::fake();
|
||||
Storage::fake('local');
|
||||
Passport::actingAs(wplabelMakeUser());
|
||||
wplabelMakeProduct(100);
|
||||
wplabelMakeShoppingUser(5714);
|
||||
|
||||
wplabelTransfer(5714, ['wp_tracking_number' => ['00340001', '00340002']])->assertOk();
|
||||
|
||||
expect(ShoppingOrder::query()->sole()->tracking)->toBe('00340001, 00340002');
|
||||
});
|
||||
|
||||
test('label kann per wp label nachgereicht werden', function () {
|
||||
Mail::fake();
|
||||
Storage::fake('local');
|
||||
Http::fake(['*' => Http::response('%PDF-1.4 nachgereicht', 200)]);
|
||||
Passport::actingAs(wplabelMakeUser());
|
||||
wplabelMakeProduct(100);
|
||||
wplabelMakeShoppingUser(5715);
|
||||
|
||||
wplabelTransfer(5715)->assertOk();
|
||||
$order = ShoppingOrder::query()->sole();
|
||||
expect($order->wp_label_path)->toBeNull();
|
||||
|
||||
test()->postJson('https://api.'.config('app.api_domain').'/wp/label', [
|
||||
'wp_order_number' => 5715,
|
||||
'wp_label_url' => 'https://shop.example/label-5715.pdf',
|
||||
'wp_tracking_number' => '00340434161094000005',
|
||||
])->assertOk()->assertJsonPath('data.wp_label_stored', true);
|
||||
|
||||
$order->refresh();
|
||||
expect($order->wp_label_path)->toBe('wp-labels/label-'.$order->id.'.pdf')
|
||||
->and($order->tracking)->toBe('00340434161094000005');
|
||||
Storage::disk('local')->assertExists($order->wp_label_path);
|
||||
});
|
||||
|
||||
test('wp label mit unbekannter bestellnummer wird abgelehnt', function () {
|
||||
Passport::actingAs(wplabelMakeUser());
|
||||
|
||||
test()->postJson('https://api.'.config('app.api_domain').'/wp/label', [
|
||||
'wp_order_number' => 99999,
|
||||
'wp_label_url' => 'https://shop.example/label.pdf',
|
||||
])->assertStatus(400);
|
||||
});
|
||||
|
||||
test('status-poll liefert die sendungsnummer zurueck', function () {
|
||||
Mail::fake();
|
||||
Storage::fake('local');
|
||||
Passport::actingAs(wplabelMakeUser());
|
||||
wplabelMakeProduct(100);
|
||||
wplabelMakeShoppingUser(5716);
|
||||
|
||||
wplabelTransfer(5716, ['wp_tracking_number' => '00340434161094000006'])->assertOk();
|
||||
|
||||
test()->postJson('https://api.'.config('app.api_domain').'/wp/status', [
|
||||
'wp_order_numbers' => [5716],
|
||||
])->assertOk()->assertJsonPath('data.0.tracking_number', '00340434161094000006');
|
||||
});
|
||||
|
||||
test('abwicklungs-board zeigt label-download und sendungsnummer', function () {
|
||||
Storage::fake('local');
|
||||
$shoppingUser = wplabelMakeShoppingUser(5717);
|
||||
$order = ShoppingOrder::query()->forceCreate([
|
||||
'shopping_user_id' => $shoppingUser->id,
|
||||
'auth_user_id' => $shoppingUser->auth_user_id,
|
||||
'country_id' => ShippingCountry::query()->first()->id,
|
||||
'shipped' => 0,
|
||||
'txaction' => 'extern',
|
||||
'paid' => true,
|
||||
'wp_label_path' => 'wp-labels/label-1.pdf',
|
||||
'tracking' => '00340434161094000007',
|
||||
]);
|
||||
|
||||
$this->actingAs(wplabelMakeUser(1))
|
||||
->get(route('admin.inventory.orders.index'))
|
||||
->assertOk()
|
||||
->assertSee(route('admin.inventory.orders.document', [$order->id, 'label']), false)
|
||||
->assertSee('00340434161094000007');
|
||||
});
|
||||
|
||||
test('label-download liefert die lokale pdf-kopie aus', function () {
|
||||
Storage::fake('local');
|
||||
$shoppingUser = wplabelMakeShoppingUser(5718);
|
||||
$order = ShoppingOrder::query()->forceCreate([
|
||||
'shopping_user_id' => $shoppingUser->id,
|
||||
'auth_user_id' => $shoppingUser->auth_user_id,
|
||||
'country_id' => ShippingCountry::query()->first()->id,
|
||||
'shipped' => 0,
|
||||
'txaction' => 'extern',
|
||||
'wp_label_path' => 'wp-labels/label-test.pdf',
|
||||
]);
|
||||
Storage::disk('local')->put('wp-labels/label-test.pdf', '%PDF-1.4 test');
|
||||
|
||||
$this->actingAs(wplabelMakeUser(1))
|
||||
->get(route('admin.inventory.orders.document', [$order->id, 'label']))
|
||||
->assertOk()
|
||||
->assertHeader('Content-Type', 'application/pdf');
|
||||
});
|
||||
|
||||
test('label-download ohne gespeichertes label liefert 404', function () {
|
||||
Storage::fake('local');
|
||||
$shoppingUser = wplabelMakeShoppingUser(5719);
|
||||
$order = ShoppingOrder::query()->forceCreate([
|
||||
'shopping_user_id' => $shoppingUser->id,
|
||||
'auth_user_id' => $shoppingUser->auth_user_id,
|
||||
'country_id' => ShippingCountry::query()->first()->id,
|
||||
'shipped' => 0,
|
||||
'txaction' => 'extern',
|
||||
]);
|
||||
|
||||
$this->actingAs(wplabelMakeUser(1))
|
||||
->get(route('admin.inventory.orders.document', [$order->id, 'label']))
|
||||
->assertNotFound();
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue