Warenwirtschaft: OPT-1 Quick Wins + Entwicklungsplan V6.0

- N+1-Fix Ausschussliste: user.account eager laden (StockDisposalController@index)
- Composite-Indizes stock_entries(entry_type,status,ingredient_id/packaging_item_id) für InventoryService-Aggregationen
- Ungenutzten Eager-Load producedByUser aus ProductionRepository::listForIndex entfernt
- ExampleTest auf assertRedirect umgestellt (Suite 100% grün: 155 Tests)
- Query-Count-Regressionstest für die Ausschussliste
- Plan V6.0 (Code-Verifikation, OPT-Block, geklärte Kundenfragen)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-06 09:54:24 +00:00
parent e53201f229
commit 65f949dd7a
6 changed files with 240 additions and 5 deletions

View file

@ -1,11 +1,13 @@
<?php
use App\Models\Country;
use App\Models\Ingredient;
use App\Models\Location;
use App\Models\PackagingItem;
use App\Models\StockDisposal;
use App\Models\StockEntry;
use App\Models\Supplier;
use App\Models\UserAccount;
use App\Services\InventoryService;
use App\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
@ -207,6 +209,50 @@ test('liste und formular rendern', function () {
->assertSee('AP12-Render');
});
test('ausschuss-liste laedt benutzerkonten ohne n+1', function () {
$admin = ap12MakeUser(7);
$location = Location::factory()->create();
$ing = ap12MakeIngredient('AP12-N1');
$country = Country::query()->firstOrCreate(
['code' => 'DE'],
['phone' => '00', 'en' => 'Germany', 'de' => 'Deutschland', 'es' => 'Germany', 'fr' => 'Germany', 'it' => 'Germany', 'ru' => 'Germany', 'active' => true]
);
$makeDisposal = function () use ($ing, $location, $country) {
$account = UserAccount::query()->create(['first_name' => 'Vera', 'last_name' => 'Sucher', 'country_id' => $country->id]);
$user = ap12MakeUser(1);
$user->forceFill(['account_id' => $account->id])->save();
StockDisposal::query()->create([
'disposal_type' => 'ingredient', 'ingredient_id' => $ing->id, 'location_id' => $location->id,
'quantity' => 10, 'unit' => 'gram', 'reason' => 'Bruch / Beschädigung',
'disposed_at' => '2026-03-01', 'user_id' => $user->id,
]);
};
$this->actingAs($admin, 'user');
$countQueries = function (): int {
DB::flushQueryLog();
DB::enableQueryLog();
$this->get(route('admin.inventory.stock-disposals.index'))->assertSuccessful();
$count = count(DB::getQueryLog());
DB::disableQueryLog();
return $count;
};
$makeDisposal();
$this->get(route('admin.inventory.stock-disposals.index'))->assertSuccessful(); // Warm-up
$baseline = $countQueries();
foreach (range(1, 5) as $i) {
$makeDisposal();
}
expect($countQueries())->toBeLessThanOrEqual($baseline);
});
test('chargen-endpoint liefert eingegangene chargen', function () {
$user = ap12MakeUser(7);
$location = Location::factory()->create();