feat: Items API에 group_id 파라미터 지원 추가

- common_codes에 item_group 추가 및 item_type parent_id 연결
- /api/v1/items?type=RM → 단일 품목 유형 조회
- /api/v1/items?group_id=103 → 그룹 전체 품목 조회 (FG,PT,SM,RM,CS)
- ItemService에 getItemTypesByGroupId(), newQueryForTypes() 메서드 추가
- 에러 메시지 추가 (item_type_or_group_required, invalid_group_id)
This commit is contained in:
2025-12-15 14:47:04 +09:00
parent aaf7979d5f
commit b1bcad3be6
4 changed files with 113 additions and 7 deletions

View File

@@ -27,6 +27,7 @@ public function index(Request $request)
'q' => $request->input('q') ?? $request->input('search'),
'category_id' => $request->input('category_id'),
'item_type' => $request->input('type') ?? $request->input('item_type'),
'group_id' => $request->input('group_id'),
'active' => $request->input('is_active') ?? $request->input('active'),
];

View File

@@ -79,6 +79,32 @@ private function newQuery(string $itemType)
->where('item_type', strtoupper($itemType));
}
/**
* group_id로 해당 그룹의 item_type 목록 조회
*
* @param int $groupId common_codes의 item_group id
* @return array item_type 코드 배열 ['FG', 'PT', 'SM', 'RM', 'CS']
*/
private function getItemTypesByGroupId(int $groupId): array
{
return \DB::table('common_codes')
->where('code_group', 'item_type')
->where('parent_id', $groupId)
->where('is_active', true)
->pluck('code')
->toArray();
}
/**
* 여러 item_type으로 Query Builder 생성
*/
private function newQueryForTypes(array $itemTypes)
{
return \App\Models\Items\Item::query()
->where('tenant_id', $this->tenantId())
->whereIn('item_type', array_map('strtoupper', $itemTypes));
}
/**
* items 테이블의 고정 컬럼 목록 조회 (SystemFields + ItemField 기반)
*/
@@ -252,7 +278,7 @@ protected function fetchCategoryTree(?int $parentId = null)
/**
* 목록/검색 (동적 테이블 라우팅)
*
* @param array $params 검색 파라미터 (item_type 필수)
* @param array $params 검색 파라미터 (item_type 또는 group_id 필수)
*/
public function index(array $params): LengthAwarePaginator
{
@@ -260,16 +286,27 @@ public function index(array $params): LengthAwarePaginator
$q = trim((string) ($params['q'] ?? $params['search'] ?? ''));
$categoryId = $params['category_id'] ?? null;
$itemType = $params['item_type'] ?? null;
$groupId = $params['group_id'] ?? null;
$active = $params['active'] ?? null;
// item_type 필수 검증
if (! $itemType) {
throw new BadRequestHttpException(__('error.item_type_required'));
// item_type 또는 group_id 필수 검증
if (! $itemType && ! $groupId) {
throw new BadRequestHttpException(__('error.item_type_or_group_required'));
}
// 동적 테이블 라우팅
$query = $this->newQuery($itemType)
->with(['category:id,name', 'details']);
// group_id로 조회 시 해당 그룹의 모든 item_type 조회
if ($groupId && ! $itemType) {
$itemTypes = $this->getItemTypesByGroupId((int) $groupId);
if (empty($itemTypes)) {
throw new BadRequestHttpException(__('error.invalid_group_id'));
}
$query = $this->newQueryForTypes($itemTypes)
->with(['category:id,name', 'details']);
} else {
// 단일 item_type 조회
$query = $this->newQuery($itemType)
->with(['category:id,name', 'details']);
}
// 검색어
if ($q !== '') {

View File

@@ -0,0 +1,66 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
/**
* common_codes에 item_group 추가 및 item_type과 연결
*
* 구조:
* - item_group (부모): code_group='item_group', code='ITEM', name='품목'
* - item_type (자식): parent_id로 item_group 연결
*/
return new class extends Migration
{
public function up(): void
{
// 1. item_group 추가 (품목 그룹)
$itemGroupId = DB::table('common_codes')->insertGetId([
'tenant_id' => 1,
'code_group' => 'item_group',
'code' => 'ITEM',
'name' => '품목',
'description' => '품목 관리 그룹 (FG, PT, SM, RM, CS)',
'is_active' => true,
'sort_order' => 1,
'created_at' => now(),
'updated_at' => now(),
]);
// 2. 기존 item_type의 parent_id를 item_group으로 연결
DB::table('common_codes')
->where('code_group', 'item_type')
->whereIn('code', ['FG', 'PT', 'SM', 'RM', 'CS'])
->update(['parent_id' => $itemGroupId]);
// 3. item_type의 attributes에서 source_table을 items로 통일
$itemTypes = DB::table('common_codes')
->where('code_group', 'item_type')
->whereIn('code', ['FG', 'PT', 'SM', 'RM', 'CS'])
->get();
foreach ($itemTypes as $itemType) {
$attributes = json_decode($itemType->attributes, true) ?? [];
$attributes['source_table'] = 'items';
DB::table('common_codes')
->where('id', $itemType->id)
->update(['attributes' => json_encode($attributes)]);
}
}
public function down(): void
{
// 1. item_type의 parent_id 초기화
DB::table('common_codes')
->where('code_group', 'item_type')
->whereIn('code', ['FG', 'PT', 'SM', 'RM', 'CS'])
->update(['parent_id' => null]);
// 2. item_group 삭제
DB::table('common_codes')
->where('code_group', 'item_group')
->where('code', 'ITEM')
->delete();
}
};

View File

@@ -112,7 +112,9 @@
'field_key_reserved' => '":field_key"은(는) 시스템 예약어로 사용할 수 없습니다.',
'bom_not_found' => 'BOM 항목을 찾을 수 없습니다.',
'item_type_required' => '품목 유형(item_type)은 필수입니다.',
'item_type_or_group_required' => '품목 유형(item_type) 또는 그룹 ID(group_id)는 필수입니다.',
'invalid_item_type' => '유효하지 않은 품목 유형입니다.',
'invalid_group_id' => '유효하지 않은 그룹 ID이거나 해당 그룹에 품목 유형이 없습니다.',
'invalid_source_table' => '품목 유형에 대한 소스 테이블이 설정되지 않았습니다.',
// 품목 관리 관련