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