diff --git a/database/seeders/Kyungdong/KyungdongItemSeeder.php b/database/seeders/Kyungdong/KyungdongItemSeeder.php index 4136797..bce7a85 100644 --- a/database/seeders/Kyungdong/KyungdongItemSeeder.php +++ b/database/seeders/Kyungdong/KyungdongItemSeeder.php @@ -12,6 +12,8 @@ * Phase 1.0: chandj.KDunitprice (601건) → items, prices * Phase 1.1: chandj.models (18건) → items (FG), prices * Phase 1.2: chandj.item_list (9건) → items (PT), prices + * Phase 2.1: chandj.BDmodels.seconditem → items (PT) 누락 부품 추가 + * Phase 2.2: chandj.BDmodels → items.bom JSON (FG ↔ PT 연결) * * @see docs/plans/kd-items-migration-plan.md */ @@ -60,14 +62,21 @@ public function run(): void // Phase 1.2: item_list → items (PT) $itemListCount = $this->migrateItemList($tenantId, $userId); + // Phase 2.1: BDmodels.seconditem → items (PT) 누락 부품 + $bdPartsCount = $this->migrateBDmodelsParts($tenantId, $userId); + // prices 생성 (모든 items 기반) $priceCount = $this->migratePrices($tenantId, $userId); - $totalItems = $itemCount + $modelCount + $itemListCount; + // Phase 2.2: BDmodels → items.bom JSON + $bomCount = $this->migrateBom($tenantId); + + $totalItems = $itemCount + $modelCount + $itemListCount + $bdPartsCount; $this->command->info(''); $this->command->info('✅ 마이그레이션 완료:'); - $this->command->info(" → items: {$totalItems}건 (KDunitprice {$itemCount} + models {$modelCount} + item_list {$itemListCount})"); + $this->command->info(" → items: {$totalItems}건 (KDunitprice {$itemCount} + models {$modelCount} + item_list {$itemListCount} + BDmodels부품 {$bdPartsCount})"); $this->command->info(" → prices: {$priceCount}건"); + $this->command->info(" → BOM 연결: {$bomCount}건"); } /** @@ -382,4 +391,193 @@ private function mapItemType(?string $itemDiv): string { return self::ITEM_TYPE_MAP[$itemDiv] ?? 'SM'; } + + /** + * Phase 2.1: BDmodels.seconditem → items (PT) 누락 부품 추가 + * + * item_list에 없는 BDmodels.seconditem을 PT items로 생성 + */ + private function migrateBDmodelsParts(int $tenantId, int $userId): int + { + $this->command->info(''); + $this->command->info('📦 [Phase 2.1] BDmodels.seconditem → items (PT) 누락 부품...'); + + // BDmodels에서 고유한 seconditem 목록 조회 + $bdSecondItems = DB::connection('chandj') + ->table('BDmodels') + ->where(function ($q) { + $q->where('is_deleted', 0)->orWhereNull('is_deleted'); + }) + ->whereNotNull('seconditem') + ->where('seconditem', '!=', '') + ->distinct() + ->pluck('seconditem'); + + // 이미 존재하는 PT items 코드 조회 + $existingPtCodes = DB::table('items') + ->where('tenant_id', $tenantId) + ->where('item_type', 'PT') + ->pluck('code') + ->map(fn ($code) => str_starts_with($code, 'PT-') ? substr($code, 3) : $code) + ->toArray(); + + $items = []; + $now = now(); + + foreach ($bdSecondItems as $secondItem) { + // 이미 PT items에 있으면 스킵 + if (in_array($secondItem, $existingPtCodes)) { + continue; + } + + $code = "PT-{$secondItem}"; + + $items[] = [ + 'tenant_id' => $tenantId, + 'item_type' => 'PT', + 'code' => $code, + 'name' => $secondItem, + 'unit' => 'EA', + 'category_id' => null, + 'process_type' => null, + 'item_category' => null, + 'bom' => null, + 'attributes' => json_encode([ + 'legacy_source' => 'BDmodels_seconditem', + ]), + 'attributes_archive' => null, + 'options' => null, + 'description' => null, + 'is_active' => true, + 'created_by' => $userId, + 'updated_by' => $userId, + 'created_at' => $now, + 'updated_at' => $now, + ]; + } + + if (! empty($items)) { + DB::table('items')->insert($items); + } + + $this->command->info(" → 소스 데이터: {$bdSecondItems->count()}건 (중복 제외 ".count($items).'건 신규)'); + $this->command->info(' ✓ items (PT): '.count($items).'건 생성 완료'); + + return count($items); + } + + /** + * Phase 2.2: BDmodels → items.bom JSON (FG ↔ PT 연결) + * + * models 기반 FG items에 BOM 연결 + * bom: [{child_item_id: X, quantity: Y}, ...] + */ + private function migrateBom(int $tenantId): int + { + $this->command->info(''); + $this->command->info('🔗 [Phase 2.2] BDmodels → items.bom JSON 연결...'); + + // PT items 조회 (code → id 매핑) + $ptItems = DB::table('items') + ->where('tenant_id', $tenantId) + ->where('item_type', 'PT') + ->pluck('id', 'code') + ->toArray(); + + // PT- prefix 없는 버전도 매핑 추가 + $ptItemsByName = []; + foreach ($ptItems as $code => $id) { + $name = str_starts_with($code, 'PT-') ? substr($code, 3) : $code; + $ptItemsByName[$name] = $id; + } + + // FG items 조회 (models 기반) + $fgItems = DB::table('items') + ->where('tenant_id', $tenantId) + ->where('item_type', 'FG') + ->whereNotNull('attributes') + ->get(['id', 'code', 'attributes']); + + // BDmodels 데이터 조회 + $bdModels = DB::connection('chandj') + ->table('BDmodels') + ->where(function ($q) { + $q->where('is_deleted', 0)->orWhereNull('is_deleted'); + }) + ->whereNotNull('model_name') + ->where('model_name', '!=', '') + ->get(['model_name', 'seconditem', 'savejson']); + + // model_name → seconditems 그룹핑 + $modelBomMap = []; + foreach ($bdModels as $bd) { + if (empty($bd->seconditem)) { + continue; + } + + $modelName = $bd->model_name; + if (! isset($modelBomMap[$modelName])) { + $modelBomMap[$modelName] = []; + } + + // savejson에서 수량 파싱 (col8이 수량) + $quantity = 1; + if (! empty($bd->savejson)) { + $json = json_decode($bd->savejson, true); + if (is_array($json) && ! empty($json)) { + // 첫 번째 항목의 col8(수량) 사용 + $quantity = (int) ($json[0]['col8'] ?? 1); + } + } + + // 중복 체크 후 추가 + $found = false; + foreach ($modelBomMap[$modelName] as &$existing) { + if ($existing['seconditem'] === $bd->seconditem) { + $found = true; + break; + } + } + if (! $found) { + $modelBomMap[$modelName][] = [ + 'seconditem' => $bd->seconditem, + 'quantity' => $quantity, + ]; + } + } + + $updatedCount = 0; + + foreach ($fgItems as $fgItem) { + $attributes = json_decode($fgItem->attributes, true) ?? []; + $modelName = $attributes['model_name'] ?? null; + + if (empty($modelName) || ! isset($modelBomMap[$modelName])) { + continue; + } + + $bomArray = []; + foreach ($modelBomMap[$modelName] as $bomItem) { + $childItemId = $ptItemsByName[$bomItem['seconditem']] ?? null; + if ($childItemId) { + $bomArray[] = [ + 'child_item_id' => $childItemId, + 'quantity' => $bomItem['quantity'], + ]; + } + } + + if (! empty($bomArray)) { + DB::table('items') + ->where('id', $fgItem->id) + ->update(['bom' => json_encode($bomArray)]); + $updatedCount++; + } + } + + $this->command->info(' → BDmodels 모델: '.count($modelBomMap).'개'); + $this->command->info(" ✓ items.bom 연결: {$updatedCount}건 완료"); + + return $updatedCount; + } }