Warenwirtschaft: F-04 — Rezeptur-Phase an Verbrauchszeilen, keine Vervielfachung beim Wiederöffnen
production_ingredients.recipe_phase_id; Formular sendet die Phase je Zeile, Vorbelegung je Rohstoff|Phase. Altbestand ohne Phase wird nur einmal eingesetzt. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
859b1f083d
commit
104671e929
8 changed files with 109 additions and 3 deletions
|
|
@ -6,6 +6,7 @@ use App\Models\Location;
|
|||
use App\Models\Product;
|
||||
use App\Models\ProductIngredient;
|
||||
use App\Models\Production;
|
||||
use App\Models\RecipePhase;
|
||||
use App\Models\StockEntry;
|
||||
use App\Models\Supplier;
|
||||
use App\Services\InventoryService;
|
||||
|
|
@ -346,3 +347,49 @@ test('F-03: entwurf mit gewähltem ergebnisprodukt ohne stückzahl wird gespeich
|
|||
->and($draft->outputs()->first()->batch_number)->toBe('VORLAEUFIG')
|
||||
->and(app(ProductStockService::class)->currentStock($product->id))->toBe(0);
|
||||
});
|
||||
|
||||
test('F-04: derselbe rohstoff in zwei phasen behält beim wiederöffnen je phase seinen anteil und lässt sich unverändert abschließen', function () {
|
||||
$user = draftUser();
|
||||
$location = Location::factory()->create();
|
||||
$supplier = Supplier::factory()->create();
|
||||
$ing = draftIngredient();
|
||||
$stock = draftStock($ing, $location, $supplier, $user);
|
||||
|
||||
$product = Product::query()->create(['name' => 'Draft-Phasen', 'title' => 'Draft-Phasen', 'active' => true]);
|
||||
$phaseA = RecipePhase::query()->create(['product_id' => $product->id, 'name' => 'Phase A', 'pos' => 0]);
|
||||
$phaseB = RecipePhase::query()->create(['product_id' => $product->id, 'name' => 'Phase B', 'pos' => 1]);
|
||||
ProductIngredient::query()->create(['product_id' => $product->id, 'ingredient_id' => $ing->id, 'pos' => 0, 'gram' => 6, 'factor' => 1.0, 'recipe_type' => 'manufacturer', 'recipe_phase_id' => $phaseA->id]);
|
||||
ProductIngredient::query()->create(['product_id' => $product->id, 'ingredient_id' => $ing->id, 'pos' => 1, 'gram' => 4, 'factor' => 1.0, 'recipe_type' => 'manufacturer', 'recipe_phase_id' => $phaseB->id]);
|
||||
|
||||
Passport::actingAs($user);
|
||||
$this->actingAs($user, 'user');
|
||||
|
||||
$head = ['product_id' => $product->id, 'location_id' => $location->id, 'produced_at' => '2026-08-01', 'quantity' => 1];
|
||||
$lines = [
|
||||
['ingredient_id' => $ing->id, 'batch_key' => $stock->batchGroupKey(), 'recipe_phase_id' => $phaseA->id, 'quantity_used' => '6'],
|
||||
['ingredient_id' => $ing->id, 'batch_key' => $stock->batchGroupKey(), 'recipe_phase_id' => $phaseB->id, 'quantity_used' => '4'],
|
||||
];
|
||||
|
||||
$this->post(route('admin.inventory.productions.store'), $head + ['save_mode' => 'draft', 'ingredient_lines' => $lines])
|
||||
->assertRedirect()->assertSessionHasNoErrors();
|
||||
|
||||
$draft = Production::query()->where('product_id', $product->id)->sole();
|
||||
$html = $this->get(route('admin.inventory.productions.edit', $draft))->assertOk()->getContent();
|
||||
$existing = json_decode(substr($html, strpos($html, 'var existingLines = ') + strlen('var existingLines = '), strpos($html, ';', strpos($html, 'var existingLines = ')) - strpos($html, 'var existingLines = ') - strlen('var existingLines = ')), true);
|
||||
|
||||
expect($existing)->toHaveKeys([$ing->id.'|'.$phaseA->id, $ing->id.'|'.$phaseB->id])
|
||||
->and($existing[$ing->id.'|'.$phaseA->id][0]['quantity_used'])->toEqual(6)
|
||||
->and($existing[$ing->id.'|'.$phaseB->id][0]['quantity_used'])->toEqual(4);
|
||||
|
||||
// Unverändert abschließen: Summe 10 g = Soll 10 g, je Phase bleibt der Anteil erhalten.
|
||||
$this->put(route('admin.inventory.productions.update', $draft), $head + [
|
||||
'save_mode' => 'complete', 'ingredient_lines' => $lines,
|
||||
'outputs' => [['product_id' => $product->id, 'quantity' => 1, 'batch_number' => null]],
|
||||
])->assertSessionHasNoErrors();
|
||||
|
||||
$done = $draft->fresh();
|
||||
expect($done->isDraft())->toBeFalse()
|
||||
->and($done->productionIngredients()->where('recipe_phase_id', $phaseA->id)->sum('quantity_used'))->toEqual(6)
|
||||
->and($done->productionIngredients()->where('recipe_phase_id', $phaseB->id)->sum('quantity_used'))->toEqual(4)
|
||||
->and((float) app(InventoryService::class)->remainingByIngredient([$ing->id])[$ing->id])->toBe(990.0);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue