From c7b2e97189c048073a9da9de3293860743dd7c54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Wed, 28 Jan 2026 19:22:18 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EA=B2=BD=EB=8F=99=EA=B8=B0=EC=97=85=20?= =?UTF-8?q?=ED=92=88=EB=AA=A9/=EB=8B=A8=EA=B0=80=20=EB=A7=88=EC=9D=B4?= =?UTF-8?q?=EA=B7=B8=EB=A0=88=EC=9D=B4=EC=85=98=20Seeder=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(Phase=201.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - KyungdongItemSeeder.php 생성 - chandj.KDunitprice → samdb.items, prices 마이그레이션 - is_deleted=NULL 조건 반영 (레거시 데이터 특성) Co-Authored-By: Claude --- .../seeders/Kyungdong/KyungdongItemSeeder.php | 221 ++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 database/seeders/Kyungdong/KyungdongItemSeeder.php diff --git a/database/seeders/Kyungdong/KyungdongItemSeeder.php b/database/seeders/Kyungdong/KyungdongItemSeeder.php new file mode 100644 index 0000000..bdcfc16 --- /dev/null +++ b/database/seeders/Kyungdong/KyungdongItemSeeder.php @@ -0,0 +1,221 @@ + 'FG', + '[상품]' => 'FG', + '[반제품]' => 'PT', + '[부재료]' => 'SM', + '[원재료]' => 'RM', + '[무형상품]' => 'CS', + ]; + + /** + * 경동기업 품목/단가 마이그레이션 실행 + */ + public function run(): void + { + $tenantId = DummyDataSeeder::TENANT_ID; + $userId = DummyDataSeeder::USER_ID; + + $this->command->info('🚀 경동기업 품목/단가 마이그레이션 시작...'); + $this->command->info(" 대상 테넌트: ID {$tenantId}"); + + // 1. 기존 데이터 삭제 + $this->cleanupExistingData($tenantId); + + // 2. KDunitprice → items + $itemCount = $this->migrateItems($tenantId, $userId); + + // 3. items 기반 → prices + $priceCount = $this->migratePrices($tenantId, $userId); + + $this->command->info(''); + $this->command->info("✅ 마이그레이션 완료: items {$itemCount}건, prices {$priceCount}건"); + } + + /** + * 기존 데이터 삭제 (tenant_id 기준) + */ + private function cleanupExistingData(int $tenantId): void + { + $this->command->info(''); + $this->command->info('🧹 기존 데이터 삭제 중...'); + + // prices 먼저 삭제 (FK 관계) + $priceCount = DB::table('prices')->where('tenant_id', $tenantId)->count(); + DB::table('prices')->where('tenant_id', $tenantId)->delete(); + $this->command->info(" → prices: {$priceCount}건 삭제"); + + // items 삭제 + $itemCount = DB::table('items')->where('tenant_id', $tenantId)->count(); + DB::table('items')->where('tenant_id', $tenantId)->delete(); + $this->command->info(" → items: {$itemCount}건 삭제"); + } + + /** + * KDunitprice → items 마이그레이션 + */ + private function migrateItems(int $tenantId, int $userId): int + { + $this->command->info(''); + $this->command->info('📦 KDunitprice → items 마이그레이션...'); + + // chandj.KDunitprice에서 데이터 조회 (is_deleted=NULL이 활성 상태) + $kdItems = DB::connection('chandj') + ->table('KDunitprice') + ->whereNull('is_deleted') + ->whereNotNull('prodcode') + ->where('prodcode', '!=', '') + ->get(); + + $this->command->info(" → 소스 데이터: {$kdItems->count()}건"); + + $items = []; + $now = now(); + $batchCount = 0; + + foreach ($kdItems as $kd) { + $items[] = [ + 'tenant_id' => $tenantId, + 'item_type' => $this->mapItemType($kd->item_div), + 'code' => $kd->prodcode, + 'name' => $kd->item_name, + 'unit' => $kd->unit, + 'category_id' => null, + 'process_type' => null, + 'item_category' => null, + 'bom' => null, + 'attributes' => json_encode([ + 'spec' => $kd->spec, + 'item_div' => $kd->item_div, + 'legacy_source' => 'KDunitprice', + 'legacy_num' => $kd->num, + ]), + 'attributes_archive' => null, + 'options' => null, + 'description' => null, + 'is_active' => true, + 'created_by' => $userId, + 'updated_by' => $userId, + 'created_at' => $now, + 'updated_at' => $now, + ]; + + // 500건씩 배치 INSERT + if (count($items) >= 500) { + DB::table('items')->insert($items); + $batchCount += count($items); + $this->command->info(" → {$batchCount}건 완료..."); + $items = []; + } + } + + // 남은 데이터 INSERT + if (! empty($items)) { + DB::table('items')->insert($items); + $batchCount += count($items); + } + + $this->command->info(" ✓ items: {$batchCount}건 생성 완료"); + + return $batchCount; + } + + /** + * items 기반 → prices 마이그레이션 + */ + private function migratePrices(int $tenantId, int $userId): int + { + $this->command->info(''); + $this->command->info('💰 items → prices 마이그레이션...'); + + // 생성된 items와 KDunitprice 조인하여 prices 생성 + $items = DB::table('items') + ->where('tenant_id', $tenantId) + ->get(['id', 'code', 'item_type']); + + $kdPrices = DB::connection('chandj') + ->table('KDunitprice') + ->whereNull('is_deleted') + ->whereNotNull('prodcode') + ->where('prodcode', '!=', '') + ->pluck('unitprice', 'prodcode'); + + $prices = []; + $now = now(); + $batchCount = 0; + + foreach ($items as $item) { + $unitPrice = $kdPrices[$item->code] ?? 0; + + $prices[] = [ + 'tenant_id' => $tenantId, + 'item_type_code' => $item->item_type, + 'item_id' => $item->id, + 'client_group_id' => null, + 'purchase_price' => 0, + 'processing_cost' => null, + 'loss_rate' => null, + 'margin_rate' => null, + 'sales_price' => $unitPrice, + 'rounding_rule' => 'round', + 'rounding_unit' => 1, + 'supplier' => null, + 'effective_from' => now()->toDateString(), + 'effective_to' => null, + 'note' => 'KDunitprice 마이그레이션', + 'status' => 'active', + 'is_final' => false, + 'created_by' => $userId, + 'updated_by' => $userId, + 'created_at' => $now, + 'updated_at' => $now, + ]; + + // 500건씩 배치 INSERT + if (count($prices) >= 500) { + DB::table('prices')->insert($prices); + $batchCount += count($prices); + $this->command->info(" → {$batchCount}건 완료..."); + $prices = []; + } + } + + // 남은 데이터 INSERT + if (! empty($prices)) { + DB::table('prices')->insert($prices); + $batchCount += count($prices); + } + + $this->command->info(" ✓ prices: {$batchCount}건 생성 완료"); + + return $batchCount; + } + + /** + * item_div → item_type 매핑 + */ + private function mapItemType(?string $itemDiv): string + { + return self::ITEM_TYPE_MAP[$itemDiv] ?? 'SM'; + } +}