Warenwirtschaft: N-06 — Dichte-Snapshot der ml-Bestellung gilt auch im Bearbeiten

Formular, Update-Validierung und Repository nutzen bei unverändertem Rohstoff den
Snapshot als Rückfall; bei Rohstoffwechsel wird keine fremde Dichte übernommen.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-09-08 11:48:02 +00:00
parent 9acb05380a
commit 5d82875d2f
4 changed files with 73 additions and 1 deletions

View file

@ -196,3 +196,60 @@ test('F-16: wareneingang prueft „offen“ innerhalb der sperre — zweite buch
expect((float) $entry->fresh()->received_quantity)->toBe(500.0)
->and($entry->fresh()->batch_number)->toBe('F16-1');
});
test('N-06: ml-kopie ohne stammdatendichte übersteht bearbeiten, speichern und wareneingang', function () {
[$admin, $ingredient, $location, $supplier, $quality] = densSetup(0.79);
$this->actingAs($admin, 'user');
$this->post(route('admin.inventory.stock-entries.store'), [
'entry_type' => 'ingredient', 'ingredient_id' => (string) $ingredient->id, 'supplier_id' => (string) $supplier->id,
'location_id' => (string) $location->id, 'quality_id' => (string) $quality->id, 'ordered_at' => '2026-08-01',
'ordered_quantity' => '100', 'ordered_unit' => 'ml', 'price_per_kg' => '10,00',
])->assertRedirect();
$original = StockEntry::query()->latest('id')->firstOrFail();
$ingredient->forceFill(['density' => null])->save();
$this->post(route('admin.inventory.stock-entries.copy', $original))->assertRedirect();
$copy = StockEntry::query()->latest('id')->firstOrFail();
// Bearbeitungsformular: ml bleibt wählbar (Dichte-Snapshot als data-density), Menge 100,00 ml.
$this->get(route('admin.inventory.stock-entries.edit', $copy))->assertOk()
->assertSee('data-density="0.79', false)
->assertSee('value="100,00"', false);
// Unverändert speichern (wie die Kopiermeldung es verlangt).
$this->put(route('admin.inventory.stock-entries.update', $copy), [
'entry_type' => 'ingredient', 'ingredient_id' => (string) $ingredient->id, 'supplier_id' => (string) $supplier->id,
'location_id' => (string) $location->id, 'quality_id' => (string) $quality->id, 'ordered_at' => '2026-08-02',
'ordered_quantity' => '100', 'ordered_unit' => 'ml', 'price_per_kg' => '10,00',
])->assertRedirect()->assertSessionHasNoErrors();
$copy->refresh();
expect($copy->purchase_unit)->toBe('ml')
->and((float) $copy->density_used)->toBe(0.79)
->and((float) $copy->ordered_quantity)->toBe(79.0);
$this->put(route('admin.inventory.stock-entries.receive', $copy), [
'received_at' => '2026-08-05', 'received_quantity' => '100', 'batch_number' => 'N06-1', 'best_before' => '2030-12-31',
])->assertRedirect();
expect((float) $copy->fresh()->received_quantity)->toBe(79.0);
});
test('N-06: bei rohstoffwechsel wird keine fremde alte dichte übernommen', function () {
[$admin, $ingredient, $location, $supplier, $quality] = densSetup(0.79);
$other = Ingredient::query()->create(['name' => 'INCI-ohne-Dichte', 'active' => true, 'pos' => 0, 'density' => null]);
$this->actingAs($admin, 'user');
$this->post(route('admin.inventory.stock-entries.store'), [
'entry_type' => 'ingredient', 'ingredient_id' => (string) $ingredient->id, 'supplier_id' => (string) $supplier->id,
'location_id' => (string) $location->id, 'quality_id' => (string) $quality->id, 'ordered_at' => '2026-08-01',
'ordered_quantity' => '100', 'ordered_unit' => 'ml', 'price_per_kg' => '10,00',
])->assertRedirect();
$entry = StockEntry::query()->latest('id')->firstOrFail();
$this->from(route('admin.inventory.stock-entries.edit', $entry))->put(route('admin.inventory.stock-entries.update', $entry), [
'entry_type' => 'ingredient', 'ingredient_id' => (string) $other->id, 'supplier_id' => (string) $supplier->id,
'location_id' => (string) $location->id, 'quality_id' => (string) $quality->id, 'ordered_at' => '2026-08-02',
'ordered_quantity' => '100', 'ordered_unit' => 'ml', 'price_per_kg' => '10,00',
])->assertSessionHasErrors('ordered_quantity');
});