'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(); } }