182 lines
6.1 KiB
PHP
182 lines
6.1 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\VarietyVariation;
|
|
use App\Models\VineyardRow;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Support\Carbon;
|
|
|
|
class VineyardMapController extends Controller
|
|
{
|
|
/**
|
|
* Display a read-only vineyard map with available actions.
|
|
*/
|
|
public function index()
|
|
{
|
|
$rows = VineyardRow::with([
|
|
'varietyVariation.grapeVariety',
|
|
'treatments' => function ($query) {
|
|
$query->latest('created_at');
|
|
},
|
|
'sprayings' => function ($query) {
|
|
$query->with('plannedTask')->orderByDesc('created_at');
|
|
},
|
|
'harvests' => function ($query) {
|
|
$query->with('plannedTask')->orderByDesc('date');
|
|
},
|
|
])->get();
|
|
|
|
$actionGroups = [
|
|
'Treatment' => [
|
|
'watering',
|
|
'pruning',
|
|
'fertilisation',
|
|
'pesticide',
|
|
],
|
|
'Manage Crops' => [
|
|
'harvest',
|
|
'add-plants',
|
|
'discard-plants',
|
|
],
|
|
];
|
|
|
|
return view('vineyard.map.index', [
|
|
'rows' => $this->formatRows($rows),
|
|
'actions' => array_merge(...array_values($actionGroups)),
|
|
'actionGroups' => $actionGroups,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Display the editable vineyard map.
|
|
*/
|
|
public function edit()
|
|
{
|
|
$rows = VineyardRow::with(['varietyVariation.grapeVariety'])->get();
|
|
$variations = VarietyVariation::with('grapeVariety')
|
|
->orderBy('grape_variety_id')
|
|
->get()
|
|
->map(function (VarietyVariation $variation) {
|
|
$grape = $variation->grapeVariety;
|
|
$label = $grape
|
|
? sprintf('%s — %s', $grape->variety_name, ucfirst($variation->color))
|
|
: ucfirst($variation->color);
|
|
|
|
return [
|
|
'id' => $variation->getKey(),
|
|
'label' => $label,
|
|
];
|
|
});
|
|
|
|
return view('vineyard.map.edit', [
|
|
'rows' => $this->formatRows($rows),
|
|
'statuses' => ['active', 'inactive', 'replanting', 'discarded'],
|
|
'variationOptions' => $variations,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Transform rows into a structure suitable for the front-end map.
|
|
*/
|
|
protected function formatRows(Collection $rows): Collection
|
|
{
|
|
return $rows->map(function (VineyardRow $row) {
|
|
[$x, $y] = $this->parseLocation($row->location);
|
|
|
|
$variation = $row->varietyVariation;
|
|
$grapeVariety = $variation?->grapeVariety;
|
|
|
|
$lastTreatmentDate = optional($row->treatments->first())->created_at;
|
|
|
|
$pesticideCompleted = $row->sprayings->map(function ($spraying) {
|
|
$executionDate = optional($spraying->plannedTask)->execution_date;
|
|
if ($executionDate) {
|
|
return Carbon::parse($executionDate)->toDateString();
|
|
}
|
|
|
|
return optional($spraying->created_at)?->toDateString();
|
|
})->filter()->unique()->sort()->values()->all();
|
|
|
|
$pesticidePlanned = $row->sprayings->map(function ($spraying) {
|
|
$plannedDate = optional($spraying->plannedTask)->planned_date;
|
|
if ($plannedDate) {
|
|
return Carbon::parse($plannedDate)->toDateString();
|
|
}
|
|
|
|
return null;
|
|
})->filter()->unique()->sort()->values()->all();
|
|
|
|
$harvestCompleted = $row->harvests->map(function ($harvest) {
|
|
$executionDate = optional($harvest->plannedTask)->execution_date;
|
|
if ($executionDate) {
|
|
return Carbon::parse($executionDate)->toDateString();
|
|
}
|
|
|
|
$harvestDate = $harvest->date;
|
|
return $harvestDate ? Carbon::parse($harvestDate)->toDateString() : null;
|
|
})->filter()->unique()->sort()->values()->all();
|
|
|
|
$harvestPlanned = $row->harvests->map(function ($harvest) {
|
|
$plannedDate = optional($harvest->plannedTask)->planned_date;
|
|
if ($plannedDate) {
|
|
return Carbon::parse($plannedDate)->toDateString();
|
|
}
|
|
|
|
return null;
|
|
})->filter()->unique()->sort()->values()->all();
|
|
|
|
return [
|
|
'id' => $row->getKey(),
|
|
'location' => [
|
|
'x' => $x,
|
|
'y' => $y,
|
|
],
|
|
'dimensions' => [
|
|
'width' => 1,
|
|
'height' => 1,
|
|
],
|
|
'vine_count' => $row->vine_count,
|
|
'status' => $row->status,
|
|
'notes' => $row->notes,
|
|
'planting_year' => $row->planting_year,
|
|
'variety' => $variation ? [
|
|
'id' => $variation->getKey(),
|
|
'color' => $variation->color,
|
|
'label' => $grapeVariety
|
|
? sprintf('%s — %s', $grapeVariety->variety_name, ucfirst($variation->color))
|
|
: ucfirst($variation->color),
|
|
] : null,
|
|
'last_treatment_at' => $lastTreatmentDate,
|
|
'timeline' => [
|
|
'pesticide' => [
|
|
'completed' => $pesticideCompleted,
|
|
'planned' => $pesticidePlanned,
|
|
],
|
|
'harvest' => [
|
|
'completed' => $harvestCompleted,
|
|
'planned' => $harvestPlanned,
|
|
],
|
|
],
|
|
];
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Parse the "x,y" string stored on vineyard rows.
|
|
*/
|
|
protected function parseLocation(?string $location): array
|
|
{
|
|
if (blank($location)) {
|
|
return [0, 0];
|
|
}
|
|
|
|
$parts = Str::of($location)->explode(',')->map(fn ($fragment) => (int) trim($fragment));
|
|
|
|
return [
|
|
$parts->get(0, 0),
|
|
$parts->get(1, 0),
|
|
];
|
|
}
|
|
}
|