ultimatepos/Modules/Maintenance/Services/MaintenanceReportService.php

178 lines
6.5 KiB
PHP

<?php
namespace Modules\Maintenance\Services;
use App\Business;
use Modules\Maintenance\Models\Equipment;
use Modules\Maintenance\Models\FailureReport;
use Modules\Maintenance\Models\Overhaul;
use Modules\Maintenance\Models\SparePartConsumption;
use Modules\Maintenance\Models\WorkOrder;
use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Schema;
use Modules\Maintenance\Utils\MaintenanceUtil;
class MaintenanceReportService
{
public function __construct(
protected MaintenanceUtil $maintenanceUtil
) {}
public function equipmentCostReport(Business $business, ?int $equipmentId = null): Collection
{
$query = WorkOrder::where('business_id', $business->id)
->where('status', 'completed')
->with('equipment:id,name,code');
if ($equipmentId) {
$query->where('equipment_id', $equipmentId);
}
return $query->get()
->groupBy('equipment_id')
->map(fn ($orders, $eqId) => [
'equipment_id' => (int) $eqId,
'equipment' => $orders->first()->equipment,
'total_cost' => (int) $orders->sum('cost'),
'work_order_count' => $orders->count(),
])
->values();
}
public function downtimeReport(Business $business, ?string $from = null, ?string $to = null): Collection
{
if (! Schema::hasTable('maintenance_failure_reports')) {
return collect();
}
$query = FailureReport::where('business_id', $business->id)->with('equipment:id,name,code');
if ($from) {
$query->where('reported_at', '>=', $from);
}
if ($to) {
$query->where('reported_at', '<=', $to);
}
return $query->get()->map(fn ($r) => [
'equipment' => $r->equipment,
'failure_type' => $r->failure_type,
'downtime_hours' => (float) $r->downtime_hours,
'repair_hours' => (float) $r->repair_hours,
'cost' => (int) $r->cost,
'reported_at' => $r->reported_at?->toDateTimeString(),
]);
}
public function technicianPerformance(Business $business): Collection
{
return WorkOrder::where('business_id', $business->id)
->where('status', 'completed')
->whereNotNull('assigned_technician_id')
->with('assignedTechnician:id,name')
->get()
->groupBy('assigned_technician_id')
->map(fn ($orders, $techId) => [
'technician_id' => (int) $techId,
'technician' => $orders->first()->assignedTechnician,
'completed_count' => $orders->count(),
'total_labor_hours' => (float) $orders->sum('labor_hours'),
'total_cost' => (int) $orders->sum('cost'),
])
->values();
}
public function sparePartsConsumption(Business $business, ?string $from = null, ?string $to = null): Collection
{
if (! Schema::hasTable('maintenance_spare_part_consumptions')) {
return collect();
}
$query = SparePartConsumption::where('business_id', $business->id)
->with(['sparePart:id,part_number,name', 'equipment:id,name']);
if ($from) {
$query->where('created_at', '>=', $from);
}
if ($to) {
$query->where('created_at', '<=', $to);
}
return $query->orderByDesc('created_at')->get();
}
public function monthlyStatistics(Business $business, int $year, int $month): array
{
$start = Carbon::create($year, $month, 1)->startOfMonth();
$end = $start->copy()->endOfMonth();
$bid = $business->id;
return [
'period' => $start->format('Y-m'),
'period_jalali' => $this->maintenanceUtil->formatMonthLabel($start),
'work_orders_completed' => WorkOrder::where('business_id', $bid)
->where('status', 'completed')
->whereBetween('completed_at', [$start, $end])
->count(),
'overhauls_completed' => Overhaul::where('business_id', $bid)
->where('status', 'completed')
->whereBetween('updated_at', [$start, $end])
->count(),
'failures' => FailureReport::where('business_id', $bid)
->whereBetween('reported_at', [$start, $end])
->count(),
'total_cost' => (int) WorkOrder::where('business_id', $bid)
->where('status', 'completed')
->whereBetween('completed_at', [$start, $end])
->sum('cost'),
'total_downtime_hours' => (float) FailureReport::where('business_id', $bid)
->whereBetween('reported_at', [$start, $end])
->sum('downtime_hours'),
];
}
public function failureAnalysis(Business $business): Collection
{
if (! Schema::hasTable('maintenance_failure_reports')) {
return collect();
}
return FailureReport::where('business_id', $business->id)
->selectRaw('failure_type, count(*) as count, sum(downtime_hours) as total_downtime, sum(cost) as total_cost')
->groupBy('failure_type')
->get();
}
public function exportActivityCsv(Business $business, ?string $from = null, ?string $to = null): array
{
$rows = [];
if (Schema::hasTable('maintenance_activity_logs')) {
$query = \Illuminate\Support\Facades\DB::table('maintenance_activity_logs')
->where('business_id', $business->id);
if ($from) {
$query->where('created_at', '>=', $from);
}
if ($to) {
$query->where('created_at', '<=', $to);
}
foreach ($query->orderByDesc('created_at')->limit(5000)->get() as $log) {
$rows[] = ['activity', $log->created_at, $log->description ?? $log->action, ''];
}
}
$woQuery = WorkOrder::where('business_id', $business->id)->where('status', 'completed');
if ($from) {
$woQuery->where('completed_at', '>=', $from);
}
if ($to) {
$woQuery->where('completed_at', '<=', $to);
}
foreach ($woQuery->orderByDesc('completed_at')->limit(2000)->get() as $wo) {
$rows[] = ['work_order', $wo->completed_at?->toDateTimeString(), $wo->work_order_number, (string) $wo->cost];
}
return $rows;
}
}