Kundenentscheid 26.08.: „Waldbröl" gibt es nicht mehr, alles wird Köln; die Standort-Funktion bleibt für künftige Standorte. - LocationController::destroy überschrieben: ein belegter Lagerort lässt sich löschen, indem seine Buchungen (Wareneingänge, Produktionen, Ausschuss) transaktional auf einen Ziel-Lagerort übernommen werden. Ohne Ziel-Lagerort bleibt die Sperre bestehen; unbelegte Orte werden direkt gelöscht. - Lagerort-Liste: Ziel-Auswahl („→ Köln" vorbelegt) im Lösch-Formular. - Wareneingang: Köln als Standard-Lagerort vorbelegt (wie in der Produktion). Außerdem AP-49-Folgeanpassung: Test-Helper hängt die Kategorie „Kosmetikrohstoffe" an, damit Lieferanten im gefilterten INCI-Formular erscheinen; Lagerort-Sperr-Test prüft die neue Meldung. Suite 322 grün. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
67 lines
2.7 KiB
PHP
67 lines
2.7 KiB
PHP
<?php
|
|
|
|
use App\Models\Ingredient;
|
|
use App\Models\Location;
|
|
use App\Models\StockEntry;
|
|
use App\Models\Supplier;
|
|
use App\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
uses(TestCase::class, RefreshDatabase::class);
|
|
|
|
function locDelAdmin(): User
|
|
{
|
|
$user = User::query()->create(['email' => uniqid('loc_', true).'@test.example', 'password' => bcrypt('password')]);
|
|
$user->forceFill(['admin' => 8, 'confirmed' => true, 'active' => true, 'wizard' => 100, 'blocked' => false])->save();
|
|
|
|
return $user->fresh();
|
|
}
|
|
|
|
function locDelStock(Location $location): StockEntry
|
|
{
|
|
$ing = Ingredient::query()->create(['name' => 'INCI-'.uniqid('', true), 'active' => true, 'pos' => 0]);
|
|
$supplier = Supplier::factory()->create();
|
|
|
|
return StockEntry::query()->create([
|
|
'entry_type' => 'ingredient', 'ingredient_id' => $ing->id, 'supplier_id' => $supplier->id,
|
|
'location_id' => $location->id, 'unit' => 'gram', 'ordered_by' => 1, 'ordered_at' => '2026-01-01',
|
|
'ordered_quantity' => 500, 'status' => 'received', 'received_at' => '2026-01-10',
|
|
'received_quantity' => 500, 'batch_number' => 'LOC-1', 'best_before' => '2030-12-31',
|
|
]);
|
|
}
|
|
|
|
test('AP-50: belegter lagerort wird gelöscht und buchungen auf ziel-lagerort übernommen', function () {
|
|
$this->actingAs(locDelAdmin(), 'user');
|
|
$waldbroel = Location::query()->create(['name' => 'Waldbröl', 'active' => true]);
|
|
$koeln = Location::query()->create(['name' => 'Köln', 'active' => true]);
|
|
$entry = locDelStock($waldbroel);
|
|
|
|
$this->delete(route('admin.inventory.locations.destroy', $waldbroel), ['reassign_to' => $koeln->id])
|
|
->assertRedirect(route('admin.inventory.locations.index'));
|
|
|
|
expect(Location::query()->find($waldbroel->id))->toBeNull()
|
|
->and($entry->fresh()->location_id)->toBe($koeln->id);
|
|
});
|
|
|
|
test('AP-50: belegter lagerort ohne ziel-lagerort bleibt gesperrt', function () {
|
|
$this->actingAs(locDelAdmin(), 'user');
|
|
$waldbroel = Location::query()->create(['name' => 'Waldbröl', 'active' => true]);
|
|
Location::query()->create(['name' => 'Köln', 'active' => true]);
|
|
locDelStock($waldbroel);
|
|
|
|
$this->delete(route('admin.inventory.locations.destroy', $waldbroel))
|
|
->assertRedirect(route('admin.inventory.locations.index'));
|
|
|
|
expect(Location::query()->find($waldbroel->id))->not->toBeNull();
|
|
});
|
|
|
|
test('AP-50: unbelegter lagerort wird direkt gelöscht', function () {
|
|
$this->actingAs(locDelAdmin(), 'user');
|
|
$leer = Location::query()->create(['name' => 'Leerstand', 'active' => true]);
|
|
|
|
$this->delete(route('admin.inventory.locations.destroy', $leer))
|
|
->assertRedirect(route('admin.inventory.locations.index'));
|
|
|
|
expect(Location::query()->find($leer->id))->toBeNull();
|
|
});
|