diff --git a/database/seeders/Kyungdong/KyungdongItemSeeder.php b/database/seeders/Kyungdong/KyungdongItemSeeder.php index bdcfc16..4136797 100644 --- a/database/seeders/Kyungdong/KyungdongItemSeeder.php +++ b/database/seeders/Kyungdong/KyungdongItemSeeder.php @@ -9,8 +9,9 @@ /** * 경동기업 품목/단가 마이그레이션 Seeder * - * 소스: chandj.KDunitprice (603건) - * 타겟: samdb.items, samdb.prices + * 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 * * @see docs/plans/kd-items-migration-plan.md */ @@ -28,6 +29,14 @@ class KyungdongItemSeeder extends Seeder '[무형상품]' => 'CS', ]; + /** + * finishing_type 약어 매핑 + */ + private const FINISHING_MAP = [ + 'SUS마감' => 'SUS', + 'EGI마감' => 'EGI', + ]; + /** * 경동기업 품목/단가 마이그레이션 실행 */ @@ -42,14 +51,23 @@ public function run(): void // 1. 기존 데이터 삭제 $this->cleanupExistingData($tenantId); - // 2. KDunitprice → items + // Phase 1.0: KDunitprice → items $itemCount = $this->migrateItems($tenantId, $userId); - // 3. items 기반 → prices + // Phase 1.1: models → items (FG) + $modelCount = $this->migrateModels($tenantId, $userId); + + // Phase 1.2: item_list → items (PT) + $itemListCount = $this->migrateItemList($tenantId, $userId); + + // prices 생성 (모든 items 기반) $priceCount = $this->migratePrices($tenantId, $userId); + $totalItems = $itemCount + $modelCount + $itemListCount; $this->command->info(''); - $this->command->info("✅ 마이그레이션 완료: items {$itemCount}건, prices {$priceCount}건"); + $this->command->info('✅ 마이그레이션 완료:'); + $this->command->info(" → items: {$totalItems}건 (KDunitprice {$itemCount} + models {$modelCount} + item_list {$itemListCount})"); + $this->command->info(" → prices: {$priceCount}건"); } /** @@ -148,11 +166,12 @@ private function migratePrices(int $tenantId, int $userId): int $this->command->info(''); $this->command->info('💰 items → prices 마이그레이션...'); - // 생성된 items와 KDunitprice 조인하여 prices 생성 + // 생성된 items 조회 $items = DB::table('items') ->where('tenant_id', $tenantId) - ->get(['id', 'code', 'item_type']); + ->get(['id', 'code', 'item_type', 'attributes']); + // KDunitprice 단가 (code → unitprice) $kdPrices = DB::connection('chandj') ->table('KDunitprice') ->whereNull('is_deleted') @@ -160,12 +179,31 @@ private function migratePrices(int $tenantId, int $userId): int ->where('prodcode', '!=', '') ->pluck('unitprice', 'prodcode'); + // item_list 단가 (item_name → col13) + $itemListPrices = DB::connection('chandj') + ->table('item_list') + ->pluck('col13', 'item_name'); + $prices = []; $now = now(); $batchCount = 0; foreach ($items as $item) { - $unitPrice = $kdPrices[$item->code] ?? 0; + $attributes = json_decode($item->attributes, true) ?? []; + $legacySource = $attributes['legacy_source'] ?? ''; + + // 소스별 단가 결정 + $unitPrice = match ($legacySource) { + 'KDunitprice' => $kdPrices[$item->code] ?? 0, + 'item_list' => $itemListPrices[$attributes['legacy_num'] ? $this->getItemListName($item->code) : ''] ?? $attributes['base_price'] ?? 0, + 'models' => 0, // models는 단가 없음 + default => 0, + }; + + // item_list의 경우 attributes에 저장된 base_price 사용 + if ($legacySource === 'item_list' && isset($attributes['base_price'])) { + $unitPrice = $attributes['base_price']; + } $prices[] = [ 'tenant_id' => $tenantId, @@ -182,7 +220,7 @@ private function migratePrices(int $tenantId, int $userId): int 'supplier' => null, 'effective_from' => now()->toDateString(), 'effective_to' => null, - 'note' => 'KDunitprice 마이그레이션', + 'note' => "{$legacySource} 마이그레이션", 'status' => 'active', 'is_final' => false, 'created_by' => $userId, @@ -211,6 +249,132 @@ private function migratePrices(int $tenantId, int $userId): int return $batchCount; } + /** + * PT-{name} 코드에서 name 추출 + */ + private function getItemListName(string $code): string + { + return str_starts_with($code, 'PT-') ? substr($code, 3) : ''; + } + + /** + * Phase 1.1: models → items (FG) 마이그레이션 + */ + private function migrateModels(int $tenantId, int $userId): int + { + $this->command->info(''); + $this->command->info('📦 [Phase 1.1] models → items (FG) 마이그레이션...'); + + $models = DB::connection('chandj') + ->table('models') + ->where(function ($q) { + $q->where('is_deleted', 0)->orWhereNull('is_deleted'); + }) + ->get(); + + $this->command->info(" → 소스 데이터: {$models->count()}건"); + + $items = []; + $now = now(); + + foreach ($models as $model) { + $finishingShort = self::FINISHING_MAP[$model->finishing_type] ?? 'STD'; + $code = "FG-{$model->model_name}-{$model->guiderail_type}-{$finishingShort}"; + $name = "{$model->model_name} {$model->major_category} {$model->finishing_type} {$model->guiderail_type}"; + + $items[] = [ + 'tenant_id' => $tenantId, + 'item_type' => 'FG', + 'code' => $code, + 'name' => trim($name), + 'unit' => 'EA', + 'category_id' => null, + 'process_type' => null, + 'item_category' => $model->major_category, + 'bom' => null, + 'attributes' => json_encode([ + 'model_name' => $model->model_name, + 'major_category' => $model->major_category, + 'finishing_type' => $model->finishing_type, + 'guiderail_type' => $model->guiderail_type, + 'legacy_source' => 'models', + 'legacy_model_id' => $model->model_id, + ]), + '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(" ✓ items (FG): {$models->count()}건 생성 완료"); + + return $models->count(); + } + + /** + * Phase 1.2: item_list → items (PT) 마이그레이션 + */ + private function migrateItemList(int $tenantId, int $userId): int + { + $this->command->info(''); + $this->command->info('📦 [Phase 1.2] item_list → items (PT) 마이그레이션...'); + + $itemList = DB::connection('chandj') + ->table('item_list') + ->get(); + + $this->command->info(" → 소스 데이터: {$itemList->count()}건"); + + $items = []; + $now = now(); + + foreach ($itemList as $item) { + $code = "PT-{$item->item_name}"; + + $items[] = [ + 'tenant_id' => $tenantId, + 'item_type' => 'PT', + 'code' => $code, + 'name' => $item->item_name, + 'unit' => 'EA', + 'category_id' => null, + 'process_type' => null, + 'item_category' => null, + 'bom' => null, + 'attributes' => json_encode([ + 'base_price' => $item->col13, + 'legacy_source' => 'item_list', + 'legacy_num' => $item->num, + ]), + '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(" ✓ items (PT): {$itemList->count()}건 생성 완료"); + + return $itemList->count(); + } + /** * item_div → item_type 매핑 */