feat: 견적 V2 동적 카테고리 시스템 구현

- CategoryService: tree 메서드에 code_group 필터 지원 추가
- FormulaEvaluatorService: 하드코딩된 process_type을 동적 카테고리로 변경
  - groupItemsByProcess(): item_category 필드 기반 그룹화
  - getItemCategoryTree(): DB에서 카테고리 트리 조회
  - buildCategoryMapping(): BENDING 하위 카테고리 처리
  - addProcessGroupToItems(): category_code 필드 추가 (레거시 호환 유지)
- QuoteItemCategorySeeder: 품목 카테고리 초기 데이터 시더 추가
  - BODY, BENDING(하위 3개), MOTOR_CTRL, ACCESSORY

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-01-27 15:17:30 +09:00
parent 4c22b74b27
commit 8a1e78ec72
3 changed files with 239 additions and 33 deletions

View File

@@ -0,0 +1,107 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
/**
* 견적 품목 카테고리 시더
*
* 상위 카테고리 추가 및 기존 세부 항목 연결
* - 본체, 절곡품(>가이드레일,케이스,하단마감재), 모터&제어기, 부자재
*/
class QuoteItemCategorySeeder extends Seeder
{
public function run(): void
{
$tenantId = 1;
$codeGroup = 'item_category';
$now = now();
// 1. 상위 카테고리 추가
$parentCategories = [
['code' => 'BODY', 'name' => '본체', 'sort_order' => 1],
['code' => 'BENDING', 'name' => '절곡품', 'sort_order' => 2],
['code' => 'MOTOR_CTRL', 'name' => '모터 & 제어기', 'sort_order' => 3],
['code' => 'ACCESSORY', 'name' => '부자재', 'sort_order' => 4],
];
$parentIds = [];
foreach ($parentCategories as $cat) {
$parentIds[$cat['code']] = DB::table('categories')->insertGetId([
'tenant_id' => $tenantId,
'parent_id' => null,
'code_group' => $codeGroup,
'code' => $cat['code'],
'name' => $cat['name'],
'sort_order' => $cat['sort_order'],
'is_active' => true,
'created_at' => $now,
'updated_at' => $now,
]);
}
// 2. 절곡품 하위 3개 중간 카테고리 추가
$bendingSubCategories = [
['code' => 'BENDING_GUIDE', 'name' => '가이드레일', 'sort_order' => 1],
['code' => 'BENDING_CASE', 'name' => '케이스', 'sort_order' => 2],
['code' => 'BENDING_BOTTOM', 'name' => '하단마감재', 'sort_order' => 3],
];
$bendingSubIds = [];
foreach ($bendingSubCategories as $cat) {
$bendingSubIds[$cat['code']] = DB::table('categories')->insertGetId([
'tenant_id' => $tenantId,
'parent_id' => $parentIds['BENDING'],
'code_group' => $codeGroup,
'code' => $cat['code'],
'name' => $cat['name'],
'sort_order' => $cat['sort_order'],
'is_active' => true,
'created_at' => $now,
'updated_at' => $now,
]);
}
// 3. 기존 세부 항목들의 parent_id 업데이트
$mappings = [
// 본체
'BODY' => ['SILICA_BODY', 'WIRE_BODY', 'FIBER_BODY', 'COLUMNLESS_BODY', 'SLAT_BODY'],
// 절곡품 > 가이드레일
'BENDING_GUIDE' => ['GUIDE_RAIL', 'SMOKE_SEAL'],
// 절곡품 > 케이스
'BENDING_CASE' => ['SHUTTER_BOX', 'TOP_COVER', 'END_PLATE'],
// 절곡품 > 하단마감재
'BENDING_BOTTOM' => ['BOTTOM_TRIM', 'HAJANG_BAR', 'SPECIAL_TRIM', 'FLOOR_CUT_PLATE'],
// 모터 & 제어기
'MOTOR_CTRL' => ['MOTOR_SET', 'INTERLOCK_CTRL', 'EMBED_BACK_BOX'],
// 부자재
'ACCESSORY' => ['JOINT_BAR', 'SQUARE_PIPE', 'WINDING_SHAFT', 'ANGLE', 'ROUND_BAR', 'L_BAR', 'REINF_FLAT_BAR', 'WEIGHT_FLAT_BAR'],
];
foreach ($mappings as $parentCode => $childCodes) {
// 상위 카테고리 ID 찾기
$parentId = $parentIds[$parentCode] ?? $bendingSubIds[$parentCode] ?? null;
if ($parentId) {
DB::table('categories')
->where('tenant_id', $tenantId)
->where('code_group', $codeGroup)
->whereIn('code', $childCodes)
->whereNull('deleted_at')
->update(['parent_id' => $parentId, 'updated_at' => $now]);
}
}
$this->command->info('견적 품목 카테고리 시딩 완료!');
$this->command->info('- 상위 카테고리 4개 추가');
$this->command->info('- 절곡품 하위 카테고리 3개 추가');
$this->command->info('- 기존 세부 항목 parent_id 연결 완료');
}
}