158 lines
4 KiB
PHP
158 lines
4 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
use Illuminate\Database\Eloquent\Relations\MorphOne;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
|
|
|
class Harvest extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $table = 'harvests';
|
|
|
|
protected $fillable = [
|
|
'vineyard_row_id',
|
|
'weight',
|
|
'variety_variation_id',
|
|
'sugar_content',
|
|
'date',
|
|
'user_id',
|
|
'quality',
|
|
'grape_condition',
|
|
'notes',
|
|
'weather_conditions',
|
|
'harvest_time',
|
|
];
|
|
|
|
protected $casts = [
|
|
'date' => 'date',
|
|
'weight' => 'decimal:2',
|
|
'sugar_content' => 'decimal:2',
|
|
];
|
|
|
|
/**
|
|
* Get the vineyard row for this harvest.
|
|
*/
|
|
public function vineyardRow(): BelongsTo
|
|
{
|
|
return $this->belongsTo(VineyardRow::class, 'vineyard_row_id');
|
|
}
|
|
|
|
/**
|
|
* Get the planned task associated with this treatment.
|
|
*/
|
|
public function plannedTask(): MorphOne
|
|
{
|
|
return $this->morphOne(PlannedTask::class, 'taskable');
|
|
}
|
|
|
|
/**
|
|
* Get the variety variation for this harvest.
|
|
*/
|
|
public function varietyVariation(): BelongsTo
|
|
{
|
|
return $this->belongsTo(VarietyVariation::class, 'variety_variation_id');
|
|
}
|
|
|
|
/**
|
|
* Get the user who performed this harvest.
|
|
*/
|
|
public function user(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class, 'user_id');
|
|
}
|
|
|
|
/**
|
|
* Get the wine production records for this harvest.
|
|
*/
|
|
public function wineProductions(): HasMany
|
|
{
|
|
return $this->hasMany(WineProduction::class, 'harvest_id');
|
|
}
|
|
|
|
/**
|
|
* Get the wines produced from this harvest (many-to-many through wine_productions).
|
|
*/
|
|
public function wines(): BelongsToMany
|
|
{
|
|
return $this->belongsToMany(Wine::class, 'wine_productions', 'harvest_id', 'wine_id')
|
|
->withPivot('consumed_weight', 'blend_percentage')
|
|
->withTimestamps();
|
|
}
|
|
|
|
/**
|
|
* Get the total consumed weight from all wine productions.
|
|
*/
|
|
public function getConsumedWeightAttribute(): float
|
|
{
|
|
return $this->wineProductions()->sum('consumed_weight') ?? 0;
|
|
}
|
|
|
|
/**
|
|
* Get the remaining available weight.
|
|
*/
|
|
public function getRemainingWeightAttribute(): float
|
|
{
|
|
return max(0, $this->weight - $this->consumed_weight);
|
|
}
|
|
|
|
/**
|
|
* Get the usage percentage.
|
|
*/
|
|
public function getUsagePercentageAttribute(): float
|
|
{
|
|
if ($this->weight <= 0) {
|
|
return 0;
|
|
}
|
|
return min(100, ($this->consumed_weight / $this->weight) * 100);
|
|
}
|
|
|
|
/**
|
|
* Check if harvest is fully used.
|
|
*/
|
|
public function isFullyUsed(): bool
|
|
{
|
|
return $this->remaining_weight <= 0.01; // Allow small floating point difference
|
|
}
|
|
|
|
/**
|
|
* Check if harvest is partially used.
|
|
*/
|
|
public function isPartiallyUsed(): bool
|
|
{
|
|
return $this->consumed_weight > 0 && !$this->isFullyUsed();
|
|
}
|
|
|
|
/**
|
|
* Check if harvest is available (not used at all).
|
|
*/
|
|
public function isAvailable(): bool
|
|
{
|
|
return $this->consumed_weight < 0.01; // Allow small floating point difference
|
|
}
|
|
|
|
/**
|
|
* Check if there are any wines still in the cellar that were made from this harvest.
|
|
* Returns true if any connected wine has bottles in stock.
|
|
*/
|
|
public function hasWinesInCellar(): bool
|
|
{
|
|
return $this->wines()->where('bottles_in_stock', '>', 0)->exists();
|
|
}
|
|
|
|
/**
|
|
* Check if harvest can be safely deleted.
|
|
* A harvest can only be deleted when:
|
|
* 1. It has been fully used in wine production
|
|
* 2. All wines made from it have been sold out (no bottles in cellar)
|
|
*/
|
|
public function canBeDeleted(): bool
|
|
{
|
|
return $this->isFullyUsed() && !$this->hasWinesInCellar();
|
|
}
|
|
}
|