first&last
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Priority;
|
||||
use App\Models\RequestType;
|
||||
use App\Models\ServiceRequest;
|
||||
use App\Models\Status;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class ReportService
|
||||
{
|
||||
public function requestBaseQuery(array $filters = []): Builder
|
||||
{
|
||||
return ServiceRequest::query()
|
||||
->with(['assignee', 'type', 'status', 'priority'])
|
||||
->when($filters['date_from'] ?? null, fn (Builder $q, $v) => $q->whereDate('created_at', '>=', $v))
|
||||
->when($filters['date_to'] ?? null, fn (Builder $q, $v) => $q->whereDate('created_at', '<=', $v))
|
||||
->when($filters['technician_id'] ?? null, fn (Builder $q, $v) => $q->where('assigned_to', $v))
|
||||
->when($filters['type_id'] ?? null, fn (Builder $q, $v) => $q->where('type_id', $v))
|
||||
->when($filters['status_id'] ?? null, fn (Builder $q, $v) => $q->where('status_id', $v));
|
||||
}
|
||||
|
||||
public function requestsByStatus(array $filters = []): Collection
|
||||
{
|
||||
return $this->requestBaseQuery($filters)
|
||||
->selectRaw('status_id, COUNT(*) as total')
|
||||
->groupBy('status_id')
|
||||
->get()
|
||||
->map(function ($item) {
|
||||
$status = Status::query()->find($item->status_id);
|
||||
|
||||
return [
|
||||
'status' => $status?->name ?? 'Неизвестно',
|
||||
'color' => $status?->color_hex ?? '#2563eb',
|
||||
'total' => (int) $item->total,
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function requestsByPriority(array $filters = []): Collection
|
||||
{
|
||||
return $this->requestBaseQuery($filters)
|
||||
->selectRaw('priority_id, COUNT(*) as total')
|
||||
->groupBy('priority_id')
|
||||
->get()
|
||||
->map(fn ($item) => [
|
||||
'priority' => Priority::query()->find($item->priority_id)?->name,
|
||||
'total' => (int) $item->total,
|
||||
]);
|
||||
}
|
||||
|
||||
public function technicianPerformance(array $filters = []): Collection
|
||||
{
|
||||
$technicians = User::query()->where('role', 'technician')->get();
|
||||
|
||||
return $technicians->map(function (User $tech) use ($filters) {
|
||||
$query = $this->requestBaseQuery($filters)->where('assigned_to', $tech->id);
|
||||
$assigned = (clone $query)->count();
|
||||
$resolved = (clone $query)->whereHas('status', fn (Builder $q) => $q->whereIn('slug', ['resolved', 'closed']))->count();
|
||||
$overdue = (clone $query)->overdue()->count();
|
||||
$avgResolution = (clone $query)
|
||||
->whereNotNull('completed_at')
|
||||
->selectRaw('AVG(TIMESTAMPDIFF(HOUR, created_at, completed_at)) as avg_hours')
|
||||
->value('avg_hours');
|
||||
$rating = (clone $query)->whereNotNull('client_rating')->avg('client_rating');
|
||||
|
||||
return [
|
||||
'technician' => $tech->name,
|
||||
'assigned' => $assigned,
|
||||
'resolved' => $resolved,
|
||||
'avg_resolution_hours' => $avgResolution ? round((float) $avgResolution, 1) : 0,
|
||||
'rating' => $rating ? round((float) $rating, 2) : 0,
|
||||
'overdue' => $overdue,
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function slaCompliance(array $filters = []): Collection
|
||||
{
|
||||
$rows = $this->requestBaseQuery($filters)->with('type')->get()->groupBy('type_id');
|
||||
|
||||
return $rows->map(function (Collection $requests, $typeId) {
|
||||
$type = RequestType::query()->find($typeId);
|
||||
$total = $requests->count();
|
||||
$withinSla = $requests
|
||||
->filter(fn (ServiceRequest $request) => $request->completed_at && $request->deadline_at && $request->completed_at->lte($request->deadline_at))
|
||||
->count();
|
||||
|
||||
return [
|
||||
'type' => $type?->name ?? 'Неизвестно',
|
||||
'total' => $total,
|
||||
'within_sla' => $withinSla,
|
||||
'percent' => $total > 0 ? round(($withinSla / $total) * 100, 2) : 0,
|
||||
];
|
||||
})->values();
|
||||
}
|
||||
|
||||
public function equipmentFailureFrequency(array $filters = []): Collection
|
||||
{
|
||||
return $this->requestBaseQuery($filters)
|
||||
->whereNotNull('equipment_id')
|
||||
->with('equipment')
|
||||
->get()
|
||||
->groupBy('equipment_id')
|
||||
->map(fn (Collection $requests, $equipmentId) => [
|
||||
'equipment' => $requests->first()?->equipment?->name ?? 'Неизвестно',
|
||||
'total_requests' => $requests->count(),
|
||||
'open' => $requests->filter(fn (ServiceRequest $r) => !$r->status?->is_final)->count(),
|
||||
'closed' => $requests->filter(fn (ServiceRequest $r) => $r->status?->is_final)->count(),
|
||||
])
|
||||
->values();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user