['prod' => 'R', 'spec' => 'M', 'label' => '가이드레일(벽면) 본체', 'bending' => '가이드레일', 'material' => 'EGI 1.55T'], 'RT' => ['prod' => 'R', 'spec' => 'T', 'label' => '가이드레일(벽면) 본체(철재)', 'bending' => '가이드레일', 'material' => 'EGI 1.55T'], 'RC' => ['prod' => 'R', 'spec' => 'C', 'label' => '가이드레일(벽면) C형', 'bending' => '가이드레일', 'material' => 'EGI 1.55T'], 'RD' => ['prod' => 'R', 'spec' => 'D', 'label' => '가이드레일(벽면) D형', 'bending' => '가이드레일', 'material' => 'EGI 1.55T'], 'RS' => ['prod' => 'R', 'spec' => 'S', 'label' => '가이드레일(벽면) SUS마감재', 'bending' => '가이드레일', 'material' => 'SUS 1.2T'], 'RW' => ['prod' => 'R', 'spec' => 'W', 'label' => '가이드레일(벽면) 본체(L120)', 'bending' => '가이드레일', 'material' => 'EGI 1.55T'], 'RF' => ['prod' => 'R', 'spec' => 'F', 'label' => '가이드레일(벽면) SUS마감재(L120)', 'bending' => '가이드레일', 'material' => 'SUS 1.2T'], // 가이드레일(측면형) S 'SM' => ['prod' => 'S', 'spec' => 'M', 'label' => '가이드레일(측면) 본체디딤', 'bending' => '가이드레일', 'material' => 'EGI 1.55T'], 'ST' => ['prod' => 'S', 'spec' => 'T', 'label' => '가이드레일(측면) 본체(철재)', 'bending' => '가이드레일', 'material' => 'EGI 1.55T'], 'SC' => ['prod' => 'S', 'spec' => 'C', 'label' => '가이드레일(측면) C형', 'bending' => '가이드레일', 'material' => 'EGI 1.55T'], 'SD' => ['prod' => 'S', 'spec' => 'D', 'label' => '가이드레일(측면) D형', 'bending' => '가이드레일', 'material' => 'EGI 1.55T'], 'SS' => ['prod' => 'S', 'spec' => 'S', 'label' => '가이드레일(측면) SUS마감재(3)', 'bending' => '가이드레일', 'material' => 'SUS 1.2T'], 'SU' => ['prod' => 'S', 'spec' => 'U', 'label' => '가이드레일(측면) SUS마감재(3)', 'bending' => '가이드레일', 'material' => 'SUS 1.2T'], 'SW' => ['prod' => 'S', 'spec' => 'W', 'label' => '가이드레일(측면) 본체(L120)', 'bending' => '가이드레일', 'material' => 'EGI 1.55T'], 'SF' => ['prod' => 'S', 'spec' => 'F', 'label' => '가이드레일(측면) SUS마감재(L120)', 'bending' => '가이드레일', 'material' => 'SUS 1.2T'], // 케이스 C 'CF' => ['prod' => 'C', 'spec' => 'F', 'label' => '케이스 전면부', 'bending' => '케이스', 'material' => 'EGI 1.55T'], 'CP' => ['prod' => 'C', 'spec' => 'P', 'label' => '케이스 점검구', 'bending' => '케이스', 'material' => 'EGI 1.55T'], 'CL' => ['prod' => 'C', 'spec' => 'L', 'label' => '케이스 린텔부', 'bending' => '케이스', 'material' => 'EGI 1.55T'], 'CB' => ['prod' => 'C', 'spec' => 'B', 'label' => '케이스 후면코너부', 'bending' => '케이스', 'material' => 'EGI 1.55T'], // 하단마감재 'BS' => ['prod' => 'B', 'spec' => 'S', 'label' => '하단마감재(스크린) SUS', 'bending' => '하단마감재', 'material' => 'SUS 1.2T'], 'BE' => ['prod' => 'B', 'spec' => 'E', 'label' => '하단마감재(스크린) EGI', 'bending' => '하단마감재', 'material' => 'EGI 1.55T'], 'TS' => ['prod' => 'T', 'spec' => 'S', 'label' => '하단마감재(철재) SUS', 'bending' => '하단마감재', 'material' => 'SUS 1.2T'], 'TE' => ['prod' => 'T', 'spec' => 'E', 'label' => '하단마감재(철재) EGI', 'bending' => '하단마감재', 'material' => 'EGI 1.55T'], // L-Bar 'LA' => ['prod' => 'L', 'spec' => 'A', 'label' => 'L-Bar 스크린용', 'bending' => 'L-BAR', 'material' => 'EGI 1.55T'], // 연기차단재 'GI' => ['prod' => 'G', 'spec' => 'I', 'label' => '연기차단재 화이바원단(W50)', 'bending' => '연기차단재', 'material' => '화이바원단', 'type' => 'both'], 'GH' => ['prod' => 'G', 'spec' => 'H', 'label' => '연기차단재 화이바원단(W80)', 'bending' => '연기차단재', 'material' => '화이바원단', 'type' => 'both'], ]; // ========================================================================= // 2. 길이 코드 정의 // ========================================================================= $generalLengths = [ '06' => '610mm', '12' => '1219mm', '17' => '1750mm', '20' => '2000mm', '24' => '2438mm', '30' => '3000mm', '35' => '3500mm', '40' => '4000mm', '41' => '4150mm', '42' => '4200mm', '43' => '4300mm', '45' => '4500mm', ]; $smokeLengths = [ '53' => 'W50×3000', '54' => 'W50×4000', '83' => 'W80×3000', '84' => 'W80×4000', ]; // ========================================================================= // 3. 기존 품목 조회 // ========================================================================= $existingCodes = DB::table('items') ->where('tenant_id', $tenantId) ->where('item_category', 'BENDING') ->whereNull('deleted_at') ->pluck('id', 'code') ->toArray(); echo "기존 BENDING 품목: " . count($existingCodes) . "건\n\n"; // ========================================================================= // 4. 누락 품목 생성 // ========================================================================= $created = 0; $skipped = 0; $mappingCreated = 0; $now = now(); DB::beginTransaction(); try { foreach ($combos as $comboKey => $meta) { // 길이 목록 결정 (+ 연산자로 문자열 키 보존 — array_merge는 숫자형 키 재번호) $type = $meta['type'] ?? 'general'; if ($type === 'both') { $lengths = $generalLengths + $smokeLengths; } elseif ($type === 'smoke') { $lengths = $smokeLengths; } else { $lengths = $generalLengths; } foreach ($lengths as $lenCode => $lenName) { $code = "BD-{$comboKey}-{$lenCode}"; $name = "{$meta['label']} {$lenName}"; // 이미 존재하면 매핑만 확인 if (isset($existingCodes[$code])) { $itemId = $existingCodes[$code]; $skipped++; } else { // 품목 생성 $itemId = DB::table('items')->insertGetId([ 'tenant_id' => $tenantId, 'item_type' => 'PT', 'code' => $code, 'name' => $name, 'unit' => 'EA', 'item_category' => 'BENDING', 'is_active' => true, 'options' => json_encode([ 'item_bending' => $meta['bending'], 'material' => $meta['material'], ]), 'created_at' => $now, 'updated_at' => $now, ]); $created++; echo " ✅ {$code} | {$name}\n"; } // bending_item_mappings 등록 (중복 방지) $mappingExists = DB::table('bending_item_mappings') ->where('tenant_id', $tenantId) ->where('prod_code', $meta['prod']) ->where('spec_code', $meta['spec']) ->where('length_code', $lenCode) ->exists(); if (! $mappingExists) { DB::table('bending_item_mappings')->insert([ 'tenant_id' => $tenantId, 'prod_code' => $meta['prod'], 'spec_code' => $meta['spec'], 'length_code' => $lenCode, 'item_id' => $itemId, 'is_active' => true, 'created_at' => $now, 'updated_at' => $now, ]); $mappingCreated++; } } } DB::commit(); echo "\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"; echo " 품목 신규 생성: {$created}건\n"; echo " 품목 기존 유지: {$skipped}건\n"; echo " 매핑 등록: {$mappingCreated}건\n"; echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n"; } catch (\Exception $e) { DB::rollBack(); echo "\n❌ 오류 발생: " . $e->getMessage() . "\n"; echo "롤백 완료\n"; }