where('status', '!=', 'disposed') ->with(['manager', 'subManager']); if ($productionLine) { $equipmentQuery->where('production_line', $productionLine); } if ($equipmentId) { $equipmentQuery->where('id', $equipmentId); } $equipments = $equipmentQuery->orderBy('sort_order')->orderBy('name')->get(); $labels = InspectionCycle::columnLabels($cycle, $period); $result = []; foreach ($equipments as $equipment) { $templates = EquipmentInspectionTemplate::where('equipment_id', $equipment->id) ->where('inspection_cycle', $cycle) ->where('is_active', true) ->orderBy('sort_order') ->get(); if ($templates->isEmpty()) { continue; } $inspection = EquipmentInspection::where('equipment_id', $equipment->id) ->where('inspection_cycle', $cycle) ->where('year_month', $period) ->first(); $details = []; if ($inspection) { $details = EquipmentInspectionDetail::where('inspection_id', $inspection->id) ->get() ->groupBy(function ($d) { return $d->template_item_id.'_'.$d->check_date->format('Y-m-d'); }); } $result[] = [ 'equipment' => $equipment, 'templates' => $templates, 'inspection' => $inspection, 'details' => $details, 'labels' => $labels, 'can_inspect' => $equipment->canInspect(), ]; } return $result; } /** * 하위호환: 기존 getMonthlyInspections 유지 */ public function getMonthlyInspections(string $yearMonth, ?string $productionLine = null, ?int $equipmentId = null): array { return $this->getInspections(InspectionCycle::DAILY, $yearMonth, $productionLine, $equipmentId); } /** * 셀 토글 (점검 결과 순환) */ public function toggleDetail(int $equipmentId, int $templateItemId, string $checkDate, string $cycle = 'daily'): array { $equipment = Equipment::findOrFail($equipmentId); if (! $equipment->canInspect()) { throw new \Exception('점검 권한이 없습니다.'); } $period = InspectionCycle::resolvePeriod($cycle, $checkDate); if ($cycle === InspectionCycle::DAILY) { $holidayDates = InspectionCycle::getHolidayDates($cycle, $period); if (InspectionCycle::isNonWorkingDay($checkDate, $holidayDates)) { throw new \Exception('휴일/주말에는 점검을 기록할 수 없습니다.'); } } $tenantId = session('selected_tenant_id', 1); $inspection = EquipmentInspection::firstOrCreate( [ 'tenant_id' => $tenantId, 'equipment_id' => $equipmentId, 'inspection_cycle' => $cycle, 'year_month' => $period, ], [ 'created_by' => auth()->id(), ] ); $detail = EquipmentInspectionDetail::where('inspection_id', $inspection->id) ->where('template_item_id', $templateItemId) ->where('check_date', $checkDate) ->first(); if ($detail) { $nextResult = EquipmentInspectionDetail::getNextResult($detail->result); if ($nextResult === null) { $detail->delete(); return ['result' => null, 'symbol' => '', 'color' => 'text-gray-400']; } $detail->update(['result' => $nextResult]); } else { $detail = EquipmentInspectionDetail::create([ 'inspection_id' => $inspection->id, 'template_item_id' => $templateItemId, 'check_date' => $checkDate, 'result' => 'good', ]); $nextResult = 'good'; } return [ 'result' => $nextResult, 'symbol' => $detail->fresh()->result_symbol, 'color' => $detail->fresh()->result_color, ]; } /** * 점검 결과 직접 설정 (모바일용) */ public function setResult(int $equipmentId, int $templateItemId, string $checkDate, string $cycle, ?string $result): array { $equipment = Equipment::findOrFail($equipmentId); if (! $equipment->canInspect()) { throw new \Exception('점검 권한이 없습니다.'); } $period = InspectionCycle::resolvePeriod($cycle, $checkDate); if ($cycle === InspectionCycle::DAILY) { $holidayDates = InspectionCycle::getHolidayDates($cycle, $period); if (InspectionCycle::isNonWorkingDay($checkDate, $holidayDates)) { throw new \Exception('휴일/주말에는 점검을 기록할 수 없습니다.'); } } $tenantId = session('selected_tenant_id', 1); $inspection = EquipmentInspection::firstOrCreate( [ 'tenant_id' => $tenantId, 'equipment_id' => $equipmentId, 'inspection_cycle' => $cycle, 'year_month' => $period, ], [ 'created_by' => auth()->id(), ] ); $detail = EquipmentInspectionDetail::where('inspection_id', $inspection->id) ->where('template_item_id', $templateItemId) ->where('check_date', $checkDate) ->first(); if ($result === null) { if ($detail) { $detail->delete(); } return ['result' => null, 'symbol' => '', 'color' => 'text-gray-400']; } if ($detail) { $detail->update(['result' => $result]); } else { $detail = EquipmentInspectionDetail::create([ 'inspection_id' => $inspection->id, 'template_item_id' => $templateItemId, 'check_date' => $checkDate, 'result' => $result, ]); } return [ 'result' => $result, 'symbol' => $detail->fresh()->result_symbol, 'color' => $detail->fresh()->result_color, ]; } public function updateInspectionNotes(int $equipmentId, string $yearMonth, array $data, string $cycle = 'daily'): EquipmentInspection { $tenantId = session('selected_tenant_id', 1); $inspection = EquipmentInspection::firstOrCreate( [ 'tenant_id' => $tenantId, 'equipment_id' => $equipmentId, 'inspection_cycle' => $cycle, 'year_month' => $yearMonth, ], [ 'created_by' => auth()->id(), ] ); $inspection->update(array_merge($data, ['updated_by' => auth()->id()])); return $inspection->fresh(); } /** * 개별 설비 점검 데이터 초기화 (해당 주기/기간) */ public function resetEquipmentInspection(int $equipmentId, string $cycle, string $period): int { $equipment = Equipment::findOrFail($equipmentId); if (! $equipment->canInspect()) { throw new \Exception('점검 권한이 없습니다.'); } $tenantId = session('selected_tenant_id', 1); $inspection = EquipmentInspection::where('tenant_id', $tenantId) ->where('equipment_id', $equipmentId) ->where('inspection_cycle', $cycle) ->where('year_month', $period) ->first(); if (! $inspection) { return 0; } $deleted = EquipmentInspectionDetail::where('inspection_id', $inspection->id)->delete(); $inspection->update([ 'overall_judgment' => null, 'repair_note' => null, 'issue_note' => null, 'inspector_id' => null, 'updated_by' => auth()->id(), ]); return $deleted; } /** * 전체 점검 데이터 초기화 (해당 주기/기간의 모든 설비) */ public function resetAllInspections(string $cycle, string $period): int { $tenantId = session('selected_tenant_id', 1); $inspections = EquipmentInspection::where('tenant_id', $tenantId) ->where('inspection_cycle', $cycle) ->where('year_month', $period) ->get(); if ($inspections->isEmpty()) { return 0; } $totalDeleted = 0; foreach ($inspections as $inspection) { $totalDeleted += EquipmentInspectionDetail::where('inspection_id', $inspection->id)->delete(); $inspection->update([ 'overall_judgment' => null, 'repair_note' => null, 'issue_note' => null, 'inspector_id' => null, 'updated_by' => auth()->id(), ]); } return $totalDeleted; } public function getMonthlyStats(string $yearMonth): array { $totalEquipments = Equipment::where('is_active', true) ->where('status', '!=', 'disposed') ->count(); $inspected = EquipmentInspection::where('year_month', $yearMonth)->count(); $issueCount = EquipmentInspectionDetail::whereHas('inspection', function ($q) use ($yearMonth) { $q->where('year_month', $yearMonth); })->where('result', 'bad')->count(); return [ 'total' => $totalEquipments, 'inspected' => $inspected, 'issue_count' => $issueCount, ]; } public function saveTemplate(int $equipmentId, array $data): EquipmentInspectionTemplate { $tenantId = session('selected_tenant_id', 1); return EquipmentInspectionTemplate::create(array_merge($data, [ 'tenant_id' => $tenantId, 'equipment_id' => $equipmentId, ])); } public function updateTemplate(int $id, array $data): EquipmentInspectionTemplate { $template = EquipmentInspectionTemplate::findOrFail($id); $template->update($data); return $template->fresh(); } public function deleteTemplate(int $id): bool { return EquipmentInspectionTemplate::findOrFail($id)->delete(); } /** * 점검항목을 다른 주기로 복사 */ public function copyTemplatesToCycles(int $equipmentId, string $sourceCycle, array $targetCycles): array { $tenantId = session('selected_tenant_id', 1); $sourceTemplates = EquipmentInspectionTemplate::where('equipment_id', $equipmentId) ->where('inspection_cycle', $sourceCycle) ->where('is_active', true) ->orderBy('sort_order') ->get(); if ($sourceTemplates->isEmpty()) { throw new \Exception('복사할 점검항목이 없습니다.'); } $copiedCount = 0; $skippedCount = 0; foreach ($targetCycles as $targetCycle) { foreach ($sourceTemplates as $template) { $exists = EquipmentInspectionTemplate::where('equipment_id', $equipmentId) ->where('inspection_cycle', $targetCycle) ->where('item_no', $template->item_no) ->exists(); if ($exists) { $skippedCount++; continue; } EquipmentInspectionTemplate::create([ 'tenant_id' => $tenantId, 'equipment_id' => $equipmentId, 'inspection_cycle' => $targetCycle, 'item_no' => $template->item_no, 'check_point' => $template->check_point, 'check_item' => $template->check_item, 'check_timing' => $template->check_timing, 'check_frequency' => $template->check_frequency, 'check_method' => $template->check_method, 'sort_order' => $template->sort_order, 'is_active' => true, ]); $copiedCount++; } } return [ 'copied' => $copiedCount, 'skipped' => $skippedCount, 'source_count' => $sourceTemplates->count(), 'target_cycles' => $targetCycles, ]; } /** * 설비에 등록된 점검주기 목록 반환 (항목이 있는 주기만) */ public function getActiveCycles(int $equipmentId): array { return EquipmentInspectionTemplate::where('equipment_id', $equipmentId) ->where('is_active', true) ->distinct() ->pluck('inspection_cycle') ->toArray(); } }