query('date')) { return redirect()->route('vineyard.map') ->with('error', 'Please choose a date on the vineyard map before planning watering.'); } return $this->renderForm('watering', 'planned-tasks.watering', $request); } public function showPruningForm(Request $request) { if (! $request->query('date')) { return redirect()->route('vineyard.map') ->with('error', 'Please choose a date on the vineyard map before planning pruning.'); } return $this->renderForm('pruning', 'planned-tasks.pruning', $request); } public function showFertilisationForm(Request $request) { if (! $request->query('date')) { return redirect()->route('vineyard.map') ->with('error', 'Please choose a date on the vineyard map before planning fertilisation.'); } return $this->renderForm('fertilization', 'planned-tasks.fertilisation', $request, 'fertilisation'); } public function showPesticideForm(Request $request) { if (! $request->query('date')) { return redirect()->route('vineyard.map') ->with('error', 'Please choose a date on the vineyard map before planning pesticide treatment.'); } return $this->renderForm('spraying', 'planned-tasks.pesticide', $request, 'pesticide'); } public function showHarvestForm(Request $request) { if (! $request->query('date')) { return redirect()->route('vineyard.map') ->with('error', 'Please choose a date on the vineyard map before planning harvest.'); } return $this->renderForm('harvest', 'planned-tasks.harvest', $request); } public function storeBulk(StoreBulkPlannedTasksRequest $request) { $result = $this->bulkService->handle($request->validated()); $status = $result['success'] ? 201 : 422; return response()->json($result, $status); } protected function renderForm(string $actionKey, string $view, Request $request, ?string $displayAction = null) { $selectedRowIds = $this->parseRowIds($request->input('rows', [])); $plannedDate = $request->query('date'); $rows = VineyardRow::with('varietyVariation.grapeVariety') ->when($selectedRowIds->isNotEmpty(), fn ($query) => $query->whereIn('id', $selectedRowIds)) ->orderBy('id') ->get(); return view($view, [ 'action' => $displayAction ?? $actionKey, 'actionKey' => $actionKey, 'rows' => $rows, 'selectedRowIds' => $selectedRowIds, 'plannedDate' => $plannedDate, ]); } protected function parseRowIds(array|string $value): Collection { if (is_string($value)) { $value = explode(',', $value); } return collect($value) ->map(fn ($id) => (int) $id) ->filter(fn ($id) => $id > 0) ->values(); } public function edit(PlannedTask $task) { $task->load('taskable'); // Find all tasks in the same group (same type, date, note) $groupTasks = PlannedTask::with('taskable') ->where('type', $task->type) ->where('planned_date', $task->planned_date) ->where(function($query) use ($task) { if ($task->note) { $query->where('note', $task->note); } else { $query->whereNull('note'); } }) ->whereNull('execution_date') ->get(); // Build task_rows array with task IDs and vineyard row info $taskRows = $groupTasks->map(function($t) { $row = null; if (!$t->taskable) { return null; } // Check taskable type to determine how to get vineyard row $taskableType = $t->taskable_type; // For Harvest, vineyard_row_id is directly on the taskable if (str_contains($taskableType, 'Harvest') && $t->taskable->vineyard_row_id) { $row = VineyardRow::with('varietyVariation.grapeVariety') ->find($t->taskable->vineyard_row_id); } // For treatment types (Watering, Spraying, Fertilization, Pruning), get it through parent Treatment elseif ($t->taskable->treatment_id) { $treatment = Treatment::with('vineyardRow.varietyVariation.grapeVariety') ->find($t->taskable->treatment_id); if ($treatment && $treatment->vineyardRow) { $row = $treatment->vineyardRow; } } return $row ? [ 'task_id' => $t->planned_task_id, 'row_id' => $row->id, 'row' => $row, ] : null; })->filter()->sortBy('row_id')->values(); // Get the vineyard row for the main task (for display) $vineyardRow = null; if ($task->taskable) { $taskableType = $task->taskable_type; // For Harvest if (str_contains($taskableType, 'Harvest') && $task->taskable->vineyard_row_id) { $vineyardRow = VineyardRow::with('varietyVariation.grapeVariety') ->find($task->taskable->vineyard_row_id); } // For treatment types elseif ($task->taskable->treatment_id) { $treatment = Treatment::with('vineyardRow.varietyVariation.grapeVariety') ->find($task->taskable->treatment_id); if ($treatment) { $vineyardRow = $treatment->vineyardRow; } } } return view('planned-tasks.edit', [ 'task' => $task, 'vineyardRow' => $vineyardRow, 'taskRows' => $taskRows, ]); } public function update(UpdatePlannedTaskRequest $request, PlannedTask $task) { $validated = $request->validated(); // Get selected task IDs (if provided, otherwise just update the single task) $taskIds = $request->input('task_ids', [$task->planned_task_id]); // Get all selected tasks $tasksToUpdate = PlannedTask::with('taskable') ->whereIn('planned_task_id', $taskIds) ->whereNull('execution_date') ->get(); foreach ($tasksToUpdate as $taskToUpdate) { // Update PlannedTask $updateData = [ 'note' => $validated['note'] ?? null, ]; // For spraying and harvest tasks, don't update the date (it's readonly) if (!str_contains($taskToUpdate->taskable_type, 'Spraying') && !str_contains($taskToUpdate->taskable_type, 'Harvest') && isset($validated['planned_date'])) { $updateData['planned_date'] = $validated['planned_date']; } $taskToUpdate->update($updateData); // Update taskable (Treatment/Harvest) specific fields if ($taskToUpdate->taskable) { $taskableData = []; $taskableType = $taskToUpdate->taskable_type; if (str_contains($taskableType, 'Watering')) { $taskableData = [ 'time_interval' => $validated['time_interval'] ?? null, 'amount' => $validated['amount'], ]; } elseif (str_contains($taskableType, 'Fertilization')) { $taskableData = [ 'substance' => $validated['substance'], 'concentration' => $validated['concentration'] ?? null, ]; } elseif (str_contains($taskableType, 'Spraying')) { $taskableData = [ 'pesticide' => $validated['pesticide'], 'concentration' => $validated['concentration'] ?? null, ]; } elseif (str_contains($taskableType, 'Pruning')) { $taskableData = [ 'method' => $validated['method'], 'percentage_removed' => $validated['percentage_removed'] ?? null, ]; } if (!empty($taskableData)) { $taskToUpdate->taskable->update($taskableData); } } } $count = $tasksToUpdate->count(); $message = $count === 1 ? 'Planned task updated successfully.' : "{$count} planned tasks updated successfully."; return redirect()->route('winemaker.planned-tasks') ->with('success', $message); } public function destroy(PlannedTask $task) { // Delete the taskable first (Treatment/Harvest) if ($task->taskable) { $task->taskable->delete(); } // Delete the planned task $task->delete(); return redirect()->route('winemaker.planned-tasks') ->with('success', 'Planned task deleted successfully.'); } }