feat: implement project planning wizard with task, resource allocation, and approval management modules

This commit is contained in:
Ajjj
2026-08-04 15:35:17 +08:00
parent 3c1cd2dada
commit 7cb5494692
12 changed files with 637 additions and 344 deletions

View File

@@ -508,6 +508,43 @@ class ProjectController extends Controller
]);
}
public function saveWizardDetails(Project $project, Request $request)
{
if ($project->current_wizard_step >= 8) {
return redirect()->back()->with('error', 'Cannot update details: This project has been approved and locked.');
}
$validated = $request->validate([
'name' => 'required|string|max:255',
'client_name' => 'nullable|string|max:255',
'description' => 'nullable|string',
'location' => 'nullable|string|max:255',
'contract_value' => 'nullable|numeric|min:0',
'contract_duration' => 'nullable|integer|min:0',
'start_date' => 'nullable|date',
'target_end_date' => 'nullable|date|after_or_equal:start_date',
'project_type' => 'required|string|in:standard,special,extension',
'parent_project_id' => 'nullable|string',
'is_unprofitable' => 'nullable|boolean',
]);
if (!empty($validated['parent_project_id'])) {
$validated['parent_project_id'] = Project::resolveUlidToId($validated['parent_project_id']);
} else {
$validated['parent_project_id'] = null;
}
$validated['is_unprofitable'] = $validated['is_unprofitable'] ?? false;
if ($project->current_wizard_step < 2) {
$validated['current_wizard_step'] = 2;
}
$project->update($validated);
return redirect()->route('projects.wizard', [$project, 'step' => 2])
->with('success', 'Project details saved.');
}
public function saveWizardTasks(Project $project, Request $request)
{
if ($project->current_wizard_step >= 8) {
@@ -764,15 +801,35 @@ class ProjectController extends Controller
public function submitWizardForApproval(Project $project, Request $request)
{
$validated = $request->validate([
'approver_ids' => 'required|array',
'approver_ids' => 'nullable|array',
'approver_ids.*' => 'string',
'notes' => 'nullable|string',
]);
\DB::transaction(function () use ($project, $validated) {
$approverIds = array_map(function ($ulid) {
return User::resolveUlidToId($ulid);
}, $validated['approver_ids']);
$approverIds = [];
if (!empty($validated['approver_ids'])) {
$approverIds = array_map(function ($ulid) {
return User::resolveUlidToId($ulid);
}, $validated['approver_ids']);
} else {
// Auto-target higher-ups: First Super Admin or Admin user
$higherUp = User::where(function ($q) {
$q->where('user_type', 'admin')
->orWhereHas('roles', function ($rq) {
$rq->whereIn('name', ['Super Admin', 'admin', 'Admin']);
});
})->first();
if ($higherUp) {
$approverIds = [$higherUp->id];
} else {
$firstAdmin = User::first();
if ($firstAdmin) {
$approverIds = [$firstAdmin->id];
}
}
}
$approvalService = app(\Modules\ApprovalWorkflow\Services\ApprovalService::class);
$approvalService->createChain(