gruene-seele/tests/Feature/ProductFillWeightTest.php
Kevin Adametz 2796b1103e Warenwirtschaft: F-08 — Füllgewicht mit Nachkommastellen
fill_weight decimal(10,3) + float-Cast; deutsche Eingabe normalisiert,
positiv validiert, Fehler im Formular sichtbar. Tests für F-07/F-08.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 10:59:48 +00:00

74 lines
3.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
use App\Models\Location;
use App\Models\PackagingItem;
use App\Models\PackagingMaterial;
use App\Models\Product;
use App\Models\Supplier;
use App\Services\ProductionService;
use App\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
uses(TestCase::class, RefreshDatabase::class);
/**
* Prüfung 08.09.2026 F-08: Füllgewicht mit Nachkommastellen (Dezimalspalte, deutsche Eingabe, Validierung).
*/
function fwUser(): User
{
$user = User::query()->create(['email' => uniqid('fw_', true).'@test.example', 'password' => bcrypt('password')]);
$user->forceFill(['admin' => 7, 'confirmed' => true, 'active' => true, 'wizard' => 100, 'blocked' => false])->save();
return $user->fresh();
}
test('F-08: füllgewicht 39,5 wird mit nachkommastellen gespeichert und skaliert die rezeptur exakt', function () {
$this->actingAs(fwUser(), 'user');
$this->post(route('admin_product_store'), ['id' => 'new', 'name' => 'FW-Dezimal', 'fill_weight' => '39,5'])
->assertRedirect()->assertSessionHasNoErrors();
$product = Product::query()->where('name', 'FW-Dezimal')->firstOrFail();
expect($product->fill_weight)->toBe(39.5)
->and(app(ProductionService::class)->recipeGramScale($product))->toBe(0.395);
// Punkt mit 1–2 Nachkommastellen gilt als Dezimaltrenner (WaWi-Konvention), leer = null.
$this->post(route('admin_product_store'), ['id' => $product->id, 'name' => 'FW-Dezimal', 'fill_weight' => '4.5'])->assertSessionHasNoErrors();
expect($product->fresh()->fill_weight)->toBe(4.5);
$this->post(route('admin_product_store'), ['id' => $product->id, 'name' => 'FW-Dezimal', 'fill_weight' => ''])->assertSessionHasNoErrors();
expect($product->fresh()->fill_weight)->toBeNull();
});
test('F-08: ungültiges oder negatives füllgewicht wird abgelehnt', function () {
$this->actingAs(fwUser(), 'user');
$product = Product::query()->create(['name' => 'FW-Invalid', 'title' => 'x', 'active' => true, 'fill_weight' => 10]);
// Der Produkt-Controller rendert bei Fehlern das Formular direkt (kein Redirect).
foreach (['abc', '-5', '0'] as $bad) {
$this->post(route('admin_product_store'), ['id' => $product->id, 'name' => 'FW-Invalid', 'fill_weight' => $bad])
->assertOk()
->assertSee('is-invalid', false);
}
expect($product->fresh()->fill_weight)->toBe(10.0);
});
test('F-07: produktionsformular liefert die verpackungs-stückliste je ergebnisprodukt für die vorschau', function () {
$this->actingAs(fwUser(), 'user');
$supplier = Supplier::factory()->create();
$material = PackagingMaterial::factory()->create();
$pk = PackagingItem::factory()->create(['packaging_material_id' => $material->id, 'supplier_id' => $supplier->id, 'name' => 'F07-Tiegel', 'category' => 'packaging']);
$small = Product::query()->create(['name' => 'F07-5ml', 'title' => 'x', 'active' => true, 'no_recipe_required' => true, 'production_relevant' => false]);
$small->packagings()->sync([$pk->id => ['quantity' => 2, 'pos' => 0]]);
Location::factory()->create();
$html = $this->get(route('admin.inventory.productions.create'))->assertOk()->getContent();
$start = strpos($html, "data-packaging-bom='") + strlen("data-packaging-bom='");
$bom = json_decode(substr($html, $start, strpos($html, "'", $start) - $start), true);
expect($bom)->toHaveKey((string) $small->id)
->and($bom[$small->id][0]['name'])->toBe('F07-Tiegel')
->and($bom[$small->id][0]['per_unit'])->toEqual(2)
->and($html)->toContain('renderPackagingPreview');
});