Files
sam-manage/app/Services/Roadmap/RoadmapPlanService.php

186 lines
5.3 KiB
PHP
Raw Normal View History

<?php
namespace App\Services\Roadmap;
use App\Models\Admin\AdminRoadmapMilestone;
use App\Models\Admin\AdminRoadmapPlan;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
class RoadmapPlanService
{
public function getPlans(array $filters = [], int $perPage = 15): LengthAwarePaginator
{
$query = AdminRoadmapPlan::query()
->withCount('milestones')
->withTrashed();
if (! empty($filters['search'])) {
$search = $filters['search'];
$query->where(function ($q) use ($search) {
$q->where('title', 'like', "%{$search}%")
->orWhere('description', 'like', "%{$search}%");
});
}
if (! empty($filters['status'])) {
$query->where('status', $filters['status']);
}
if (! empty($filters['category'])) {
$query->where('category', $filters['category']);
}
if (! empty($filters['priority'])) {
$query->where('priority', $filters['priority']);
}
if (! empty($filters['phase'])) {
$query->where('phase', $filters['phase']);
}
if (isset($filters['trashed'])) {
if ($filters['trashed'] === 'only') {
$query->onlyTrashed();
}
}
$sortBy = $filters['sort_by'] ?? 'sort_order';
$sortDirection = $filters['sort_direction'] ?? 'asc';
$query->orderBy($sortBy, $sortDirection)->orderBy('id', 'desc');
return $query->paginate($perPage);
}
public function getTimelineData(?string $phase = null): array
{
$query = AdminRoadmapPlan::query()
->whereIn('status', [
AdminRoadmapPlan::STATUS_PLANNED,
AdminRoadmapPlan::STATUS_IN_PROGRESS,
AdminRoadmapPlan::STATUS_COMPLETED,
AdminRoadmapPlan::STATUS_DELAYED,
])
->withCount('milestones')
->orderBy('phase')
->orderBy('sort_order')
->orderBy('start_date');
if ($phase) {
$query->where('phase', $phase);
}
$plans = $query->get();
$grouped = [];
foreach (AdminRoadmapPlan::getPhases() as $key => $label) {
$phasePlans = $plans->where('phase', $key);
if ($phase && $key !== $phase) {
continue;
}
$grouped[$key] = [
'label' => $label,
'plans' => $phasePlans->values(),
];
}
return $grouped;
}
public function getStats(): array
{
return [
'total' => AdminRoadmapPlan::count(),
'planned' => AdminRoadmapPlan::status(AdminRoadmapPlan::STATUS_PLANNED)->count(),
'in_progress' => AdminRoadmapPlan::status(AdminRoadmapPlan::STATUS_IN_PROGRESS)->count(),
'completed' => AdminRoadmapPlan::status(AdminRoadmapPlan::STATUS_COMPLETED)->count(),
'delayed' => AdminRoadmapPlan::status(AdminRoadmapPlan::STATUS_DELAYED)->count(),
'cancelled' => AdminRoadmapPlan::status(AdminRoadmapPlan::STATUS_CANCELLED)->count(),
];
}
public function getDashboardSummary(): array
{
$stats = $this->getStats();
$timeline = $this->getTimelineData();
return [
'stats' => $stats,
'timeline' => $timeline,
];
}
public function getPlanById(int $id, bool $withTrashed = false): ?AdminRoadmapPlan
{
$query = AdminRoadmapPlan::query()
->with(['milestones' => function ($q) {
$q->orderBy('sort_order')->orderBy('id');
}, 'milestones.assignee', 'creator', 'updater'])
->withCount('milestones');
if ($withTrashed) {
$query->withTrashed();
}
return $query->find($id);
}
public function createPlan(array $data): AdminRoadmapPlan
{
$data['created_by'] = auth()->id();
return AdminRoadmapPlan::create($data);
}
public function updatePlan(int $id, array $data): bool
{
$plan = AdminRoadmapPlan::findOrFail($id);
$data['updated_by'] = auth()->id();
return $plan->update($data);
}
public function deletePlan(int $id): bool
{
$plan = AdminRoadmapPlan::findOrFail($id);
$plan->deleted_by = auth()->id();
$plan->save();
return $plan->delete();
}
public function restorePlan(int $id): bool
{
$plan = AdminRoadmapPlan::onlyTrashed()->findOrFail($id);
$plan->deleted_by = null;
return $plan->restore();
}
public function changeStatus(int $id, string $status): AdminRoadmapPlan
{
$plan = AdminRoadmapPlan::findOrFail($id);
$plan->status = $status;
$plan->updated_by = auth()->id();
$plan->save();
return $plan;
}
public function recalculateProgress(int $planId): void
{
$plan = AdminRoadmapPlan::findOrFail($planId);
$total = $plan->milestones()->count();
if ($total === 0) {
return;
}
$completed = $plan->milestones()
->where('status', AdminRoadmapMilestone::STATUS_COMPLETED)
->count();
$plan->progress = (int) round(($completed / $total) * 100);
$plan->save();
}
}