Projects/3BIT/winter-semester/IIS/xnecasr00/app/Http/Controllers/WinemakerController.php
2026-04-14 19:28:46 +02:00

422 lines
17 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\PlannedTask;
use App\Models\Treatment;
use App\Models\Wine;
use App\Models\WineProduction;
use App\Models\Harvest;
use App\Models\VineyardRow;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class WinemakerController extends Controller
{
/**
* Display the winemaker dashboard.
*/
public function dashboard()
{
// ========================================
// PLANNED ACTIONS
// ========================================
// Get planned tasks (not yet executed) - including overdue tasks from past 7 days and upcoming tasks for next 7 days
$plannedTasksRaw = PlannedTask::with(['taskable'])
->whereNull('execution_date')
->where('planned_date', '>=', now()->subDays(7))
->where('planned_date', '<=', now()->addDays(7))
->orderBy('planned_date')
->get();
// Load parent Treatment records for treatment types (to access vineyard row data)
foreach ($plannedTasksRaw as $task) {
if (in_array($task->taskable_type, [
'App\Models\Spraying',
'App\Models\Watering',
'App\Models\Fertilization',
'App\Models\Pruning'
]) && $task->taskable) {
$task->treatment = Treatment::with('vineyardRow')->find($task->taskable->treatment_id);
}
}
// Group planned tasks by type, date, and note
$plannedTasks = $plannedTasksRaw->groupBy(function($task) {
return $task->type . '|' . $task->planned_date->format('Y-m-d') . '|' . ($task->note ?? '');
})->map(function($group) {
$first = $group->first();
$first->vineyard_rows = $group->map(function($task) {
if ($task->taskable_type === VineyardRow::class) {
return $task->taskable;
}
// For Treatment types, use the parent Treatment record
if (isset($task->treatment) && $task->treatment) {
return $task->treatment->vineyardRow;
}
// For Harvest, load the vineyardRow if it exists
if ($task->taskable && method_exists($task->taskable, 'vineyardRow')) {
return $task->taskable->vineyardRow;
}
return null;
})->filter()->values();
// Map task IDs to their vineyard rows
$first->task_rows = $group->map(function($task) {
$row = null;
if ($task->taskable_type === VineyardRow::class) {
$row = $task->taskable;
} elseif (isset($task->treatment) && $task->treatment) {
$row = $task->treatment->vineyardRow;
} elseif ($task->taskable && method_exists($task->taskable, 'vineyardRow')) {
$row = $task->taskable->vineyardRow;
}
return $row ? [
'task_id' => $task->planned_task_id,
'row_id' => $row->id,
'row' => $row,
] : null;
})->filter()->values();
$first->task_count = $group->count();
return $first;
})->values();
// Sort all planned tasks chronologically
$allPlannedTasks = $plannedTasks->sortBy('planned_date')->values();
// ========================================
// COMPLETED ACTIONS
// ========================================
$completedActivities = collect();
// 1. Completed treatments and tasks (including completed Harvests)
$completedTasksRaw = PlannedTask::with(['taskable'])
->whereNotNull('execution_date')
->where('execution_date', '>=', now()->subDays(30))
->orderBy('execution_date', 'desc')
->get();
// Load parent Treatment records for treatment types
foreach ($completedTasksRaw as $task) {
if (in_array($task->taskable_type, [
'App\Models\Spraying',
'App\Models\Watering',
'App\Models\Fertilization',
'App\Models\Pruning'
]) && $task->taskable) {
$task->treatment = Treatment::with('vineyardRow')->find($task->taskable->treatment_id);
}
}
// Group completed tasks by type, execution date, and note
$completedTasks = $completedTasksRaw->groupBy(function($task) {
return $task->type . '|' . $task->execution_date->format('Y-m-d') . '|' . ($task->note ?? '');
})->map(function($group) {
$first = $group->first();
$first->vineyard_rows = $group->map(function($task) {
if ($task->taskable_type === VineyardRow::class) {
return $task->taskable;
}
// For Treatment types, use the parent Treatment record
if (isset($task->treatment) && $task->treatment) {
return $task->treatment->vineyardRow;
}
// For Harvest, load the vineyardRow if it exists
if ($task->taskable && method_exists($task->taskable, 'vineyardRow')) {
return $task->taskable->vineyardRow;
}
return null;
})->filter()->values();
$first->task_count = $group->count();
$first->activity_type = 'task';
$first->activity_date = $first->execution_date;
return $first;
})->values();
$completedActivities = $completedActivities->concat($completedTasks);
// 2. Recent wine productions (bottling/blending) - DISABLED FOR RECENT ACTIVITY
// Note: Bottling and blending activities are only shown in "All Completed Activities"
// They are excluded from the recent activity timeline on the dashboard
/*
$recentProductions = WineProduction::with(['wine.grapeVariety', 'harvest.vineyardRow.varietyVariation'])
->where('created_at', '>=', now()->subDays(30))
->orderBy('created_at', 'desc')
->get();
// Group by wine to detect blends
$productionsByWine = $recentProductions->groupBy('wine_id');
foreach ($productionsByWine as $wineId => $productions) {
$wine = $productions->first()->wine;
if (!$wine) continue;
$activity = (object)[
'activity_type' => 'production',
'activity_date' => $productions->first()->created_at,
'wine' => $wine,
'productions' => $productions,
'is_blend' => $productions->count() > 1,
'total_weight' => $productions->sum('consumed_weight'),
];
$completedActivities->push($activity);
}
*/
// 3. Recent harvests (not from planned tasks) - DISABLED
// Note: Only showing "Harvest completed" from PlannedTask, not "Harvest Recorded"
// Harvest recorded activities are excluded from recent activity timeline
/*
$recentHarvests = Harvest::with(['vineyardRow.varietyVariation.grapeVariety'])
->where('date', '>=', now()->subDays(30))
->orderBy('date', 'desc')
->get()
->map(function($harvest) {
// Check if this harvest is already represented in completed tasks
$existingTask = PlannedTask::where('taskable_type', Harvest::class)
->where('taskable_id', $harvest->id)
->whereNotNull('execution_date')
->exists();
if ($existingTask) {
return null; // Skip to avoid duplicates
}
return (object)[
'activity_type' => 'harvest',
'activity_date' => $harvest->date,
'harvest' => $harvest,
];
})
->filter();
$completedActivities = $completedActivities->concat($recentHarvests);
*/
// Sort all completed activities by date (most recent first)
$completedActivities = $completedActivities
->sortByDesc('activity_date')
->take(20)
->values();
// ========================================
// STATISTICS
// ========================================
// Wine statistics
$wineStats = [
'total_bottles' => Wine::sum('bottles_in_stock') ?? 0,
'by_status' => Wine::select('status', DB::raw('count(*) as count'))
->groupBy('status')
->pluck('count', 'status')
->toArray(),
];
// Harvest statistics
$totalHarvestWeight = Harvest::sum('weight') ?? 0;
$totalConsumedWeight = WineProduction::sum('consumed_weight') ?? 0;
$harvestStats = [
'total_harvest' => $totalHarvestWeight,
'consumed' => $totalConsumedWeight,
'available_weight' => max(0, $totalHarvestWeight - $totalConsumedWeight),
];
// Vineyard statistics
$vineyardStats = [
'total_rows' => VineyardRow::count(),
'active_rows' => VineyardRow::where('status', 'active')->count(),
'total_area' => VineyardRow::sum('area') ?? 0,
];
return view('winemaker.dashboard.index', compact(
'allPlannedTasks',
'completedActivities',
'wineStats',
'harvestStats',
'vineyardStats'
));
}
/**
* Display all planned tasks.
*/
public function allPlannedTasks()
{
// Get all planned tasks (not yet executed) - including overdue tasks
$plannedTasksRaw = PlannedTask::with(['taskable'])
->whereNull('execution_date')
->orderBy('planned_date')
->get();
// Load parent Treatment records for treatment types
foreach ($plannedTasksRaw as $task) {
if (in_array($task->taskable_type, [
'App\Models\Spraying',
'App\Models\Watering',
'App\Models\Fertilization',
'App\Models\Pruning'
]) && $task->taskable) {
$task->treatment = Treatment::with('vineyardRow')->find($task->taskable->treatment_id);
}
}
// Group planned tasks by type, date, and note
$plannedTasks = $plannedTasksRaw->groupBy(function($task) {
return $task->type . '|' . $task->planned_date->format('Y-m-d') . '|' . ($task->note ?? '');
})->map(function($group) {
$first = $group->first();
$first->vineyard_rows = $group->map(function($task) {
if ($task->taskable_type === VineyardRow::class) {
return $task->taskable;
}
// For Treatment types, use the parent Treatment record
if (isset($task->treatment) && $task->treatment) {
return $task->treatment->vineyardRow;
}
// For Harvest, load the vineyardRow if it exists
if ($task->taskable && method_exists($task->taskable, 'vineyardRow')) {
return $task->taskable->vineyardRow;
}
return null;
})->filter()->values();
// Map task IDs to their vineyard rows
$first->task_rows = $group->map(function($task) {
$row = null;
if ($task->taskable_type === VineyardRow::class) {
$row = $task->taskable;
} elseif (isset($task->treatment) && $task->treatment) {
$row = $task->treatment->vineyardRow;
} elseif ($task->taskable && method_exists($task->taskable, 'vineyardRow')) {
$row = $task->taskable->vineyardRow;
}
return $row ? [
'task_id' => $task->planned_task_id,
'row_id' => $row->id,
'row' => $row,
] : null;
})->filter()->values();
$first->task_count = $group->count();
return $first;
})->values();
// Sort all planned tasks chronologically
$allPlannedTasks = $plannedTasks->sortBy('planned_date')->values();
return view('winemaker.dashboard.planned-tasks', compact('allPlannedTasks'));
}
/**
* Display all completed activities.
*/
public function allCompletedActivities()
{
$completedActivities = collect();
// 1. Completed treatments and tasks
$completedTasksRaw = PlannedTask::with(['taskable'])
->whereNotNull('execution_date')
->orderBy('execution_date', 'desc')
->get();
// Load parent Treatment records for treatment types
foreach ($completedTasksRaw as $task) {
if (in_array($task->taskable_type, [
'App\Models\Spraying',
'App\Models\Watering',
'App\Models\Fertilization',
'App\Models\Pruning'
]) && $task->taskable) {
$task->treatment = Treatment::with('vineyardRow')->find($task->taskable->treatment_id);
}
}
// Group completed tasks by type, execution date, and note
$completedTasks = $completedTasksRaw->groupBy(function($task) {
return $task->type . '|' . $task->execution_date->format('Y-m-d') . '|' . ($task->note ?? '');
})->map(function($group) {
$first = $group->first();
$first->vineyard_rows = $group->map(function($task) {
if ($task->taskable_type === VineyardRow::class) {
return $task->taskable;
}
// For Treatment types, use the parent Treatment record
if (isset($task->treatment) && $task->treatment) {
return $task->treatment->vineyardRow;
}
// For Harvest, load the vineyardRow if it exists
if ($task->taskable && method_exists($task->taskable, 'vineyardRow')) {
return $task->taskable->vineyardRow;
}
return null;
})->filter()->values();
$first->task_count = $group->count();
$first->activity_type = 'task';
$first->activity_date = $first->execution_date;
return $first;
})->values();
$completedActivities = $completedActivities->concat($completedTasks);
// 2. All wine productions (bottling/blending)
$allProductions = WineProduction::with(['wine.grapeVariety', 'harvest.vineyardRow.varietyVariation'])
->orderBy('created_at', 'desc')
->get();
// Group by wine to detect blends
$productionsByWine = $allProductions->groupBy('wine_id');
foreach ($productionsByWine as $wineId => $productions) {
$wine = $productions->first()->wine;
if (!$wine) continue;
$activity = (object)[
'activity_type' => 'production',
'activity_date' => $productions->first()->created_at,
'wine' => $wine,
'productions' => $productions,
'is_blend' => $productions->count() > 1,
'total_weight' => $productions->sum('consumed_weight'),
];
$completedActivities->push($activity);
}
// 3. All harvests (not from planned tasks)
$allHarvests = Harvest::with(['vineyardRow.varietyVariation.grapeVariety', 'plannedTask'])
->orderBy('date', 'desc')
->get()
->map(function($harvest) {
$existingTask = PlannedTask::where('taskable_type', Harvest::class)
->where('taskable_id', $harvest->id)
->whereNotNull('execution_date')
->exists();
if ($existingTask) {
return null;
}
// Use execution_date from plannedTask if available, otherwise use harvest date
$activityDate = ($harvest->plannedTask && $harvest->plannedTask->execution_date)
? $harvest->plannedTask->execution_date
: $harvest->date;
return (object)[
'activity_type' => 'harvest',
'activity_date' => $activityDate,
'harvest' => $harvest,
];
})
->filter();
$completedActivities = $completedActivities->concat($allHarvests);
// Sort all completed activities by date (most recent first)
$completedActivities = $completedActivities
->sortByDesc('activity_date')
->values();
return view('winemaker.dashboard.completed-activities', compact('completedActivities'));
}
}