diff --git a/Modules/Project/Entities/ProjectStages.php b/Modules/Project/Entities/ProjectStages.php
new file mode 100644
index 0000000000..c7a18c4c28
--- /dev/null
+++ b/Modules/Project/Entities/ProjectStages.php
@@ -0,0 +1,17 @@
+belongsTo(Project::class, 'project_id', 'id');
+ }
+}
diff --git a/Modules/Project/Entities/ProjectStagesListing.php b/Modules/Project/Entities/ProjectStagesListing.php
new file mode 100644
index 0000000000..5136c81199
--- /dev/null
+++ b/Modules/Project/Entities/ProjectStagesListing.php
@@ -0,0 +1,14 @@
+authorizeResource(Project::class);
$this->service = $service;
+ $this->projectService = $projectService;
}
/**
@@ -109,6 +112,7 @@ public function show(Request $request, Project $project)
'effortData' => $effortData,
'totalEffort' => json_encode($totalEffort),
'dailyEffort' => $dailyEffort,
+ 'stages' => $this->projectService->getProjectStages($project),
]);
}
@@ -197,6 +201,47 @@ public function projectResource()
'jobName' => $jobName,
]);
}
+
+ public function manageStage(Request $request)
+ {
+ $validatedData = $request->validate([
+ 'project_id' => 'required|integer|exists:projects,id',
+ 'newStages' => 'nullable|array',
+ 'newStages.*.stage_name' => 'required|string',
+ 'newStages.*.comments' => 'nullable|string',
+ 'newStages.*.status' => 'nullable|string',
+ 'newStages.*.expected_end_date' => 'required|date',
+ 'deletedStages' => 'nullable|array',
+ 'deletedStages.*' => 'required|integer|exists:project_old_stages,id',
+ 'updatedStages' => 'nullable|array',
+ 'updatedStages.*.id' => 'required|integer|exists:project_old_stages,id',
+ ]);
+
+ if (empty($validatedData['deletedStages']) && empty($validatedData['newStages']) && empty($validatedData['updatedStages'])) {
+ return response()->json([
+ 'status' => 400,
+ 'error' => 'No New Changes Detected',
+ ], 400);
+ }
+
+ if (! empty($validatedData['deletedStages'])) {
+ $this->projectService->removeStage($validatedData['deletedStages']);
+ }
+
+ if (! empty($validatedData['newStages'])) {
+ $this->projectService->storeStage($validatedData['newStages'], $validatedData['project_id']);
+ }
+
+ if (! empty($validatedData['updatedStages'])) {
+ $this->projectService->updateStage($validatedData['updatedStages']);
+ }
+
+ return response()->json([
+ 'status' => 200,
+ 'success' => 'Stages managed successfully!',
+ ]);
+ }
+
// storing Contract related data here
private function getContractData(Project $project)
{
diff --git a/Modules/Project/Resources/views/layouts/master.blade.php b/Modules/Project/Resources/views/layouts/master.blade.php
index ed4b265e74..eaa1a8fb1d 100644
--- a/Modules/Project/Resources/views/layouts/master.blade.php
+++ b/Modules/Project/Resources/views/layouts/master.blade.php
@@ -4,4 +4,5 @@
@endsection
@section('css_scripts')
+
@endsection
diff --git a/Modules/Project/Resources/views/show.blade.php b/Modules/Project/Resources/views/show.blade.php
index d54c4da754..95c7737eac 100644
--- a/Modules/Project/Resources/views/show.blade.php
+++ b/Modules/Project/Resources/views/show.blade.php
@@ -294,7 +294,7 @@
@can('finance_reports.view')
-
-
@endcan
+
+
+ @include('project::subviews.project-stages')
+
+
+
@endsection
+@section('vue_scripts')
+
+@endsection
\ No newline at end of file
diff --git a/Modules/Project/Resources/views/subviews/project-stages.blade.php b/Modules/Project/Resources/views/subviews/project-stages.blade.php
new file mode 100644
index 0000000000..b2ed7455a9
--- /dev/null
+++ b/Modules/Project/Resources/views/subviews/project-stages.blade.php
@@ -0,0 +1,85 @@
+
diff --git a/Modules/Project/Routes/web.php b/Modules/Project/Routes/web.php
index 79c151a686..131dc14a95 100644
--- a/Modules/Project/Routes/web.php
+++ b/Modules/Project/Routes/web.php
@@ -22,5 +22,6 @@
Route::delete('client/{project}/edit', 'ProjectController@destroy')->name('project.destroy');
Route::post('/project-fte-export', 'ProjectController@projectFTEExport')->name('project.fte.export');
Route::get('/project-resource', 'ProjectController@projectResource')->name('project.resource-requirement');
+ Route::post('/projects/manage-stage', 'ProjectController@manageStage')->name('projects.manage-stage');
//Route::get('/', 'ProjectController@edit')->name('project.edit');
});
diff --git a/Modules/Project/Services/ProjectService.php b/Modules/Project/Services/ProjectService.php
index e6b7850287..98a137f197 100644
--- a/Modules/Project/Services/ProjectService.php
+++ b/Modules/Project/Services/ProjectService.php
@@ -17,6 +17,8 @@
use Modules\Project\Entities\ProjectMeta;
use Modules\Project\Entities\ProjectRepository;
use Modules\Project\Entities\ProjectResourceRequirement;
+use Modules\Project\Entities\ProjectStages;
+use Modules\Project\Entities\ProjectStagesListing;
use Modules\Project\Entities\ProjectTeamMember;
use Modules\Project\Entities\ProjectTeamMembersEffort;
use Modules\Project\Exports\ProjectFTEExport;
@@ -381,6 +383,84 @@ public function getProjectApprovedPipelineHour($project)
];
}
+ public function getProjectStages(Project $project)
+ {
+ $project_id = $project->id;
+ $stages = ProjectStages::where('project_id', $project_id)->orderBy('id')->get();
+
+ return $stages;
+ }
+
+ public function storeStage(array $newStages, int $projectId)
+ {
+ foreach ($newStages as $stage) {
+ $stageData = $this->prepareStageData($stage);
+
+ ProjectStages::create(array_merge($stageData, [
+ 'project_id' => $projectId,
+ 'created_at' => now(),
+ 'updated_at' => now(),
+ ]));
+ }
+ }
+
+ public function updateStage(array $updatedStages)
+ {
+ foreach ($updatedStages as $stage) {
+ $stageData = $this->prepareStageData($stage);
+
+ $existingStage = ProjectStages::find($stage['id']);
+ if ($existingStage) {
+ $existingStage->update(array_merge($stageData, [
+ 'updated_at' => now(),
+ ]));
+ }
+ }
+ }
+
+ public function removeStage(array $idArr)
+ {
+ ProjectStages::whereIn('id', $idArr)->delete();
+ }
+
+ public function createProjectStageList(string $stageName)
+ {
+ $formattedStageName = strtolower($stageName);
+ ProjectStagesListing::firstOrCreate(
+ ['name' => $formattedStageName]
+ );
+ }
+
+ private function prepareStageData(array $stage): array
+ {
+ $startDate = null;
+ $endDate = null;
+ $duration = null;
+
+ if ($stage['start_date']) {
+ $formattedStartDate = Carbon::parse($stage['start_date']);
+ $startDate = $formattedStartDate->setTimezone(config('app.timezone'))->format(config('constants.datetime_format'));
+ }
+
+ if ($stage['end_date']) {
+ $formattedEndDate = Carbon::parse($stage['end_date']);
+ $endDate = $formattedEndDate->setTimezone(config('app.timezone'))->format(config('constants.datetime_format'));
+ $duration = Carbon::parse($stage['start_date'])->diffInSeconds($formattedEndDate);
+ }
+
+ $this->createProjectStageList($stage['stage_name']);
+
+ return [
+ 'stage_name' => $stage['stage_name'],
+ 'comments' => $stage['comments'] ?? null,
+ 'status' => $stage['status'] ?? 'pending',
+ 'start_date' => $startDate,
+ 'end_date' => $endDate,
+ 'expected_end_date' => $stage['expected_end_date'],
+ 'duration' => $duration,
+ ];
+ }
+
private function getListTabCounts($filters, $showAllProjects, $userId)
{
$counts = [
diff --git a/database/migrations/2024_06_15_142418_update_project_old_stage_table.php b/database/migrations/2024_06_15_142418_update_project_old_stage_table.php
new file mode 100644
index 0000000000..ab01c5bac3
--- /dev/null
+++ b/database/migrations/2024_06_15_142418_update_project_old_stage_table.php
@@ -0,0 +1,60 @@
+dropForeign(['project_id']);
+
+ $table->dropColumn(['project_id', 'name', 'cost', 'currency_cost', 'type', 'cost_include_gst']);
+ $table->text('comments')->nullable();
+ $table->datetime('start_date')->nullable()->change();
+ $table->datetime('end_date')->nullable()->change();
+ $table->date('expected_end_date')->nullable()->after('end_date');
+ });
+ Schema::table('project_old_stages', function (Blueprint $table) {
+ $table->unsignedBigInteger('project_id')->nullable()->after('id');
+ $table->text('stage_name')->after('project_id');
+ $table->text('status')->after('stage_name')->nullable();
+ $table->Integer('duration')->after('status')->nullable();
+ $table->foreign('project_id')->references('id')->on('projects');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('project_old_stages', function (Blueprint $table) {
+ $table->dropColumn('comments');
+ $table->dropColumn('stage_name');
+ $table->dropColumn('status');
+ $table->dropColumn('project_id');
+ $table->dropColumn('duration');
+ $table->dropColumn('expected_end_date');
+ });
+ Schema::table('project_old_stages', function (Blueprint $table) {
+ $table->string('name')->nullable();
+ $table->decimal('cost', 8, 2)->nullable();
+ $table->string('currency_cost')->nullable();
+ $table->string('type')->nullable();
+ $table->string('cost_include_gst')->nullable();
+ $table->date('start_date')->nullable()->change();
+ $table->date('end_date')->nullable()->change();
+ $table->unsignedInteger('project_id');
+ });
+ }
+}
diff --git a/database/migrations/2024_06_24_181032_create_project_stages_new_listing_table.php b/database/migrations/2024_06_24_181032_create_project_stages_new_listing_table.php
new file mode 100644
index 0000000000..0c80f5fcc9
--- /dev/null
+++ b/database/migrations/2024_06_24_181032_create_project_stages_new_listing_table.php
@@ -0,0 +1,32 @@
+increments('id');
+ $table->string('name');
+ $table->timestamps();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::dropIfExists('project_stages_listing');
+ }
+}