Introduce spice_stock_movements ledger for traceable stock changes
Deploy / deploy (push) Successful in 16s
Deploy / deploy (push) Successful in 16s
Every delivery and batch now writes a signed movement entry instead of directly incrementing/decrementing spice.quantity. The balance is always the sum of all movements. Existing data is backfilled in the migration. Rohstoff edit page shows the full movement history (Lagerbewegungen tab). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
7545aed494
commit
fb19e9a579
9 files changed
+179
-43
No files matched your search
+29
-25
@@ -38,58 +38,62 @@ class Batch extends Model
|
||||
|
||||
protected static function booted(): void
|
||||
{
|
||||
// Auto-calculate quantity_g before saving
|
||||
static::saving(function (Batch $batch) {
|
||||
if ($batch->units_produced && $batch->size_id) {
|
||||
$gramsPerUnit = $batch->size?->packing?->size ?? 0;
|
||||
$batch->quantity_g = $batch->units_produced * $gramsPerUnit;
|
||||
$batch->quantity_g = $batch->units_produced * ($batch->size?->packing?->size ?? 0);
|
||||
}
|
||||
});
|
||||
|
||||
static::created(function (Batch $batch) {
|
||||
$batch->deductSpices();
|
||||
$batch->writeSpiceMovements();
|
||||
});
|
||||
|
||||
static::updated(function (Batch $batch) {
|
||||
if ($batch->wasChanged(['recipe_id', 'size_id', 'units_produced'])) {
|
||||
$batch->restoreSpices(
|
||||
$batch->getOriginal('recipe_id'),
|
||||
$batch->getOriginal('quantity_g'),
|
||||
);
|
||||
$batch->deductSpices();
|
||||
$batch->deleteSpiceMovements();
|
||||
$batch->writeSpiceMovements();
|
||||
}
|
||||
});
|
||||
|
||||
static::deleting(function (Batch $batch) {
|
||||
$batch->restoreSpices($batch->recipe_id, $batch->quantity_g);
|
||||
$batch->deleteSpiceMovements();
|
||||
});
|
||||
}
|
||||
|
||||
private function deductSpices(): void
|
||||
private function writeSpiceMovements(): void
|
||||
{
|
||||
if (! $this->quantity_g || ! $this->recipe_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
$recipe = Recipe::with('spices')->find($this->recipe_id);
|
||||
|
||||
foreach ($recipe->spices as $spice) {
|
||||
$grams = $this->quantity_g * $spice->pivot->amount_in_percent / 100;
|
||||
$spice->decrement('quantity', $grams);
|
||||
}
|
||||
}
|
||||
|
||||
private function restoreSpices(int $recipeId, float $quantityG): void
|
||||
{
|
||||
if (! $quantityG || ! $recipeId) {
|
||||
if (! $recipe) {
|
||||
return;
|
||||
}
|
||||
|
||||
$recipe = Recipe::with('spices')->find($recipeId);
|
||||
|
||||
foreach ($recipe->spices as $spice) {
|
||||
$grams = $quantityG * $spice->pivot->amount_in_percent / 100;
|
||||
$spice->increment('quantity', $grams);
|
||||
$grams = $this->quantity_g * $spice->pivot->amount_in_percent / 100;
|
||||
SpiceStockMovement::create([
|
||||
'spice_id' => $spice->id,
|
||||
'amount' => -$grams,
|
||||
'source_type' => 'batch',
|
||||
'source_id' => $this->id,
|
||||
'description' => 'Charge ' . $this->lot_number . ' (' . $spice->pivot->amount_in_percent . '%)',
|
||||
]);
|
||||
$spice->recalculateQuantity();
|
||||
}
|
||||
}
|
||||
|
||||
private function deleteSpiceMovements(): void
|
||||
{
|
||||
$spiceIds = SpiceStockMovement::where('source_type', 'batch')
|
||||
->where('source_id', $this->id)
|
||||
->pluck('spice_id');
|
||||
|
||||
SpiceStockMovement::where('source_type', 'batch')
|
||||
->where('source_id', $this->id)
|
||||
->delete();
|
||||
|
||||
Spice::whereIn('id', $spiceIds)->get()->each->recalculateQuantity();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user