feat: Phase 5.1-1 사용자 초대 + Phase 5.2 알림 설정 API 연동
- 사용자 초대 API: role 문자열 지원 추가 (React 호환) - 알림 설정 API: 그룹 기반 계층 구조 구현 - notification_setting_groups 테이블 추가 - notification_setting_group_items 테이블 추가 - notification_setting_group_states 테이블 추가 - GET/PUT /api/v1/settings/notifications 엔드포인트 추가 - Pint 코드 스타일 정리
This commit is contained in:
@@ -32,9 +32,9 @@ public function handle(): int
|
||||
$step = $this->option('step');
|
||||
$rollback = $this->option('rollback');
|
||||
|
||||
$this->info("=== 5130 → SAM 품목 마이그레이션 ===");
|
||||
$this->info('=== 5130 → SAM 품목 마이그레이션 ===');
|
||||
$this->info("Tenant ID: {$tenantId}");
|
||||
$this->info("Mode: " . ($dryRun ? 'DRY-RUN (시뮬레이션)' : 'LIVE'));
|
||||
$this->info('Mode: '.($dryRun ? 'DRY-RUN (시뮬레이션)' : 'LIVE'));
|
||||
$this->info("Step: {$step}");
|
||||
$this->newLine();
|
||||
|
||||
@@ -64,7 +64,7 @@ public function handle(): int
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
$this->info("=== 마이그레이션 완료 ===");
|
||||
$this->info('=== 마이그레이션 완료 ===');
|
||||
$this->showSummary();
|
||||
|
||||
return self::SUCCESS;
|
||||
@@ -82,7 +82,7 @@ private function loadExistingMappings(): void
|
||||
$this->idMappings[$key] = $mapping->item_id;
|
||||
}
|
||||
|
||||
$this->line("Loaded " . count($this->idMappings) . " existing mappings");
|
||||
$this->line('Loaded '.count($this->idMappings).' existing mappings');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,7 +90,7 @@ private function loadExistingMappings(): void
|
||||
*/
|
||||
private function migrateModels(int $tenantId, bool $dryRun): void
|
||||
{
|
||||
$this->info("Migrating models → items (FG)...");
|
||||
$this->info('Migrating models → items (FG)...');
|
||||
|
||||
$models = DB::connection('chandj')->table('models')
|
||||
->where('is_deleted', 0)
|
||||
@@ -107,6 +107,7 @@ private function migrateModels(int $tenantId, bool $dryRun): void
|
||||
// 이미 마이그레이션된 경우 스킵
|
||||
if (isset($this->idMappings[$mappingKey])) {
|
||||
$bar->advance();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -130,7 +131,7 @@ private function migrateModels(int $tenantId, bool $dryRun): void
|
||||
'updated_at' => $model->updated_at ?? now(),
|
||||
];
|
||||
|
||||
if (!$dryRun) {
|
||||
if (! $dryRun) {
|
||||
$itemId = DB::connection('mysql')->table('items')->insertGetId($itemData);
|
||||
|
||||
// 매핑 기록
|
||||
@@ -150,7 +151,7 @@ private function migrateModels(int $tenantId, bool $dryRun): void
|
||||
|
||||
$bar->finish();
|
||||
$this->newLine();
|
||||
$this->info("Models migration completed");
|
||||
$this->info('Models migration completed');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,7 +159,7 @@ private function migrateModels(int $tenantId, bool $dryRun): void
|
||||
*/
|
||||
private function migrateParts(int $tenantId, bool $dryRun): void
|
||||
{
|
||||
$this->info("Migrating parts → items (PT)...");
|
||||
$this->info('Migrating parts → items (PT)...');
|
||||
|
||||
$parts = DB::connection('chandj')->table('parts')
|
||||
->where('is_deleted', 0)
|
||||
@@ -174,6 +175,7 @@ private function migrateParts(int $tenantId, bool $dryRun): void
|
||||
|
||||
if (isset($this->idMappings[$mappingKey])) {
|
||||
$bar->advance();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -200,7 +202,7 @@ private function migrateParts(int $tenantId, bool $dryRun): void
|
||||
'updated_at' => $part->updated_at ?? now(),
|
||||
];
|
||||
|
||||
if (!$dryRun) {
|
||||
if (! $dryRun) {
|
||||
$itemId = DB::connection('mysql')->table('items')->insertGetId($itemData);
|
||||
|
||||
DB::connection('mysql')->table('item_id_mappings')->insert([
|
||||
@@ -219,7 +221,7 @@ private function migrateParts(int $tenantId, bool $dryRun): void
|
||||
|
||||
$bar->finish();
|
||||
$this->newLine();
|
||||
$this->info("Parts migration completed");
|
||||
$this->info('Parts migration completed');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,7 +229,7 @@ private function migrateParts(int $tenantId, bool $dryRun): void
|
||||
*/
|
||||
private function migratePartsSub(int $tenantId, bool $dryRun): void
|
||||
{
|
||||
$this->info("Migrating parts_sub → items (RM)...");
|
||||
$this->info('Migrating parts_sub → items (RM)...');
|
||||
|
||||
$partsSub = DB::connection('chandj')->table('parts_sub')
|
||||
->where('is_deleted', 0)
|
||||
@@ -243,6 +245,7 @@ private function migratePartsSub(int $tenantId, bool $dryRun): void
|
||||
|
||||
if (isset($this->idMappings[$mappingKey])) {
|
||||
$bar->advance();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -274,7 +277,7 @@ private function migratePartsSub(int $tenantId, bool $dryRun): void
|
||||
'updated_at' => $sub->updated_at ?? now(),
|
||||
];
|
||||
|
||||
if (!$dryRun) {
|
||||
if (! $dryRun) {
|
||||
$itemId = DB::connection('mysql')->table('items')->insertGetId($itemData);
|
||||
|
||||
DB::connection('mysql')->table('item_id_mappings')->insert([
|
||||
@@ -293,7 +296,7 @@ private function migratePartsSub(int $tenantId, bool $dryRun): void
|
||||
|
||||
$bar->finish();
|
||||
$this->newLine();
|
||||
$this->info("Parts_sub migration completed");
|
||||
$this->info('Parts_sub migration completed');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,7 +304,7 @@ private function migratePartsSub(int $tenantId, bool $dryRun): void
|
||||
*/
|
||||
private function migrateBDModels(int $tenantId, bool $dryRun): void
|
||||
{
|
||||
$this->info("Migrating BDmodels → items (PT + RM with BOM)...");
|
||||
$this->info('Migrating BDmodels → items (PT + RM with BOM)...');
|
||||
|
||||
$bdmodels = DB::connection('chandj')->table('BDmodels')
|
||||
->where('is_deleted', 0)
|
||||
@@ -320,6 +323,7 @@ private function migrateBDModels(int $tenantId, bool $dryRun): void
|
||||
// 이미 마이그레이션된 경우 스킵
|
||||
if (isset($this->idMappings[$mappingKey])) {
|
||||
$bar->advance();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -330,7 +334,7 @@ private function migrateBDModels(int $tenantId, bool $dryRun): void
|
||||
'tenant_id' => $tenantId,
|
||||
'item_type' => 'PT',
|
||||
'code' => $code,
|
||||
'name' => $bd->seconditem ?: $bd->model_name ?: "(이름없음)",
|
||||
'name' => $bd->seconditem ?: $bd->model_name ?: '(이름없음)',
|
||||
'unit' => 'EA',
|
||||
'description' => $bd->description,
|
||||
'attributes' => json_encode([
|
||||
@@ -353,7 +357,7 @@ private function migrateBDModels(int $tenantId, bool $dryRun): void
|
||||
|
||||
$parentItemId = null;
|
||||
|
||||
if (!$dryRun) {
|
||||
if (! $dryRun) {
|
||||
$parentItemId = DB::connection('mysql')->table('items')->insertGetId($itemData);
|
||||
|
||||
DB::connection('mysql')->table('item_id_mappings')->insert([
|
||||
@@ -368,7 +372,7 @@ private function migrateBDModels(int $tenantId, bool $dryRun): void
|
||||
}
|
||||
|
||||
// savejson → 자식 items (RM: 원자재) + 관계
|
||||
if (!empty($bd->savejson)) {
|
||||
if (! empty($bd->savejson)) {
|
||||
$bomItems = json_decode($bd->savejson, true);
|
||||
|
||||
if (is_array($bomItems)) {
|
||||
@@ -383,8 +387,8 @@ private function migrateBDModels(int $tenantId, bool $dryRun): void
|
||||
|
||||
// col1: 품명, col2: 재질, col3: 여유, col4: 전개, col5: 합계
|
||||
// col6: 단가, col7: 금액, col8: 수량, col9: 총액, col10: 비고
|
||||
$childName = $bomItem['col1'] ?? "(BOM항목)";
|
||||
$childCode = $this->generateCode('RM', $childName . "_" . $bd->num . "_" . $orderNo);
|
||||
$childName = $bomItem['col1'] ?? '(BOM항목)';
|
||||
$childCode = $this->generateCode('RM', $childName.'_'.$bd->num.'_'.$orderNo);
|
||||
|
||||
$childData = [
|
||||
'tenant_id' => $tenantId,
|
||||
@@ -412,7 +416,7 @@ private function migrateBDModels(int $tenantId, bool $dryRun): void
|
||||
'updated_at' => now(),
|
||||
];
|
||||
|
||||
if (!$dryRun) {
|
||||
if (! $dryRun) {
|
||||
$childItemId = DB::connection('mysql')->table('items')->insertGetId($childData);
|
||||
|
||||
// BOM 항목은 item_id_mappings에 저장하지 않음
|
||||
@@ -460,10 +464,10 @@ private function migrateBDModels(int $tenantId, bool $dryRun): void
|
||||
*/
|
||||
private function migrateRelations(int $tenantId, bool $dryRun): void
|
||||
{
|
||||
$this->info("Migrating relations → entity_relationships...");
|
||||
$this->info('Migrating relations → entity_relationships...');
|
||||
|
||||
// 1. models ↔ parts 관계
|
||||
$this->info(" → models ↔ parts relations...");
|
||||
$this->info(' → models ↔ parts relations...');
|
||||
$parts = DB::connection('chandj')->table('parts')
|
||||
->where('is_deleted', 0)
|
||||
->get();
|
||||
@@ -473,7 +477,7 @@ private function migrateRelations(int $tenantId, bool $dryRun): void
|
||||
$parentKey = "models:{$part->model_id}";
|
||||
$childKey = "parts:{$part->part_id}";
|
||||
|
||||
if (!isset($this->idMappings[$parentKey]) || !isset($this->idMappings[$childKey])) {
|
||||
if (! isset($this->idMappings[$parentKey]) || ! isset($this->idMappings[$childKey])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -485,7 +489,7 @@ private function migrateRelations(int $tenantId, bool $dryRun): void
|
||||
->where('child_id', $this->idMappings[$childKey])
|
||||
->exists();
|
||||
|
||||
if (!$exists && !$dryRun) {
|
||||
if (! $exists && ! $dryRun) {
|
||||
DB::connection('mysql')->table('entity_relationships')->insert([
|
||||
'tenant_id' => $tenantId,
|
||||
'group_id' => 1,
|
||||
@@ -508,7 +512,7 @@ private function migrateRelations(int $tenantId, bool $dryRun): void
|
||||
$this->line(" Created {$relCount} model-part relations");
|
||||
|
||||
// 2. parts ↔ parts_sub 관계
|
||||
$this->info(" → parts ↔ parts_sub relations...");
|
||||
$this->info(' → parts ↔ parts_sub relations...');
|
||||
$partsSub = DB::connection('chandj')->table('parts_sub')
|
||||
->where('is_deleted', 0)
|
||||
->get();
|
||||
@@ -518,7 +522,7 @@ private function migrateRelations(int $tenantId, bool $dryRun): void
|
||||
$parentKey = "parts:{$sub->part_id}";
|
||||
$childKey = "parts_sub:{$sub->subpart_id}";
|
||||
|
||||
if (!isset($this->idMappings[$parentKey]) || !isset($this->idMappings[$childKey])) {
|
||||
if (! isset($this->idMappings[$parentKey]) || ! isset($this->idMappings[$childKey])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -530,7 +534,7 @@ private function migrateRelations(int $tenantId, bool $dryRun): void
|
||||
->where('child_id', $this->idMappings[$childKey])
|
||||
->exists();
|
||||
|
||||
if (!$exists && !$dryRun) {
|
||||
if (! $exists && ! $dryRun) {
|
||||
DB::connection('mysql')->table('entity_relationships')->insert([
|
||||
'tenant_id' => $tenantId,
|
||||
'group_id' => 1,
|
||||
@@ -552,7 +556,7 @@ private function migrateRelations(int $tenantId, bool $dryRun): void
|
||||
}
|
||||
$this->line(" Created {$relCount} part-subpart relations");
|
||||
|
||||
$this->info("Relations migration completed");
|
||||
$this->info('Relations migration completed');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -560,10 +564,11 @@ private function migrateRelations(int $tenantId, bool $dryRun): void
|
||||
*/
|
||||
private function rollbackMigration(int $tenantId, bool $dryRun): int
|
||||
{
|
||||
$this->warn("=== 롤백 모드 ===");
|
||||
$this->warn('=== 롤백 모드 ===');
|
||||
|
||||
if (!$this->confirm('5130에서 마이그레이션된 모든 데이터를 삭제하시겠습니까?')) {
|
||||
if (! $this->confirm('5130에서 마이그레이션된 모든 데이터를 삭제하시겠습니까?')) {
|
||||
$this->info('롤백 취소됨');
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
@@ -573,7 +578,7 @@ private function rollbackMigration(int $tenantId, bool $dryRun): int
|
||||
->whereRaw("JSON_EXTRACT(metadata, '$.source') = '5130'")
|
||||
->count();
|
||||
|
||||
if (!$dryRun) {
|
||||
if (! $dryRun) {
|
||||
DB::connection('mysql')->table('entity_relationships')
|
||||
->where('tenant_id', $tenantId)
|
||||
->whereRaw("JSON_EXTRACT(metadata, '$.source') = '5130'")
|
||||
@@ -585,20 +590,21 @@ private function rollbackMigration(int $tenantId, bool $dryRun): int
|
||||
$mappings = DB::connection('mysql')->table('item_id_mappings')->get();
|
||||
$itemIds = $mappings->pluck('item_id')->toArray();
|
||||
|
||||
if (!$dryRun && !empty($itemIds)) {
|
||||
if (! $dryRun && ! empty($itemIds)) {
|
||||
DB::connection('mysql')->table('items')
|
||||
->whereIn('id', $itemIds)
|
||||
->delete();
|
||||
}
|
||||
$this->line("Deleted " . count($itemIds) . " items");
|
||||
$this->line('Deleted '.count($itemIds).' items');
|
||||
|
||||
// 3. item_id_mappings 삭제
|
||||
if (!$dryRun) {
|
||||
if (! $dryRun) {
|
||||
DB::connection('mysql')->table('item_id_mappings')->truncate();
|
||||
}
|
||||
$this->line("Cleared item_id_mappings");
|
||||
$this->line('Cleared item_id_mappings');
|
||||
|
||||
$this->info('롤백 완료');
|
||||
|
||||
$this->info("롤백 완료");
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
@@ -608,7 +614,7 @@ private function rollbackMigration(int $tenantId, bool $dryRun): int
|
||||
private function generateCode(string $prefix, ?string $name): string
|
||||
{
|
||||
if (empty($name)) {
|
||||
return $prefix . '-' . Str::random(8);
|
||||
return $prefix.'-'.Str::random(8);
|
||||
}
|
||||
|
||||
// 한글은 유지, 특수문자 제거, 공백→언더스코어
|
||||
@@ -616,7 +622,7 @@ private function generateCode(string $prefix, ?string $name): string
|
||||
$code = preg_replace('/\s+/', '_', trim($code));
|
||||
$code = Str::upper($code);
|
||||
|
||||
return $prefix . '-' . Str::limit($code, 50, '');
|
||||
return $prefix.'-'.Str::limit($code, 50, '');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -629,6 +635,7 @@ private function parseNumber(?string $value): ?float
|
||||
}
|
||||
|
||||
$cleaned = preg_replace('/[^\d.-]/', '', $value);
|
||||
|
||||
return is_numeric($cleaned) ? (float) $cleaned : null;
|
||||
}
|
||||
|
||||
@@ -641,11 +648,11 @@ private function showSummary(): void
|
||||
$this->table(
|
||||
['Source Table', 'Migrated Count'],
|
||||
[
|
||||
['models', count(array_filter(array_keys($this->idMappings), fn($k) => str_starts_with($k, 'models:')))],
|
||||
['parts', count(array_filter(array_keys($this->idMappings), fn($k) => str_starts_with($k, 'parts:') && !str_starts_with($k, 'parts_sub:')))],
|
||||
['parts_sub', count(array_filter(array_keys($this->idMappings), fn($k) => str_starts_with($k, 'parts_sub:')))],
|
||||
['BDmodels', count(array_filter(array_keys($this->idMappings), fn($k) => str_starts_with($k, 'BDmodels:') && !str_starts_with($k, 'BDmodels_bom:')))],
|
||||
['BDmodels_bom', count(array_filter(array_keys($this->idMappings), fn($k) => str_starts_with($k, 'BDmodels_bom:')))],
|
||||
['models', count(array_filter(array_keys($this->idMappings), fn ($k) => str_starts_with($k, 'models:')))],
|
||||
['parts', count(array_filter(array_keys($this->idMappings), fn ($k) => str_starts_with($k, 'parts:') && ! str_starts_with($k, 'parts_sub:')))],
|
||||
['parts_sub', count(array_filter(array_keys($this->idMappings), fn ($k) => str_starts_with($k, 'parts_sub:')))],
|
||||
['BDmodels', count(array_filter(array_keys($this->idMappings), fn ($k) => str_starts_with($k, 'BDmodels:') && ! str_starts_with($k, 'BDmodels_bom:')))],
|
||||
['BDmodels_bom', count(array_filter(array_keys($this->idMappings), fn ($k) => str_starts_with($k, 'BDmodels_bom:')))],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user