chore: update document approval workflow and bug fixes
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\TimelineScheduling\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Modules\ProjectManagement\Enums\WeatherCondition;
|
||||
use Modules\ProjectManagement\Models\Project;
|
||||
use Modules\ProjectManagement\Models\ProjectMilestone;
|
||||
|
||||
class MilestoneController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$projectUlid = $request->query('project');
|
||||
$project = null;
|
||||
|
||||
if ($projectUlid) {
|
||||
$project = Project::where('ulid', $projectUlid)->firstOrFail();
|
||||
$project->load([
|
||||
'tasks' => fn ($q) => $q->select('id', 'project_id')->with('delays'),
|
||||
'milestones',
|
||||
]);
|
||||
}
|
||||
|
||||
return \Inertia\Inertia::render('TimelineScheduling::Timeline/Index', [
|
||||
'project' => $project,
|
||||
'projects' => Project::select('id', 'ulid', 'name')->get(),
|
||||
'milestones' => $project ? $project->milestones->map(fn ($m) => array_merge($m->toArray(), [
|
||||
'is_completed' => $m->is_completed,
|
||||
'is_overdue' => $m->is_overdue,
|
||||
'status' => $m->status,
|
||||
'status_color' => $m->status_color,
|
||||
'days_delayed' => $m->days_delayed,
|
||||
])) : [],
|
||||
'milestoneStats' => $project ? [
|
||||
'total' => $project->milestones->count(),
|
||||
'completed' => $project->milestones->where('actual_date', '!=', null)->count(),
|
||||
'completion_percentage' => $project->milestone_completion,
|
||||
'weather_delay_days' => $project->weather_delay_days,
|
||||
] : null,
|
||||
'weatherConditions' => collect(WeatherCondition::cases())->map(fn ($c) => [
|
||||
'value' => $c->value,
|
||||
'label' => $c->label(),
|
||||
'icon' => $c->icon(),
|
||||
]),
|
||||
'allowedTransitions' => $project ? collect($project->status->allowedTransitions())->map(fn ($s) => [
|
||||
'value' => $s->value,
|
||||
'label' => $s->label(),
|
||||
]) : [],
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'project_id' => 'required|exists:projects,id',
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'planned_date' => 'nullable|date',
|
||||
'weight_percentage' => 'required|numeric|min:0|max:100',
|
||||
]);
|
||||
|
||||
$project = Project::findOrFail($validated['project_id']);
|
||||
$validated['sort_order'] = $project->milestones()->count();
|
||||
$validated['is_default'] = false;
|
||||
|
||||
ProjectMilestone::create($validated);
|
||||
|
||||
return back()->with('success', 'Milestone added.');
|
||||
}
|
||||
|
||||
public function update(Request $request, ProjectMilestone $milestone)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => 'sometimes|required|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'planned_date' => 'nullable|date',
|
||||
'actual_date' => 'nullable|date',
|
||||
'weight_percentage' => 'sometimes|numeric|min:0|max:100',
|
||||
'weather_impacted' => 'sometimes|boolean',
|
||||
'weather_condition' => 'nullable|string',
|
||||
'weather_delay_days' => 'sometimes|integer|min:0',
|
||||
'weather_notes' => 'nullable|string|max:2000',
|
||||
]);
|
||||
|
||||
// Clear weather fields if not impacted
|
||||
if (isset($validated['weather_impacted']) && !$validated['weather_impacted']) {
|
||||
$validated['weather_condition'] = null;
|
||||
$validated['weather_delay_days'] = 0;
|
||||
$validated['weather_notes'] = null;
|
||||
}
|
||||
|
||||
$milestone->update($validated);
|
||||
|
||||
return back()->with('success', 'Milestone updated.');
|
||||
}
|
||||
|
||||
public function destroy(ProjectMilestone $milestone)
|
||||
{
|
||||
$milestone->delete();
|
||||
|
||||
return back()->with('success', 'Milestone removed.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\TimelineScheduling\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
use Modules\ProjectManagement\Models\Project;
|
||||
use Modules\ProjectManagement\Models\Task;
|
||||
use Modules\TimelineScheduling\Models\Milestone;
|
||||
use Modules\TimelineScheduling\Models\TaskDependency;
|
||||
use Modules\TimelineScheduling\Services\GanttDataTransformer;
|
||||
|
||||
class ScheduleController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private GanttDataTransformer $ganttTransformer,
|
||||
) {}
|
||||
|
||||
// --- Gantt view for a project ---
|
||||
public function gantt(Project $project)
|
||||
{
|
||||
$ganttData = $this->ganttTransformer->transform($project->id);
|
||||
$milestones = Milestone::where('project_id', $project->id)->orderBy('target_date')->get();
|
||||
$tasks = Task::where('project_id', $project->id)->select('id', 'ulid', 'name')->get();
|
||||
|
||||
return Inertia::render('TimelineScheduling::Schedule/Gantt', [
|
||||
'project' => $project->only('id', 'ulid', 'name', 'code'),
|
||||
'ganttData' => $ganttData,
|
||||
'milestones' => $milestones,
|
||||
'tasks' => $tasks,
|
||||
]);
|
||||
}
|
||||
|
||||
// --- API: Gantt JSON data ---
|
||||
public function ganttData(Project $project)
|
||||
{
|
||||
return response()->json($this->ganttTransformer->transform($project->id));
|
||||
}
|
||||
|
||||
// --- Update task schedule (drag-and-drop) ---
|
||||
public function updateSchedule(Request $request, Project $project, Task $task)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'start_date' => 'required|date',
|
||||
'end_date' => 'required|date|after_or_equal:start_date',
|
||||
]);
|
||||
|
||||
$task->update($validated);
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
||||
// --- Dependencies ---
|
||||
public function storeDependency(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'task_id' => 'required|string',
|
||||
'predecessor_id' => 'required|string|different:task_id',
|
||||
'dependency_type' => 'required|in:FS,FF,SS,SF',
|
||||
'lag_days' => 'nullable|integer',
|
||||
]);
|
||||
|
||||
$taskId = Task::resolveUlidToId($validated['task_id']);
|
||||
$predecessorId = Task::resolveUlidToId($validated['predecessor_id']);
|
||||
|
||||
TaskDependency::updateOrCreate(
|
||||
['task_id' => $taskId, 'predecessor_id' => $predecessorId],
|
||||
['dependency_type' => $validated['dependency_type'], 'lag_days' => $validated['lag_days'] ?? 0],
|
||||
);
|
||||
|
||||
return back()->with('success', 'Dependency added.');
|
||||
}
|
||||
|
||||
public function destroyDependency(TaskDependency $dependency)
|
||||
{
|
||||
$dependency->delete();
|
||||
return back()->with('success', 'Dependency removed.');
|
||||
}
|
||||
|
||||
// --- Milestones ---
|
||||
public function storeMilestone(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'project_id' => 'required|string',
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
'target_date' => 'required|date',
|
||||
'is_critical' => 'nullable|boolean',
|
||||
]);
|
||||
|
||||
$validated['project_id'] = Project::resolveUlidToId($validated['project_id']);
|
||||
|
||||
Milestone::create($validated);
|
||||
|
||||
return back()->with('success', 'Milestone created.');
|
||||
}
|
||||
|
||||
public function achieveMilestone(Milestone $milestone)
|
||||
{
|
||||
$milestone->update(['achieved_date' => now()->toDateString()]);
|
||||
return back()->with('success', 'Milestone marked as achieved.');
|
||||
}
|
||||
|
||||
public function destroyMilestone(Milestone $milestone)
|
||||
{
|
||||
$milestone->delete();
|
||||
return back()->with('success', 'Milestone deleted.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\TimelineScheduling\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TimelineSchedulingController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('timelinescheduling::index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('timelinescheduling::create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request) {}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
return view('timelinescheduling::show');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
return view('timelinescheduling::edit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id) {}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id) {}
|
||||
}
|
||||
Reference in New Issue
Block a user