Files
SpiceManagementSystem/app/Models/Batch.php
T
Malek TellissiandClaude Sonnet 4.6 fb19e9a579
Deploy / deploy (push) Successful in 16s
Introduce spice_stock_movements ledger for traceable stock changes
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>
2026-09-12 22:34:10 +02:00

100 lines
2.6 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Batch extends Model
{
protected $fillable = [
'lot_number', 'product_id', 'size_id', 'recipe_id',
'units_produced', 'quantity_g', 'produced_at', 'expires_at',
];
protected $casts = [
'produced_at' => 'date',
'expires_at' => 'date',
];
public function product()
{
return $this->belongsTo(Product::class);
}
public function size()
{
return $this->belongsTo(ProductSize::class);
}
public function recipe()
{
return $this->belongsTo(Recipe::class);
}
public function origins()
{
return $this->hasMany(BatchOrigin::class);
}
protected static function booted(): void
{
static::saving(function (Batch $batch) {
if ($batch->units_produced && $batch->size_id) {
$batch->quantity_g = $batch->units_produced * ($batch->size?->packing?->size ?? 0);
}
});
static::created(function (Batch $batch) {
$batch->writeSpiceMovements();
});
static::updated(function (Batch $batch) {
if ($batch->wasChanged(['recipe_id', 'size_id', 'units_produced'])) {
$batch->deleteSpiceMovements();
$batch->writeSpiceMovements();
}
});
static::deleting(function (Batch $batch) {
$batch->deleteSpiceMovements();
});
}
private function writeSpiceMovements(): void
{
if (! $this->quantity_g || ! $this->recipe_id) {
return;
}
$recipe = Recipe::with('spices')->find($this->recipe_id);
if (! $recipe) {
return;
}
foreach ($recipe->spices as $spice) {
$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();
}
}