['KSS' => 'RS', 'KQTS' => 'RS', 'KSE' => 'RE', 'KWE' => 'RE', 'KTE' => 'RS'], 'body' => 'RM', 'c_type' => 'RC', 'd_type' => 'RD', 'extra_finish' => 'YY', 'base' => 'XX', ]; /** 측면형(Side) prefix */ private const SIDE_PREFIXES = [ 'finish' => ['KSS' => 'SS', 'KQTS' => 'SS', 'KSE' => 'SE', 'KWE' => 'SE', 'KTE' => 'SS'], 'body' => 'SM', 'c_type' => 'SC', 'd_type' => 'SD', 'extra_finish' => 'YY', 'base' => 'XX', ]; /** 철재(KTE01) body 오버라이드 */ private const STEEL_BODY_OVERRIDES = [ 'wall' => 'RT', 'side' => 'ST', ]; // ───────────────────────────────────────────────── // 하단마감재 Prefix 맵 // ───────────────────────────────────────────────── /** 하단마감재 main prefix: finishMaterial 기반 */ private const BOTTOM_BAR_MAIN = [ 'EGI' => 'BE', 'SUS' => 'BS', 'STEEL' => 'TS', ]; // ───────────────────────────────────────────────── // 셔터박스 Prefix 맵 // ───────────────────────────────────────────────── /** 표준 사이즈(500*380) 셔터박스 prefix */ private const SHUTTER_STANDARD = [ 'front' => 'CF', 'lintel' => 'CL', 'inspection' => 'CP', 'rear_corner' => 'CB', 'top_cover' => 'XX', 'fin_cover' => 'XX', ]; // ───────────────────────────────────────────────── // 길이코드 매핑 // ───────────────────────────────────────────────── private const LENGTH_TO_CODE = [ 1219 => '12', 2438 => '24', 3000 => '30', 3500 => '35', 4000 => '40', 4150 => '41', 4200 => '42', 4300 => '43', ]; /** 연기차단재 전용 길이코드 */ private const SMOKE_LENGTH_TO_CODE = [ 'w50' => [3000 => '53', 4000 => '54'], 'w80' => [3000 => '83', 4000 => '84'], ]; /** 파트타입 한글명 */ private const PART_TYPE_NAMES = [ 'finish' => '마감재', 'body' => '본체', 'c_type' => 'C형', 'd_type' => 'D형', 'extra_finish' => '별도마감', 'base' => '하부BASE', 'main' => '메인', 'lbar' => 'L-Bar', 'reinforce' => '보강평철', 'extra' => '별도마감', 'front' => '전면부', 'lintel' => '린텔부', 'inspection' => '점검구', 'rear_corner' => '후면코너부', 'top_cover' => '상부덮개', 'fin_cover' => '마구리', 'smoke' => '연기차단재', ]; /** items.id 캐시: code → id */ private array $itemIdCache = []; // ───────────────────────────────────────────────── // 가이드레일 // ───────────────────────────────────────────────── /** * 가이드레일 세부품목의 prefix 결정 * * @param string $partType 'finish', 'body', 'c_type', 'd_type', 'extra_finish', 'base' * @param string $guideType 'wall', 'side' * @param string $productCode 'KSS01', 'KSE01', 'KWE01', 'KTE01', 'KQTS01' * @return string prefix (빈 문자열이면 해당 파트 없음) */ public function resolveGuideRailPrefix(string $partType, string $guideType, string $productCode): string { $prefixMap = $guideType === 'wall' ? self::WALL_PREFIXES : self::SIDE_PREFIXES; $codePrefix = $this->extractCodePrefix($productCode); $isSteel = $codePrefix === 'KTE'; // body: 철재 오버라이드 if ($partType === 'body' && $isSteel) { return self::STEEL_BODY_OVERRIDES[$guideType] ?? ''; } // finish: productCode별 분기 if ($partType === 'finish') { $finishMap = $prefixMap['finish'] ?? []; return $finishMap[$codePrefix] ?? ''; } // extra_finish, base, c_type, d_type, body: 고정 prefix return $prefixMap[$partType] ?? ''; } // ───────────────────────────────────────────────── // 하단마감재 // ───────────────────────────────────────────────── /** * 하단마감재 세부품목의 prefix 결정 * * @param string $partType 'main', 'lbar', 'reinforce', 'extra' * @param string $productCode 'KSS01', 'KSE01', etc. * @param string $finishMaterial 'EGI마감', 'SUS마감' * @return string prefix */ public function resolveBottomBarPrefix(string $partType, string $productCode, string $finishMaterial): string { if ($partType === 'lbar') { return 'LA'; } if ($partType === 'reinforce') { return 'HH'; } if ($partType === 'extra') { return 'YY'; } // main: 재질 기반 $codePrefix = $this->extractCodePrefix($productCode); $isSteel = $codePrefix === 'KTE'; if ($isSteel) { return 'TS'; } $isSUS = in_array($codePrefix, ['KSS', 'KQTS']); return $isSUS ? 'BS' : 'BE'; } // ───────────────────────────────────────────────── // 셔터박스 // ───────────────────────────────────────────────── /** * 셔터박스 세부품목의 prefix 결정 * * CF/CL/CP/CB 품목은 모든 길이에 등록되어 있으므로 boxSize 무관하게 적용. * top_cover, fin_cover는 전용 품목 없이 XX(하부BASE/상부/마구리) 공용. * * @param string $partType 'front', 'lintel', 'inspection', 'rear_corner', 'top_cover', 'fin_cover' * @return string prefix */ public function resolveShutterBoxPrefix(string $partType): string { return self::SHUTTER_STANDARD[$partType] ?? 'XX'; } // ───────────────────────────────────────────────── // 연기차단재 // ───────────────────────────────────────────────── /** * 연기차단재 세부품목의 prefix 결정 (항상 GI) */ public function resolveSmokeBarrierPrefix(): string { return 'GI'; } // ───────────────────────────────────────────────── // 코드 생성 및 조회 // ───────────────────────────────────────────────── /** * prefix + 길이(mm) → BD-XX-NN 코드 생성 * * @param string $prefix LOT prefix (RS, RM, etc.) * @param int $lengthMm 길이 (mm) * @param string|null $smokeCategory 연기차단재 카테고리 ('w50', 'w80') * @return string|null BD 코드 (길이코드 변환 실패 시 null) */ public function buildItemCode(string $prefix, int $lengthMm, ?string $smokeCategory = null): ?string { $lengthCode = self::lengthToCode($lengthMm, $smokeCategory); if ($lengthCode === null) { return null; } return "BD-{$prefix}-{$lengthCode}"; } /** * BD-XX-NN 코드 → items.id 조회 (캐시) * * @return int|null items.id (미등록 시 null) */ public function resolveItemId(string $itemCode, int $tenantId = 287): ?int { $cacheKey = "{$tenantId}:{$itemCode}"; if (isset($this->itemIdCache[$cacheKey])) { return $this->itemIdCache[$cacheKey]; } $id = DB::table('items') ->where('tenant_id', $tenantId) ->where('code', $itemCode) ->whereNull('deleted_at') ->value('id'); $this->itemIdCache[$cacheKey] = $id; return $id; } /** * 길이(mm) → 길이코드 변환 * * @param int $lengthMm 길이 (mm) * @param string|null $smokeCategory 연기차단재 카테고리 ('w50', 'w80') * @return string|null 길이코드 (변환 불가 시 null) */ public static function lengthToCode(int $lengthMm, ?string $smokeCategory = null): ?string { // 연기차단재 전용 코드 if ($smokeCategory && isset(self::SMOKE_LENGTH_TO_CODE[$smokeCategory][$lengthMm])) { return self::SMOKE_LENGTH_TO_CODE[$smokeCategory][$lengthMm]; } return self::LENGTH_TO_CODE[$lengthMm] ?? null; } /** * 파트타입 한글명 반환 */ public static function partTypeName(string $partType): string { return self::PART_TYPE_NAMES[$partType] ?? $partType; } /** * 캐시 초기화 (테스트 용) */ public function clearCache(): void { $this->itemIdCache = []; } // ───────────────────────────────────────────────── // private // ───────────────────────────────────────────────── /** * 'KSS01' → 'KSS', 'KQTS01' → 'KQTS' 등 제품코드 prefix 추출 */ private function extractCodePrefix(string $productCode): string { return preg_replace('/\d+$/', '', $productCode); } }