'decimal:3', 'quantity_fulfilled' => 'decimal:3', ]; public function materialList() { return $this->belongsTo(MaterialList::class, 'material_list_id'); } public function business() { return $this->belongsTo(Business::class); } public function sparePart() { return $this->belongsTo(SparePart::class, 'spare_part_id'); } public function product() { return $this->belongsTo(Product::class); } public function variation() { return $this->belongsTo(Variation::class); } public function suggestedSupplier() { return $this->belongsTo(Contact::class, 'suggested_supplier_id'); } public function procurements() { return $this->hasMany(MaterialProcurement::class, 'material_line_id'); } public function repairDispatches() { return $this->hasMany(RepairDispatch::class, 'material_line_id'); } public function activeRepairDispatch() { return $this->hasOne(RepairDispatch::class, 'material_line_id') ->whereNotIn('status', ['received', 'cancelled']) ->latest('id'); } public function isRepairLine(): bool { return $this->line_type === 'repair'; } public function displayName(): string { if ($this->sparePart) { return $this->sparePart->name; } return $this->part_name ?: '—'; } public function shortfall(): float { return max(0, (float) $this->quantity_required - (float) $this->quantity_fulfilled); } }