From e061faadc205fb4bf21ee81a44ec4c3f5389eaac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Tue, 10 Mar 2026 17:55:00 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20[QMS]=20Auditable=20trait=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95=20+=20=ED=92=88=EC=A7=88=20?= =?UTF-8?q?=EB=8D=94=EB=AF=B8=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20Seeder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AuditChecklist.php: App\Models\Traits → App\Traits 경로 수정 - QualityDummyDataSeeder: 3개 품질 페이지용 더미 데이터 생성 - 품질관리서 10건, 실적신고 6건, 점검표 2건(Q1/Q2), 항목 54건, 기준문서 114건 Co-Authored-By: Claude Opus 4.6 --- app/Models/Qualitys/AuditChecklist.php | 4 +- database/seeders/QualityDummyDataSeeder.php | 608 ++++++++++++++++++++ 2 files changed, 610 insertions(+), 2 deletions(-) create mode 100644 database/seeders/QualityDummyDataSeeder.php diff --git a/app/Models/Qualitys/AuditChecklist.php b/app/Models/Qualitys/AuditChecklist.php index af878d5..d620270 100644 --- a/app/Models/Qualitys/AuditChecklist.php +++ b/app/Models/Qualitys/AuditChecklist.php @@ -2,8 +2,8 @@ namespace App\Models\Qualitys; -use App\Models\Traits\Auditable; -use App\Models\Traits\BelongsToTenant; +use App\Traits\Auditable; +use App\Traits\BelongsToTenant; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\SoftDeletes; diff --git a/database/seeders/QualityDummyDataSeeder.php b/database/seeders/QualityDummyDataSeeder.php new file mode 100644 index 0000000..63c007c --- /dev/null +++ b/database/seeders/QualityDummyDataSeeder.php @@ -0,0 +1,608 @@ +where('tenant_id', $tenantId) + ->where('quality_doc_number', 'like', 'KD-QD-202604-%') + ->count(); + + if ($existing > 0) { + $this->command->info(' ⚠ quality_documents: 이미 '.$existing.'개 존재 (스킵)'); + + return; + } + + DB::transaction(function () use ($tenantId, $userId, $now) { + // ============================================================ + // Page 1: 제품검사/품질관리서 (quality_documents + orders + locations) + // ============================================================ + $this->command->info('📋 Page 1: 제품검사/품질관리서 더미 데이터 생성...'); + + $qualityDocs = [ + [ + 'quality_doc_number' => 'KD-QD-202604-0001', + 'site_name' => '강남 르네상스 오피스텔 신축공사', + 'status' => 'completed', + 'client_id' => self::CLIENT_IDS[0], + 'inspector_id' => $userId, + 'received_date' => '2026-02-15', + 'options' => json_encode([ + 'manager' => ['name' => '김현수', 'phone' => '010-1111-2222'], + 'contractor' => ['name' => '이건설', 'phone' => '02-3333-4444', 'address' => '서울시 강남구 역삼동', 'company' => '대한건설(주)'], + 'inspection' => ['end_date' => '2026-03-05', 'start_date' => '2026-03-03', 'request_date' => '2026-02-28'], + 'supervisor' => ['name' => '박감리', 'phone' => '02-5555-6666', 'office' => '한국감리사무소', 'address' => '서울시 서초구'], + 'site_address' => ['detail' => '강남 르네상스 오피스텔 B1~15F', 'address' => '서울시 강남구 역삼동 123-45', 'postal_code' => '06241'], + 'construction_site' => ['name' => '강남 르네상스 오피스텔 신축공사', 'lot_number' => '123-45', 'land_location' => '서울시 강남구 역삼동'], + 'material_distributor' => ['ceo' => '최대표', 'phone' => '02-7777-8888', 'address' => '서울시 송파구', 'company' => '경동자재(주)'], + ]), + ], + [ + 'quality_doc_number' => 'KD-QD-202604-0002', + 'site_name' => '판교 테크노밸리 물류센터', + 'status' => 'completed', + 'client_id' => self::CLIENT_IDS[1], + 'inspector_id' => $userId, + 'received_date' => '2026-02-20', + 'options' => json_encode([ + 'manager' => ['name' => '정우성', 'phone' => '010-2222-3333'], + 'contractor' => ['name' => '박시공', 'phone' => '031-4444-5555', 'address' => '경기도 성남시 분당구', 'company' => '판교건설(주)'], + 'inspection' => ['end_date' => '2026-03-08', 'start_date' => '2026-03-06', 'request_date' => '2026-03-01'], + 'supervisor' => ['name' => '이감리', 'phone' => '031-6666-7777', 'office' => '성남감리사무소', 'address' => '경기도 성남시 분당구'], + 'site_address' => ['detail' => '판교 테크노밸리 3단지 물류동', 'address' => '경기도 성남시 분당구 판교동 678-9', 'postal_code' => '13487'], + 'construction_site' => ['name' => '판교 테크노밸리 물류센터 신축', 'lot_number' => '678-9', 'land_location' => '경기도 성남시 분당구 판교동'], + 'material_distributor' => ['ceo' => '김대표', 'phone' => '031-8888-9999', 'address' => '경기도 용인시', 'company' => '한국자재유통(주)'], + ]), + ], + [ + 'quality_doc_number' => 'KD-QD-202604-0003', + 'site_name' => '잠실 롯데월드타워 리모델링', + 'status' => 'completed', + 'client_id' => self::CLIENT_IDS[2], + 'inspector_id' => $userId, + 'received_date' => '2026-02-25', + 'options' => json_encode([ + 'manager' => ['name' => '송민호', 'phone' => '010-3333-4444'], + 'contractor' => ['name' => '최시공', 'phone' => '02-5555-6666', 'address' => '서울시 송파구 잠실동', 'company' => '잠실건설(주)'], + 'inspection' => ['end_date' => '2026-03-12', 'start_date' => '2026-03-10', 'request_date' => '2026-03-05'], + 'supervisor' => ['name' => '강감리', 'phone' => '02-7777-8888', 'office' => '송파감리사무소', 'address' => '서울시 송파구'], + 'site_address' => ['detail' => '잠실 롯데월드타워 15~20F', 'address' => '서울시 송파구 잠실동 29', 'postal_code' => '05551'], + 'construction_site' => ['name' => '잠실 롯데월드타워 리모델링 공사', 'lot_number' => '29', 'land_location' => '서울시 송파구 잠실동'], + 'material_distributor' => ['ceo' => '한대표', 'phone' => '02-9999-0000', 'address' => '서울시 강동구', 'company' => '동부자재(주)'], + ]), + ], + [ + 'quality_doc_number' => 'KD-QD-202604-0004', + 'site_name' => '마곡 LG사이언스파크 증축', + 'status' => 'completed', + 'client_id' => self::CLIENT_IDS[3], + 'inspector_id' => $userId, + 'received_date' => '2026-03-01', + 'options' => json_encode([ + 'manager' => ['name' => '윤서연', 'phone' => '010-4444-5555'], + 'contractor' => ['name' => '임시공', 'phone' => '02-1234-5678', 'address' => '서울시 강서구 마곡동', 'company' => '마곡종합건설(주)'], + 'inspection' => ['end_date' => '2026-03-15', 'start_date' => '2026-03-13', 'request_date' => '2026-03-08'], + 'supervisor' => ['name' => '오감리', 'phone' => '02-2345-6789', 'office' => '강서감리사무소', 'address' => '서울시 강서구'], + 'site_address' => ['detail' => 'LG사이언스파크 E동 증축', 'address' => '서울시 강서구 마곡동 757', 'postal_code' => '07796'], + 'construction_site' => ['name' => '마곡 LG사이언스파크 증축공사', 'lot_number' => '757', 'land_location' => '서울시 강서구 마곡동'], + 'material_distributor' => ['ceo' => '장대표', 'phone' => '02-3456-7890', 'address' => '서울시 영등포구', 'company' => '서부자재(주)'], + ]), + ], + [ + 'quality_doc_number' => 'KD-QD-202604-0005', + 'site_name' => '인천 송도 스마트시티 아파트', + 'status' => 'in_progress', + 'client_id' => self::CLIENT_IDS[3], + 'inspector_id' => $userId, + 'received_date' => '2026-03-05', + 'options' => json_encode([ + 'manager' => ['name' => '안재현', 'phone' => '010-5555-6666'], + 'contractor' => ['name' => '배시공', 'phone' => '032-1111-2222', 'address' => '인천시 연수구 송도동', 'company' => '송도종합건설(주)'], + 'inspection' => ['end_date' => null, 'start_date' => '2026-03-18', 'request_date' => '2026-03-10'], + 'supervisor' => ['name' => '황감리', 'phone' => '032-3333-4444', 'office' => '인천감리사무소', 'address' => '인천시 연수구'], + 'site_address' => ['detail' => '송도 스마트시티 A블록 101~105동', 'address' => '인천시 연수구 송도동 100-1', 'postal_code' => '21990'], + 'construction_site' => ['name' => '인천 송도 스마트시티 아파트 신축', 'lot_number' => '100-1', 'land_location' => '인천시 연수구 송도동'], + 'material_distributor' => ['ceo' => '서대표', 'phone' => '032-5555-6666', 'address' => '인천시 남동구', 'company' => '인천자재(주)'], + ]), + ], + [ + 'quality_doc_number' => 'KD-QD-202604-0006', + 'site_name' => '화성 동탄2 행복주택 단지', + 'status' => 'in_progress', + 'client_id' => self::CLIENT_IDS[4], + 'inspector_id' => $userId, + 'received_date' => '2026-03-06', + 'options' => json_encode([ + 'manager' => ['name' => '류준열', 'phone' => '010-6666-7777'], + 'contractor' => ['name' => '조시공', 'phone' => '031-2222-3333', 'address' => '경기도 화성시 동탄', 'company' => '동탄건설(주)'], + 'inspection' => ['end_date' => null, 'start_date' => null, 'request_date' => '2026-03-12'], + 'supervisor' => ['name' => '문감리', 'phone' => '031-4444-5555', 'office' => '화성감리사무소', 'address' => '경기도 화성시'], + 'site_address' => ['detail' => '동탄2 행복주택 A1~A5동', 'address' => '경기도 화성시 동탄면 200-3', 'postal_code' => '18450'], + 'construction_site' => ['name' => '화성 동탄2 행복주택 단지 신축공사', 'lot_number' => '200-3', 'land_location' => '경기도 화성시 동탄면'], + 'material_distributor' => ['ceo' => '남대표', 'phone' => '031-6666-7777', 'address' => '경기도 오산시', 'company' => '경기자재(주)'], + ]), + ], + [ + 'quality_doc_number' => 'KD-QD-202604-0007', + 'site_name' => '세종시 정부청사 별관', + 'status' => 'in_progress', + 'client_id' => self::CLIENT_IDS[0], + 'inspector_id' => null, + 'received_date' => '2026-03-07', + 'options' => json_encode([ + 'manager' => ['name' => '김세종', 'phone' => '010-7777-8888'], + 'contractor' => ['name' => '정시공', 'phone' => '044-1111-2222', 'address' => '세종시 어진동', 'company' => '세종건설(주)'], + 'inspection' => ['end_date' => null, 'start_date' => null, 'request_date' => null], + 'supervisor' => ['name' => '고감리', 'phone' => '044-3333-4444', 'office' => '세종감리사무소', 'address' => '세종시 나성동'], + 'site_address' => ['detail' => '정부세종청사 별관동', 'address' => '세종시 어진동 850', 'postal_code' => '30113'], + 'construction_site' => ['name' => '세종시 정부청사 별관 신축공사', 'lot_number' => '850', 'land_location' => '세종시 어진동'], + 'material_distributor' => ['ceo' => '윤대표', 'phone' => '044-5555-6666', 'address' => '대전시 유성구', 'company' => '중부자재(주)'], + ]), + ], + [ + 'quality_doc_number' => 'KD-QD-202604-0008', + 'site_name' => '부산 해운대 엘시티 주상복합', + 'status' => 'in_progress', + 'client_id' => self::CLIENT_IDS[1], + 'inspector_id' => null, + 'received_date' => '2026-03-08', + 'options' => json_encode([ + 'manager' => ['name' => '이부산', 'phone' => '010-8888-9999'], + 'contractor' => ['name' => '노시공', 'phone' => '051-1111-2222', 'address' => '부산시 해운대구', 'company' => '해운대건설(주)'], + 'inspection' => ['end_date' => null, 'start_date' => null, 'request_date' => null], + 'supervisor' => ['name' => '차감리', 'phone' => '051-3333-4444', 'office' => '부산감리사무소', 'address' => '부산시 해운대구'], + 'site_address' => ['detail' => '해운대 엘시티 B동 전층', 'address' => '부산시 해운대구 우동 1478', 'postal_code' => '48060'], + 'construction_site' => ['name' => '부산 해운대 엘시티 주상복합 리모델링', 'lot_number' => '1478', 'land_location' => '부산시 해운대구 우동'], + 'material_distributor' => ['ceo' => '백대표', 'phone' => '051-5555-6666', 'address' => '부산시 사하구', 'company' => '남부자재(주)'], + ]), + ], + [ + 'quality_doc_number' => 'KD-QD-202604-0009', + 'site_name' => '수원 광교 복합문화센터', + 'status' => 'draft', + 'client_id' => self::CLIENT_IDS[4], + 'inspector_id' => null, + 'received_date' => '2026-03-09', + 'options' => json_encode([ + 'manager' => ['name' => '한지민', 'phone' => '010-5555-6666'], + 'contractor' => ['name' => '', 'phone' => '', 'address' => '', 'company' => ''], + 'inspection' => ['end_date' => null, 'start_date' => null, 'request_date' => null], + 'supervisor' => ['name' => '', 'phone' => '', 'office' => '', 'address' => ''], + 'site_address' => ['detail' => '광교 복합문화센터 전관', 'address' => '경기도 수원시 영통구 광교동 200', 'postal_code' => '16508'], + 'construction_site' => ['name' => '수원 광교 복합문화센터 신축공사', 'lot_number' => '200', 'land_location' => '경기도 수원시 영통구 광교동'], + 'material_distributor' => ['ceo' => '', 'phone' => '', 'address' => '', 'company' => ''], + ]), + ], + [ + 'quality_doc_number' => 'KD-QD-202604-0010', + 'site_name' => '대구 수성 의료복합단지', + 'status' => 'draft', + 'client_id' => self::CLIENT_IDS[2], + 'inspector_id' => null, + 'received_date' => '2026-03-10', + 'options' => json_encode([ + 'manager' => ['name' => '박대구', 'phone' => '010-9999-0000'], + 'contractor' => ['name' => '', 'phone' => '', 'address' => '', 'company' => ''], + 'inspection' => ['end_date' => null, 'start_date' => null, 'request_date' => null], + 'supervisor' => ['name' => '', 'phone' => '', 'office' => '', 'address' => ''], + 'site_address' => ['detail' => '수성 의료복합단지 본관', 'address' => '대구시 수성구 범어동 350', 'postal_code' => '42020'], + 'construction_site' => ['name' => '대구 수성 의료복합단지 신축공사', 'lot_number' => '350', 'land_location' => '대구시 수성구 범어동'], + 'material_distributor' => ['ceo' => '', 'phone' => '', 'address' => '', 'company' => ''], + ]), + ], + ]; + + $qualityDocIds = []; + foreach ($qualityDocs as $doc) { + $qualityDocIds[] = DB::table('quality_documents')->insertGetId(array_merge($doc, [ + 'tenant_id' => $tenantId, + 'created_by' => $userId, + 'updated_by' => $userId, + 'created_at' => $now, + 'updated_at' => $now, + ])); + } + $this->command->info(' ✅ quality_documents: '.count($qualityDocIds).'개 생성'); + + // completed/in_progress 문서에 수주 연결 (draft 제외) + $docOrderMapping = [ + $qualityDocIds[0] => [self::ORDER_IDS[0], self::ORDER_IDS[1]], // completed + $qualityDocIds[1] => [self::ORDER_IDS[2], self::ORDER_IDS[3], self::ORDER_IDS[4]], // completed + $qualityDocIds[2] => [self::ORDER_IDS[5], self::ORDER_IDS[6]], // completed + $qualityDocIds[3] => [self::ORDER_IDS[7], self::ORDER_IDS[8]], // completed + $qualityDocIds[4] => [self::ORDER_IDS[9], self::ORDER_IDS[0]], // in_progress + $qualityDocIds[5] => [self::ORDER_IDS[1], self::ORDER_IDS[2]], // in_progress + $qualityDocIds[6] => [self::ORDER_IDS[3]], // in_progress + $qualityDocIds[7] => [self::ORDER_IDS[4], self::ORDER_IDS[5]], // in_progress + ]; + + $qdoMap = []; + $qdoCount = 0; + foreach ($docOrderMapping as $docId => $orderIds) { + foreach ($orderIds as $orderId) { + $qdoId = DB::table('quality_document_orders')->insertGetId([ + 'quality_document_id' => $docId, + 'order_id' => $orderId, + 'created_at' => $now, + 'updated_at' => $now, + ]); + $qdoMap[$docId][$orderId] = $qdoId; + $qdoCount++; + } + } + $this->command->info(' ✅ quality_document_orders: '.$qdoCount.'개 생성'); + + // 각 수주별 order_items 조회 후 locations 생성 + $inspectionDataSets = [ + json_encode(['motor' => 'pass', 'material' => 'pass', 'impactTest' => 'pass', 'productName' => '방화셔터', 'guideRailGap' => 'pass', 'openCloseTest' => 'pass']), + json_encode(['motor' => 'pass', 'material' => 'pass', 'impactTest' => 'fail', 'productName' => '방화셔터', 'guideRailGap' => 'pass', 'openCloseTest' => 'pass']), + json_encode(['motor' => 'pass', 'material' => 'pass', 'impactTest' => 'pass', 'productName' => '방화문', 'guideRailGap' => 'N/A', 'openCloseTest' => 'pass']), + json_encode(['motor' => 'N/A', 'material' => 'pass', 'impactTest' => 'pass', 'productName' => '스크린셔터', 'guideRailGap' => 'pass', 'openCloseTest' => 'pass']), + json_encode(['motor' => 'pass', 'material' => 'fail', 'impactTest' => 'pass', 'productName' => '방화셔터', 'guideRailGap' => 'pass', 'openCloseTest' => 'fail']), + json_encode(['motor' => 'pass', 'material' => 'pass', 'impactTest' => 'pass', 'productName' => '절곡셔터', 'guideRailGap' => 'pass', 'openCloseTest' => 'pass']), + ]; + + $completedDocIds = array_slice($qualityDocIds, 0, 4); // 처음 4개가 completed + $locationCount = 0; + foreach ($qdoMap as $docId => $orderMap) { + foreach ($orderMap as $orderId => $qdoId) { + $orderItemIds = DB::table('order_items') + ->where('order_id', $orderId) + ->pluck('id') + ->take(4) + ->toArray(); + + if (empty($orderItemIds)) { + // order_items가 없으면 order_nodes → order_items 경로 시도 + $nodeIds = DB::table('order_nodes') + ->where('order_id', $orderId) + ->pluck('id'); + $orderItemIds = DB::table('order_items') + ->whereIn('order_node_id', $nodeIds) + ->pluck('id') + ->take(4) + ->toArray(); + } + + if (empty($orderItemIds)) { + $this->command->warn(' ⚠ order_id='.$orderId.'에 order_items 없음 (스킵)'); + + continue; + } + + foreach ($orderItemIds as $idx => $orderItemId) { + $isCompleted = in_array($docId, $completedDocIds); + $inspectionStatus = $isCompleted + ? ($idx === 1 ? 'fail' : 'pass') + : 'pending'; + + $inspectionData = $isCompleted + ? $inspectionDataSets[$idx % count($inspectionDataSets)] + : null; + + $postWidth = ($isCompleted || $idx < 2) ? rand(1800, 3200) : null; + $postHeight = ($isCompleted || $idx < 2) ? rand(2100, 3800) : null; + $changeReason = ($isCompleted && $idx === 0) ? '현장 사정으로 규격 변경' : null; + + $locOptions = null; + if ($isCompleted) { + $locOptions = json_encode([ + 'lot_audit_confirmed' => $idx !== 1, + 'lot_audit_confirmed_at' => $idx !== 1 ? $now->toDateTimeString() : null, + 'lot_audit_confirmed_by' => $idx !== 1 ? $userId : null, + ]); + } + + DB::table('quality_document_locations')->insert([ + 'quality_document_id' => $docId, + 'quality_document_order_id' => $qdoId, + 'order_item_id' => $orderItemId, + 'post_width' => $postWidth, + 'post_height' => $postHeight, + 'change_reason' => $changeReason, + 'inspection_data' => $inspectionData, + 'document_id' => null, + 'inspection_status' => $inspectionStatus, + 'options' => $locOptions, + 'created_at' => $now, + 'updated_at' => $now, + ]); + $locationCount++; + } + } + } + $this->command->info(' ✅ quality_document_locations: '.$locationCount.'개 생성'); + + // ============================================================ + // Page 2: 실적신고 (performance_reports) + // ============================================================ + $this->command->info('📊 Page 2: 실적신고 더미 데이터 생성...'); + + $existingReports = DB::table('performance_reports') + ->where('tenant_id', $tenantId) + ->whereIn('quality_document_id', $qualityDocIds) + ->count(); + + if ($existingReports > 0) { + $this->command->info(' ⚠ performance_reports: 이미 '.$existingReports.'개 존재 (스킵)'); + } else { + $performanceReports = [ + [ + 'quality_document_id' => $qualityDocIds[0], + 'year' => 2026, 'quarter' => 1, + 'confirmation_status' => 'confirmed', + 'confirmed_date' => '2026-03-06', + 'confirmed_by' => $userId, + 'memo' => '1분기 검사 완료 - 강남 르네상스 건', + ], + [ + 'quality_document_id' => $qualityDocIds[1], + 'year' => 2026, 'quarter' => 1, + 'confirmation_status' => 'confirmed', + 'confirmed_date' => '2026-03-09', + 'confirmed_by' => $userId, + 'memo' => '판교 물류센터 건 - 확인 완료', + ], + [ + 'quality_document_id' => $qualityDocIds[2], + 'year' => 2026, 'quarter' => 1, + 'confirmation_status' => 'unconfirmed', + 'confirmed_date' => null, + 'confirmed_by' => null, + 'memo' => '잠실 리모델링 건 - 확인 대기중', + ], + [ + 'quality_document_id' => $qualityDocIds[3], + 'year' => 2026, 'quarter' => 1, + 'confirmation_status' => 'confirmed', + 'confirmed_date' => '2026-03-16', + 'confirmed_by' => $userId, + 'memo' => '마곡 LG사이언스파크 건 - 확인 완료', + ], + [ + 'quality_document_id' => $qualityDocIds[4], + 'year' => 2026, 'quarter' => 1, + 'confirmation_status' => 'pending', + 'confirmed_date' => null, + 'confirmed_by' => null, + 'memo' => '송도 아파트 건 - 검사 진행중', + ], + [ + 'quality_document_id' => $qualityDocIds[5], + 'year' => 2026, 'quarter' => 1, + 'confirmation_status' => 'pending', + 'confirmed_date' => null, + 'confirmed_by' => null, + 'memo' => '동탄 행복주택 건 - 검사 진행중', + ], + ]; + + foreach ($performanceReports as $report) { + DB::table('performance_reports')->insert(array_merge($report, [ + 'tenant_id' => $tenantId, + 'created_by' => $userId, + 'updated_by' => $userId, + 'created_at' => $now, + 'updated_at' => $now, + ])); + } + $this->command->info(' ✅ performance_reports: '.count($performanceReports).'개 생성'); + } + + // ============================================================ + // Page 3: 품질인정심사 (audit_checklists + categories + items + standard_documents) + // ============================================================ + $this->command->info('🏅 Page 3: 품질인정심사 더미 데이터 생성...'); + + $existingChecklist = DB::table('audit_checklists') + ->where('tenant_id', $tenantId) + ->where('year', 2026) + ->where('type', 'standard_manual') + ->first(); + + if ($existingChecklist) { + $this->command->info(' ⚠ audit_checklists: 이미 존재 (스킵)'); + } else { + // Q1 점검표 (in_progress) + $this->seedChecklist($tenantId, $userId, $now, 2026, 1, 'in_progress', '정기심사'); + // Q2 점검표 (draft) + $this->seedChecklist($tenantId, $userId, $now, 2026, 2, 'draft', '중간심사'); + } + + $this->command->info(''); + $this->command->info('🎉 품질 더미 데이터 생성 완료!'); + }); + } + + private function seedChecklist(int $tenantId, int $userId, Carbon $now, int $year, int $quarter, string $status, string $auditType): void + { + $checklistId = DB::table('audit_checklists')->insertGetId([ + 'tenant_id' => $tenantId, + 'year' => $year, + 'quarter' => $quarter, + 'type' => 'standard_manual', + 'status' => $status, + 'options' => json_encode([ + 'audit_date' => $year.'-'.str_pad($quarter * 3, 2, '0', STR_PAD_LEFT).'-15', + 'auditor' => '한국품질인증원', + 'audit_type' => $auditType, + ]), + 'created_by' => $userId, + 'updated_by' => $userId, + 'created_at' => $now, + 'updated_at' => $now, + ]); + $this->command->info(' ✅ audit_checklists: '.$year.' Q'.$quarter.' ('.$status.') 생성'); + + $isActive = $status !== 'draft'; + + $categoriesData = [ + [ + 'title' => '품질경영 시스템', + 'sort_order' => 1, + 'items' => [ + ['name' => '품질방침 수립 및 공표', 'description' => '최고경영자의 품질방침 수립, 문서화 및 전직원 공표 여부', 'is_completed' => $isActive, + 'docs' => [['title' => '품질매뉴얼 Rev.5', 'version' => '5.0', 'date' => '2025-12-01'], ['title' => '품질방침 선언서', 'version' => '3.0', 'date' => '2025-06-15']]], + ['name' => '품질목표 설정 및 관리', 'description' => '연간 품질목표 설정, 실행계획 수립 및 주기적 모니터링', 'is_completed' => $isActive, + 'docs' => [['title' => $year.'년 품질목표 관리대장', 'version' => '1.0', 'date' => $year.'-01-05'], ['title' => '품질목표 관리절차서', 'version' => '2.1', 'date' => '2025-09-10']]], + ['name' => '내부심사 계획 및 실시', 'description' => '연간 내부심사 계획 수립 및 실시 기록', 'is_completed' => false, + 'docs' => [['title' => '내부심사 절차서', 'version' => '4.0', 'date' => '2025-03-20'], ['title' => $year.'년 내부심사 계획서', 'version' => '1.0', 'date' => $year.'-01-15'], ['title' => '내부심사 보고서 양식', 'version' => '2.0', 'date' => '2025-07-01']]], + ['name' => '경영검토 실시', 'description' => '최고경영자 주관 경영검토 실시 및 기록 유지', 'is_completed' => false, + 'docs' => [['title' => '경영검토 절차서', 'version' => '3.2', 'date' => '2025-08-01'], ['title' => '2025년 하반기 경영검토 회의록', 'version' => '1.0', 'date' => '2025-12-20']]], + ['name' => '문서 및 기록 관리 체계', 'description' => '품질문서 체계(매뉴얼, 절차서, 지침서) 수립 및 관리', 'is_completed' => $isActive, + 'docs' => [['title' => '문서관리 절차서', 'version' => '4.5', 'date' => '2025-10-01'], ['title' => '기록관리 절차서', 'version' => '4.0', 'date' => '2025-03-10']]], + ], + ], + [ + 'title' => '설계 및 개발', + 'sort_order' => 2, + 'items' => [ + ['name' => '설계 입력 관리', 'description' => '설계 입력 요구사항 식별, 문서화 및 검토', 'is_completed' => $isActive, + 'docs' => [['title' => '설계관리 절차서', 'version' => '4.1', 'date' => '2025-10-15'], ['title' => '설계입력 검토서 양식', 'version' => '2.0', 'date' => '2025-05-20']]], + ['name' => '설계 출력 관리', 'description' => '설계 출력물 문서화 및 입력 요구사항 충족 확인', 'is_completed' => $isActive, + 'docs' => [['title' => '설계출력 검증서 양식', 'version' => '2.0', 'date' => '2025-06-15'], ['title' => '도면 관리기준서', 'version' => '3.0', 'date' => '2025-08-20']]], + ['name' => '설계 검증 및 유효성 확인', 'description' => '설계 출력물에 대한 검증/유효성 확인 절차 운영', 'is_completed' => false, + 'docs' => [['title' => '설계검증 절차서', 'version' => '3.0', 'date' => '2025-04-10'], ['title' => '설계유효성확인 체크리스트', 'version' => '1.5', 'date' => '2025-11-01'], ['title' => '시제품 시험성적서 양식', 'version' => '2.0', 'date' => '2025-06-30']]], + ['name' => '설계 변경 관리', 'description' => '설계 변경 요청, 승인 및 이력 관리', 'is_completed' => false, + 'docs' => [['title' => '설계변경 관리절차서', 'version' => '2.3', 'date' => '2025-07-15'], ['title' => '설계변경 요청서(ECR) 양식', 'version' => '1.0', 'date' => '2025-01-10']]], + ['name' => 'FMEA 및 위험 분석', 'description' => '설계 고장모드 영향분석(FMEA) 실시 및 관리', 'is_completed' => false, + 'docs' => [['title' => 'FMEA 절차서', 'version' => '2.0', 'date' => '2025-09-01'], ['title' => 'DFMEA 양식', 'version' => '1.5', 'date' => '2025-11-20']]], + ], + ], + [ + 'title' => '구매 관리', + 'sort_order' => 3, + 'items' => [ + ['name' => '협력업체 평가 및 선정', 'description' => '협력업체 초기평가, 정기평가 기준 및 실시 기록', 'is_completed' => $isActive, + 'docs' => [['title' => '협력업체 관리절차서', 'version' => '5.0', 'date' => '2025-09-01'], ['title' => '2025년 협력업체 평가결과', 'version' => '1.0', 'date' => '2025-12-15']]], + ['name' => '수입검사 절차', 'description' => '구매 자재 수입검사 기준 및 합/불합격 처리 절차', 'is_completed' => $isActive, + 'docs' => [['title' => '수입검사 절차서', 'version' => '3.1', 'date' => '2025-08-20'], ['title' => '수입검사 기준서', 'version' => '4.0', 'date' => '2025-11-10'], ['title' => '자재별 검사항목 목록', 'version' => '2.0', 'date' => '2025-10-01']]], + ['name' => '부적합 자재 처리', 'description' => '수입검사 불합격 자재의 격리, 반품, 특채 처리', 'is_completed' => false, + 'docs' => [['title' => '부적합품 관리절차서', 'version' => '3.0', 'date' => '2025-05-15'], ['title' => '특채 요청서 양식', 'version' => '1.2', 'date' => '2025-09-20']]], + ['name' => '구매문서 관리', 'description' => '구매 사양서, 발주서 등 구매문서 관리 체계', 'is_completed' => false, + 'docs' => [['title' => '구매관리 절차서', 'version' => '4.2', 'date' => '2025-07-01']]], + ['name' => '입고 및 자재 보관 관리', 'description' => '입고 검수, 자재 보관 조건 및 선입선출 관리', 'is_completed' => $isActive, + 'docs' => [['title' => '자재관리 절차서', 'version' => '3.5', 'date' => '2025-08-01'], ['title' => '창고관리 기준서', 'version' => '2.0', 'date' => '2025-10-15']]], + ], + ], + [ + 'title' => '제조 공정 관리', + 'sort_order' => 4, + 'items' => [ + ['name' => '공정 관리 계획', 'description' => '제조 공정별 관리항목, 관리기준, 검사방법 수립', 'is_completed' => $isActive, + 'docs' => [['title' => '공정관리 절차서', 'version' => '4.0', 'date' => '2025-07-10'], ['title' => 'QC공정도', 'version' => '3.0', 'date' => '2025-09-15']]], + ['name' => '작업표준서 관리', 'description' => '공정별 작업표준서 작성, 배포 및 최신본 관리', 'is_completed' => $isActive, + 'docs' => [['title' => '작업표준서 관리절차', 'version' => '2.5', 'date' => '2025-06-20'], ['title' => '방화셔터 조립 작업표준서', 'version' => '5.0', 'date' => '2025-11-01']]], + ['name' => '공정검사 실시', 'description' => '제조 공정 중 품질검사 기준 및 기록 관리', 'is_completed' => false, + 'docs' => [['title' => '공정검사 절차서', 'version' => '3.5', 'date' => '2025-10-20'], ['title' => '공정검사 체크시트', 'version' => '2.0', 'date' => '2025-11-15']]], + ['name' => '부적합품 관리', 'description' => '공정 중 발생한 부적합품 식별, 격리, 처리', 'is_completed' => false, + 'docs' => [['title' => '부적합품 관리절차서', 'version' => '3.0', 'date' => '2025-05-15'], ['title' => '부적합 처리대장 양식', 'version' => '2.0', 'date' => '2025-08-01']]], + ], + ], + [ + 'title' => '검사 및 시험', + 'sort_order' => 5, + 'items' => [ + ['name' => '최종검사 및 시험', 'description' => '완제품 출하 전 최종검사 기준 및 기록', 'is_completed' => false, + 'docs' => [['title' => '최종검사 절차서', 'version' => '4.0', 'date' => '2025-06-01'], ['title' => '방화셔터 시험성적서 양식', 'version' => '3.0', 'date' => '2025-08-10'], ['title' => '제품검사 기준서', 'version' => '5.1', 'date' => '2025-12-05']]], + ['name' => '검사·측정 장비 관리', 'description' => '검사장비 교정, 유지보수 계획 및 이력 관리', 'is_completed' => $isActive, + 'docs' => [['title' => '계측기 관리절차서', 'version' => '2.8', 'date' => '2025-04-15'], ['title' => $year.'년 교정계획표', 'version' => '1.0', 'date' => $year.'-01-10']]], + ['name' => '시정 및 예방조치', 'description' => '부적합 발생 시 시정조치, 재발방지 및 예방조치 관리', 'is_completed' => false, + 'docs' => [['title' => '시정예방조치 절차서', 'version' => '3.3', 'date' => '2025-09-25'], ['title' => '시정조치 보고서 양식', 'version' => '2.0', 'date' => '2025-05-01']]], + ['name' => '품질기록 관리', 'description' => '품질기록 식별, 보관, 보호, 검색, 폐기 절차', 'is_completed' => $isActive, + 'docs' => [['title' => '기록관리 절차서', 'version' => '4.0', 'date' => '2025-03-10'], ['title' => '기록보존 기간표', 'version' => '2.5', 'date' => '2025-07-20']]], + ['name' => '출하 및 인도 관리', 'description' => '완제품 출하검사, 포장, 운송 및 인도 절차', 'is_completed' => false, + 'docs' => [['title' => '출하관리 절차서', 'version' => '3.0', 'date' => '2025-05-20'], ['title' => '포장 및 운송 기준서', 'version' => '2.5', 'date' => '2025-09-10']]], + ], + ], + [ + 'title' => '고객만족 및 지속적 개선', + 'sort_order' => 6, + 'items' => [ + ['name' => '고객 불만 처리', 'description' => '고객 불만 접수, 처리, 회신 및 재발방지 체계', 'is_completed' => $isActive, + 'docs' => [['title' => '고객불만 처리절차서', 'version' => '3.0', 'date' => '2025-04-01'], ['title' => '고객불만 처리대장 양식', 'version' => '2.0', 'date' => '2025-07-15']]], + ['name' => '고객만족도 조사', 'description' => '정기적 고객만족도 조사 실시 및 결과 분석', 'is_completed' => false, + 'docs' => [['title' => '고객만족도 조사절차서', 'version' => '2.0', 'date' => '2025-06-01'], ['title' => '2025년 고객만족도 조사결과', 'version' => '1.0', 'date' => '2025-12-30']]], + ['name' => '지속적 개선 활동', 'description' => '품질개선 과제 발굴, 실행 및 효과 확인', 'is_completed' => false, + 'docs' => [['title' => '지속적개선 절차서', 'version' => '2.5', 'date' => '2025-08-15'], ['title' => '개선활동 보고서 양식', 'version' => '1.5', 'date' => '2025-10-20']]], + ], + ], + ]; + + $categoryCount = 0; + $itemCount = 0; + $docCount = 0; + + foreach ($categoriesData as $catData) { + $categoryId = DB::table('audit_checklist_categories')->insertGetId([ + 'tenant_id' => $tenantId, + 'checklist_id' => $checklistId, + 'title' => $catData['title'], + 'sort_order' => $catData['sort_order'], + 'options' => null, + 'created_at' => $now, + 'updated_at' => $now, + ]); + $categoryCount++; + + foreach ($catData['items'] as $itemIdx => $itemData) { + $completedAt = $itemData['is_completed'] ? $now->copy()->subDays(rand(1, 15)) : null; + + $itemId = DB::table('audit_checklist_items')->insertGetId([ + 'tenant_id' => $tenantId, + 'category_id' => $categoryId, + 'name' => $itemData['name'], + 'description' => $itemData['description'], + 'is_completed' => $itemData['is_completed'], + 'completed_at' => $completedAt, + 'completed_by' => $itemData['is_completed'] ? $userId : null, + 'sort_order' => $itemIdx + 1, + 'options' => null, + 'created_at' => $now, + 'updated_at' => $now, + ]); + $itemCount++; + + foreach ($itemData['docs'] as $docData) { + DB::table('audit_standard_documents')->insert([ + 'tenant_id' => $tenantId, + 'checklist_item_id' => $itemId, + 'title' => $docData['title'], + 'version' => $docData['version'], + 'date' => $docData['date'], + 'document_id' => null, + 'options' => null, + 'created_at' => $now, + 'updated_at' => $now, + ]); + $docCount++; + } + } + } + + $this->command->info(' ✅ audit_checklist_categories: '.$categoryCount.'개 생성'); + $this->command->info(' ✅ audit_checklist_items: '.$itemCount.'개 생성'); + $this->command->info(' ✅ audit_standard_documents: '.$docCount.'개 생성'); + } +}