MIF_E31221361/app/Models/ProductRecipe.php

158 lines
4.1 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Helpers\UnitConverter;
class ProductRecipe extends Model
{
use HasFactory;
protected $fillable = [
'produk_id',
'raw_material_id',
'quantity',
'unit',
'notes'
];
protected $casts = [
'quantity' => 'decimal:3'
];
// Available units for recipes
const AVAILABLE_UNITS = ['g', 'kg', 'ml', 'l', 'pcs'];
public function produk()
{
return $this->belongsTo(Produk::class);
}
public function rawMaterial()
{
return $this->belongsTo(RawMaterial::class);
}
/**
* Get quantity in material's unit
*/
public function getQuantityInMaterialUnit()
{
if (!$this->rawMaterial) {
throw new \Exception("Raw material not found for this recipe.");
}
try {
return UnitConverter::convert(
$this->quantity,
$this->unit,
$this->rawMaterial->unit
);
} catch (\InvalidArgumentException $e) {
throw new \Exception("Cannot convert recipe unit {$this->unit} to material unit " . ($this->rawMaterial ? $this->rawMaterial->unit : 'null'));
}
}
/**
* Check if material has sufficient stock for this recipe
*/
public function hasSufficientStock($multiplier = 1)
{
// Handle if rawMaterial is null
if (!$this->rawMaterial) {
return false;
}
return $this->rawMaterial->hasSufficientStock(
$this->quantity * $multiplier,
$this->unit
);
}
/**
* Get required amount in material's unit
*/
public function getRequiredAmountInMaterialUnit($multiplier = 1)
{
if (!$this->rawMaterial) {
return null;
}
try {
return UnitConverter::convert(
$this->quantity * $multiplier,
$this->unit,
$this->rawMaterial->unit
);
} catch (\InvalidArgumentException $e) {
return null;
}
}
/**
* Consume materials for production
*/
public function consumeForProduction($multiplier = 1, $notes = null)
{
if (!$this->rawMaterial) {
throw new \Exception("Raw material not found for this recipe.");
}
$requiredAmount = $this->quantity * $multiplier;
$productName = $this->produk->nama_produk ?? 'Unknown Product';
$defaultNotes = "Production of {$productName} - Recipe item: {$this->rawMaterial->name}";
return $this->rawMaterial->reduceStock(
$requiredAmount,
$this->unit,
$notes ?? $defaultNotes
);
}
/**
* Get formatted quantity with unit
*/
public function getFormattedQuantity()
{
return UnitConverter::formatValue($this->quantity, $this->unit);
}
/**
* Validate if recipe unit is compatible with material unit
*/
public function validateUnitCompatibility()
{
if (!$this->rawMaterial) {
return false;
}
return UnitConverter::areUnitsCompatible($this->unit, $this->rawMaterial->unit);
}
/**
* Get available units for this recipe based on material
*/
public function getAvailableUnits()
{
if (!$this->rawMaterial) {
return [];
}
$materialCategory = $this->rawMaterial->getUnitCategory();
return UnitConverter::getUnitsByCategory($materialCategory);
}
/**
* Boot method to add model events
*/
protected static function boot()
{
parent::boot();
// Validate unit compatibility before saving
static::saving(function ($recipe) {
if ($recipe->rawMaterial && !$recipe->validateUnitCompatibility()) {
throw new \Exception(
"Recipe unit '{$recipe->unit}' is not compatible with material unit '{$recipe->rawMaterial->unit}'"
);
}
});
}
}